Merge branch 'master' into review

pull/1990/head
Kim Kulling 2018-06-16 09:10:41 +02:00 committed by GitHub
commit 3e45acbf4e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
281 changed files with 10818 additions and 3554 deletions

3
.gitignore vendored
View File

@ -12,6 +12,8 @@ build
bin/ bin/
lib/ lib/
# QtCreator
CMakeLists.txt.user
# Generated # Generated
assimp.pc assimp.pc
@ -38,6 +40,7 @@ tools/assimp_cmd/Makefile
# Tests # Tests
test/results test/results
test/readlinetest*
# Python # Python
__pycache__ __pycache__

258
CHANGES
View File

@ -1,6 +1,264 @@
---------------------------------------------------------------------- ----------------------------------------------------------------------
CHANGELOG CHANGELOG
---------------------------------------------------------------------- ----------------------------------------------------------------------
4.1.0 (2017-12):
- FEATURES:
- Export 3MF ( experimental )
- Import / Export glTF 2
- Introduce new zib-lib to eb able to export zip-archives
- FIXES/HOUSEKEEPING:
- Added missing include to stdlib.h and remove load library call
- Fix install for builds with MSVC compiler and NMake.
- Update list of supported file formats.
- Add TriLib to the official list of supported ports.
- Re-enabling PACK_STRUCT for MDL files.
- Use std.::unique_ptr
- Update D3MFExporter.h
- Update MD3Loader.cpp, using index
- Fix all warnings on MSVC14
- Copy assimp dll to unit folder on windows
- Update jvm port supported formats
- Add support for building Mac OS X Framework bundles
- Check for nullptr dereferencing before copying scene data
- Update ValidateDataStructure.h, typo
- Enable data structure validation in cases where it doesn't cause failures
- Remove some dead assignments
- fast_atof: Silence some uninitialized variable warnings
- Check for area test if the face is a triangle.
- Set mNumUVComponents to 0 when deleting texture coordinate sets
- Only scale the root node because this will rescale all children nodes as well.
- Issue 1514: Fix frame pointer arithmetic
- Prevent failing stringstream to crash the export process
- powf -> pow
- add Defines.h to include folder for install.
- Android:
- Fix android build
- Fix assimp for cross compile for android
- Use define for D_FILE_OFFSET_BITS only for not-android systems.
- FBX:
- Fix handling with embedded textures
- FBX 7500 Binary reading
- Remove dead assignment
- Fix export of deleted meshes; Add LazyDict::Remove method
- Log an error instead of letting the fbx-importer crash. ( issue 213 )
- Replace bad pointer casting with memcpy
- Remove useless const qualifier from return value
- Add explicit instantiation of log_prefix so other FBX source files can see it
- add missing inversion of postrotation matrix for fbx.
- FIReader: Silence uninitialized variable warning
- Update version check in FBX reader to check for version >= 7500
- Use actual min/max of anim keys when start/stop time is missing
- GLTF1:
- Fix output of glTF 1 version string
- Fix delete / delete[] mismatch in glTFAsset
- Don’t ignore rgba(1,1,1,1) color properties
- glTF2 primitives fixes
- Don’t ignore rgba(1,1,1,1) color properties
- Fix delete / delete[] mismatch in glTFAsset
- Remove KHR_binary_glTF code
- glTF nodes can only hold one mesh. this simply assigns to and check’s a Node’s Mesh
- version in glb header is stored as uint32_t
- GLTF2:
- node name conflict fix
- Fix transform matrices multiplication order
- Preserve node names when importing
- Add support for tangents in import
- Fix typo on gltf2 camera parameters
- Moved byteStride from accessor to bufferView
- Implemented reading binary glTF2 (glb) files
- Fix signed/unsigned warning
- Add postprocess step for scaling
- Fix shininess to roughness conversion
- Prefer “BLEND” over “MASK” as an alphaMode default
- Approximate specularity / glossiness in metallicRoughness materials
- Diffuse color and diffuse texture import and export improvements
- Addressed some mismatched news/deletes caused by the new glTF2 sources.
- Fix delete / delete[] mismatches in glTF2 importer
- use correct name of exporter to gltf2
- Fix possible infinite loop when exporting to gltf2
- Fix glTF2::Asset::FindUniqueID() when the input string is >= 256 chars
- Fix glTF2 alphaMode storage and reading
- Fix glTF 2.0 multi-primitive support
- Load gltf .bin files from correct directory
- Add support for importing both glTF and glTF2 files
- ampler improvements; Add new LazyDict method
- Changes to GLTF2 materials
- Remove Light, Technique references
- Start removing materials common, and adding pbrSpecularGlossiness
- Use !ObjectEmpty() vs. MemberCount() > 0
- Working read, import, export, and write of gltf2 (pbr) material
- Check in gltf2 models to test directory
- Remove un-needed test models
- Start managing and importing gltf2 pbr materials
- Update glTF2 Asset to use indexes
- Duplicate gltfImporter as gltf2Importer; Include glTF2 importer in CMake List
- glTF2: Fix animation export
- use opacity for diffuse alpha + alphaMode
- STL:
- Restore import of multi mesh binary STLs
- Blender:
- Silence warning about uninitialized member
- MDLImporter:
- Don't take address of packed struct member
- assimp_cmd:
- Fix strict-aliasing warnings
- Open3DGC:
- Fix strict-aliasing warnings
- Add assertions to silence static analyzer warnings
- Remove redundant const qualifiers from return types
- Fix some uninitialized variable warnings
- Remove OPEN3DGC and compression references
- unzip:
- Remove dead assignment
- Bail on bad compression method
- Fix possibly uninitialized variables
- clipper:
- Add assertion to silence a static analyzer warning
- OpenDDLExport:
- Reduce scope of a variable
- Remove dead variable
- Remove dead assignment
- Fix another potential memory leak
- X3DImporter:
- Add assertions to silence static analyzer warnings
- Add missing unittest
- Workaround for buggy Android NDK (issue #1361)
- TerragenLoader:
- Remove unused variable
- SIBImporter:
- Add assertions to silence static analyzer warnings
- IFC:
- Remove dead code
- Add explicit instantiation of log_prefix so IFCMaterial.cpp can see it
- PLY:
- Remove dead assignment and reduce scope of a variable
- fix vertex attribute lookup.
- OpenGEX:
- Add assertion to silence a static analyzer warning
- Fix for TextureFile with number in file name
- Return early when element is TextureFile
- NFF:
- Add assertions to silence static analyzer warnings
- Split up some complicated assignments
- Raw: Fix misleading indentation warning
- Reduce scope of a variable
- LWO
- Reduce scope of a variable
- IRRLoader:
- Fix confusing boolean casting
- AssbinExporter:
- Add assertion to silence a static analyzer warning
- ASE:
- Add assertion to silence a static analyzer warning
- AMFImporter:
- Add assertion to silence a static analyzer warning
- Add a block
- OptimizeGraph:
- Fix possible null pointer dereference
- RemoveRedundantMaterials:
- Add assertion to silence a static analyzer warning
- ImproveCacheLocality:
- Add assertion to silence a static analyzer warning
- RemoveRedundantMaterials:
- Set pointer to nullptr after deleting it
- Travis:
- Disable unit tests in scan-build config
- Move slower builds earlier to improve parallelization
- Add static analysis to build
- Remove unused branch rule for travis.
- Add Clang UBSan build configuration
- Treat warnings as errors, without typos this time
- Unittests:
- Add VS-based source groups for the unittests.
- Collada:
- export <library_animations> tag
- Update ColladaExporter.cpp
- Silence uninitialized variable warning
- Add support for line strip primitives
- Obj Wavefront:
- check in exporting against out-of-bounds-access .
- Issue 1351: use correct name for obj-meshname export for groups.
- fix mem-lead: face will be not released in case of an error.
- Anatoscope obj exporter nomtl
- Raise exception when obj file contains invalid face indices
- Added alternative displacement texture token in OBJ MTL material.
- Obj: rename attribute from exporter.
- Fix OBJ discarding all material names if the material library is missing
- Step:
- use correct lookup for utf32
- MD2:
- Fix MD2 frames containing garbage
- STL
- add missing const.
- Fix memory-alignment bug.
- Fix issue 104: deal with more solids in one STL file.
- CMake
- Fix issue 213: use correct include folder for assimp
- Doxygen
- Fix issue 1513: put irrXML onto exclucde list for doxygen run
- PyAssimp:
- Search for libassimp.so in LD_LIBRARY_PATH if available.
- Fix operator precedence issue in header check
- Split setup.py into multiple lines
- Detect if Anaconda and fixed 3d_viewer for Python 3
- created a python3 version of the 3dviewer and fixed the / = float in py3
- Blender:
- Fix invalid access to mesh array when the array is empty.
- Fix short overflow.
- Silence warning about inline function which is declared but not defined
- JAssimp
- Changed license header for IHMC contributions from Apache 2.0 to BSD
- Add Node metadata to the Jassmip Java API
- Added supported for custom IO Systems in Java. Implemented ClassLoader IO System
- Added a link to pure jvm assimp port
- Clang sanitizer:
- Undefined Behavior sanitizer
- Fixed a divide by zero error in IFCBoolean that was latent, but nevertheless a bug
- B3DImporter:
- Replace bad pointer casting with memcpy
- AppVeyor:
- Cleanup and Addition of VS 2017 and running Tests
- Fixed File Size reported as 0 in tests that use temporary files
- x86 isn't a valid VS platform. Win32 it is, then.
- Replaced the worker image name, which doesn't work as generator name, with a manually created generator name.
- Cleaned up appveyor setup, added VS 2017 to the build matrix and attempted to add running of tests.
- Treat warnings as errors on Appveyor
- Disable warning 4351 on MSVC 2013
- OpenGEXImporter:
- Copy materials to scene
- Store RefInfo in unique_ptr so they get automatically cleaned up
- Fix IOStream leak
- Store ChildInfo in unique_ptr so they get automatically cleaned up
- improve logging to be able to detect error-prone situations.
- AMFImporter:
- Fix memory leak
- UnrealLoader:
- Fix IOStream leak
- Upgrade RapidJSON to get rid of a clang warning
- zlib:
- Update zlib contribution
- Removed unnecessary files from zlib contribution
- Replaced unsigned long for the crc table to z_crc_t, to match what is returned by get-crc_table
- MakeVerboseFormat:
- Fix delete / delete[] mismatches in MakeVerboseFormat
- MaterialSystem:
- Fix out-of-bounds read in MaterialSystem unit test
- SIB:
- Added support for SIB models from Silo 2.5
- AssbinExporter:
- Fix strict aliasing violation
- Add Write specialization for aiColor3D
- DefaultLogger:
- Whitespace cleanup to fix GCC misleading indentation warning
- MDP:
- Fix encoding issues.
- PreTransformVertices:
- fix name lost in mesh and nodes when load with flag
- C4D:
- Fixes for C4D importer
- Unzip:
- Latest greatest.
4.0.1 (2017-07-28) 4.0.1 (2017-07-28)
- FIXES/HOUSEKEEPING: - FIXES/HOUSEKEEPING:
- fix version test. - fix version test.

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
@ -162,7 +160,7 @@ EXECUTE_PROCESS(
) )
IF(NOT GIT_COMMIT_HASH) IF(NOT GIT_COMMIT_HASH)
SET(GIT_COMMIT_HASH 0) SET(GIT_COMMIT_HASH 0)
ENDIF(NOT GIT_COMMIT_HASH) ENDIF(NOT GIT_COMMIT_HASH)
IF(ASSIMP_DOUBLE_PRECISION) IF(ASSIMP_DOUBLE_PRECISION)
@ -180,10 +178,10 @@ CONFIGURE_FILE(
) )
INCLUDE_DIRECTORIES( INCLUDE_DIRECTORIES(
./ ./
include include
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}/include ${CMAKE_CURRENT_BINARY_DIR}/include
) )
LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules" ) LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules" )
@ -193,14 +191,6 @@ SET(CPACK_COMPONENTS_ALL assimp-bin ${LIBASSIMP_COMPONENT} ${LIBASSIMP-DEV_COMPO
SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names") SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names")
IF( UNIX ) IF( UNIX )
# Ensure that we do not run into issues like http://www.tcm.phy.cam.ac.uk/sw/inodes64.html on 32 bit linux
IF( ${OPERATING_SYSTEM} MATCHES "Android")
ELSE()
IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit linux
#ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 )
ENDIF()
ENDIF()
# Use GNUInstallDirs for Unix predefined directories # Use GNUInstallDirs for Unix predefined directories
INCLUDE(GNUInstallDirs) INCLUDE(GNUInstallDirs)
ENDIF( UNIX ) ENDIF( UNIX )
@ -213,13 +203,13 @@ IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW)
SET(LIBSTDC++_LIBRARIES -lstdc++) SET(LIBSTDC++_LIBRARIES -lstdc++)
ELSEIF(MSVC) ELSEIF(MSVC)
# enable multi-core compilation with MSVC # enable multi-core compilation with MSVC
add_compile_options(/MP) ADD_COMPILE_OPTIONS(/MP)
if("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)") IF("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
add_compile_options( /bigobj ) ADD_COMPILE_OPTIONS( /bigobj )
endif() ENDIF()
# disable "elements of array '' will be default initialized" warning on MSVC2013 # disable "elements of array '' will be default initialized" warning on MSVC2013
IF(MSVC12) IF(MSVC12)
add_compile_options(/wd4351) ADD_COMPILE_OPTIONS(/wd4351)
ENDIF() ENDIF()
ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -Wno-long-long -std=c++11" ) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -Wno-long-long -std=c++11" )
@ -230,34 +220,39 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW )
ADD_DEFINITIONS( -U__STRICT_ANSI__ ) ADD_DEFINITIONS( -U__STRICT_ANSI__ )
ENDIF() ENDIF()
if (ASSIMP_COVERALLS) IF (IOS)
MESSAGE(STATUS "Coveralls enabled") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3")
INCLUDE(Coveralls) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") ENDIF()
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
endif()
if (ASSIMP_WERROR) IF (ASSIMP_COVERALLS)
MESSAGE(STATUS "Coveralls enabled")
INCLUDE(Coveralls)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
ENDIF()
IF (ASSIMP_WERROR)
MESSAGE(STATUS "Treating warnings as errors") MESSAGE(STATUS "Treating warnings as errors")
IF (MSVC) IF (MSVC)
add_compile_options(/WX) ADD_COMPILE_OPTIONS(/WX)
ELSE() ELSE()
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
ENDIF() ENDIF()
endif() ENDIF()
if (ASSIMP_ASAN) IF (ASSIMP_ASAN)
MESSAGE(STATUS "AddressSanitizer enabled") MESSAGE(STATUS "AddressSanitizer enabled")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address")
endif() ENDIF()
if (ASSIMP_UBSAN) IF (ASSIMP_UBSAN)
MESSAGE(STATUS "Undefined Behavior sanitizer enabled") MESSAGE(STATUS "Undefined Behavior sanitizer enabled")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined -fno-sanitize-recover=all")
endif() ENDIF()
INCLUDE (FindPkgMacros) INCLUDE (FindPkgMacros)
INCLUDE (PrecompiledHeader) INCLUDE (PrecompiledHeader)
@ -290,42 +285,42 @@ ENDIF()
IF (NOT TARGET uninstall) IF (NOT TARGET uninstall)
# add make uninstall capability # add make uninstall capability
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY)
add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake")
ENDIF() ENDIF()
# cmake configuration files # cmake configuration files
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE) CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE) CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT}) INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT})
FIND_PACKAGE( DirectX ) FIND_PACKAGE( DirectX )
IF( BUILD_DOCS ) IF( BUILD_DOCS )
add_subdirectory(doc) ADD_SUBDIRECTORY(doc)
ENDIF( BUILD_DOCS ) ENDIF( BUILD_DOCS )
# Look for system installed irrXML # Look for system installed irrXML
IF ( SYSTEM_IRRXML ) IF ( SYSTEM_IRRXML )
find_package( IrrXML REQUIRED ) FIND_PACKAGE( IrrXML REQUIRED )
ENDIF( SYSTEM_IRRXML ) ENDIF( SYSTEM_IRRXML )
# Search for external dependencies, and build them from source if not found # Search for external dependencies, and build them from source if not found
# Search for zlib # Search for zlib
IF ( NOT ASSIMP_BUILD_ZLIB ) IF ( NOT ASSIMP_BUILD_ZLIB )
find_package(ZLIB) FIND_PACKAGE(ZLIB)
ENDIF( NOT ASSIMP_BUILD_ZLIB ) ENDIF( NOT ASSIMP_BUILD_ZLIB )
IF( NOT ZLIB_FOUND ) IF( NOT ZLIB_FOUND )
message(STATUS "compiling zlib from souces") MESSAGE(STATUS "compiling zlib from sources")
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,39 +405,14 @@ 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 )
ENDIF ( WIN32 AND DirectX_D3DX9_LIBRARY ) ENDIF ( WIN32 AND DirectX_D3DX9_LIBRARY )
ADD_SUBDIRECTORY( tools/assimp_cmd/ ) ADD_SUBDIRECTORY( tools/assimp_cmd/ )
ADD_SUBDIRECTORY( tools/assimp_qt_viewer/ )
# Check dependencies for assimp_qt_viewer.
# Why here? Maybe user do not want Qt viewer and have no Qt.
# Why assimp_qt_viewer/CMakeLists.txt still contain similar check?
# Because viewer can be build independently of Assimp.
FIND_PACKAGE(Qt5Widgets QUIET)
FIND_PACKAGE(DevIL QUIET)
FIND_PACKAGE(OpenGL QUIET)
IF ( Qt5Widgets_FOUND AND IL_FOUND AND OPENGL_FOUND)
ADD_SUBDIRECTORY( tools/assimp_qt_viewer/ )
ELSE()
SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "")
IF (NOT Qt5_FOUND)
SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} Qt5")
ENDIF (NOT Qt5_FOUND)
IF (NOT IL_FOUND)
SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} DevIL")
ENDIF (NOT IL_FOUND)
IF (NOT OPENGL_FOUND)
SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} OpengGL")
ENDIF (NOT OPENGL_FOUND)
MESSAGE (WARNING "Build of assimp_qt_viewer is disabled. Unsatisfied dendencies: ${ASSIMP_QT_VIEWER_DEPENDENCIES}")
ENDIF ( Qt5Widgets_FOUND AND IL_FOUND AND OPENGL_FOUND)
ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS ) ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS )
IF ( ASSIMP_BUILD_SAMPLES) IF ( ASSIMP_BUILD_SAMPLES)
@ -460,7 +432,7 @@ INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTAL
IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES) IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
# Packing information # Packing information
SET(CPACK_PACKAGE_NAME "assimp{ASSIMP_VERSION_MAJOR}") SET(CPACK_PACKAGE_NAME "assimp{ASSIMP_VERSION_MAJOR}.{ASSIMP_VERSION_MINOR}")
SET(CPACK_PACKAGE_CONTACT "" CACHE STRING "Package maintainer and PGP signer.") SET(CPACK_PACKAGE_CONTACT "" CACHE STRING "Package maintainer and PGP signer.")
SET(CPACK_PACKAGE_VENDOR "https://github.com/assimp") SET(CPACK_PACKAGE_VENDOR "https://github.com/assimp")
SET(CPACK_PACKAGE_DISPLAY_NAME "Assimp ${ASSIMP_VERSION}") SET(CPACK_PACKAGE_DISPLAY_NAME "Assimp ${ASSIMP_VERSION}")
@ -472,8 +444,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}" )
@ -490,8 +462,8 @@ IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES)
SET(CPACK_DEBIAN_PACKAGE_SECTION "libs" ) SET(CPACK_DEBIAN_PACKAGE_SECTION "libs" )
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_COMPONENTS_ALL}") SET(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_COMPONENTS_ALL}")
SET(CPACK_DEBIAN_PACKAGE_SUGGESTS) SET(CPACK_DEBIAN_PACKAGE_SUGGESTS)
SET(CPACK_DEBIAN_PACKAGE_NAME "assimp") set(cPACK_DEBIAN_PACKAGE_NAME "assimp")
SET(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES contrib/cppunit-1.12.1 contrib/cppunit_note.txt contrib/zlib workspaces test doc obj samples packaging) SET(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES contrib/gtest contrib/zlib workspaces test doc obj samples packaging)
SET(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force) SET(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force)
SET(CPACK_DEBIAN_CHANGELOG) SET(CPACK_DEBIAN_CHANGELOG)
execute_process(COMMAND lsb_release -is execute_process(COMMAND lsb_release -is
@ -503,8 +475,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 +488,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 +518,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)

10
CONTRIBUTING.md 100644
View File

@ -0,0 +1,10 @@
# How to contribute
If you want to contribute, follow these steps:
- First, create your own clone of assimp.
- When you want to fix a bug or add a new feature, create a branch on your own fork following [these instructions](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).
- Push it to your fork of the repository and open a pull request.
- A pull request will start our continuous integration service, which checks if the build works for Linux and Windows.
It will check for memory leaks, compiler warnings and memory alignment issues. If any of these tests fail, fix it and the tests will be restarted automatically.
- At the end, we will perform a code review and merge your branch to the master branch.

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

@ -42,3 +42,6 @@ For Windows:
1. Open a command prompt 1. Open a command prompt
2. cmake CMakeLists.txt 2. cmake CMakeLists.txt
2. Open your default IDE and build it 2. Open your default IDE and build it
For iOS:
Just check the following project, which deploys a compiler toolchain for different iOS-versions: https://github.com/assimp/assimp/tree/master/port/iOS

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.
@ -138,8 +140,6 @@ Open Asset Import Library is implemented in C++. The directory structure is:
/tools Tools (old assimp viewer, command line `assimp`) /tools Tools (old assimp viewer, command line `assimp`)
/samples A small number of samples to illustrate possible /samples A small number of samples to illustrate possible
use cases for Assimp use cases for Assimp
/workspaces Build environments for vc,xcode,... (deprecated,
CMake has superseeded all legacy build options!)
### Where to get help ### ### Where to get help ###

View File

@ -32,6 +32,9 @@ install:
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" set CMAKE_GENERATOR_NAME=Visual Studio 15 2017 - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" set CMAKE_GENERATOR_NAME=Visual Studio 15 2017
- if "%platform%"=="x64" set CMAKE_GENERATOR_NAME=%CMAKE_GENERATOR_NAME% Win64 - if "%platform%"=="x64" set CMAKE_GENERATOR_NAME=%CMAKE_GENERATOR_NAME% Win64
- cmake %CMAKE_DEFINES% -G "%CMAKE_GENERATOR_NAME%" - cmake %CMAKE_DEFINES% -G "%CMAKE_GENERATOR_NAME%"
- set PATH=%PATH%;"C:\\Program Files (x86)\\Inno Setup 5"
- ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/5/7/b/57b2947c-7221-4f33-b35e-2fc78cb10df4/vc_redist.x64.exe -OutFile .\packaging\windows-innosetup\vc_redist.x64.exe
- ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/1/d/8/1d8137db-b5bb-4925-8c5d-927424a2e4de/vc_redist.x86.exe -OutFile .\packaging\windows-innosetup\vc_redist.x86.exe
cache: cache:
- code\assimp.dir\%CONFIGURATION% - code\assimp.dir\%CONFIGURATION%
@ -50,6 +53,7 @@ build:
project: Assimp.sln project: Assimp.sln
after_build: after_build:
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" iscc packaging\windows-innosetup\script.iss
- 7z a assimp.7z bin\%CONFIGURATION%\* lib\%CONFIGURATION%\* - 7z a assimp.7z bin\%CONFIGURATION%\* lib\%CONFIGURATION%\*
test_script: test_script:

View File

@ -10,10 +10,7 @@
# ASSIMP_LIBRARY_DIRS - link directories # ASSIMP_LIBRARY_DIRS - link directories
# ASSIMP_LIBRARIES - libraries to link plugins with # ASSIMP_LIBRARIES - libraries to link plugins with
# ASSIMP_Boost_VERSION - the boost version assimp was compiled with # ASSIMP_Boost_VERSION - the boost version assimp was compiled with
get_filename_component(_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) get_filename_component(ASSIMP_ROOT_DIR "@CMAKE_INSTALL_PREFIX@" REALPATH)
get_filename_component(_PREFIX "${_PREFIX}" PATH)
get_filename_component(_PREFIX "${_PREFIX}" PATH)
get_filename_component(ASSIMP_ROOT_DIR "${_PREFIX}" PATH)
if( MSVC ) if( MSVC )
# in order to prevent DLL hell, each of the DLLs have to be suffixed with the major version and msvc prefix # in order to prevent DLL hell, each of the DLLs have to be suffixed with the major version and msvc prefix
@ -34,36 +31,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 +53,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 ) );
} }
@ -120,7 +120,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
else if ( (*a) >= mScene->mMaterials.size()) else if ( (*a) >= mScene->mMaterials.size())
{ {
(*a) = idx; (*a) = idx;
DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material"); ASSIMP_LOG_WARN("Material index overflow in 3DS file. Using default material");
++cnt; ++cnt;
} }
} }
@ -132,7 +132,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f); sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f);
mScene->mMaterials.push_back(sMat); mScene->mMaterials.push_back(sMat);
DefaultLogger::get()->info("3DS: Generating default material"); ASSIMP_LOG_INFO("3DS: Generating default material");
} }
} }
@ -147,12 +147,12 @@ void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh)
{ {
if ((*i).mIndices[a] >= sMesh.mPositions.size()) if ((*i).mIndices[a] >= sMesh.mPositions.size())
{ {
DefaultLogger::get()->warn("3DS: Vertex index overflow)"); ASSIMP_LOG_WARN("3DS: Vertex index overflow)");
(*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1; (*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1;
} }
if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size()) if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size())
{ {
DefaultLogger::get()->warn("3DS: Texture coordinate index overflow)"); ASSIMP_LOG_WARN("3DS: Texture coordinate index overflow)");
(*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1; (*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1;
} }
} }
@ -204,8 +204,9 @@ void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type)
mat.AddProperty<ai_real>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0)); mat.AddProperty<ai_real>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0));
// Setup the texture mapping mode // Setup the texture mapping mode
mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0)); int mapMode = static_cast<int>(texture.mMapMode);
mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0)); mat.AddProperty<int>(&mapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0));
mat.AddProperty<int>(&mapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0));
// Mirroring - double the scaling values // Mirroring - double the scaling values
// FIXME: this is not really correct ... // FIXME: this is not really correct ...
@ -313,7 +314,8 @@ void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat,
case D3DS::Discreet3DS::Blinn : case D3DS::Discreet3DS::Blinn :
eShading = aiShadingMode_Blinn; break; eShading = aiShadingMode_Blinn; break;
} }
mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL); int eShading_ = static_cast<int>(eShading);
mat.AddProperty<int>(&eShading_, 1, AI_MATKEY_SHADING_MODEL);
// DIFFUSE texture // DIFFUSE texture
if( oldMat.sTexDiffuse.mMapName.length() > 0) if( oldMat.sTexDiffuse.mMapName.length() > 0)
@ -497,7 +499,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
pvCurrent->x *= -1.f; pvCurrent->x *= -1.f;
t2->x *= -1.f; t2->x *= -1.f;
} }
DefaultLogger::get()->info("3DS: Flipping mesh X-Axis"); ASSIMP_LOG_INFO("3DS: Flipping mesh X-Axis");
} }
// Handle pivot point // Handle pivot point
@ -573,11 +575,11 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
pcIn->aTargetPositionKeys.size() > 1) pcIn->aTargetPositionKeys.size() > 1)
{ {
aiAnimation* anim = pcSOut->mAnimations[0]; aiAnimation* anim = pcSOut->mAnimations[0];
ai_assert(NULL != anim); ai_assert(nullptr != anim);
if (pcIn->aCameraRollKeys.size() > 1) if (pcIn->aCameraRollKeys.size() > 1)
{ {
DefaultLogger::get()->debug("3DS: Converting camera roll track ..."); ASSIMP_LOG_DEBUG("3DS: Converting camera roll track ...");
// Camera roll keys - in fact they're just rotations // Camera roll keys - in fact they're just rotations
// around the camera's z axis. The angles are given // around the camera's z axis. The angles are given
@ -597,7 +599,7 @@ void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,
#if 0 #if 0
if (pcIn->aTargetPositionKeys.size() > 1) if (pcIn->aTargetPositionKeys.size() > 1)
{ {
DefaultLogger::get()->debug("3DS: Converting target track ..."); ASSIMP_LOG_DEBUG("3DS: Converting target track ...");
// Camera or spot light - need to convert the separate // Camera or spot light - need to convert the separate
// target position channel to our representation // target position channel to our representation
@ -743,7 +745,7 @@ void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut)
// | | | | | // | | | | |
// MESH_0 MESH_1 MESH_2 ... MESH_N CAMERA_0 .... // MESH_0 MESH_1 MESH_2 ... MESH_N CAMERA_0 ....
// //
DefaultLogger::get()->warn("No hierarchy information has been found in the file. "); ASSIMP_LOG_WARN("No hierarchy information has been found in the file. ");
pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes + pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes +
static_cast<unsigned int>(mScene->mCameras.size() + mScene->mLights.size()); static_cast<unsigned int>(mScene->mCameras.size() + mScene->mLights.size());

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)
{ {
@ -381,7 +381,7 @@ void Discreet3DSExporter::WriteTexture(const aiMaterial& mat, aiTextureType type
// TODO: handle embedded textures properly // TODO: handle embedded textures properly
if (path.data[0] == '*') { if (path.data[0] == '*') {
DefaultLogger::get()->error("Ignoring embedded texture for export: " + std::string(path.C_Str())); ASSIMP_LOG_ERROR("Ignoring embedded texture for export: " + std::string(path.C_Str()));
return; return;
} }

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"
}; };
@ -127,7 +127,7 @@ Discreet3DSImporter::~Discreet3DSImporter() {
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { bool Discreet3DSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
std::string extension = GetExtension(pFile); std::string extension = GetExtension(pFile);
if(extension == "3ds" || extension == "prj" ) { if(extension == "3ds" || extension == "prj") {
return true; return true;
} }
@ -258,8 +258,9 @@ void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk* pcOut)
if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSize()) if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSize())
throw DeadlyImportError("Chunk is too large"); throw DeadlyImportError("Chunk is too large");
if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSizeToLimit()) if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSizeToLimit()) {
DefaultLogger::get()->error("3DS: Chunk overflow"); ASSIMP_LOG_ERROR("3DS: Chunk overflow");
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -320,7 +321,7 @@ void Discreet3DSImporter::ParseEditorChunk()
// print the version number // print the version number
char buff[10]; char buff[10];
ASSIMP_itoa10(buff,stream->GetI2()); ASSIMP_itoa10(buff,stream->GetI2());
DefaultLogger::get()->info(std::string("3DS file format version: ") + buff); ASSIMP_LOG_INFO_F(std::string("3DS file format version: "), buff);
} }
break; break;
}; };
@ -349,7 +350,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;
@ -361,7 +362,7 @@ void Discreet3DSImporter::ParseObjectChunk()
if (is_qnan(mClrAmbient.r)) if (is_qnan(mClrAmbient.r))
{ {
// We failed to read the ambient base color. // We failed to read the ambient base color.
DefaultLogger::get()->error("3DS: Failed to read ambient base color"); ASSIMP_LOG_ERROR("3DS: Failed to read ambient base color");
mClrAmbient.r = mClrAmbient.g = mClrAmbient.b = 0.0f; mClrAmbient.r = mClrAmbient.g = mClrAmbient.b = 0.0f;
} }
break; break;
@ -463,7 +464,7 @@ void Discreet3DSImporter::ParseChunk(const char* name, unsigned int num)
if (len < 1e-5) { if (len < 1e-5) {
// There are some files with lookat == position. Don't know why or whether it's ok or not. // There are some files with lookat == position. Don't know why or whether it's ok or not.
DefaultLogger::get()->error("3DS: Unable to read proper camera look-at vector"); ASSIMP_LOG_ERROR("3DS: Unable to read proper camera look-at vector");
camera->mLookAt = aiVector3D(0.0,1.0,0.0); camera->mLookAt = aiVector3D(0.0,1.0,0.0);
} }
@ -629,9 +630,9 @@ void Discreet3DSImporter::SkipTCBInfo()
if (!flags) { if (!flags) {
// Currently we can't do anything with these values. They occur // Currently we can't do anything with these values. They occur
// quite rare, so it wouldn't be worth the effort implementing // quite rare, so it wouldn't be worth the effort implementing
// them. 3DS ist not really suitable for complex animations, // them. 3DS is not really suitable for complex animations,
// so full support is not required. // so full support is not required.
DefaultLogger::get()->warn("3DS: Skipping TCB animation info"); ASSIMP_LOG_WARN("3DS: Skipping TCB animation info");
} }
if (flags & Discreet3DS::KEY_USE_TENS) { if (flags & Discreet3DS::KEY_USE_TENS) {
@ -732,7 +733,6 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
// If object name is DUMMY, take this one instead // If object name is DUMMY, take this one instead
if (mCurrentNode->mName == "$$$DUMMY") { if (mCurrentNode->mName == "$$$DUMMY") {
//DefaultLogger::get()->warn("3DS: Skipping dummy object name for non-dummy object");
mCurrentNode->mName = std::string(sz); mCurrentNode->mName = std::string(sz);
break; break;
} }
@ -743,7 +743,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
if ( Discreet3DS::CHUNK_TRACKINFO != parent) if ( Discreet3DS::CHUNK_TRACKINFO != parent)
{ {
DefaultLogger::get()->warn("3DS: Skipping pivot subchunk for non usual object"); ASSIMP_LOG_WARN("3DS: Skipping pivot subchunk for non usual object");
break; break;
} }
@ -805,7 +805,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
{ {
// roll keys are accepted for cameras only // roll keys are accepted for cameras only
if (parent != Discreet3DS::CHUNK_TRACKCAMERA) { if (parent != Discreet3DS::CHUNK_TRACKCAMERA) {
DefaultLogger::get()->warn("3DS: Ignoring roll track for non-camera object"); ASSIMP_LOG_WARN("3DS: Ignoring roll track for non-camera object");
break; break;
} }
bool sortKeys = false; bool sortKeys = false;
@ -845,7 +845,7 @@ void Discreet3DSImporter::ParseHierarchyChunk(uint16_t parent)
// CAMERA FOV KEYFRAME // CAMERA FOV KEYFRAME
case Discreet3DS::CHUNK_TRACKFOV: case Discreet3DS::CHUNK_TRACKFOV:
{ {
DefaultLogger::get()->error("3DS: Skipping FOV animation track. " ASSIMP_LOG_ERROR("3DS: Skipping FOV animation track. "
"This is not supported"); "This is not supported");
} }
break; break;
@ -985,7 +985,7 @@ void Discreet3DSImporter::ParseFaceChunk()
} }
} }
if (0xcdcdcdcd == idx) { if (0xcdcdcdcd == idx) {
DefaultLogger::get()->error(std::string("3DS: Unknown material: ") + sz); ASSIMP_LOG_ERROR_F( "3DS: Unknown material: ", sz);
} }
// Now continue and read all material indices // Now continue and read all material indices
@ -995,7 +995,7 @@ void Discreet3DSImporter::ParseFaceChunk()
// check range // check range
if (fidx >= mMesh.mFaceMaterials.size()) { if (fidx >= mMesh.mFaceMaterials.size()) {
DefaultLogger::get()->error("3DS: Invalid face index in face material list"); ASSIMP_LOG_ERROR("3DS: Invalid face index in face material list");
} }
else mMesh.mFaceMaterials[fidx] = idx; else mMesh.mFaceMaterials[fidx] = idx;
}} }}
@ -1110,7 +1110,7 @@ void Discreet3DSImporter::ParseMaterialChunk()
if (!cnt) { if (!cnt) {
// This may not be, we use the default name instead // This may not be, we use the default name instead
DefaultLogger::get()->error("3DS: Empty material name"); ASSIMP_LOG_ERROR("3DS: Empty material name");
} }
else mScene->mMaterials.back().mName = std::string(sz,cnt); else mScene->mMaterials.back().mName = std::string(sz,cnt);
} }
@ -1123,7 +1123,7 @@ void Discreet3DSImporter::ParseMaterialChunk()
ParseColorChunk(pc); ParseColorChunk(pc);
if (is_qnan(pc->r)) { if (is_qnan(pc->r)) {
// color chunk is invalid. Simply ignore it // color chunk is invalid. Simply ignore it
DefaultLogger::get()->error("3DS: Unable to read DIFFUSE chunk"); ASSIMP_LOG_ERROR("3DS: Unable to read DIFFUSE chunk");
pc->r = pc->g = pc->b = 1.0f; pc->r = pc->g = pc->b = 1.0f;
}} }}
break; break;
@ -1135,7 +1135,7 @@ void Discreet3DSImporter::ParseMaterialChunk()
ParseColorChunk(pc); ParseColorChunk(pc);
if (is_qnan(pc->r)) { if (is_qnan(pc->r)) {
// color chunk is invalid. Simply ignore it // color chunk is invalid. Simply ignore it
DefaultLogger::get()->error("3DS: Unable to read SPECULAR chunk"); ASSIMP_LOG_ERROR("3DS: Unable to read SPECULAR chunk");
pc->r = pc->g = pc->b = 1.0f; pc->r = pc->g = pc->b = 1.0f;
}} }}
break; break;
@ -1147,7 +1147,7 @@ void Discreet3DSImporter::ParseMaterialChunk()
ParseColorChunk(pc); ParseColorChunk(pc);
if (is_qnan(pc->r)) { if (is_qnan(pc->r)) {
// color chunk is invalid. Simply ignore it // color chunk is invalid. Simply ignore it
DefaultLogger::get()->error("3DS: Unable to read AMBIENT chunk"); ASSIMP_LOG_ERROR("3DS: Unable to read AMBIENT chunk");
pc->r = pc->g = pc->b = 0.0f; pc->r = pc->g = pc->b = 0.0f;
}} }}
break; break;
@ -1159,7 +1159,7 @@ void Discreet3DSImporter::ParseMaterialChunk()
ParseColorChunk(pc); ParseColorChunk(pc);
if (is_qnan(pc->r)) { if (is_qnan(pc->r)) {
// color chunk is invalid. Simply ignore it // color chunk is invalid. Simply ignore it
DefaultLogger::get()->error("3DS: Unable to read EMISSIVE chunk"); ASSIMP_LOG_ERROR("3DS: Unable to read EMISSIVE chunk");
pc->r = pc->g = pc->b = 0.0f; pc->r = pc->g = pc->b = 0.0f;
}} }}
break; break;
@ -1293,7 +1293,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
pcOut->mScaleU = stream->GetF4(); pcOut->mScaleU = stream->GetF4();
if (0.0f == pcOut->mScaleU) if (0.0f == pcOut->mScaleU)
{ {
DefaultLogger::get()->warn("Texture coordinate scaling in the x direction is zero. Assuming 1."); ASSIMP_LOG_WARN("Texture coordinate scaling in the x direction is zero. Assuming 1.");
pcOut->mScaleU = 1.0f; pcOut->mScaleU = 1.0f;
} }
break; break;
@ -1302,7 +1302,7 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut)
pcOut->mScaleV = stream->GetF4(); pcOut->mScaleV = stream->GetF4();
if (0.0f == pcOut->mScaleV) if (0.0f == pcOut->mScaleV)
{ {
DefaultLogger::get()->warn("Texture coordinate scaling in the y direction is zero. Assuming 1."); ASSIMP_LOG_WARN("Texture coordinate scaling in the y direction is zero. Assuming 1.");
pcOut->mScaleV = 1.0f; pcOut->mScaleV = 1.0f;
} }
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

@ -85,7 +85,7 @@ static const aiImporterDesc desc = {
#define AI_AC_SKIP_TO_NEXT_TOKEN() \ #define AI_AC_SKIP_TO_NEXT_TOKEN() \
if (!SkipSpaces(&buffer)) \ if (!SkipSpaces(&buffer)) \
{ \ { \
DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL"); \ ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL"); \
continue; \ continue; \
} }
@ -101,7 +101,7 @@ static const aiImporterDesc desc = {
{ \ { \
if (IsLineEnd( *buffer )) \ if (IsLineEnd( *buffer )) \
{ \ { \
DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL in string"); \ ASSIMP_LOG_ERROR("AC3D: Unexpected EOF/EOL in string"); \
out = "ERROR"; \ out = "ERROR"; \
break; \ break; \
} \ } \
@ -120,7 +120,7 @@ static const aiImporterDesc desc = {
{ \ { \
if (strncmp(buffer,name,name_length) || !IsSpace(buffer[name_length])) \ if (strncmp(buffer,name,name_length) || !IsSpace(buffer[name_length])) \
{ \ { \
DefaultLogger::get()->error("AC3D: Unexpexted token. " name " was expected."); \ ASSIMP_LOG_ERROR("AC3D: Unexpexted token. " name " was expected."); \
continue; \ continue; \
} \ } \
buffer += name_length+1; \ buffer += name_length+1; \
@ -217,7 +217,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
light->mName.length = ::ai_snprintf(light->mName.data, MAXLEN, "ACLight_%i",static_cast<unsigned int>(mLights->size())-1); light->mName.length = ::ai_snprintf(light->mName.data, MAXLEN, "ACLight_%i",static_cast<unsigned int>(mLights->size())-1);
obj.name = std::string( light->mName.data ); obj.name = std::string( light->mName.data );
DefaultLogger::get()->debug("AC3D: Light source encountered"); ASSIMP_LOG_DEBUG("AC3D: Light source encountered");
obj.type = Object::Light; obj.type = Object::Light;
} }
else if (!ASSIMP_strincmp(buffer,"group",5)) else if (!ASSIMP_strincmp(buffer,"group",5))
@ -307,12 +307,12 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
{ {
if (!GetNextLine()) if (!GetNextLine())
{ {
DefaultLogger::get()->error("AC3D: Unexpected EOF: not all vertices have been parsed yet"); ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: not all vertices have been parsed yet");
break; break;
} }
else if (!IsNumeric(*buffer)) else if (!IsNumeric(*buffer))
{ {
DefaultLogger::get()->error("AC3D: Unexpected token: not all vertices have been parsed yet"); ASSIMP_LOG_ERROR("AC3D: Unexpected token: not all vertices have been parsed yet");
--buffer; // make sure the line is processed a second time --buffer; // make sure the line is processed a second time
break; break;
} }
@ -338,8 +338,8 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
// example writes no surf chunks // example writes no surf chunks
if (!Q3DWorkAround) if (!Q3DWorkAround)
{ {
DefaultLogger::get()->warn("AC3D: SURF token was expected"); ASSIMP_LOG_WARN("AC3D: SURF token was expected");
DefaultLogger::get()->debug("Continuing with Quick3D Workaround enabled"); ASSIMP_LOG_DEBUG("Continuing with Quick3D Workaround enabled");
} }
--buffer; // make sure the line is processed a second time --buffer; // make sure the line is processed a second time
// break; --- see fix notes above // break; --- see fix notes above
@ -384,7 +384,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
{ {
if(!GetNextLine()) if(!GetNextLine())
{ {
DefaultLogger::get()->error("AC3D: Unexpected EOF: surface references are incomplete"); ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: surface references are incomplete");
break; break;
} }
surf.entries.push_back(Surface::SurfaceEntry()); surf.entries.push_back(Surface::SurfaceEntry());
@ -405,7 +405,7 @@ void AC3DImporter::LoadObjectSection(std::vector<Object>& objects)
} }
} }
} }
DefaultLogger::get()->error("AC3D: Unexpected EOF: \'kids\' line was expected"); ASSIMP_LOG_ERROR("AC3D: Unexpected EOF: \'kids\' line was expected");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -478,7 +478,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
therefore: if no surfaces are defined return point data only therefore: if no surfaces are defined return point data only
*/ */
DefaultLogger::get()->info("AC3D: No surfaces defined in object definition, " ASSIMP_LOG_INFO("AC3D: No surfaces defined in object definition, "
"a point list is returned"); "a point list is returned");
meshes.push_back(new aiMesh()); meshes.push_back(new aiMesh());
@ -519,12 +519,12 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
unsigned int idx = (*it).mat; unsigned int idx = (*it).mat;
if (idx >= needMat.size()) if (idx >= needMat.size())
{ {
DefaultLogger::get()->error("AC3D: material index is out of range"); ASSIMP_LOG_ERROR("AC3D: material index is out of range");
idx = 0; idx = 0;
} }
if ((*it).entries.empty()) if ((*it).entries.empty())
{ {
DefaultLogger::get()->warn("AC3D: surface her zero vertex references"); ASSIMP_LOG_WARN("AC3D: surface her zero vertex references");
} }
// validate all vertex indices to make sure we won't crash here // validate all vertex indices to make sure we won't crash here
@ -533,7 +533,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
{ {
if ((*it2).first >= object.vertices.size()) if ((*it2).first >= object.vertices.size())
{ {
DefaultLogger::get()->warn("AC3D: Invalid vertex reference"); ASSIMP_LOG_WARN("AC3D: Invalid vertex reference");
(*it2).first = 0; (*it2).first = 0;
} }
} }
@ -561,7 +561,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
if ((*it).flags & 0xf) if ((*it).flags & 0xf)
{ {
DefaultLogger::get()->warn("AC3D: The type flag of a surface is unknown"); ASSIMP_LOG_WARN("AC3D: The type flag of a surface is unknown");
(*it).flags &= ~(0xf); (*it).flags &= ~(0xf);
} }
@ -712,7 +712,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
if (object.subDiv) { if (object.subDiv) {
if (configEvalSubdivision) { if (configEvalSubdivision) {
std::unique_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE)); std::unique_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE));
DefaultLogger::get()->info("AC3D: Evaluating subdivision surface: "+object.name); ASSIMP_LOG_INFO("AC3D: Evaluating subdivision surface: "+object.name);
std::vector<aiMesh*> cpy(meshes.size()-oldm,NULL); std::vector<aiMesh*> cpy(meshes.size()-oldm,NULL);
div->Subdivide(&meshes[oldm],cpy.size(),&cpy.front(),object.subDiv,true); div->Subdivide(&meshes[oldm],cpy.size(),&cpy.front(),object.subDiv,true);
@ -721,7 +721,7 @@ aiNode* AC3DImporter::ConvertObjectSection(Object& object,
// previous meshes are deleted vy Subdivide(). // previous meshes are deleted vy Subdivide().
} }
else { else {
DefaultLogger::get()->info("AC3D: Letting the subdivision surface untouched due to my configuration: " ASSIMP_LOG_INFO("AC3D: Letting the subdivision surface untouched due to my configuration: "
+object.name); +object.name);
} }
} }
@ -813,7 +813,7 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
unsigned int version = HexDigitToDecimal( buffer[4] ); unsigned int version = HexDigitToDecimal( buffer[4] );
char msg[3]; char msg[3];
ASSIMP_itoa10(msg,3,version); ASSIMP_itoa10(msg,3,version);
DefaultLogger::get()->info(std::string("AC3D file format version: ") + msg); ASSIMP_LOG_INFO_F("AC3D file format version: ", msg);
std::vector<Material> materials; std::vector<Material> materials;
materials.reserve(5); materials.reserve(5);
@ -857,7 +857,7 @@ void AC3DImporter::InternReadFile( const std::string& pFile,
} }
if (materials.empty()) if (materials.empty())
{ {
DefaultLogger::get()->warn("AC3D: No material has been found"); ASSIMP_LOG_WARN("AC3D: No material has been found");
materials.push_back(Material()); materials.push_back(Material());
} }

View File

@ -230,7 +230,7 @@ casu_cres:
if(!skipped_before[sk_idx]) if(!skipped_before[sk_idx])
{ {
skipped_before[sk_idx] = true; skipped_before[sk_idx] = true;
LogWarning("Skipping node \"" + nn + "\" in " + pParentNodeName + "."); ASSIMP_LOG_WARN_F("Skipping node \"", nn, "\" in ", pParentNodeName, ".");
} }
} }

View File

@ -358,18 +358,6 @@ private:
/************** Functions: LOG set *************/ /************** Functions: LOG set *************/
/***********************************************/ /***********************************************/
/// \fn void LogInfo(const std::string& pMessage)
/// Short variant for calling \ref DefaultLogger::get()->info()
void LogInfo(const std::string& pMessage) { DefaultLogger::get()->info(pMessage); }
/// \fn void LogWarning(const std::string& pMessage)
/// Short variant for calling \ref DefaultLogger::get()->warn()
void LogWarning(const std::string& pMessage) { DefaultLogger::get()->warn(pMessage); }
/// \fn void LogError(const std::string& pMessage)
/// Short variant for calling \ref DefaultLogger::get()->error()
void LogError(const std::string& pMessage) { DefaultLogger::get()->error(pMessage); }
/***********************************************/ /***********************************************/
/************** Functions: XML set *************/ /************** Functions: XML set *************/
/***********************************************/ /***********************************************/

View File

@ -71,7 +71,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
} }
/// \def MACRO_ATTRREAD_CHECK_REF /// \def MACRO_ATTRREAD_CHECK_REF
/// Check curent attribute name and if it equal to requested then read value. Result write to output variable by reference. If result was read then /// Check current attribute name and if it equal to requested then read value. Result write to output variable by reference. If result was read then
/// "continue" will called. /// "continue" will called.
/// \param [in] pAttrName - attribute name. /// \param [in] pAttrName - attribute name.
/// \param [out] pVarName - output variable name. /// \param [out] pVarName - output variable name.
@ -84,7 +84,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
} }
/// \def MACRO_ATTRREAD_CHECK_RET /// \def MACRO_ATTRREAD_CHECK_RET
/// Check curent attribute name and if it equal to requested then read value. Result write to output variable using return value of \ref pFunction. /// Check current attribute name and if it equal to requested then read value. Result write to output variable using return value of \ref pFunction.
/// If result was read then "continue" will called. /// If result was read then "continue" will called.
/// \param [in] pAttrName - attribute name. /// \param [in] pAttrName - attribute name.
/// \param [out] pVarName - output variable name. /// \param [out] pVarName - output variable name.
@ -130,7 +130,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
} while(false) } while(false)
/// \def MACRO_NODECHECK_READCOMP_F /// \def MACRO_NODECHECK_READCOMP_F
/// Check curent node name and if it equal to requested then read value. Result write to output variable of type "float". /// Check current node name and if it equal to requested then read value. Result write to output variable of type "float".
/// If result was read then "continue" will called. Also check if node data already read then raise exception. /// If result was read then "continue" will called. Also check if node data already read then raise exception.
/// \param [in] pNodeName - node name. /// \param [in] pNodeName - node name.
/// \param [in, out] pReadFlag - read flag. /// \param [in, out] pReadFlag - read flag.
@ -147,7 +147,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
} }
/// \def MACRO_NODECHECK_READCOMP_U32 /// \def MACRO_NODECHECK_READCOMP_U32
/// Check curent node name and if it equal to requested then read value. Result write to output variable of type "uint32_t". /// Check current node name and if it equal to requested then read value. Result write to output variable of type "uint32_t".
/// If result was read then "continue" will called. Also check if node data already read then raise exception. /// If result was read then "continue" will called. Also check if node data already read then raise exception.
/// \param [in] pNodeName - node name. /// \param [in] pNodeName - node name.
/// \param [in, out] pReadFlag - read flag. /// \param [in, out] pReadFlag - read flag.

View File

@ -99,7 +99,7 @@ CAMFImporter_NodeElement* ne;
ParseHelper_Node_Exit(); ParseHelper_Node_Exit();
// check that all components was defined // check that all components was defined
if(!(read_flag[0] && read_flag[1] && read_flag[2])) throw DeadlyImportError("Not all color components are defined."); if(!(read_flag[0] && read_flag[1] && read_flag[2])) throw DeadlyImportError("Not all color components are defined.");
// check if <a> is absent. Then manualy add "a == 1". // check if <a> is absent. Then manually add "a == 1".
if(!read_flag[3]) als.Color.a = 1; if(!read_flag[3]) als.Color.a = 1;
}// if(!mReader->isEmptyElement()) }// if(!mReader->isEmptyElement())

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;
}
} }
// //
@ -769,7 +770,7 @@ std::list<aiNode*> ch_node;
// find referenced object // find referenced object
if(!Find_ConvertedNode(als.ObjectID, pNodeList, &found_node)) Throw_ID_NotFound(als.ObjectID); if(!Find_ConvertedNode(als.ObjectID, pNodeList, &found_node)) Throw_ID_NotFound(als.ObjectID);
// create node for apllying transformation // create node for applying transformation
t_node = new aiNode; t_node = new aiNode;
t_node->mParent = con_node; t_node->mParent = con_node;
// apply transformation // apply transformation

View File

@ -200,7 +200,7 @@ void ASEImporter::InternReadFile( const std::string& pFile,
ConvertMeshes(*i,avOutMeshes); ConvertMeshes(*i,avOutMeshes);
} }
if (tookNormals) { if (tookNormals) {
DefaultLogger::get()->debug("ASE: Taking normals from the file. Use " ASSIMP_LOG_DEBUG("ASE: Taking normals from the file. Use "
"the AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS setting if you " "the AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS setting if you "
"experience problems"); "experience problems");
} }
@ -297,15 +297,15 @@ void ASEImporter::BuildAnimations(const std::vector<BaseNode*>& nodes)
// TODO: Implement Bezier & TCB support // TODO: Implement Bezier & TCB support
if ((*i)->mAnim.mPositionType != ASE::Animation::TRACK) { if ((*i)->mAnim.mPositionType != ASE::Animation::TRACK) {
DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. " ASSIMP_LOG_WARN("ASE: Position controller uses Bezier/TCB keys. "
"This is not supported."); "This is not supported.");
} }
if ((*i)->mAnim.mRotationType != ASE::Animation::TRACK) { if ((*i)->mAnim.mRotationType != ASE::Animation::TRACK) {
DefaultLogger::get()->warn("ASE: Rotation controller uses Bezier/TCB keys. " ASSIMP_LOG_WARN("ASE: Rotation controller uses Bezier/TCB keys. "
"This is not supported."); "This is not supported.");
} }
if ((*i)->mAnim.mScalingType != ASE::Animation::TRACK) { if ((*i)->mAnim.mScalingType != ASE::Animation::TRACK) {
DefaultLogger::get()->warn("ASE: Position controller uses Bezier/TCB keys. " ASSIMP_LOG_WARN("ASE: Position controller uses Bezier/TCB keys. "
"This is not supported."); "This is not supported.");
} }
@ -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);
} }
@ -624,7 +624,7 @@ void ASEImporter::AddNodes (const std::vector<BaseNode*>& nodes,
node->mNumChildren++; node->mNumChildren++;
// What we did is so great, it is at least worth a debug message // What we did is so great, it is at least worth a debug message
DefaultLogger::get()->debug("ASE: Generating separate target node ("+snode->mName+")"); ASSIMP_LOG_DEBUG("ASE: Generating separate target node ("+snode->mName+")");
} }
} }
@ -947,7 +947,7 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
// validate the material index of the mesh // validate the material index of the mesh
if (mesh.iMaterialIndex >= mParser->m_vMaterials.size()) { if (mesh.iMaterialIndex >= mParser->m_vMaterials.size()) {
mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size()-1; mesh.iMaterialIndex = (unsigned int)mParser->m_vMaterials.size()-1;
DefaultLogger::get()->warn("Material index is out of range"); ASSIMP_LOG_WARN("Material index is out of range");
} }
// If the material the mesh is assigned to is consisting of submeshes, split it // If the material the mesh is assigned to is consisting of submeshes, split it
@ -957,11 +957,11 @@ void ASEImporter::ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOutMesh
std::vector<unsigned int>* aiSplit = new std::vector<unsigned int>[vSubMaterials.size()]; std::vector<unsigned int>* aiSplit = new std::vector<unsigned int>[vSubMaterials.size()];
// build a list of all faces per submaterial // build a list of all faces per sub-material
for (unsigned int i = 0; i < mesh.mFaces.size();++i) { for (unsigned int i = 0; i < mesh.mFaces.size();++i) {
// check range // check range
if (mesh.mFaces[i].iMaterial >= vSubMaterials.size()) { if (mesh.mFaces[i].iMaterial >= vSubMaterials.size()) {
DefaultLogger::get()->warn("Submaterial index is out of range"); ASSIMP_LOG_WARN("Submaterial index is out of range");
// use the last material instead // use the last material instead
aiSplit[vSubMaterials.size()-1].push_back(i); aiSplit[vSubMaterials.size()-1].push_back(i);

View File

@ -151,7 +151,7 @@ void Parser::LogWarning(const char* szWarn)
#endif #endif
// output the warning to the logger ... // output the warning to the logger ...
DefaultLogger::get()->warn(szTemp); ASSIMP_LOG_WARN(szTemp);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -167,7 +167,7 @@ void Parser::LogInfo(const char* szWarn)
#endif #endif
// output the information to the logger ... // output the information to the logger ...
DefaultLogger::get()->info(szTemp); ASSIMP_LOG_INFO(szTemp);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -267,7 +267,9 @@ void Parser::Parse()
// at the file extension (ASE, ASK, ASC) // at the file extension (ASE, ASK, ASC)
// ************************************************************* // *************************************************************
if (fmt)iFileFormat = fmt; if ( fmt ) {
iFileFormat = fmt;
}
continue; continue;
} }
// main scene information // main scene information
@ -427,28 +429,25 @@ void Parser::ParseLV1SoftSkinBlock()
// Reserve enough storage // Reserve enough storage
vert.mBoneWeights.reserve(numWeights); vert.mBoneWeights.reserve(numWeights);
for (unsigned int w = 0; w < numWeights;++w) std::string bone;
{ for (unsigned int w = 0; w < numWeights;++w) {
std::string bone; bone.clear();
ParseString(bone,"*MESH_SOFTSKINVERTS.Bone"); ParseString(bone,"*MESH_SOFTSKINVERTS.Bone");
// Find the bone in the mesh's list // Find the bone in the mesh's list
std::pair<int,ai_real> me; std::pair<int,ai_real> me;
me.first = -1; me.first = -1;
for (unsigned int n = 0; n < curMesh->mBones.size();++n) for (unsigned int n = 0; n < curMesh->mBones.size();++n) {
{ if (curMesh->mBones[n].mName == bone) {
if (curMesh->mBones[n].mName == bone)
{
me.first = n; me.first = n;
break; break;
} }
} }
if (-1 == me.first) if (-1 == me.first) {
{
// We don't have this bone yet, so add it to the list // We don't have this bone yet, so add it to the list
me.first = (int)curMesh->mBones.size(); me.first = static_cast<int>( curMesh->mBones.size() );
curMesh->mBones.push_back(ASE::Bone(bone)); curMesh->mBones.push_back( ASE::Bone( bone ) );
} }
ParseLV4MeshFloat( me.second ); ParseLV4MeshFloat( me.second );
@ -745,6 +744,7 @@ void Parser::ParseLV3MapBlock(Texture& map)
// empty the texture won't be used later. // empty the texture won't be used later.
// *********************************************************** // ***********************************************************
bool parsePath = true; bool parsePath = true;
std::string temp;
while (true) while (true)
{ {
if ('*' == *filePtr) if ('*' == *filePtr)
@ -753,12 +753,12 @@ 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")
{ {
DefaultLogger::get()->warn("ASE: Skipping unknown map type: " + temp); ASSIMP_LOG_WARN_F("ASE: Skipping unknown map type: ", temp);
parsePath = false; parsePath = false;
} }
continue; continue;
@ -773,7 +773,7 @@ void Parser::ParseLV3MapBlock(Texture& map)
{ {
// Files with 'None' as map name are produced by // Files with 'None' as map name are produced by
// an Maja to ASE exporter which name I forgot .. // an Maja to ASE exporter which name I forgot ..
DefaultLogger::get()->warn("ASE: Skipping invalid map entry"); ASSIMP_LOG_WARN("ASE: Skipping invalid map entry");
map.mMapName = ""; map.mMapName = "";
} }
@ -1072,7 +1072,7 @@ void Parser::ParseLV2AnimationBlock(ASE::BaseNode& mesh)
( mesh.mType != BaseNode::Light || ((ASE::Light&)mesh).mLightType != ASE::Light::TARGET)) ( mesh.mType != BaseNode::Light || ((ASE::Light&)mesh).mLightType != ASE::Light::TARGET))
{ {
DefaultLogger::get()->error("ASE: Found target animation channel " ASSIMP_LOG_ERROR("ASE: Found target animation channel "
"but the node is neither a camera nor a spot light"); "but the node is neither a camera nor a spot light");
anim = NULL; anim = NULL;
} }
@ -1098,7 +1098,7 @@ void Parser::ParseLV2AnimationBlock(ASE::BaseNode& mesh)
if (!anim || anim == &mesh.mTargetAnim) if (!anim || anim == &mesh.mTargetAnim)
{ {
// Target animation channels may have no rotation channels // Target animation channels may have no rotation channels
DefaultLogger::get()->error("ASE: Ignoring scaling channel in target animation"); ASSIMP_LOG_ERROR("ASE: Ignoring scaling channel in target animation");
SkipSection(); SkipSection();
} }
else ParseLV3ScaleAnimationBlock(*anim); else ParseLV3ScaleAnimationBlock(*anim);
@ -1112,7 +1112,7 @@ void Parser::ParseLV2AnimationBlock(ASE::BaseNode& mesh)
if (!anim || anim == &mesh.mTargetAnim) if (!anim || anim == &mesh.mTargetAnim)
{ {
// Target animation channels may have no rotation channels // Target animation channels may have no rotation channels
DefaultLogger::get()->error("ASE: Ignoring rotation channel in target animation"); ASSIMP_LOG_ERROR("ASE: Ignoring rotation channel in target animation");
SkipSection(); SkipSection();
} }
else ParseLV3RotAnimationBlock(*anim); else ParseLV3RotAnimationBlock(*anim);
@ -1295,12 +1295,14 @@ void Parser::ParseLV2NodeTransformBlock(ASE::BaseNode& mesh)
{ {
mode = 2; mode = 2;
} }
else DefaultLogger::get()->error("ASE: Ignoring target transform, " else {
"this is no spot light or target camera"); ASSIMP_LOG_ERROR("ASE: Ignoring target transform, "
"this is no spot light or target camera");
}
} }
else else
{ {
DefaultLogger::get()->error("ASE: Unknown node transformation: " + temp); ASSIMP_LOG_ERROR("ASE: Unknown node transformation: " + temp);
// mode = 0 // mode = 0
} }
continue; continue;
@ -1916,7 +1918,7 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh)
else if (index == face.mIndices[2]) else if (index == face.mIndices[2])
index = 2; index = 2;
else { else {
DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_VERTEXNORMAL section"); ASSIMP_LOG_ERROR("ASE: Invalid vertex index in MESH_VERTEXNORMAL section");
continue; continue;
} }
// We'll renormalize later // We'll renormalize later
@ -1928,7 +1930,7 @@ void Parser::ParseLV3MeshNormalListBlock(ASE::Mesh& sMesh)
ParseLV4MeshFloatTriple(&vNormal.x,faceIdx); ParseLV4MeshFloatTriple(&vNormal.x,faceIdx);
if (faceIdx >= sMesh.mFaces.size()) { if (faceIdx >= sMesh.mFaces.size()) {
DefaultLogger::get()->error("ASE: Invalid vertex index in MESH_FACENORMAL section"); ASSIMP_LOG_ERROR("ASE: Invalid vertex index in MESH_FACENORMAL section");
continue; continue;
} }

View File

@ -427,7 +427,7 @@ public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
//! Construct a parser from a given input file which is //! Construct a parser from a given input file which is
//! guaranted to be terminated with zero. //! guaranteed to be terminated with zero.
//! @param szFile Input file //! @param szFile Input file
//! @param fileFormatDefault Assumed file format version. If the //! @param fileFormatDefault Assumed file format version. If the
//! file format is specified in the file the new value replaces //! file format is specified in the file the new value replaces

View File

@ -146,7 +146,7 @@ private:
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ReportSceneNotFoundError() { void ReportSceneNotFoundError() {
DefaultLogger::get()->error("Unable to find the Assimp::Importer for this aiScene. " ASSIMP_LOG_ERROR("Unable to find the Assimp::Importer for this aiScene. "
"The C-API does not accept scenes produced by the C++ API and vice versa"); "The C-API does not accept scenes produced by the C++ API and vice versa");
ai_assert(false); ai_assert(false);

View File

@ -614,7 +614,7 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
if (!DefaultLogger::isNullLogger()) { if (!DefaultLogger::isNullLogger()) {
char dmp[128]; char dmp[128];
ai_snprintf(dmp, 128, "B3D file format version: %i",version); ai_snprintf(dmp, 128, "B3D file format version: %i",version);
DefaultLogger::get()->info(dmp); ASSIMP_LOG_INFO(dmp);
} }
while( ChunkSize() ){ while( ChunkSize() ){

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

@ -64,23 +64,24 @@ using namespace Assimp;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
BaseImporter::BaseImporter() BaseImporter::BaseImporter()
: m_progress() : m_progress() {
{
// nothing to do here // nothing to do here
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
BaseImporter::~BaseImporter() BaseImporter::~BaseImporter() {
{
// nothing to do here // nothing to do here
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports the given file and returns the imported data. // Imports the given file and returns the imported data.
aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, IOSystem* pIOHandler) aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, IOSystem* pIOHandler) {
{
m_progress = pImp->GetProgressHandler(); m_progress = pImp->GetProgressHandler();
if (nullptr == m_progress) {
return nullptr;
}
ai_assert(m_progress); ai_assert(m_progress);
// Gather configuration properties for this run // Gather configuration properties for this run
@ -100,8 +101,8 @@ aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile,
} catch( const std::exception& err ) { } catch( const std::exception& err ) {
// extract error description // extract error description
m_ErrorText = err.what(); m_ErrorText = err.what();
DefaultLogger::get()->error(m_ErrorText); ASSIMP_LOG_ERROR(m_ErrorText);
return NULL; return nullptr;
} }
// return what we gathered from the import. // return what we gathered from the import.
@ -115,13 +116,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,12 +145,13 @@ 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() ) {
@ -178,16 +179,24 @@ void BaseImporter::GetExtensionList(std::set<std::string>& extensions)
} }
*cur2 = '\0'; *cur2 = '\0';
for (unsigned int i = 0; i < numTokens;++i) { std::string token;
ai_assert(NULL != tokens[i]); for (unsigned int i = 0; i < numTokens; ++i ) {
const char* r = strstr(buffer,tokens[i]); ai_assert( nullptr != tokens[i] );
const size_t len( strlen( tokens[ i ] ) );
token.clear();
const char *ptr( tokens[ i ] );
for ( size_t tokIdx = 0; tokIdx < len; ++tokIdx ) {
token.push_back( tolower( *ptr ) );
++ptr;
}
const char* r = strstr( buffer, token.c_str() );
if( !r ) { if( !r ) {
continue; continue;
} }
// We got a match, either we don't care where it is, or it happens to // We got a match, either we don't care where it is, or it happens to
// be in the beginning of the file / line // be in the beginning of the file / line
if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') { if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') {
DefaultLogger::get()->debug(std::string("Found positive match for header keyword: ") + tokens[i]); ASSIMP_LOG_DEBUG_F( "Found positive match for header keyword: ", tokens[i] );
return true; return true;
} }
} }
@ -243,7 +252,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;
@ -313,7 +323,7 @@ void BaseImporter::ConvertToUTF8(std::vector<char>& data)
// UTF 8 with BOM // UTF 8 with BOM
if((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) { if((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) {
DefaultLogger::get()->debug("Found UTF-8 BOM ..."); ASSIMP_LOG_DEBUG("Found UTF-8 BOM ...");
std::copy(data.begin()+3,data.end(),data.begin()); std::copy(data.begin()+3,data.end(),data.begin());
data.resize(data.size()-3); data.resize(data.size()-3);
@ -332,7 +342,7 @@ void BaseImporter::ConvertToUTF8(std::vector<char>& data)
// UTF 32 LE with BOM // UTF 32 LE with BOM
if(*((uint32_t*)&data.front()) == 0x0000FFFE) { if(*((uint32_t*)&data.front()) == 0x0000FFFE) {
DefaultLogger::get()->debug("Found UTF-32 BOM ..."); ASSIMP_LOG_DEBUG("Found UTF-32 BOM ...");
std::vector<char> output; std::vector<char> output;
int *ptr = (int*)&data[ 0 ]; int *ptr = (int*)&data[ 0 ];
@ -352,7 +362,7 @@ void BaseImporter::ConvertToUTF8(std::vector<char>& data)
// UTF 16 LE with BOM // UTF 16 LE with BOM
if(*((uint16_t*)&data.front()) == 0xFEFF) { if(*((uint16_t*)&data.front()) == 0xFEFF) {
DefaultLogger::get()->debug("Found UTF-16 BOM ..."); ASSIMP_LOG_DEBUG("Found UTF-16 BOM ...");
std::vector<unsigned char> output; std::vector<unsigned char> output;
utf8::utf16to8(data.begin(), data.end(), back_inserter(output)); utf8::utf16to8(data.begin(), data.end(), back_inserter(output));
@ -377,16 +387,14 @@ void BaseImporter::ConvertUTF8toISO8859_1(std::string& data)
data[j] = ((unsigned char) data[++i] + 0x40); data[j] = ((unsigned char) data[++i] + 0x40);
} else { } else {
std::stringstream stream; std::stringstream stream;
stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1."; stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1.";
ASSIMP_LOG_ERROR( stream.str() );
DefaultLogger::get()->error(stream.str());
data[j++] = data[i++]; data[j++] = data[i++];
data[j] = data[i]; data[j] = data[i];
} }
} else { } else {
DefaultLogger::get()->error("UTF8 code but only one character remaining"); ASSIMP_LOG_ERROR("UTF8 code but only one character remaining");
data[j] = data[i]; data[j] = data[i];
} }
@ -402,7 +410,7 @@ void BaseImporter::TextFileToBuffer(IOStream* stream,
std::vector<char>& data, std::vector<char>& data,
TextFileMode mode) TextFileMode mode)
{ {
ai_assert(NULL != stream); ai_assert(nullptr != stream);
const size_t fileSize = stream->FileSize(); const size_t fileSize = stream->FileSize();
if (mode == FORBID_EMPTY) { if (mode == FORBID_EMPTY) {
@ -463,14 +471,14 @@ struct Assimp::BatchData {
, pImporter( nullptr ) , pImporter( nullptr )
, next_id(0xffff) , next_id(0xffff)
, validate( validate ) { , validate( validate ) {
ai_assert( NULL != pIO ); ai_assert( nullptr != pIO );
pImporter = new Importer(); pImporter = new Importer();
pImporter->SetIOHandler( pIO ); pImporter->SetIOHandler( pIO );
} }
~BatchData() { ~BatchData() {
pImporter->SetIOHandler( NULL ); /* get pointer back into our possession */ pImporter->SetIOHandler( nullptr ); /* get pointer back into our possession */
delete pImporter; delete pImporter;
} }
@ -496,9 +504,8 @@ struct Assimp::BatchData {
typedef std::list<LoadRequest>::iterator LoadReqIt; typedef std::list<LoadRequest>::iterator LoadReqIt;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
BatchLoader::BatchLoader(IOSystem* pIO, bool validate ) BatchLoader::BatchLoader(IOSystem* pIO, bool validate ) {
{ ai_assert(nullptr != pIO);
ai_assert(NULL != pIO);
m_data = new BatchData( pIO, validate ); m_data = new BatchData( pIO, validate );
} }
@ -564,7 +571,7 @@ aiScene* BatchLoader::GetImport( unsigned int which )
return sc; return sc;
} }
} }
return NULL; return nullptr;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -587,13 +594,13 @@ void BatchLoader::LoadAll()
if (!DefaultLogger::isNullLogger()) if (!DefaultLogger::isNullLogger())
{ {
DefaultLogger::get()->info("%%% BEGIN EXTERNAL FILE %%%"); ASSIMP_LOG_INFO("%%% BEGIN EXTERNAL FILE %%%");
DefaultLogger::get()->info("File: " + (*it).file); ASSIMP_LOG_INFO_F("File: ", (*it).file);
} }
m_data->pImporter->ReadFile((*it).file,pp); m_data->pImporter->ReadFile((*it).file,pp);
(*it).scene = m_data->pImporter->GetOrphanedScene(); (*it).scene = m_data->pImporter->GetOrphanedScene();
(*it).loaded = true; (*it).loaded = true;
DefaultLogger::get()->info("%%% END EXTERNAL FILE %%%"); ASSIMP_LOG_INFO("%%% END EXTERNAL FILE %%%");
} }
} }

View File

@ -85,7 +85,7 @@ void BaseProcess::ExecuteOnScene( Importer* pImp)
// extract error description // extract error description
pImp->Pimpl()->mErrorString = err.what(); pImp->Pimpl()->mErrorString = err.what();
DefaultLogger::get()->error(pImp->Pimpl()->mErrorString); ASSIMP_LOG_ERROR(pImp->Pimpl()->mErrorString);
// and kill the partially imported data // and kill the partially imported data
delete pImp->Pimpl()->mScene; delete pImp->Pimpl()->mScene;

View File

@ -0,0 +1,185 @@
#include "BlenderCustomData.h"
#include "BlenderDNA.h"
#include <array>
#include <functional>
namespace Assimp {
namespace Blender {
/**
* @brief read/convert of Structure array to memory
*/
template<typename T>
bool read(const Structure &s, T *p, const size_t cnt, const FileDatabase &db) {
for (size_t i = 0; i < cnt; ++i) {
T read;
s.Convert(read, db);
*p = read;
p++;
}
return true;
}
/**
* @brief pointer to function read memory for n CustomData types
*/
typedef bool (*PRead)(ElemBase *pOut, const size_t cnt, const FileDatabase &db);
typedef ElemBase * (*PCreate)(const size_t cnt);
typedef void(*PDestroy)(ElemBase *);
#define IMPL_STRUCT_READ(ty) \
bool read##ty(ElemBase *v, const size_t cnt, const FileDatabase &db) { \
return read<ty>(db.dna[#ty], dynamic_cast<ty *>(v), cnt, db); \
}
#define IMPL_STRUCT_CREATE(ty) \
ElemBase *create##ty(const size_t cnt) { \
return new ty[cnt]; \
}
#define IMPL_STRUCT_DESTROY(ty) \
void destroy##ty(ElemBase *pE) { \
ty *p = dynamic_cast<ty *>(pE); \
delete[]p; \
}
/**
* @brief helper macro to define Structure functions
*/
#define IMPL_STRUCT(ty) \
IMPL_STRUCT_READ(ty) \
IMPL_STRUCT_CREATE(ty) \
IMPL_STRUCT_DESTROY(ty)
// supported structures for CustomData
IMPL_STRUCT(MVert)
IMPL_STRUCT(MEdge)
IMPL_STRUCT(MFace)
IMPL_STRUCT(MTFace)
IMPL_STRUCT(MTexPoly)
IMPL_STRUCT(MLoopUV)
IMPL_STRUCT(MLoopCol)
IMPL_STRUCT(MPoly)
IMPL_STRUCT(MLoop)
/**
* @brief describes the size of data and the read function to be used for single CustomerData.type
*/
struct CustomDataTypeDescription {
PRead Read; ///< function to read one CustomData type element
PCreate Create; ///< function to allocate n type elements
PDestroy Destroy;
CustomDataTypeDescription(PRead read, PCreate create, PDestroy destroy)
: Read(read)
, Create(create)
, Destroy(destroy)
{}
};
/**
* @brief helper macro to define Structure type specific CustomDataTypeDescription
* @note IMPL_STRUCT_READ for same ty must be used earlier to implement the typespecific read function
*/
#define DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(ty) \
CustomDataTypeDescription{&read##ty, &create##ty, &destroy##ty}
/**
* @brief helper macro to define CustomDataTypeDescription for UNSUPPORTED type
*/
#define DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION \
CustomDataTypeDescription{nullptr, nullptr, nullptr}
/**
* @brief descriptors for data pointed to from CustomDataLayer.data
* @note some of the CustomData uses already well defined Structures
* other (like CD_ORCO, ...) uses arrays of rawtypes or even arrays of Structures
* use a special readfunction for that cases
*/
std::array<CustomDataTypeDescription, CD_NUMTYPES> customDataTypeDescriptions = { {
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MVert),
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MEdge),
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MFace),
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MTFace),
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MTexPoly),
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoopUV),
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoopCol),
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MPoly),
DECL_STRUCT_CUSTOMDATATYPEDESCRIPTION(MLoop),
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION,
DECL_UNSUPPORTED_CUSTOMDATATYPEDESCRIPTION
}};
bool isValidCustomDataType(const int cdtype) {
return cdtype >= 0 && cdtype < CD_NUMTYPES;
}
bool readCustomData(std::shared_ptr<ElemBase> &out, const int cdtype, const size_t cnt, const FileDatabase &db) {
if (!isValidCustomDataType(cdtype)) {
throw Error((Formatter::format(), "CustomData.type ", cdtype, " out of index"));
}
const CustomDataTypeDescription cdtd = customDataTypeDescriptions[cdtype];
if (cdtd.Read && cdtd.Create && cdtd.Destroy && cnt > 0) {
// allocate cnt elements and parse them from file
out.reset(cdtd.Create(cnt), cdtd.Destroy);
return cdtd.Read(out.get(), cnt, db);
}
return false;
}
std::shared_ptr<CustomDataLayer> getCustomDataLayer(const CustomData &customdata, const CustomDataType cdtype, const std::string &name) {
for (auto it = customdata.layers.begin(); it != customdata.layers.end(); ++it) {
if (it->get()->type == cdtype && name == it->get()->name) {
return *it;
}
}
return nullptr;
}
const ElemBase * getCustomDataLayerData(const CustomData &customdata, const CustomDataType cdtype, const std::string &name)
{
const std::shared_ptr<CustomDataLayer> pLayer = getCustomDataLayer(customdata, cdtype, name);
if (pLayer && pLayer->data) {
return pLayer->data.get();
}
return nullptr;
}
}
}

View File

@ -0,0 +1,89 @@
#pragma once
#include "BlenderDNA.h"
#include "BlenderScene.h"
#include <memory>
namespace Assimp {
namespace Blender {
/* CustomData.type from Blender (2.79b) */
enum CustomDataType {
CD_AUTO_FROM_NAME = -1,
CD_MVERT = 0,
#ifdef DNA_DEPRECATED
CD_MSTICKY = 1, /* DEPRECATED */
#endif
CD_MDEFORMVERT = 2,
CD_MEDGE = 3,
CD_MFACE = 4,
CD_MTFACE = 5,
CD_MCOL = 6,
CD_ORIGINDEX = 7,
CD_NORMAL = 8,
/* CD_POLYINDEX = 9, */
CD_PROP_FLT = 10,
CD_PROP_INT = 11,
CD_PROP_STR = 12,
CD_ORIGSPACE = 13, /* for modifier stack face location mapping */
CD_ORCO = 14,
CD_MTEXPOLY = 15,
CD_MLOOPUV = 16,
CD_MLOOPCOL = 17,
CD_TANGENT = 18,
CD_MDISPS = 19,
CD_PREVIEW_MCOL = 20, /* for displaying weightpaint colors */
/* CD_ID_MCOL = 21, */
CD_TEXTURE_MLOOPCOL = 22,
CD_CLOTH_ORCO = 23,
CD_RECAST = 24,
/* BMESH ONLY START */
CD_MPOLY = 25,
CD_MLOOP = 26,
CD_SHAPE_KEYINDEX = 27,
CD_SHAPEKEY = 28,
CD_BWEIGHT = 29,
CD_CREASE = 30,
CD_ORIGSPACE_MLOOP = 31,
CD_PREVIEW_MLOOPCOL = 32,
CD_BM_ELEM_PYPTR = 33,
/* BMESH ONLY END */
CD_PAINT_MASK = 34,
CD_GRID_PAINT_MASK = 35,
CD_MVERT_SKIN = 36,
CD_FREESTYLE_EDGE = 37,
CD_FREESTYLE_FACE = 38,
CD_MLOOPTANGENT = 39,
CD_TESSLOOPNORMAL = 40,
CD_CUSTOMLOOPNORMAL = 41,
CD_NUMTYPES = 42
};
/**
* @brief check if given cdtype is valid (ie >= 0 and < CD_NUMTYPES)
* @param[in] cdtype to check
* @return true when valid
*/
bool isValidCustomDataType(const int cdtype);
/**
* @brief returns CustomDataLayer ptr for given cdtype and name
* @param[in] customdata CustomData to search for wanted layer
* @param[in] cdtype to search for
* @param[in] name to search for
* @return CustomDataLayer * or nullptr if not found
*/
std::shared_ptr<CustomDataLayer> getCustomDataLayer(const CustomData &customdata, CustomDataType cdtype, const std::string &name);
/**
* @brief returns CustomDataLayer data ptr for given cdtype and name
* @param[in] customdata CustomData to search for wanted layer
* @param[in] cdtype to search for
* @param[in] name to search for
* @return * to struct data or nullptr if not found
*/
const ElemBase * getCustomDataLayerData(const CustomData &customdata, CustomDataType cdtype, const std::string &name);
}
}

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]);
} }
@ -211,8 +210,7 @@ void DNAParser::Parse ()
s.size = offset; s.size = offset;
} }
DefaultLogger::get()->debug((format(),"BlenderDNA: Got ",dna.structures.size(), ASSIMP_LOG_DEBUG_F( "BlenderDNA: Got ", dna.structures.size()," structures with totally ",fields," fields");
" structures with totally ",fields," fields"));
#ifdef ASSIMP_BUILD_BLENDER_DEBUG #ifdef ASSIMP_BUILD_BLENDER_DEBUG
dna.DumpToFile(); dna.DumpToFile();
@ -229,12 +227,12 @@ void DNAParser::Parse ()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void DNA :: DumpToFile() void DNA :: DumpToFile()
{ {
// we dont't bother using the VFS here for this is only for debugging. // we don't bother using the VFS here for this is only for debugging.
// (and all your bases are belong to us). // (and all your bases are belong to us).
std::ofstream f("dna.txt"); std::ofstream f("dna.txt");
if (f.fail()) { if (f.fail()) {
DefaultLogger::get()->error("Could not dump dna to dna.txt"); ASSIMP_LOG_ERROR("Could not dump dna to dna.txt");
return; return;
} }
f << "Field format: type name offset size" << "\n"; f << "Field format: type name offset size" << "\n";
@ -249,7 +247,7 @@ void DNA :: DumpToFile()
} }
f << std::flush; f << std::flush;
DefaultLogger::get()->info("BlenderDNA: Dumped dna to dna.txt"); ASSIMP_LOG_INFO("BlenderDNA: Dumped dna to dna.txt");
} }
#endif #endif
@ -368,7 +366,7 @@ void SectionParser :: Next()
} }
#ifdef ASSIMP_BUILD_BLENDER_DEBUG #ifdef ASSIMP_BUILD_BLENDER_DEBUG
DefaultLogger::get()->debug(current.id); ASSIMP_LOG_DEBUG(current.id);
#endif #endif
} }

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
@ -309,6 +309,28 @@ public:
void ReadField(T& out, const char* name, void ReadField(T& out, const char* name,
const FileDatabase& db) const; const FileDatabase& db) const;
// --------------------------------------------------------
/**
* @brief field parsing for dynamic vectors
* @param[in] out vector of struct to be filled
* @param[in] name of field
* @param[in] db to access the file, dna, ...
* @return true when read was successful
*/
template <int error_policy, template <typename> class TOUT, typename T>
bool ReadFieldPtrVector(vector<TOUT<T>>&out, const char* name, const FileDatabase& db) const;
/**
* @brief parses raw customdata
* @param[in] out shared_ptr to be filled
* @param[in] cdtype customdata type to read
* @param[in] name of field ptr
* @param[in] db to access the file, dna, ...
* @return true when read was successful
*/
template <int error_policy>
bool ReadCustomDataPtr(std::shared_ptr<ElemBase>&out, int cdtype, const char* name, const FileDatabase& db) const;
private: private:
// -------------------------------------------------------- // --------------------------------------------------------
@ -381,7 +403,7 @@ template <> struct Structure :: _defaultInitializer<ErrorPolicy_Warn> {
template <typename T> template <typename T>
void operator ()(T& out, const char* reason = "<add reason>") { void operator ()(T& out, const char* reason = "<add reason>") {
DefaultLogger::get()->warn(reason); ASSIMP_LOG_WARN(reason);
// ... and let the show go on // ... and let the show go on
_defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out); _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out);
@ -663,7 +685,7 @@ public:
/** Check whether a specific item is in the cache. /** Check whether a specific item is in the cache.
* @param s Data type of the item * @param s Data type of the item
* @param out Output pointer. Unchanged if the * @param out Output pointer. Unchanged if the
* cache doens't know the item yet. * cache doesn't know the item yet.
* @param ptr Item address to look for. */ * @param ptr Item address to look for. */
template <typename T> void get ( template <typename T> void get (
const Structure& s, const Structure& s,
@ -803,6 +825,17 @@ private:
FileDatabase& db; FileDatabase& db;
}; };
/**
* @brief read CustomData's data to ptr to mem
* @param[out] out memory ptr to set
* @param[in] cdtype to read
* @param[in] cnt cnt of elements to read
* @param[in] db to read elements from
* @return true when ok
*/
bool readCustomData(std::shared_ptr<ElemBase> &out, int cdtype, size_t cnt, const FileDatabase &db);
} // end Blend } // end Blend
} // end Assimp } // end Assimp

View File

@ -307,6 +307,108 @@ void Structure :: ReadField(T& out, const char* name, const FileDatabase& db) co
} }
//--------------------------------------------------------------------------------
// field parsing for raw untyped data (like CustomDataLayer.data)
template <int error_policy>
bool Structure::ReadCustomDataPtr(std::shared_ptr<ElemBase>&out, int cdtype, const char* name, const FileDatabase& db) const {
const StreamReaderAny::pos old = db.reader->GetCurrentPos();
Pointer ptrval;
const Field* f;
try {
f = &(*this)[name];
// sanity check, should never happen if the genblenddna script is right
if (!(f->flags & FieldFlag_Pointer)) {
throw Error((Formatter::format(), "Field `", name, "` of structure `",
this->name, "` ought to be a pointer"));
}
db.reader->IncPtr(f->offset);
Convert(ptrval, db);
// actually it is meaningless on which Structure the Convert is called
// because the `Pointer` argument triggers a special implementation.
}
catch (const Error& e) {
_defaultInitializer<error_policy>()(out, e.what());
out.reset();
}
bool readOk = true;
if (ptrval.val) {
// get block for ptr
const FileBlockHead* block = LocateFileBlockForAddress(ptrval, db);
db.reader->SetCurrentPos(block->start + static_cast<size_t>((ptrval.val - block->address.val)));
// read block->num instances of given type to out
readOk = readCustomData(out, cdtype, block->num, db);
}
// and recover the previous stream position
db.reader->SetCurrentPos(old);
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
++db.stats().fields_read;
#endif
return readOk;
}
//--------------------------------------------------------------------------------
template <int error_policy, template <typename> class TOUT, typename T>
bool Structure::ReadFieldPtrVector(vector<TOUT<T>>&out, const char* name, const FileDatabase& db) const {
out.clear();
const StreamReaderAny::pos old = db.reader->GetCurrentPos();
Pointer ptrval;
const Field* f;
try {
f = &(*this)[name];
// sanity check, should never happen if the genblenddna script is right
if (!(f->flags & FieldFlag_Pointer)) {
throw Error((Formatter::format(), "Field `", name, "` of structure `",
this->name, "` ought to be a pointer"));
}
db.reader->IncPtr(f->offset);
Convert(ptrval, db);
// actually it is meaningless on which Structure the Convert is called
// because the `Pointer` argument triggers a special implementation.
}
catch (const Error& e) {
_defaultInitializer<error_policy>()(out, e.what());
out.clear();
return false;
}
if (ptrval.val) {
// find the file block the pointer is pointing to
const FileBlockHead* block = LocateFileBlockForAddress(ptrval, db);
db.reader->SetCurrentPos(block->start + static_cast<size_t>((ptrval.val - block->address.val)));
// FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems.
// I really ought to improve StreamReader to work with 64 bit indices exclusively.
const Structure& s = db.dna[f->type];
for (size_t i = 0; i < block->num; ++i) {
TOUT<T> p(new T);
s.Convert(*p, db);
out.push_back(p);
}
}
db.reader->SetCurrentPos(old);
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS
++db.stats().fields_read;
#endif
return false;
}
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
template <template <typename> class TOUT, typename T> template <template <typename> class TOUT, typename T>
bool Structure :: ResolvePointer(TOUT<T>& out, const Pointer & ptrval, const FileDatabase& db, bool Structure :: ResolvePointer(TOUT<T>& out, const Pointer & ptrval, const FileDatabase& db,
@ -468,9 +570,7 @@ template <> bool Structure :: ResolvePointer<std::shared_ptr,ElemBase>(std::shar
// this might happen if DNA::RegisterConverters hasn't been called so far // this might happen if DNA::RegisterConverters hasn't been called so far
// or if the target type is not contained in `our` DNA. // or if the target type is not contained in `our` DNA.
out.reset(); out.reset();
DefaultLogger::get()->warn((Formatter::format(), ASSIMP_LOG_WARN_F( "Failed to find a converter for the `",s.name,"` structure" );
"Failed to find a converter for the `",s.name,"` structure"
));
return false; return false;
} }
@ -502,7 +602,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

@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "BlenderIntermediate.h" #include "BlenderIntermediate.h"
#include "BlenderModifier.h" #include "BlenderModifier.h"
#include "BlenderBMesh.h" #include "BlenderBMesh.h"
#include "BlenderCustomData.h"
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
@ -327,12 +328,12 @@ void BlenderImporter::ExtractScene(Scene& out, const FileDatabase& file)
ss.Convert(out,file); ss.Convert(out,file);
#ifndef ASSIMP_BUILD_BLENDER_NO_STATS #ifndef ASSIMP_BUILD_BLENDER_NO_STATS
DefaultLogger::get()->info((format(), ASSIMP_LOG_INFO_F(
"(Stats) Fields read: " ,file.stats().fields_read, "(Stats) Fields read: " ,file.stats().fields_read,
", pointers resolved: " ,file.stats().pointers_resolved, ", pointers resolved: " ,file.stats().pointers_resolved,
", cache hits: " ,file.stats().cache_hits, ", cache hits: " ,file.stats().cache_hits,
", cached objects: " ,file.stats().cached_objects ", cached objects: " ,file.stats().cached_objects
)); );
#endif #endif
} }
@ -1021,6 +1022,32 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
} }
} }
// TODO should we create the TextureUVMapping map in Convert<Material> to prevent redundant processing?
// create texture <-> uvname mapping for all materials
// key is texture number, value is data *
typedef std::map<uint32_t, const MLoopUV *> TextureUVMapping;
// key is material number, value is the TextureUVMapping for the material
typedef std::map<uint32_t, TextureUVMapping> MaterialTextureUVMappings;
MaterialTextureUVMappings matTexUvMappings;
const uint32_t maxMat = static_cast<const uint32_t>(mesh->mat.size());
for (uint32_t m = 0; m < maxMat; ++m) {
// get material by index
const std::shared_ptr<Material> pMat = mesh->mat[m];
TextureUVMapping texuv;
const uint32_t maxTex = sizeof(pMat->mtex) / sizeof(pMat->mtex[0]);
for (uint32_t t = 0; t < maxTex; ++t) {
if (pMat->mtex[t] && pMat->mtex[t]->uvname[0]) {
// get the CustomData layer for given uvname and correct type
const ElemBase *pLoop = getCustomDataLayerData(mesh->ldata, CD_MLOOPUV, pMat->mtex[t]->uvname);
if (pLoop) {
texuv.insert(std::make_pair(t, dynamic_cast<const MLoopUV *>(pLoop)));
}
}
}
matTexUvMappings.insert(std::make_pair(m, texuv));
}
// collect texture coordinates, they're stored in a separate per-face buffer // collect texture coordinates, they're stored in a separate per-face buffer
if (mesh->mtface || mesh->mloopuv) { if (mesh->mtface || mesh->mloopuv) {
if (mesh->totface > static_cast<int> ( mesh->mtface.size())) { if (mesh->totface > static_cast<int> ( mesh->mtface.size())) {
@ -1028,8 +1055,17 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
} }
for (std::vector<aiMesh*>::iterator it = temp->begin()+old; it != temp->end(); ++it) { for (std::vector<aiMesh*>::iterator it = temp->begin()+old; it != temp->end(); ++it) {
ai_assert((*it)->mNumVertices && (*it)->mNumFaces); ai_assert((*it)->mNumVertices && (*it)->mNumFaces);
const auto itMatTexUvMapping = matTexUvMappings.find((*it)->mMaterialIndex);
(*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices]; if (itMatTexUvMapping == matTexUvMappings.end()) {
// default behaviour like before
(*it)->mTextureCoords[0] = new aiVector3D[(*it)->mNumVertices];
}
else {
// create texture coords for every mapped tex
for (uint32_t i = 0; i < itMatTexUvMapping->second.size(); ++i) {
(*it)->mTextureCoords[i] = new aiVector3D[(*it)->mNumVertices];
}
}
(*it)->mNumFaces = (*it)->mNumVertices = 0; (*it)->mNumFaces = (*it)->mNumVertices = 0;
} }
@ -1051,13 +1087,34 @@ void BlenderImporter::ConvertMesh(const Scene& /*in*/, const Object* /*obj*/, co
aiMesh* const out = temp[ mat_num_to_mesh_idx[ v.mat_nr ] ]; aiMesh* const out = temp[ mat_num_to_mesh_idx[ v.mat_nr ] ];
const aiFace& f = out->mFaces[out->mNumFaces++]; const aiFace& f = out->mFaces[out->mNumFaces++];
aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices]; const auto itMatTexUvMapping = matTexUvMappings.find(v.mat_nr);
for (unsigned int j = 0; j < f.mNumIndices; ++j,++vo,++out->mNumVertices) { if (itMatTexUvMapping == matTexUvMappings.end()) {
const MLoopUV& uv = mesh->mloopuv[v.loopstart + j]; // old behavior
vo->x = uv.uv[0]; aiVector3D* vo = &out->mTextureCoords[0][out->mNumVertices];
vo->y = uv.uv[1]; for (unsigned int j = 0; j < f.mNumIndices; ++j, ++vo, ++out->mNumVertices) {
const MLoopUV& uv = mesh->mloopuv[v.loopstart + j];
vo->x = uv.uv[0];
vo->y = uv.uv[1];
}
}
else {
// create textureCoords for every mapped tex
for (uint32_t m = 0; m < itMatTexUvMapping->second.size(); ++m) {
const MLoopUV *tm = itMatTexUvMapping->second[m];
aiVector3D* vo = &out->mTextureCoords[m][out->mNumVertices];
uint32_t j = 0;
for (; j < f.mNumIndices; ++j, ++vo) {
const MLoopUV& uv = tm[v.loopstart + j];
vo->x = uv.uv[0];
vo->y = uv.uv[1];
}
// only update written mNumVertices in last loop
// TODO why must the numVertices be incremented here?
if (m == itMatTexUvMapping->second.size() - 1) {
out->mNumVertices += j;
}
}
} }
} }
} }

View File

@ -70,34 +70,6 @@ static const fpCreateModifier creators[] = {
NULL // sentinel NULL // sentinel
}; };
// ------------------------------------------------------------------------------------------------
// just testing out some new macros to simplify logging
#define ASSIMP_LOG_WARN_F(string,...)\
DefaultLogger::get()->warn((Formatter::format(string),__VA_ARGS__))
#define ASSIMP_LOG_ERROR_F(string,...)\
DefaultLogger::get()->error((Formatter::format(string),__VA_ARGS__))
#define ASSIMP_LOG_DEBUG_F(string,...)\
DefaultLogger::get()->debug((Formatter::format(string),__VA_ARGS__))
#define ASSIMP_LOG_INFO_F(string,...)\
DefaultLogger::get()->info((Formatter::format(string),__VA_ARGS__))
#define ASSIMP_LOG_WARN(string)\
DefaultLogger::get()->warn(string)
#define ASSIMP_LOG_ERROR(string)\
DefaultLogger::get()->error(string)
#define ASSIMP_LOG_DEBUG(string)\
DefaultLogger::get()->debug(string)
#define ASSIMP_LOG_INFO(string)\
DefaultLogger::get()->info(string)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
struct SharedModifierData : ElemBase struct SharedModifierData : ElemBase
{ {

View File

@ -47,53 +47,57 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define INCLUDED_AI_BLEND_MODIFIER_H #define INCLUDED_AI_BLEND_MODIFIER_H
#include "BlenderIntermediate.h" #include "BlenderIntermediate.h"
#include <assimp/TinyFormatter.h>
namespace Assimp { namespace Assimp {
namespace Blender { namespace Blender {
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
/** Dummy base class for all blender modifiers. Modifiers are reused between imports, so /**
* they should be stateless and not try to cache model data. */ * Dummy base class for all blender modifiers. Modifiers are reused between imports, so
* they should be stateless and not try to cache model data.
*/
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
class BlenderModifier class BlenderModifier {
{
public: public:
/**
* The class destructor, virtual.
*/
virtual ~BlenderModifier() { virtual ~BlenderModifier() {
// empty // empty
} }
public:
// -------------------- // --------------------
/** Check if *this* modifier is active, given a ModifierData& block.*/ /**
* Check if *this* modifier is active, given a ModifierData& block.
*/
virtual bool IsActive( const ModifierData& /*modin*/) { virtual bool IsActive( const ModifierData& /*modin*/) {
return false; return false;
} }
// -------------------- // --------------------
/** Apply the modifier to a given output node. The original data used /**
* Apply the modifier to a given output node. The original data used
* to construct the node is given as well. Not called unless IsActive() * to construct the node is given as well. Not called unless IsActive()
* was called and gave positive response. */ * was called and gave positive response.
*/
virtual void DoIt(aiNode& /*out*/, virtual void DoIt(aiNode& /*out*/,
ConversionData& /*conv_data*/, ConversionData& /*conv_data*/,
const ElemBase& orig_modifier, const ElemBase& orig_modifier,
const Scene& /*in*/, const Scene& /*in*/,
const Object& /*orig_object*/ const Object& /*orig_object*/
) { ) {
DefaultLogger::get()->warn((Formatter::format("This modifier is not supported, skipping: "),orig_modifier.dna_type)); ASSIMP_LOG_INFO_F("This modifier is not supported, skipping: ",orig_modifier.dna_type );
return; return;
} }
}; };
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
/** Manage all known modifiers and instance and apply them if necessary */ /**
* Manage all known modifiers and instance and apply them if necessary
*/
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
class BlenderModifierShowcase class BlenderModifierShowcase {
{
public: public:
// -------------------- // --------------------
/** Apply all requested modifiers provided we support them. */ /** Apply all requested modifiers provided we support them. */
void ApplyModifiers(aiNode& out, void ApplyModifiers(aiNode& out,
@ -103,25 +107,18 @@ public:
); );
private: private:
TempArray< std::vector,BlenderModifier > cached_modifiers; TempArray< std::vector,BlenderModifier > cached_modifiers;
}; };
// MODIFIERS /////////////////////////////////////////////////////////////////////////////////
// MODIFIERS
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
/** Mirror modifier. Status: implemented. */ /**
* Mirror modifier. Status: implemented.
*/
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
class BlenderModifier_Mirror : public BlenderModifier class BlenderModifier_Mirror : public BlenderModifier {
{
public: public:
// -------------------- // --------------------
virtual bool IsActive( const ModifierData& modin); virtual bool IsActive( const ModifierData& modin);
@ -137,8 +134,7 @@ public:
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
/** Subdivision modifier. Status: dummy. */ /** Subdivision modifier. Status: dummy. */
// ------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------
class BlenderModifier_Subdivision : public BlenderModifier class BlenderModifier_Subdivision : public BlenderModifier {
{
public: public:
// -------------------- // --------------------
@ -153,6 +149,7 @@ public:
) ; ) ;
}; };
}
}
}}
#endif // !INCLUDED_AI_BLEND_MODIFIER_H #endif // !INCLUDED_AI_BLEND_MODIFIER_H

View File

@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "BlenderScene.h" #include "BlenderScene.h"
#include "BlenderSceneGen.h" #include "BlenderSceneGen.h"
#include "BlenderDNA.h" #include "BlenderDNA.h"
#include "BlenderCustomData.h"
using namespace Assimp; using namespace Assimp;
using namespace Assimp::Blender; using namespace Assimp::Blender;
@ -116,7 +117,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);
@ -481,6 +482,12 @@ template <> void Structure :: Convert<Mesh> (
ReadFieldPtr<ErrorPolicy_Igno>(dest.mcol,"*mcol",db); ReadFieldPtr<ErrorPolicy_Igno>(dest.mcol,"*mcol",db);
ReadFieldPtr<ErrorPolicy_Fail>(dest.mat,"**mat",db); ReadFieldPtr<ErrorPolicy_Fail>(dest.mat,"**mat",db);
ReadField<ErrorPolicy_Igno>(dest.vdata, "vdata", db);
ReadField<ErrorPolicy_Igno>(dest.edata, "edata", db);
ReadField<ErrorPolicy_Igno>(dest.fdata, "fdata", db);
ReadField<ErrorPolicy_Igno>(dest.pdata, "pdata", db);
ReadField<ErrorPolicy_Warn>(dest.ldata, "ldata", db);
db.reader->IncPtr(size); db.reader->IncPtr(size);
} }
@ -786,6 +793,42 @@ template <> void Structure :: Convert<Image> (
db.reader->IncPtr(size); db.reader->IncPtr(size);
} }
//--------------------------------------------------------------------------------
template <> void Structure::Convert<CustomData>(
CustomData& dest,
const FileDatabase& db
) const
{
ReadFieldArray<ErrorPolicy_Warn>(dest.typemap, "typemap", db);
ReadField<ErrorPolicy_Igno>(dest.pad_i1, "pad_i1", db);
ReadField<ErrorPolicy_Warn>(dest.totlayer, "totlayer", db);
ReadField<ErrorPolicy_Warn>(dest.maxlayer, "maxlayer", db);
ReadField<ErrorPolicy_Warn>(dest.totsize, "totsize", db);
ReadFieldPtrVector<ErrorPolicy_Warn>(dest.layers, "*layers", db);
db.reader->IncPtr(size);
}
//--------------------------------------------------------------------------------
template <> void Structure::Convert<CustomDataLayer>(
CustomDataLayer& dest,
const FileDatabase& db
) const
{
ReadField<ErrorPolicy_Fail>(dest.type, "type", db);
ReadField<ErrorPolicy_Fail>(dest.offset, "offset", db);
ReadField<ErrorPolicy_Fail>(dest.flag, "flag", db);
ReadField<ErrorPolicy_Fail>(dest.active, "active", db);
ReadField<ErrorPolicy_Fail>(dest.active_rnd, "active_rnd", db);
ReadField<ErrorPolicy_Fail>(dest.active_clone, "active_clone", db);
ReadField<ErrorPolicy_Fail>(dest.active_mask, "active_mask", db);
ReadField<ErrorPolicy_Fail>(dest.uid, "uid", db);
ReadFieldArray<ErrorPolicy_Warn>(dest.name, "name", db);
ReadCustomDataPtr<ErrorPolicy_Fail>(dest.data, dest.type, "*data", db);
db.reader->IncPtr(size);
}
//-------------------------------------------------------------------------------- //--------------------------------------------------------------------------------
void DNA::RegisterConverters() { void DNA::RegisterConverters() {
@ -822,6 +865,8 @@ void DNA::RegisterConverters() {
converters["Camera"] = DNA::FactoryPair( &Structure::Allocate<Camera>, &Structure::Convert<Camera> ); converters["Camera"] = DNA::FactoryPair( &Structure::Allocate<Camera>, &Structure::Convert<Camera> );
converters["MirrorModifierData"] = DNA::FactoryPair( &Structure::Allocate<MirrorModifierData>, &Structure::Convert<MirrorModifierData> ); converters["MirrorModifierData"] = DNA::FactoryPair( &Structure::Allocate<MirrorModifierData>, &Structure::Convert<MirrorModifierData> );
converters["Image"] = DNA::FactoryPair( &Structure::Allocate<Image>, &Structure::Convert<Image> ); converters["Image"] = DNA::FactoryPair( &Structure::Allocate<Image>, &Structure::Convert<Image> );
converters["CustomData"] = DNA::FactoryPair(&Structure::Allocate<CustomData>, &Structure::Convert<CustomData>);
converters["CustomDataLayer"] = DNA::FactoryPair(&Structure::Allocate<CustomDataLayer>, &Structure::Convert<CustomDataLayer>);
} }
#endif // ASSIMP_BUILD_NO_BLEND_IMPORTER #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER

View File

@ -157,10 +157,16 @@ struct World : ElemBase {
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
struct MVert : ElemBase { struct MVert : ElemBase {
float co[3] FAIL; float co[3] FAIL;
float no[3] FAIL; float no[3] FAIL; // readed as short and divided through / 32767.f
char flag; char flag;
int mat_nr WARN; int mat_nr WARN;
int bweight; int bweight;
MVert() : ElemBase()
, flag(0)
, mat_nr(0)
, bweight(0)
{}
}; };
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
@ -369,6 +375,73 @@ struct Material : ElemBase {
std::shared_ptr<MTex> mtex[18]; std::shared_ptr<MTex> mtex[18];
}; };
/*
CustomDataLayer 104
int type 0 4
int offset 4 4
int flag 8 4
int active 12 4
int active_rnd 16 4
int active_clone 20 4
int active_mask 24 4
int uid 28 4
char name 32 64
void *data 96 8
*/
struct CustomDataLayer : ElemBase {
int type;
int offset;
int flag;
int active;
int active_rnd;
int active_clone;
int active_mask;
int uid;
char name[64];
std::shared_ptr<ElemBase> data; // must be converted to real type according type member
CustomDataLayer()
: ElemBase()
, type(0)
, offset(0)
, flag(0)
, active(0)
, active_rnd(0)
, active_clone(0)
, active_mask(0)
, uid(0)
, data(nullptr)
{
memset(name, 0, sizeof name);
}
};
/*
CustomData 208
CustomDataLayer *layers 0 8
int typemap 8 168
int pad_i1 176 4
int totlayer 180 4
int maxlayer 184 4
int totsize 188 4
BLI_mempool *pool 192 8
CustomDataExternal *external 200 8
*/
struct CustomData : ElemBase {
vector<std::shared_ptr<struct CustomDataLayer> > layers;
int typemap[42]; // CD_NUMTYPES
int pad_i1;
int totlayer;
int maxlayer;
int totsize;
/*
std::shared_ptr<BLI_mempool> pool;
std::shared_ptr<CustomDataExternal> external;
*/
};
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------
struct Mesh : ElemBase { struct Mesh : ElemBase {
ID id FAIL; ID id FAIL;
@ -398,6 +471,12 @@ struct Mesh : ElemBase {
vector<MCol> mcol; vector<MCol> mcol;
vector< std::shared_ptr<Material> > mat FAIL; vector< std::shared_ptr<Material> > mat FAIL;
struct CustomData vdata;
struct CustomData edata;
struct CustomData fdata;
struct CustomData pdata;
struct CustomData ldata;
}; };
// ------------------------------------------------------------------------------- // -------------------------------------------------------------------------------

View File

@ -248,6 +248,17 @@ template <> void Structure :: Convert<Image> (
) const ) const
; ;
template <> void Structure::Convert<CustomData>(
CustomData& dest,
const FileDatabase& db
) const
;
template <> void Structure::Convert<CustomDataLayer>(
CustomDataLayer& dest,
const FileDatabase& db
) const
;
} }
} }

View File

@ -47,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define INCLUDED_AI_BLEND_TESSELLATOR_H #define INCLUDED_AI_BLEND_TESSELLATOR_H
// Use these to toggle between GLU Tessellate or poly2tri // Use these to toggle between GLU Tessellate or poly2tri
// Note (acg) keep GLU Tesselate disabled by default - if it is turned on, // Note (acg) keep GLU Tessellate disabled by default - if it is turned on,
// assimp needs to be linked against GLU, which is currently not yet // assimp needs to be linked against GLU, which is currently not yet
// made configurable in CMake and potentially not wanted by most users // made configurable in CMake and potentially not wanted by most users
// as it requires a Gl environment. // as it requires a Gl environment.

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})
@ -207,8 +208,15 @@ OPTION(ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT "default value of all ASSIMP_BUILD_
# macro to add the CMake Option ADD_ASSIMP_IMPORTER_<name> which enables compile of loader # macro to add the CMake Option ADD_ASSIMP_IMPORTER_<name> which enables compile of loader
# this way selective loaders can be compiled (reduces filesize + compile time) # this way selective loaders can be compiled (reduces filesize + compile time)
MACRO(ADD_ASSIMP_IMPORTER name) MACRO(ADD_ASSIMP_IMPORTER name)
OPTION(ASSIMP_BUILD_${name}_IMPORTER "build the ${name} importer" ${ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT}) IF (ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT)
IF(ASSIMP_BUILD_${name}_IMPORTER) set(ASSIMP_IMPORTER_ENABLED TRUE)
IF (DEFINED ASSIMP_BUILD_${name}_IMPORTER AND NOT ASSIMP_BUILD_${name}_IMPORTER)
set(ASSIMP_IMPORTER_ENABLED FALSE)
ENDIF ()
ELSE ()
set(ASSIMP_IMPORTER_ENABLED ${ASSIMP_BUILD_${name}_IMPORTER})
ENDIF ()
IF (ASSIMP_IMPORTER_ENABLED)
LIST(APPEND ASSIMP_LOADER_SRCS ${ARGN}) LIST(APPEND ASSIMP_LOADER_SRCS ${ARGN})
SET(ASSIMP_IMPORTERS_ENABLED "${ASSIMP_IMPORTERS_ENABLED} ${name}") SET(ASSIMP_IMPORTERS_ENABLED "${ASSIMP_IMPORTERS_ENABLED} ${name}")
SET(${name}_SRCS ${ARGN}) SET(${name}_SRCS ${ARGN})
@ -461,6 +469,8 @@ ADD_ASSIMP_IMPORTER( BLEND
BlenderBMesh.cpp BlenderBMesh.cpp
BlenderTessellator.h BlenderTessellator.h
BlenderTessellator.cpp BlenderTessellator.cpp
BlenderCustomData.h
BlenderCustomData.cpp
) )
ADD_ASSIMP_IMPORTER( IFC ADD_ASSIMP_IMPORTER( IFC
@ -484,9 +494,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 +532,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 +595,8 @@ SET( PostProcessing_SRCS
PolyTools.h PolyTools.h
MakeVerboseFormat.cpp MakeVerboseFormat.cpp
MakeVerboseFormat.h MakeVerboseFormat.h
ScaleProcess.cpp
ScaleProcess.h
) )
SOURCE_GROUP( PostProcessing FILES ${PostProcessing_SRCS}) SOURCE_GROUP( PostProcessing FILES ${PostProcessing_SRCS})
@ -641,7 +660,7 @@ ADD_ASSIMP_IMPORTER( X
XFileExporter.cpp XFileExporter.cpp
) )
ADD_ASSIMP_IMPORTER(X3D ADD_ASSIMP_IMPORTER( X3D
X3DExporter.cpp X3DExporter.cpp
X3DExporter.hpp X3DExporter.hpp
X3DImporter.cpp X3DImporter.cpp

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;
} }
@ -151,7 +150,7 @@ void COBImporter::InternReadFile( const std::string& pFile,
ThrowException("Could not found magic id: `Caligari`"); ThrowException("Could not found magic id: `Caligari`");
} }
DefaultLogger::get()->info("File format tag: "+std::string(head+9,6)); ASSIMP_LOG_INFO_F("File format tag: ",std::string(head+9,6));
if (head[16]!='L') { if (head[16]!='L') {
ThrowException("File is big-endian, which is not supported"); ThrowException("File is big-endian, which is not supported");
} }
@ -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 );
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -301,7 +303,7 @@ aiNode* COBImporter::BuildNodes(const Node& root,const Scene& scin,aiScene* fill
} }
std::unique_ptr<const Material> defmat; std::unique_ptr<const Material> defmat;
if(!min) { if(!min) {
DefaultLogger::get()->debug(format()<<"Could not resolve material index " ASSIMP_LOG_DEBUG(format()<<"Could not resolve material index "
<<reflist.first<<" - creating default material for this slot"); <<reflist.first<<" - creating default material for this slot");
defmat.reset(min=new Material()); defmat.reset(min=new Material());
@ -473,7 +475,7 @@ void COBImporter::UnsupportedChunk_Ascii(LineSplitter& splitter, const ChunkInfo
// we can recover if the chunk size was specified. // we can recover if the chunk size was specified.
if(nfo.size != static_cast<unsigned int>(-1)) { if(nfo.size != static_cast<unsigned int>(-1)) {
DefaultLogger::get()->error(error); ASSIMP_LOG_ERROR(error);
// (HACK) - our current position in the stream is the beginning of the // (HACK) - our current position in the stream is the beginning of the
// head line of the next chunk. That's fine, but the caller is going // head line of the next chunk. That's fine, but the caller is going
@ -485,46 +487,6 @@ void COBImporter::UnsupportedChunk_Ascii(LineSplitter& splitter, const ChunkInfo
else ThrowException(error); else ThrowException(error);
} }
// ------------------------------------------------------------------------------------------------
void COBImporter::LogWarn_Ascii(const LineSplitter& splitter, const format& message) {
LogWarn_Ascii(message << " [at line "<< splitter.get_index()<<"]");
}
// ------------------------------------------------------------------------------------------------
void COBImporter::LogError_Ascii(const LineSplitter& splitter, const format& message) {
LogError_Ascii(message << " [at line "<< splitter.get_index()<<"]");
}
// ------------------------------------------------------------------------------------------------
void COBImporter::LogInfo_Ascii(const LineSplitter& splitter, const format& message) {
LogInfo_Ascii(message << " [at line "<< splitter.get_index()<<"]");
}
// ------------------------------------------------------------------------------------------------
void COBImporter::LogDebug_Ascii(const LineSplitter& splitter, const format& message) {
LogDebug_Ascii(message << " [at line "<< splitter.get_index()<<"]");
}
// ------------------------------------------------------------------------------------------------
void COBImporter::LogWarn_Ascii(const Formatter::format& message) {
DefaultLogger::get()->warn(std::string("COB: ")+=message);
}
// ------------------------------------------------------------------------------------------------
void COBImporter::LogError_Ascii(const Formatter::format& message) {
DefaultLogger::get()->error(std::string("COB: ")+=message);
}
// ------------------------------------------------------------------------------------------------
void COBImporter::LogInfo_Ascii(const Formatter::format& message) {
DefaultLogger::get()->info(std::string("COB: ")+=message);
}
// ------------------------------------------------------------------------------------------------
void COBImporter::LogDebug_Ascii(const Formatter::format& message) {
DefaultLogger::get()->debug(std::string("COB: ")+=message);
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void COBImporter::ReadBasicNodeInfo_Ascii(Node& msh, LineSplitter& splitter, const ChunkInfo& /*nfo*/) void COBImporter::ReadBasicNodeInfo_Ascii(Node& msh, LineSplitter& splitter, const ChunkInfo& /*nfo*/)
{ {
@ -574,8 +536,7 @@ void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const Chunk
++splitter; ++splitter;
if (!splitter.match_start("mat# ")) { if (!splitter.match_start("mat# ")) {
LogWarn_Ascii(splitter,format()<< ASSIMP_LOG_WARN_F( "Expected `mat#` line in `Mat1` chunk ", nfo.id );
"Expected `mat#` line in `Mat1` chunk "<<nfo.id);
return; return;
} }
@ -587,8 +548,7 @@ void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const Chunk
++splitter; ++splitter;
if (!splitter.match_start("shader: ")) { if (!splitter.match_start("shader: ")) {
LogWarn_Ascii(splitter,format()<< ASSIMP_LOG_WARN_F( "Expected `mat#` line in `Mat1` chunk ", nfo.id);
"Expected `mat#` line in `Mat1` chunk "<<nfo.id);
return; return;
} }
std::string shader = std::string(splitter[1]); std::string shader = std::string(splitter[1]);
@ -601,14 +561,12 @@ void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const Chunk
mat.shader = Material::PHONG; mat.shader = Material::PHONG;
} }
else if (shader != "flat") { else if (shader != "flat") {
LogWarn_Ascii(splitter,format()<< ASSIMP_LOG_WARN_F( "Unknown value for `shader` in `Mat1` chunk ", nfo.id );
"Unknown value for `shader` in `Mat1` chunk "<<nfo.id);
} }
++splitter; ++splitter;
if (!splitter.match_start("rgb ")) { if (!splitter.match_start("rgb ")) {
LogWarn_Ascii(splitter,format()<< ASSIMP_LOG_WARN_F( "Expected `rgb` line in `Mat1` chunk ", nfo.id);
"Expected `rgb` line in `Mat1` chunk "<<nfo.id);
} }
const char* rgb = splitter[1]; const char* rgb = splitter[1];
@ -616,8 +574,7 @@ void COBImporter::ReadMat1_Ascii(Scene& out, LineSplitter& splitter, const Chunk
++splitter; ++splitter;
if (!splitter.match_start("alpha ")) { if (!splitter.match_start("alpha ")) {
LogWarn_Ascii(splitter,format()<< ASSIMP_LOG_WARN_F( "Expected `alpha` line in `Mat1` chunk ", nfo.id);
"Expected `alpha` line in `Mat1` chunk "<<nfo.id);
} }
const char* tokens[10]; const char* tokens[10];
@ -638,8 +595,7 @@ void COBImporter::ReadUnit_Ascii(Scene& out, LineSplitter& splitter, const Chunk
} }
++splitter; ++splitter;
if (!splitter.match_start("Units ")) { if (!splitter.match_start("Units ")) {
LogWarn_Ascii(splitter,format()<< ASSIMP_LOG_WARN_F( "Expected `Units` line in `Unit` chunk ", nfo.id);
"Expected `Units` line in `Unit` chunk "<<nfo.id);
return; return;
} }
@ -650,13 +606,12 @@ void COBImporter::ReadUnit_Ascii(Scene& out, LineSplitter& splitter, const Chunk
const unsigned int t=strtoul10(splitter[1]); const unsigned int t=strtoul10(splitter[1]);
nd->unit_scale = t>=sizeof(units)/sizeof(units[0])?( nd->unit_scale = t>=sizeof(units)/sizeof(units[0])?(
LogWarn_Ascii(splitter,format()<<t<<" is not a valid value for `Units` attribute in `Unit chunk` "<<nfo.id) ASSIMP_LOG_WARN_F(t, " is not a valid value for `Units` attribute in `Unit chunk` ", nfo.id)
,1.f):units[t]; ,1.f):units[t];
return; return;
} }
} }
LogWarn_Ascii(splitter,format()<<"`Unit` chunk "<<nfo.id<<" is a child of " ASSIMP_LOG_WARN_F( "`Unit` chunk ", nfo.id, " is a child of ", nfo.parent_id, " which does not exist");
<<nfo.parent_id<<" which does not exist");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -690,15 +645,13 @@ void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const Chunk
msh.ltype = Light::SPOT; msh.ltype = Light::SPOT;
} }
else { else {
LogWarn_Ascii(splitter,format()<< ASSIMP_LOG_WARN_F( "Unknown kind of light source in `Lght` chunk ", nfo.id, " : ", *splitter );
"Unknown kind of light source in `Lght` chunk "<<nfo.id<<" : "<<*splitter);
msh.ltype = Light::SPOT; msh.ltype = Light::SPOT;
} }
++splitter; ++splitter;
if (!splitter.match_start("color ")) { if (!splitter.match_start("color ")) {
LogWarn_Ascii(splitter,format()<< ASSIMP_LOG_WARN_F( "Expected `color` line in `Lght` chunk ", nfo.id );
"Expected `color` line in `Lght` chunk "<<nfo.id);
} }
const char* rgb = splitter[1]; const char* rgb = splitter[1];
@ -706,16 +659,14 @@ void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const Chunk
SkipSpaces(&rgb); SkipSpaces(&rgb);
if (strncmp(rgb,"cone angle",10)) { if (strncmp(rgb,"cone angle",10)) {
LogWarn_Ascii(splitter,format()<< ASSIMP_LOG_WARN_F( "Expected `cone angle` entity in `color` line in `Lght` chunk ", nfo.id );
"Expected `cone angle` entity in `color` line in `Lght` chunk "<<nfo.id);
} }
SkipSpaces(rgb+10,&rgb); SkipSpaces(rgb+10,&rgb);
msh.angle = fast_atof(&rgb); msh.angle = fast_atof(&rgb);
SkipSpaces(&rgb); SkipSpaces(&rgb);
if (strncmp(rgb,"inner angle",11)) { if (strncmp(rgb,"inner angle",11)) {
LogWarn_Ascii(splitter,format()<< ASSIMP_LOG_WARN_F( "Expected `inner angle` entity in `color` line in `Lght` chunk ", nfo.id);
"Expected `inner angle` entity in `color` line in `Lght` chunk "<<nfo.id);
} }
SkipSpaces(rgb+11,&rgb); SkipSpaces(rgb+11,&rgb);
msh.inner_angle = fast_atof(&rgb); msh.inner_angle = fast_atof(&rgb);
@ -826,7 +777,7 @@ void COBImporter::ReadPolH_Ascii(Scene& out, LineSplitter& splitter, const Chunk
for(unsigned int cur = 0; cur < cnt && ++splitter ;++cur) { for(unsigned int cur = 0; cur < cnt && ++splitter ;++cur) {
if (splitter.match_start("Hole")) { if (splitter.match_start("Hole")) {
LogWarn_Ascii(splitter,"Skipping unsupported `Hole` line"); ASSIMP_LOG_WARN( "Skipping unsupported `Hole` line" );
continue; continue;
} }
@ -886,7 +837,7 @@ void COBImporter::ReadBitM_Ascii(Scene& /*out*/, LineSplitter& splitter, const C
const unsigned int head = strtoul10((++splitter)[1]); const unsigned int head = strtoul10((++splitter)[1]);
if (head != sizeof(Bitmap::BitmapHeader)) { if (head != sizeof(Bitmap::BitmapHeader)) {
LogWarn_Ascii(splitter,"Unexpected ThumbNailHdrSize, skipping this chunk"); ASSIMP_LOG_WARN("Unexpected ThumbNailHdrSize, skipping this chunk");
return; return;
} }
@ -933,7 +884,7 @@ void COBImporter::UnsupportedChunk_Binary( StreamReaderLE& reader, const ChunkIn
// we can recover if the chunk size was specified. // we can recover if the chunk size was specified.
if(nfo.size != static_cast<unsigned int>(-1)) { if(nfo.size != static_cast<unsigned int>(-1)) {
DefaultLogger::get()->error(error); ASSIMP_LOG_ERROR(error);
reader.IncPtr(nfo.size); reader.IncPtr(nfo.size);
} }
else ThrowException(error); else ThrowException(error);
@ -1140,7 +1091,7 @@ void COBImporter::ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const
mat.type = Material::METAL; mat.type = Material::METAL;
break; break;
default: default:
LogError_Ascii(format("Unrecognized shader type in `Mat1` chunk with id ")<<nfo.id); ASSIMP_LOG_ERROR_F( "Unrecognized shader type in `Mat1` chunk with id ", nfo.id );
mat.type = Material::FLAT; mat.type = Material::FLAT;
} }
@ -1155,7 +1106,7 @@ void COBImporter::ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const
mat.autofacet = Material::SMOOTH; mat.autofacet = Material::SMOOTH;
break; break;
default: default:
LogError_Ascii(format("Unrecognized faceting mode in `Mat1` chunk with id ")<<nfo.id); ASSIMP_LOG_ERROR_F( "Unrecognized faceting mode in `Mat1` chunk with id ", nfo.id );
mat.autofacet = Material::FACETED; mat.autofacet = Material::FACETED;
} }
mat.autofacet_angle = static_cast<float>(reader.GetI1()); mat.autofacet_angle = static_cast<float>(reader.GetI1());
@ -1287,15 +1238,13 @@ void COBImporter::ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const
if (nd->id == nfo.parent_id) { if (nd->id == nfo.parent_id) {
const unsigned int t=reader.GetI2(); const unsigned int t=reader.GetI2();
nd->unit_scale = t>=sizeof(units)/sizeof(units[0])?( nd->unit_scale = t>=sizeof(units)/sizeof(units[0])?(
LogWarn_Ascii(format()<<t<<" is not a valid value for `Units` attribute in `Unit chunk` "<<nfo.id) ASSIMP_LOG_WARN_F(t," is not a valid value for `Units` attribute in `Unit chunk` ", nfo.id)
,1.f):units[t]; ,1.f):units[t];
return; return;
} }
} }
LogWarn_Ascii(format()<<"`Unit` chunk "<<nfo.id<<" is a child of " ASSIMP_LOG_WARN_F( "`Unit` chunk ", nfo.id, " is a child of ", nfo.parent_id, " which does not exist");
<<nfo.parent_id<<" which does not exist");
} }
#endif // ASSIMP_BUILD_NO_COB_IMPORTER
#endif

View File

@ -77,10 +77,7 @@ class COBImporter : public BaseImporter
public: public:
COBImporter(); COBImporter();
~COBImporter(); ~COBImporter();
public:
// -------------------- // --------------------
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
bool checkSig) const; bool checkSig) const;
@ -115,15 +112,11 @@ private:
* @param stream Stream to read from. */ * @param stream Stream to read from. */
void ReadBinaryFile(COB::Scene& out, StreamReaderLE* stream); void ReadBinaryFile(COB::Scene& out, StreamReaderLE* stream);
private:
// Conversion to Assimp output format // Conversion to Assimp output format
aiNode* BuildNodes(const COB::Node& root,const COB::Scene& scin,aiScene* fill); aiNode* BuildNodes(const COB::Node& root,const COB::Scene& scin,aiScene* fill);
private: private:
// ASCII file support // ASCII file support
void UnsupportedChunk_Ascii(LineSplitter& splitter, const COB::ChunkInfo& nfo, const char* name); void UnsupportedChunk_Ascii(LineSplitter& splitter, const COB::ChunkInfo& nfo, const char* name);
@ -142,19 +135,6 @@ private:
void ReadChan_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo); void ReadChan_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo);
// ASCII file logging stuff to add proper line numbers to messages
static void LogWarn_Ascii (const LineSplitter& splitter, const Formatter::format& message);
static void LogError_Ascii(const LineSplitter& splitter, const Formatter::format& message);
static void LogInfo_Ascii (const LineSplitter& splitter, const Formatter::format& message);
static void LogDebug_Ascii(const LineSplitter& splitter, const Formatter::format& message);
static void LogWarn_Ascii (const Formatter::format& message);
static void LogError_Ascii (const Formatter::format& message);
static void LogInfo_Ascii (const Formatter::format& message);
static void LogDebug_Ascii (const Formatter::format& message);
// Binary file support // Binary file support
void UnsupportedChunk_Binary(StreamReaderLE& reader, const COB::ChunkInfo& nfo, const char* name); void UnsupportedChunk_Binary(StreamReaderLE& reader, const COB::ChunkInfo& nfo, const char* name);

View File

@ -233,7 +233,7 @@ void CSMImporter::InternReadFile( const std::string& pFile,
if (TokenMatchI(buffer, "DROPOUT", 7)) { if (TokenMatchI(buffer, "DROPOUT", 7)) {
// seems this is invalid marker data; at least the doc says it's possible // seems this is invalid marker data; at least the doc says it's possible
DefaultLogger::get()->warn("CSM: Encountered invalid marker data (DROPOUT)"); ASSIMP_LOG_WARN("CSM: Encountered invalid marker data (DROPOUT)");
} }
else { else {
aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys; aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys;

View File

@ -95,7 +95,7 @@ void CalcTangentsProcess::Execute( aiScene* pScene)
{ {
ai_assert( NULL != pScene ); ai_assert( NULL != pScene );
DefaultLogger::get()->debug("CalcTangentsProcess begin"); ASSIMP_LOG_DEBUG("CalcTangentsProcess begin");
bool bHas = false; bool bHas = false;
for ( unsigned int a = 0; a < pScene->mNumMeshes; a++ ) { for ( unsigned int a = 0; a < pScene->mNumMeshes; a++ ) {
@ -103,9 +103,9 @@ void CalcTangentsProcess::Execute( aiScene* pScene)
} }
if ( bHas ) { if ( bHas ) {
DefaultLogger::get()->info("CalcTangentsProcess finished. Tangents have been calculated"); ASSIMP_LOG_INFO("CalcTangentsProcess finished. Tangents have been calculated");
} else { } else {
DefaultLogger::get()->debug("CalcTangentsProcess finished"); ASSIMP_LOG_DEBUG("CalcTangentsProcess finished");
} }
} }
@ -126,19 +126,19 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
// are undefined. // are undefined.
if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON)))
{ {
DefaultLogger::get()->info("Tangents are undefined for line and point meshes"); ASSIMP_LOG_INFO("Tangents are undefined for line and point meshes");
return false; return false;
} }
// what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement // what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement
if( pMesh->mNormals == NULL) if( pMesh->mNormals == NULL)
{ {
DefaultLogger::get()->error("Failed to compute tangents; need normals"); ASSIMP_LOG_ERROR("Failed to compute tangents; need normals");
return false; return false;
} }
if( configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV] ) if( configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV] )
{ {
DefaultLogger::get()->error((Formatter::format("Failed to compute tangents; need UV data in channel"),configSourceUV)); ASSIMP_LOG_ERROR((Formatter::format("Failed to compute tangents; need UV data in channel"),configSourceUV));
return false; return false;
} }
@ -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

@ -1269,7 +1269,8 @@ 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

@ -189,7 +189,7 @@ protected:
{} {}
}; };
// summarize a material in an convinient way. // summarize a material in an convenient way.
struct Material struct Material
{ {
std::string name; std::string name;

View File

@ -47,13 +47,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER #ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER
#include "ColladaLoader.h" #include "ColladaLoader.h"
#include "ColladaParser.h"
#include <assimp/anim.h> #include <assimp/anim.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/Importer.hpp> #include <assimp/Importer.hpp>
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <assimp/Defines.h>
#include "ColladaParser.h"
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include <assimp/ParsingUtils.h> #include <assimp/ParsingUtils.h>
#include <assimp/SkeletonMeshBuilder.h> #include <assimp/SkeletonMeshBuilder.h>
@ -63,7 +65,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "math.h" #include "math.h"
#include <algorithm> #include <algorithm>
#include <numeric> #include <numeric>
#include <assimp/Defines.h>
using namespace Assimp; using namespace Assimp;
using namespace Assimp::Formatter; using namespace Assimp::Formatter;
@ -131,6 +132,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;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -292,7 +294,7 @@ void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Co
nd = FindNode(pParser.mRootNode, nodeInst.mNode); nd = FindNode(pParser.mRootNode, nodeInst.mNode);
} }
if (!nd) if (!nd)
DefaultLogger::get()->error("Collada: Unable to resolve reference to instanced node " + nodeInst.mNode); ASSIMP_LOG_ERROR_F("Collada: Unable to resolve reference to instanced node ", nodeInst.mNode);
else { else {
// attach this node to the list of children // attach this node to the list of children
@ -309,7 +311,7 @@ void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler
std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel); std::map<std::string, Collada::InputSemanticMapEntry>::const_iterator it = table.mMap.find(sampler.mUVChannel);
if (it != table.mMap.end()) { if (it != table.mMap.end()) {
if (it->second.mType != Collada::IT_Texcoord) if (it->second.mType != Collada::IT_Texcoord)
DefaultLogger::get()->error("Collada: Unexpected effect input mapping"); ASSIMP_LOG_ERROR("Collada: Unexpected effect input mapping");
sampler.mUVId = it->second.mSet; sampler.mUVId = it->second.mSet;
} }
@ -325,7 +327,7 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll
ColladaParser::LightLibrary::const_iterator srcLightIt = pParser.mLightLibrary.find( lid.mLight); ColladaParser::LightLibrary::const_iterator srcLightIt = pParser.mLightLibrary.find( lid.mLight);
if( srcLightIt == pParser.mLightLibrary.end()) if( srcLightIt == pParser.mLightLibrary.end())
{ {
DefaultLogger::get()->warn("Collada: Unable to find light for ID \"" + lid.mLight + "\". Skipping."); ASSIMP_LOG_WARN_F("Collada: Unable to find light for ID \"" , lid.mLight , "\". Skipping.");
continue; continue;
} }
const Collada::Light* srcLight = &srcLightIt->second; const Collada::Light* srcLight = &srcLightIt->second;
@ -393,14 +395,14 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col
ColladaParser::CameraLibrary::const_iterator srcCameraIt = pParser.mCameraLibrary.find( cid.mCamera); ColladaParser::CameraLibrary::const_iterator srcCameraIt = pParser.mCameraLibrary.find( cid.mCamera);
if( srcCameraIt == pParser.mCameraLibrary.end()) if( srcCameraIt == pParser.mCameraLibrary.end())
{ {
DefaultLogger::get()->warn("Collada: Unable to find camera for ID \"" + cid.mCamera + "\". Skipping."); ASSIMP_LOG_WARN_F("Collada: Unable to find camera for ID \"" , cid.mCamera , "\". Skipping.");
continue; continue;
} }
const Collada::Camera* srcCamera = &srcCameraIt->second; const Collada::Camera* srcCamera = &srcCameraIt->second;
// orthographic cameras not yet supported in Assimp // orthographic cameras not yet supported in Assimp
if (srcCamera->mOrtho) { if (srcCamera->mOrtho) {
DefaultLogger::get()->warn("Collada: Orthographic cameras are not supported."); ASSIMP_LOG_WARN("Collada: Orthographic cameras are not supported.");
} }
// now fill our ai data structure // now fill our ai data structure
@ -470,7 +472,7 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
if( !srcMesh) if( !srcMesh)
{ {
DefaultLogger::get()->warn( format() << "Collada: Unable to find geometry for ID \"" << mid.mMeshOrController << "\". Skipping." ); ASSIMP_LOG_WARN_F( "Collada: Unable to find geometry for ID \"", mid.mMeshOrController, "\". Skipping." );
continue; continue;
} }
} else } else
@ -499,7 +501,8 @@ void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Coll
} }
else else
{ {
DefaultLogger::get()->warn( format() << "Collada: No material specified for subgroup <" << submesh.mMaterial << "> in geometry <" << mid.mMeshOrController << ">." ); ASSIMP_LOG_WARN_F( "Collada: No material specified for subgroup <", submesh.mMaterial, "> in geometry <",
mid.mMeshOrController, ">." );
if( !mid.mMaterials.empty() ) if( !mid.mMaterials.empty() )
meshMaterial = mid.mMaterials.begin()->second.mMatName; meshMaterial = mid.mMaterials.begin()->second.mMatName;
} }
@ -872,7 +875,7 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::
if( bnode) if( bnode)
bone->mName.Set( FindNameForNode( bnode)); bone->mName.Set( FindNameForNode( bnode));
else else
DefaultLogger::get()->warn( format() << "ColladaLoader::CreateMesh(): could not find corresponding node for joint \"" << bone->mName.data << "\"." ); ASSIMP_LOG_WARN_F( "ColladaLoader::CreateMesh(): could not find corresponding node for joint \"", bone->mName.data, "\"." );
// and insert bone // and insert bone
dstMesh->mBones[boneCount++] = bone; dstMesh->mBones[boneCount++] = bone;
@ -953,7 +956,7 @@ void ColladaLoader::StoreSceneMaterials( aiScene* pScene)
// Stores all animations // Stores all animations
void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pParser) void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pParser)
{ {
// recursivly collect all animations from the collada scene // recursively collect all animations from the collada scene
StoreAnimations( pScene, pParser, &pParser.mAnims, ""); StoreAnimations( pScene, pParser, &pParser.mAnims, "");
// catch special case: many animations with the same length, each affecting only a single node. // catch special case: many animations with the same length, each affecting only a single node.
@ -1120,6 +1123,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 +1150,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 +1165,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")
@ -1169,9 +1176,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
else if( subElement == "Z") else if( subElement == "Z")
entry.mSubElement = 2; entry.mSubElement = 2;
else else
DefaultLogger::get()->warn( format() << "Unknown anim subelement <" << subElement << ">. Ignoring" ); ASSIMP_LOG_WARN_F( "Unknown anim subelement <", subElement, ">. Ignoring" );
} else } else {
{
// no subelement following, transformId is remaining string // no subelement following, transformId is remaining string
entry.mTransformId = srcChannel.mTarget.substr( slashPos+1); entry.mTransformId = srcChannel.mTarget.substr( slashPos+1);
} }
@ -1180,7 +1186,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 +1221,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
@ -1400,7 +1406,7 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars
anims.push_back( dstAnim); anims.push_back( dstAnim);
} else } else
{ {
DefaultLogger::get()->warn( "Collada loader: found empty animation channel, ignored. Please check your exporter."); ASSIMP_LOG_WARN( "Collada loader: found empty animation channel, ignored. Please check your exporter.");
} }
if( !entries.empty() && entries.front().mTimeAccessor->mCount > 0 ) if( !entries.empty() && entries.front().mTimeAccessor->mCount > 0 )
@ -1555,7 +1561,7 @@ void ColladaLoader::AddTexture ( aiMaterial& mat, const ColladaParser& pParser,
} }
} }
if (-1 == map) { if (-1 == map) {
DefaultLogger::get()->warn("Collada: unable to determine UV channel for texture"); ASSIMP_LOG_WARN("Collada: unable to determine UV channel for texture");
map = 0; map = 0;
} }
} }
@ -1592,7 +1598,7 @@ void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pSce
break; break;
default: default:
DefaultLogger::get()->warn("Collada: Unrecognized shading mode, using gouraud shading"); ASSIMP_LOG_WARN("Collada: Unrecognized shading mode, using gouraud shading");
shadeMode = aiShadingMode_Gouraud; shadeMode = aiShadingMode_Gouraud;
break; break;
} }
@ -1651,9 +1657,10 @@ void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pSce
} }
// add textures, if given // add textures, if given
if( !effect.mTexAmbient.mName.empty()) if (!effect.mTexAmbient.mName.empty()) {
/* It is merely a lightmap */ // It is merely a light-map
AddTexture( mat, pParser, effect, effect.mTexAmbient, aiTextureType_LIGHTMAP); AddTexture(mat, pParser, effect, effect.mTexAmbient, aiTextureType_LIGHTMAP);
}
if( !effect.mTexEmissive.mName.empty()) if( !effect.mTexEmissive.mName.empty())
AddTexture( mat, pParser, effect, effect.mTexEmissive, aiTextureType_EMISSIVE); AddTexture( mat, pParser, effect, effect.mTexEmissive, aiTextureType_EMISSIVE);
@ -1681,8 +1688,8 @@ void ColladaLoader::BuildMaterials( ColladaParser& pParser, aiScene* /*pScene*/)
{ {
newMats.reserve(pParser.mMaterialLibrary.size()); newMats.reserve(pParser.mMaterialLibrary.size());
for( ColladaParser::MaterialLibrary::const_iterator matIt = pParser.mMaterialLibrary.begin(); matIt != pParser.mMaterialLibrary.end(); ++matIt) for( ColladaParser::MaterialLibrary::const_iterator matIt = pParser.mMaterialLibrary.begin();
{ matIt != pParser.mMaterialLibrary.end(); ++matIt) {
const Collada::Material& material = matIt->second; const Collada::Material& material = matIt->second;
// a material is only a reference to an effect // a material is only a reference to an effect
ColladaParser::EffectLibrary::iterator effIt = pParser.mEffectLibrary.find( material.mEffect); ColladaParser::EffectLibrary::iterator effIt = pParser.mEffectLibrary.find( material.mEffect);
@ -1746,11 +1753,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pPars
ColladaParser::ImageLibrary::const_iterator imIt = pParser.mImageLibrary.find( name); ColladaParser::ImageLibrary::const_iterator imIt = pParser.mImageLibrary.find( name);
if( imIt == pParser.mImageLibrary.end()) if( imIt == pParser.mImageLibrary.end())
{ {
//missing texture should not stop the conversion ASSIMP_LOG_WARN_F("Collada: Unable to resolve effect texture entry \"", pName, "\", ended up at ID \"", name, "\".");
//throw DeadlyImportError( format() <<
// "Collada: Unable to resolve effect texture entry \"" << pName << "\", ended up at ID \"" << name << "\"." );
DefaultLogger::get()->warn("Collada: Unable to resolve effect texture entry \"" + pName + "\", ended up at ID \"" + name + "\".");
//set default texture file name //set default texture file name
result.Set(name + ".jpg"); result.Set(name + ".jpg");
@ -1769,7 +1772,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pPars
// setup format hint // setup format hint
if (imIt->second.mEmbeddedFormat.length() > 3) { if (imIt->second.mEmbeddedFormat.length() > 3) {
DefaultLogger::get()->warn("Collada: texture format hint is too long, truncating to 3 characters"); ASSIMP_LOG_WARN("Collada: texture format hint is too long, truncating to 3 characters");
} }
strncpy(tex->achFormatHint,imIt->second.mEmbeddedFormat.c_str(),3); strncpy(tex->achFormatHint,imIt->second.mEmbeddedFormat.c_str(),3);
@ -1781,7 +1784,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pPars
// TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING" // TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING"
// In FBX files textures are now stored internally by Assimp with their filename included // In FBX files textures are now stored internally by Assimp with their filename included
// Now Assimp can lookup thru the loaded textures after all data is processed // Now Assimp can lookup through the loaded textures after all data is processed
// We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it // We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it
// This may occur on this case too, it has to be studied // This may occur on this case too, it has to be studied
// setup texture reference string // setup texture reference string
@ -1805,7 +1808,7 @@ void ColladaLoader::ConvertPath (aiString& ss)
{ {
// TODO: collada spec, p 22. Handle URI correctly. // TODO: collada spec, p 22. Handle URI correctly.
// For the moment we're just stripping the file:// away to make it work. // For the moment we're just stripping the file:// away to make it work.
// Windoes doesn't seem to be able to find stuff like // Windows doesn't seem to be able to find stuff like
// 'file://..\LWO\LWO2\MappingModes\earthSpherical.jpg' // 'file://..\LWO\LWO2\MappingModes\earthSpherical.jpg'
if (0 == strncmp(ss.data,"file://",7)) if (0 == strncmp(ss.data,"file://",7))
{ {
@ -1816,10 +1819,13 @@ void ColladaLoader::ConvertPath (aiString& ss)
// Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes... // Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes...
// I need to filter it without destroying linux paths starting with "/somewhere" // I need to filter it without destroying linux paths starting with "/somewhere"
if( ss.data[0] == '/' && isalpha( ss.data[1]) && ss.data[2] == ':' ) #if defined( _MSC_VER )
{ if( ss.data[0] == '/' && isalpha( (unsigned char) ss.data[1]) && ss.data[2] == ':' ) {
ss.length--; #else
memmove( ss.data, ss.data+1, ss.length); if (ss.data[ 0 ] == '/' && isalpha( ss.data[ 1 ] ) && ss.data[ 2 ] == ':') {
#endif
--ss.length;
::memmove( ss.data, ss.data+1, ss.length);
ss.data[ss.length] = 0; ss.data[ss.length] = 0;
} }
@ -1869,9 +1875,9 @@ const std::string& ColladaLoader::ReadString( const Collada::Accessor& pAccessor
void ColladaLoader::CollectNodes( const aiNode* pNode, std::vector<const aiNode*>& poNodes) const void ColladaLoader::CollectNodes( const aiNode* pNode, std::vector<const aiNode*>& poNodes) const
{ {
poNodes.push_back( pNode); poNodes.push_back( pNode);
for (size_t a = 0; a < pNode->mNumChildren; ++a) {
for( size_t a = 0; a < pNode->mNumChildren; ++a) CollectNodes(pNode->mChildren[a], poNodes);
CollectNodes( pNode->mChildren[a], poNodes); }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1913,6 +1919,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

@ -152,22 +152,22 @@ void ColladaParser::ReadContents()
if (!::strncmp(version,"1.5",3)) { if (!::strncmp(version,"1.5",3)) {
mFormat = FV_1_5_n; mFormat = FV_1_5_n;
DefaultLogger::get()->debug("Collada schema version is 1.5.n"); ASSIMP_LOG_DEBUG("Collada schema version is 1.5.n");
} }
else if (!::strncmp(version,"1.4",3)) { else if (!::strncmp(version,"1.4",3)) {
mFormat = FV_1_4_n; mFormat = FV_1_4_n;
DefaultLogger::get()->debug("Collada schema version is 1.4.n"); ASSIMP_LOG_DEBUG("Collada schema version is 1.4.n");
} }
else if (!::strncmp(version,"1.3",3)) { else if (!::strncmp(version,"1.3",3)) {
mFormat = FV_1_3_n; mFormat = FV_1_3_n;
DefaultLogger::get()->debug("Collada schema version is 1.3.n"); ASSIMP_LOG_DEBUG("Collada schema version is 1.3.n");
} }
} }
ReadStructure(); ReadStructure();
} else } else
{ {
DefaultLogger::get()->debug( format() << "Ignoring global element <" << mReader->getNodeName() << ">." ); ASSIMP_LOG_DEBUG_F( "Ignoring global element <", mReader->getNodeName(), ">." );
SkipElement(); SkipElement();
} }
} else } else
@ -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()
@ -968,13 +984,13 @@ void ColladaParser::ReadImage( Collada::Image& pImage)
// they're not skipped. // they're not skipped.
int attrib = TestAttribute("array_index"); int attrib = TestAttribute("array_index");
if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) { if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) {
DefaultLogger::get()->warn("Collada: Ignoring texture array index"); ASSIMP_LOG_WARN("Collada: Ignoring texture array index");
continue; continue;
} }
attrib = TestAttribute("mip_index"); attrib = TestAttribute("mip_index");
if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) { if (attrib != -1 && mReader->getAttributeValueAsInt(attrib) > 0) {
DefaultLogger::get()->warn("Collada: Ignoring MIP map layer"); ASSIMP_LOG_WARN("Collada: Ignoring MIP map layer");
continue; continue;
} }
@ -995,7 +1011,7 @@ void ColladaParser::ReadImage( Collada::Image& pImage)
// embedded image. get format // embedded image. get format
const int attrib = TestAttribute("format"); const int attrib = TestAttribute("format");
if (-1 == attrib) if (-1 == attrib)
DefaultLogger::get()->warn("Collada: Unknown image file format"); ASSIMP_LOG_WARN("Collada: Unknown image file format");
else pImage.mEmbeddedFormat = mReader->getAttributeValue(attrib); else pImage.mEmbeddedFormat = mReader->getAttributeValue(attrib);
const char* data = GetTextContent(); const char* data = GetTextContent();
@ -1574,7 +1590,7 @@ void ColladaParser::ReadSamplerProperties( Sampler& out )
out.mOp = aiTextureOp_Multiply; out.mOp = aiTextureOp_Multiply;
else { else {
DefaultLogger::get()->warn("Collada: Unsupported MAYA texture blend mode"); ASSIMP_LOG_WARN("Collada: Unsupported MAYA texture blend mode");
} }
TestClosing( "blend_mode"); TestClosing( "blend_mode");
} }
@ -2525,7 +2541,7 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si
if( pInput.mIndex == 0) if( pInput.mIndex == 0)
pMesh->mPositions.push_back( aiVector3D( obj[0], obj[1], obj[2])); pMesh->mPositions.push_back( aiVector3D( obj[0], obj[1], obj[2]));
else else
DefaultLogger::get()->error("Collada: just one vertex position stream supported"); ASSIMP_LOG_ERROR("Collada: just one vertex position stream supported");
break; break;
case IT_Normal: case IT_Normal:
// pad to current vertex count if necessary // pad to current vertex count if necessary
@ -2536,7 +2552,7 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si
if( pInput.mIndex == 0) if( pInput.mIndex == 0)
pMesh->mNormals.push_back( aiVector3D( obj[0], obj[1], obj[2])); pMesh->mNormals.push_back( aiVector3D( obj[0], obj[1], obj[2]));
else else
DefaultLogger::get()->error("Collada: just one vertex normal stream supported"); ASSIMP_LOG_ERROR("Collada: just one vertex normal stream supported");
break; break;
case IT_Tangent: case IT_Tangent:
// pad to current vertex count if necessary // pad to current vertex count if necessary
@ -2547,7 +2563,7 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si
if( pInput.mIndex == 0) if( pInput.mIndex == 0)
pMesh->mTangents.push_back( aiVector3D( obj[0], obj[1], obj[2])); pMesh->mTangents.push_back( aiVector3D( obj[0], obj[1], obj[2]));
else else
DefaultLogger::get()->error("Collada: just one vertex tangent stream supported"); ASSIMP_LOG_ERROR("Collada: just one vertex tangent stream supported");
break; break;
case IT_Bitangent: case IT_Bitangent:
// pad to current vertex count if necessary // pad to current vertex count if necessary
@ -2558,7 +2574,7 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si
if( pInput.mIndex == 0) if( pInput.mIndex == 0)
pMesh->mBitangents.push_back( aiVector3D( obj[0], obj[1], obj[2])); pMesh->mBitangents.push_back( aiVector3D( obj[0], obj[1], obj[2]));
else else
DefaultLogger::get()->error("Collada: just one vertex bitangent stream supported"); ASSIMP_LOG_ERROR("Collada: just one vertex bitangent stream supported");
break; break;
case IT_Texcoord: case IT_Texcoord:
// up to 4 texture coord sets are fine, ignore the others // up to 4 texture coord sets are fine, ignore the others
@ -2574,7 +2590,7 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si
pMesh->mNumUVComponents[pInput.mIndex]=3; pMesh->mNumUVComponents[pInput.mIndex]=3;
} else } else
{ {
DefaultLogger::get()->error("Collada: too many texture coordinate sets. Skipping."); ASSIMP_LOG_ERROR("Collada: too many texture coordinate sets. Skipping.");
} }
break; break;
case IT_Color: case IT_Color:
@ -2594,7 +2610,7 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si
pMesh->mColors[pInput.mIndex].push_back(result); pMesh->mColors[pInput.mIndex].push_back(result);
} else } else
{ {
DefaultLogger::get()->error("Collada: too many vertex color sets. Skipping."); ASSIMP_LOG_ERROR("Collada: too many vertex color sets. Skipping.");
} }
break; break;
@ -2723,7 +2739,7 @@ void ColladaParser::ReadSceneNode( Node* pNode)
{ {
const char* s = mReader->getAttributeValue(attrId); const char* s = mReader->getAttributeValue(attrId);
if (s[0] != '#') if (s[0] != '#')
DefaultLogger::get()->error("Collada: Unresolved reference format of camera"); ASSIMP_LOG_ERROR("Collada: Unresolved reference format of camera");
else else
pNode->mPrimaryCamera = s+1; pNode->mPrimaryCamera = s+1;
} }
@ -2736,7 +2752,7 @@ void ColladaParser::ReadSceneNode( Node* pNode)
{ {
const char* s = mReader->getAttributeValue(attrID); const char* s = mReader->getAttributeValue(attrID);
if (s[0] != '#') if (s[0] != '#')
DefaultLogger::get()->error("Collada: Unresolved reference format of node"); ASSIMP_LOG_ERROR("Collada: Unresolved reference format of node");
else else
{ {
pNode->mNodeInstances.push_back(NodeInstance()); pNode->mNodeInstances.push_back(NodeInstance());
@ -2754,7 +2770,7 @@ void ColladaParser::ReadSceneNode( Node* pNode)
// Reference to a light, name given in 'url' attribute // Reference to a light, name given in 'url' attribute
int attrID = TestAttribute("url"); int attrID = TestAttribute("url");
if (-1 == attrID) if (-1 == attrID)
DefaultLogger::get()->warn("Collada: Expected url attribute in <instance_light> element"); ASSIMP_LOG_WARN("Collada: Expected url attribute in <instance_light> element");
else else
{ {
const char* url = mReader->getAttributeValue( attrID); const char* url = mReader->getAttributeValue( attrID);
@ -2770,7 +2786,7 @@ void ColladaParser::ReadSceneNode( Node* pNode)
// Reference to a camera, name given in 'url' attribute // Reference to a camera, name given in 'url' attribute
int attrID = TestAttribute("url"); int attrID = TestAttribute("url");
if (-1 == attrID) if (-1 == attrID)
DefaultLogger::get()->warn("Collada: Expected url attribute in <instance_camera> element"); ASSIMP_LOG_WARN("Collada: Expected url attribute in <instance_camera> element");
else else
{ {
const char* url = mReader->getAttributeValue( attrID); const char* url = mReader->getAttributeValue( attrID);
@ -2857,7 +2873,7 @@ void ColladaParser::ReadMaterialVertexInputBinding( Collada::SemanticMappingTabl
tbl.mMap[s] = vn; tbl.mMap[s] = vn;
} }
else if( IsElement( "bind")) { else if( IsElement( "bind")) {
DefaultLogger::get()->warn("Collada: Found unsupported <bind> element"); ASSIMP_LOG_WARN("Collada: Found unsupported <bind> element");
} }
} }
else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) {
@ -2976,10 +2992,9 @@ void ColladaParser::ReportWarning(const char* msg,...)
ai_assert(iLen > 0); ai_assert(iLen > 0);
va_end(args); va_end(args);
DefaultLogger::get()->warn("Validation warning: " + std::string(szBuffer,iLen)); ASSIMP_LOG_WARN_F("Validation warning: ", std::string(szBuffer,iLen));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Skips all data until the end node of the current element // Skips all data until the end node of the current element
void ColladaParser::SkipElement() void ColladaParser::SkipElement()
@ -3090,7 +3105,7 @@ const char* ColladaParser::TestTextContent()
// read contents of the element // read contents of the element
if( !mReader->read() ) if( !mReader->read() )
return NULL; return NULL;
if( mReader->getNodeType() != irr::io::EXN_TEXT) if( mReader->getNodeType() != irr::io::EXN_TEXT && mReader->getNodeType() != irr::io::EXN_CDATA)
return NULL; return NULL;
// skip leading whitespace // skip leading whitespace
@ -3174,7 +3189,7 @@ aiMatrix4x4 ColladaParser::CalculateResultTransform( const std::vector<Transform
Collada::InputType ColladaParser::GetTypeForSemantic( const std::string& semantic) Collada::InputType ColladaParser::GetTypeForSemantic( const std::string& semantic)
{ {
if ( semantic.empty() ) { if ( semantic.empty() ) {
DefaultLogger::get()->warn( format() << "Vertex input type is empty." ); ASSIMP_LOG_WARN("Vertex input type is empty." );
return IT_Invalid; return IT_Invalid;
} }
@ -3193,7 +3208,7 @@ Collada::InputType ColladaParser::GetTypeForSemantic( const std::string& semanti
else if( semantic == "TANGENT" || semantic == "TEXTANGENT") else if( semantic == "TANGENT" || semantic == "TEXTANGENT")
return IT_Tangent; return IT_Tangent;
DefaultLogger::get()->warn( format() << "Unknown vertex input type \"" << semantic << "\". Ignoring." ); ASSIMP_LOG_WARN_F( "Unknown vertex input type \"", semantic, "\". Ignoring." );
return IT_Invalid; return IT_Invalid;
} }

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

@ -99,7 +99,7 @@ inline unsigned int FindEmptyUVChannel (aiMesh* mesh)
for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m) for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m)
if (!mesh->mTextureCoords[m])return m; if (!mesh->mTextureCoords[m])return m;
DefaultLogger::get()->error("Unable to compute UV coordinates, no free UV slot found"); ASSIMP_LOG_ERROR("Unable to compute UV coordinates, no free UV slot found");
return UINT_MAX; return UINT_MAX;
} }
@ -384,13 +384,13 @@ void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D&
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ComputeUVMappingProcess::ComputeBoxMapping( aiMesh*, aiVector3D* ) void ComputeUVMappingProcess::ComputeBoxMapping( aiMesh*, aiVector3D* )
{ {
DefaultLogger::get()->error("Mapping type currently not implemented"); ASSIMP_LOG_ERROR("Mapping type currently not implemented");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ComputeUVMappingProcess::Execute( aiScene* pScene) void ComputeUVMappingProcess::Execute( aiScene* pScene)
{ {
DefaultLogger::get()->debug("GenUVCoordsProcess begin"); ASSIMP_LOG_DEBUG("GenUVCoordsProcess begin");
char buffer[1024]; char buffer[1024];
if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT)
@ -418,7 +418,7 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex, TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex,
MappingTypeToString(mapping)); MappingTypeToString(mapping));
DefaultLogger::get()->info(buffer); ASSIMP_LOG_INFO(buffer);
} }
if (aiTextureMapping_OTHER == mapping) if (aiTextureMapping_OTHER == mapping)
@ -485,7 +485,7 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
} }
if (m && idx != outIdx) if (m && idx != outIdx)
{ {
DefaultLogger::get()->warn("UV index mismatch. Not all meshes assigned to " ASSIMP_LOG_WARN("UV index mismatch. Not all meshes assigned to "
"this material have equal numbers of UV channels. The UV index stored in " "this material have equal numbers of UV channels. The UV index stored in "
"the material structure does therefore not apply for all meshes. "); "the material structure does therefore not apply for all meshes. ");
} }
@ -502,5 +502,5 @@ void ComputeUVMappingProcess::Execute( aiScene* pScene)
} }
} }
} }
DefaultLogger::get()->debug("GenUVCoordsProcess finished"); ASSIMP_LOG_DEBUG("GenUVCoordsProcess finished");
} }

View File

@ -85,18 +85,20 @@ void MakeLeftHandedProcess::Execute( aiScene* pScene)
{ {
// Check for an existent root node to proceed // Check for an existent root node to proceed
ai_assert(pScene->mRootNode != NULL); ai_assert(pScene->mRootNode != NULL);
DefaultLogger::get()->debug("MakeLeftHandedProcess begin"); ASSIMP_LOG_DEBUG("MakeLeftHandedProcess begin");
// recursively convert all the nodes // recursively convert all the nodes
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++)
@ -108,7 +110,7 @@ void MakeLeftHandedProcess::Execute( aiScene* pScene)
ProcessAnimation( nodeAnim); ProcessAnimation( nodeAnim);
} }
} }
DefaultLogger::get()->debug("MakeLeftHandedProcess finished"); ASSIMP_LOG_DEBUG("MakeLeftHandedProcess finished");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -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 ) {
ASSIMP_LOG_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 ) {
ASSIMP_LOG_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;
} }
} }
@ -237,13 +245,13 @@ bool FlipUVsProcess::IsActive( unsigned int pFlags) const
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void FlipUVsProcess::Execute( aiScene* pScene) void FlipUVsProcess::Execute( aiScene* pScene)
{ {
DefaultLogger::get()->debug("FlipUVsProcess begin"); ASSIMP_LOG_DEBUG("FlipUVsProcess begin");
for (unsigned int i = 0; i < pScene->mNumMeshes;++i) for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
ProcessMesh(pScene->mMeshes[i]); ProcessMesh(pScene->mMeshes[i]);
for (unsigned int i = 0; i < pScene->mNumMaterials;++i) for (unsigned int i = 0; i < pScene->mNumMaterials;++i)
ProcessMaterial(pScene->mMaterials[i]); ProcessMaterial(pScene->mMaterials[i]);
DefaultLogger::get()->debug("FlipUVsProcess finished"); ASSIMP_LOG_DEBUG("FlipUVsProcess finished");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -254,7 +262,7 @@ void FlipUVsProcess::ProcessMaterial (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];
if( !prop ) { if( !prop ) {
DefaultLogger::get()->debug( "Property is null" ); ASSIMP_LOG_DEBUG( "Property is null" );
continue; continue;
} }
@ -311,10 +319,10 @@ bool FlipWindingOrderProcess::IsActive( unsigned int pFlags) const
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void FlipWindingOrderProcess::Execute( aiScene* pScene) void FlipWindingOrderProcess::Execute( aiScene* pScene)
{ {
DefaultLogger::get()->debug("FlipWindingOrderProcess begin"); ASSIMP_LOG_DEBUG("FlipWindingOrderProcess begin");
for (unsigned int i = 0; i < pScene->mNumMeshes;++i) for (unsigned int i = 0; i < pScene->mNumMeshes;++i)
ProcessMesh(pScene->mMeshes[i]); ProcessMesh(pScene->mMeshes[i]);
DefaultLogger::get()->debug("FlipWindingOrderProcess finished"); ASSIMP_LOG_DEBUG("FlipWindingOrderProcess finished");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

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 ) {
mRelOutput << "<Relationship Target=\"/" << mRelations[ i ]->target << "\" "; if ( mRelations[ i ]->target[ 0 ] == '/' ) {
mRelOutput << "<Relationship Target=\"" << mRelations[ i ]->target << "\" ";
} else {
mRelOutput << "<Relationship Target=\"/" << mRelations[ i ]->target << "\" ";
}
mRelOutput << "Id=\"" << mRelations[i]->id << "\" "; mRelOutput << "Id=\"" << mRelations[i]->id << "\" ";
mRelOutput << "Type=\"" << mRelations[ i ]->type << "\" />"; mRelOutput << "Type=\"" << mRelations[ i ]->type << "\" />";
mRelOutput << std::endl; mRelOutput << std::endl;
@ -177,6 +182,10 @@ bool D3MFExporter::export3DModel() {
mModelOutput << "<" << XmlTag::resources << ">"; mModelOutput << "<" << XmlTag::resources << ">";
mModelOutput << std::endl; mModelOutput << std::endl;
writeMetaData();
writeBaseMaterials();
writeObjects(); writeObjects();
@ -203,6 +212,63 @@ void D3MFExporter::writeHeader() {
mModelOutput << std::endl; mModelOutput << std::endl;
} }
void D3MFExporter::writeMetaData() {
if ( nullptr == mScene->mMetaData ) {
return;
}
const unsigned int numMetaEntries( mScene->mMetaData->mNumProperties );
if ( 0 == numMetaEntries ) {
return;
}
const aiString *key = nullptr;
const aiMetadataEntry *entry(nullptr);
for ( size_t i = 0; i < numMetaEntries; ++i ) {
mScene->mMetaData->Get( i, key, entry );
std::string k( key->C_Str() );
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(static_cast<unsigned int>( numMeta ) );
for ( size_t i = 0; i < numMeta; ++i ) {
aiString val( mMetaData[ i ].value );
scene->mMetaData->Set(static_cast<unsigned int>( i ), mMetaData[ i ].name, val );
}
}
// import the meshes
scene->mNumMeshes = static_cast<unsigned int>( mMeshes.size());
scene->mMeshes = new aiMesh*[scene->mNumMeshes](); scene->mMeshes = new aiMesh*[scene->mNumMeshes]();
std::copy( mMeshes.begin(), mMeshes.end(), scene->mMeshes);
std::copy(meshes.begin(), meshes.end(), scene->mMeshes); // import the materials
scene->mNumMaterials = static_cast<unsigned int>( mMatArray.size() );
if ( 0 != scene->mNumMaterials ) {
scene->mMaterials = new aiMaterial*[ scene->mNumMaterials ];
std::copy( mMatArray.begin(), mMatArray.end(), scene->mMaterials );
}
// create the scenegraph
scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size()); scene->mRootNode->mNumChildren = static_cast<unsigned int>(children.size());
scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren](); scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren]();
std::copy(children.begin(), children.end(), scene->mRootNode->mChildren); std::copy(children.begin(), children.end(), scene->mRootNode->mChildren);
} }
private: private:
aiNode* ReadObject(aiScene* scene) aiNode* ReadObject(aiScene* scene) {
{
std::unique_ptr<aiNode> node(new aiNode()); std::unique_ptr<aiNode> node(new aiNode());
std::vector<unsigned long> meshIds; std::vector<unsigned long> meshIds;
const char *attrib( nullptr ); const char *attrib( nullptr );
std::string name, type; std::string name, type;
attrib = xmlReader->getAttributeValue( D3MF::XmlTag::name.c_str() ); attrib = xmlReader->getAttributeValue( D3MF::XmlTag::id.c_str() );
if ( nullptr != attrib ) { if ( nullptr != attrib ) {
name = attrib; name = attrib;
} }
attrib = xmlReader->getAttributeValue( D3MF::XmlTag::name.c_str() ); attrib = xmlReader->getAttributeValue( D3MF::XmlTag::type.c_str() );
if ( nullptr != attrib ) { if ( nullptr != attrib ) {
type = attrib; type = attrib;
} }
@ -124,19 +160,16 @@ private:
node->mParent = scene->mRootNode; node->mParent = scene->mRootNode;
node->mName.Set(name); node->mName.Set(name);
size_t meshIdx = meshes.size(); size_t meshIdx = mMeshes.size();
while(ReadToEndElement(D3MF::XmlTag::object)) while(ReadToEndElement(D3MF::XmlTag::object)) {
{ if(xmlReader->getNodeName() == D3MF::XmlTag::mesh) {
if(xmlReader->getNodeName() == D3MF::XmlTag::mesh)
{
auto mesh = ReadMesh(); auto mesh = ReadMesh();
mesh->mName.Set(name); mesh->mName.Set(name);
meshes.push_back(mesh); mMeshes.push_back(mesh);
meshIds.push_back(static_cast<unsigned long>(meshIdx)); meshIds.push_back(static_cast<unsigned long>(meshIdx));
meshIdx++; ++meshIdx;
} }
} }
@ -147,19 +180,14 @@ private:
std::copy(meshIds.begin(), meshIds.end(), node->mMeshes); std::copy(meshIds.begin(), meshIds.end(), node->mMeshes);
return node.release(); return node.release();
} }
aiMesh* ReadMesh() { aiMesh *ReadMesh() {
aiMesh* mesh = new aiMesh(); aiMesh* mesh = new aiMesh();
while(ReadToEndElement(D3MF::XmlTag::mesh)) while(ReadToEndElement(D3MF::XmlTag::mesh)) {
{ if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) {
if(xmlReader->getNodeName() == D3MF::XmlTag::vertices)
{
ImportVertices(mesh); ImportVertices(mesh);
} } else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles) {
else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles)
{
ImportTriangles(mesh); ImportTriangles(mesh);
} }
} }
@ -167,14 +195,25 @@ private:
return mesh; return mesh;
} }
void ImportVertices(aiMesh* mesh) void ReadMetadata() {
{ const std::string name = xmlReader->getAttributeValue( D3MF::XmlTag::meta_name.c_str() );
std::vector<aiVector3D> vertices; xmlReader->read();
const std::string value = xmlReader->getNodeData();
while(ReadToEndElement(D3MF::XmlTag::vertices)) if ( name.empty() ) {
{ return;
if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) }
{
MetaEntry entry;
entry.name = name;
entry.value = value;
mMetaData.push_back( entry );
}
void ImportVertices(aiMesh* mesh) {
std::vector<aiVector3D> vertices;
while(ReadToEndElement(D3MF::XmlTag::vertices)) {
if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) {
vertices.push_back(ReadVertex()); vertices.push_back(ReadVertex());
} }
} }
@ -182,11 +221,9 @@ private:
mesh->mVertices = new aiVector3D[mesh->mNumVertices]; mesh->mVertices = new aiVector3D[mesh->mNumVertices];
std::copy(vertices.begin(), vertices.end(), mesh->mVertices); std::copy(vertices.begin(), vertices.end(), mesh->mVertices);
} }
aiVector3D ReadVertex() aiVector3D ReadVertex() {
{
aiVector3D vertex; aiVector3D vertex;
vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr); vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr);
@ -196,16 +233,18 @@ private:
return vertex; return vertex;
} }
void ImportTriangles(aiMesh* mesh) void ImportTriangles(aiMesh* mesh) {
{
std::vector<aiFace> faces; std::vector<aiFace> faces;
while(ReadToEndElement(D3MF::XmlTag::triangles)) {
while(ReadToEndElement(D3MF::XmlTag::triangles)) const std::string nodeName( xmlReader->getNodeName() );
{ if(xmlReader->getNodeName() == D3MF::XmlTag::triangle) {
if(xmlReader->getNodeName() == D3MF::XmlTag::triangle)
{
faces.push_back(ReadTriangle()); faces.push_back(ReadTriangle());
const char *pidToken( xmlReader->getAttributeValue( D3MF::XmlTag::p1.c_str() ) );
if ( nullptr != pidToken ) {
int matIdx( std::atoi( pidToken ) );
mesh->mMaterialIndex = matIdx;
}
} }
} }
@ -216,8 +255,7 @@ private:
std::copy(faces.begin(), faces.end(), mesh->mFaces); std::copy(faces.begin(), faces.end(), mesh->mFaces);
} }
aiFace ReadTriangle() aiFace ReadTriangle() {
{
aiFace face; aiFace face;
face.mNumIndices = 3; face.mNumIndices = 3;
@ -229,45 +267,150 @@ private:
return face; return face;
} }
private: void ReadBaseMaterials() {
bool ReadToStartElement(const std::string& startTag) std::vector<unsigned int> MatIdArray;
{ const char *baseMaterialId( xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_id.c_str() ) );
while(xmlReader->read()) if ( nullptr != baseMaterialId ) {
{ unsigned int id = std::atoi( baseMaterialId );
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && xmlReader->getNodeName() == startTag) const size_t newMatIdx( mMatArray.size() );
{ if ( id != mActiveMatGroup ) {
return true; mActiveMatGroup = id;
MatId2MatArray::const_iterator it( mMatId2MatArray.find( id ) );
if ( mMatId2MatArray.end() == it ) {
MatIdArray.clear();
mMatId2MatArray[ id ] = MatIdArray;
} else {
MatIdArray = it->second;
}
} }
else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && MatIdArray.push_back( static_cast<unsigned int>( newMatIdx ) );
xmlReader->getNodeName() == startTag) mMatId2MatArray[ mActiveMatGroup ] = MatIdArray;
{ }
while ( ReadToEndElement( D3MF::XmlTag::basematerials ) ) {
mMatArray.push_back( readMaterialDef() );
}
}
bool parseColor( const char *color, aiColor4D &diffuse ) {
if ( nullptr == color ) {
return false;
}
const size_t len( strlen( color ) );
if ( 9 != len ) {
return false;
}
const char *buf( color );
if ( '#' != *buf ) {
return false;
}
++buf;
char comp[ 3 ] = { 0,0,'\0' };
comp[ 0 ] = *buf;
++buf;
comp[ 1 ] = *buf;
++buf;
diffuse.r = static_cast<ai_real>( strtol( comp, NULL, 16 ) );
comp[ 0 ] = *buf;
++buf;
comp[ 1 ] = *buf;
++buf;
diffuse.g = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
comp[ 0 ] = *buf;
++buf;
comp[ 1 ] = *buf;
++buf;
diffuse.b = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
comp[ 0 ] = *buf;
++buf;
comp[ 1 ] = *buf;
++buf;
diffuse.a = static_cast< ai_real >( strtol( comp, NULL, 16 ) );
return true;
}
void assignDiffuseColor( aiMaterial *mat ) {
const char *color = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_displaycolor.c_str() );
aiColor4D diffuse;
if ( parseColor( color, diffuse ) ) {
mat->AddProperty<aiColor4D>( &diffuse, 1, AI_MATKEY_COLOR_DIFFUSE );
}
}
aiMaterial *readMaterialDef() {
aiMaterial *mat( nullptr );
const char *name( nullptr );
const std::string nodeName( xmlReader->getNodeName() );
if ( nodeName == D3MF::XmlTag::basematerials_base ) {
name = xmlReader->getAttributeValue( D3MF::XmlTag::basematerials_name.c_str() );
std::string stdMatName;
aiString matName;
std::string strId( to_string( mActiveMatGroup ) );
stdMatName += "id";
stdMatName += strId;
stdMatName += "_";
if ( nullptr != name ) {
stdMatName += std::string( name );
} else {
stdMatName += "basemat";
}
matName.Set( stdMatName );
mat = new aiMaterial;
mat->AddProperty( &matName, AI_MATKEY_NAME );
assignDiffuseColor( mat );
}
return mat;
}
private:
bool ReadToStartElement(const std::string& startTag) {
while(xmlReader->read()) {
const std::string &nodeName( xmlReader->getNodeName() );
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && nodeName == startTag) {
return true;
} else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == startTag) {
return false; return false;
} }
} }
//DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag");
return false; return false;
} }
bool ReadToEndElement(const std::string& closeTag) bool ReadToEndElement(const std::string& closeTag) {
{ while(xmlReader->read()) {
while(xmlReader->read()) const std::string &nodeName( xmlReader->getNodeName() );
{
if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) { if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) {
return true; return true;
} } else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && nodeName == closeTag) {
else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END
&& xmlReader->getNodeName() == closeTag)
{
return false; return false;
} }
} }
DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag"); ASSIMP_LOG_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,32 +267,32 @@ D3MFZipArchive::~D3MFZipArchive() {
} }
m_ArchiveMap.clear(); m_ArchiveMap.clear();
if(m_ZipFileHandle != NULL) { if(m_ZipFileHandle != nullptr) {
unzClose(m_ZipFileHandle); unzClose(m_ZipFileHandle);
m_ZipFileHandle = NULL; m_ZipFileHandle = nullptr;
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns true, if the archive is already open. // Returns true, if the archive is already open.
bool D3MFZipArchive::isOpen() const { bool D3MFZipArchive::isOpen() const {
return (m_ZipFileHandle != NULL); return (m_ZipFileHandle != nullptr );
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns true, if the filename is part of the archive. // Returns true, if the filename is part of the archive.
bool D3MFZipArchive::Exists(const char* pFile) const { bool D3MFZipArchive::Exists(const char* pFile) const {
ai_assert(pFile != NULL); ai_assert(pFile != nullptr );
bool exist = false; if ( pFile == nullptr ) {
return false;
}
if (pFile != NULL) { std::string filename(pFile);
std::string rFile(pFile); std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(filename);
std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(rFile); bool exist( false );
if(it != m_ArchiveMap.end()) {
if(it != m_ArchiveMap.end()) { exist = true;
exist = true;
}
} }
return exist; return exist;
@ -434,8 +434,8 @@ public:
std::vector<OpcPackageRelationshipPtr> m_relationShips; std::vector<OpcPackageRelationshipPtr> m_relationShips;
}; };
// ------------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------------
D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile) D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
: mRootStream(nullptr) : mRootStream(nullptr)
, mZipArchive() { , mZipArchive() {
@ -460,28 +460,19 @@ 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 );
} }
} }
DefaultLogger::get()->debug(rootFile); ASSIMP_LOG_DEBUG(rootFile);
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;
@ -64,9 +64,11 @@ class D3MFZipArchive;
class D3MFOpcPackage { class D3MFOpcPackage {
public: public:
D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile); D3MFOpcPackage( IOSystem* pIOHandler, const std::string& rFile );
~D3MFOpcPackage(); ~D3MFOpcPackage();
IOStream* RootStream() const; IOStream* RootStream() const;
bool validate();
static bool isZipArchive( IOSystem* pIOHandler, const std::string& rFile );
protected: protected:
std::string ReadPackageRootRelationship(IOStream* stream); std::string ReadPackageRootRelationship(IOStream* stream);
@ -76,7 +78,7 @@ private:
std::unique_ptr<D3MFZipArchive> mZipArchive; std::unique_ptr<D3MFZipArchive> mZipArchive;
}; };
} } // Namespace D3MF
} } // Namespace Assimp
#endif // D3MFOPCPACKAGE_H #endif // D3MFOPCPACKAGE_H

View File

@ -146,7 +146,7 @@ public:
for(;splitter->length() && splitter->at(0) != '}'; splitter++, cnt++); for(;splitter->length() && splitter->at(0) != '}'; splitter++, cnt++);
splitter++; splitter++;
DefaultLogger::get()->debug((Formatter::format("DXF: skipped over control group ("),cnt," lines)")); ASSIMP_LOG_DEBUG((Formatter::format("DXF: skipped over control group ("),cnt," lines)"));
} }
} catch(std::logic_error&) { } catch(std::logic_error&) {
ai_assert(!splitter); ai_assert(!splitter);
@ -169,7 +169,6 @@ public:
} }
private: private:
LineSplitter splitter; LineSplitter splitter;
int groupcode; int groupcode;
std::string value; std::string value;

View File

@ -119,9 +119,18 @@ DXFImporter::~DXFImporter()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// 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 DXFImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const bool DXFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig ) const {
{ const std::string& extension = GetExtension( pFile );
return SimpleExtensionCheck(pFile,"dxf"); if ( extension == "dxf" ) {
return true;
}
if ( extension.empty() || checkSig ) {
static const char *pTokens[] = { "SECTION", "HEADER", "ENDSEC", "BLOCKS" };
return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, 4, 32 );
}
return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -191,7 +200,7 @@ void DXFImporter::InternReadFile( const std::string& pFile,
// comments // comments
else if (reader.Is(999)) { else if (reader.Is(999)) {
DefaultLogger::get()->info("DXF Comment: " + reader.Value()); ASSIMP_LOG_INFO_F("DXF Comment: ", reader.Value());
} }
// don't read past the official EOF sign // don't read past the official EOF sign
@ -203,7 +212,7 @@ void DXFImporter::InternReadFile( const std::string& pFile,
++reader; ++reader;
} }
if (!eof) { if (!eof) {
DefaultLogger::get()->warn("DXF: EOF reached, but did not encounter DXF EOF marker"); ASSIMP_LOG_WARN("DXF: EOF reached, but did not encounter DXF EOF marker");
} }
ConvertMeshes(pScene,output); ConvertMeshes(pScene,output);
@ -220,7 +229,7 @@ void DXFImporter::InternReadFile( const std::string& pFile,
void DXFImporter::ConvertMeshes(aiScene* pScene, DXF::FileData& output) void DXFImporter::ConvertMeshes(aiScene* pScene, DXF::FileData& output)
{ {
// the process of resolving all the INSERT statements can grow the // the process of resolving all the INSERT statements can grow the
// polycount excessively, so log the original number. // poly-count excessively, so log the original number.
// XXX Option to import blocks as separate nodes? // XXX Option to import blocks as separate nodes?
if (!DefaultLogger::isNullLogger()) { if (!DefaultLogger::isNullLogger()) {
@ -232,16 +241,14 @@ void DXFImporter::ConvertMeshes(aiScene* pScene, DXF::FileData& output)
} }
} }
DefaultLogger::get()->debug((Formatter::format("DXF: Unexpanded polycount is "), ASSIMP_LOG_DEBUG_F("DXF: Unexpanded polycount is ", icount, ", vertex count is ", vcount);
icount,", vertex count is ",vcount
));
} }
if (! output.blocks.size() ) { if (! output.blocks.size() ) {
throw DeadlyImportError("DXF: no data blocks loaded"); throw DeadlyImportError("DXF: no data blocks loaded");
} }
DXF::Block* entities = 0; DXF::Block* entities( nullptr );
// index blocks by name // index blocks by name
DXF::BlockMap blocks_by_name; DXF::BlockMap blocks_by_name;
@ -366,9 +373,7 @@ void DXFImporter::ExpandBlockReferences(DXF::Block& bl,const DXF::BlockMap& bloc
// first check if the referenced blocks exists ... // first check if the referenced blocks exists ...
const DXF::BlockMap::const_iterator it = blocks_by_name.find(insert.name); const DXF::BlockMap::const_iterator it = blocks_by_name.find(insert.name);
if (it == blocks_by_name.end()) { if (it == blocks_by_name.end()) {
DefaultLogger::get()->error((Formatter::format("DXF: Failed to resolve block reference: "), ASSIMP_LOG_ERROR_F("DXF: Failed to resolve block reference: ", insert.name,"; skipping" );
insert.name,"; skipping"
));
continue; continue;
} }
@ -388,7 +393,7 @@ void DXFImporter::ExpandBlockReferences(DXF::Block& bl,const DXF::BlockMap& bloc
// XXX rotation currently ignored - I didn't find an appropriate sample model. // XXX rotation currently ignored - I didn't find an appropriate sample model.
if (insert.angle != 0.f) { if (insert.angle != 0.f) {
DefaultLogger::get()->warn("DXF: BLOCK rotation not currently implemented"); ASSIMP_LOG_WARN("DXF: BLOCK rotation not currently implemented");
} }
for (aiVector3D& v : pl_out->positions) { for (aiVector3D& v : pl_out->positions) {
@ -401,7 +406,6 @@ void DXFImporter::ExpandBlockReferences(DXF::Block& bl,const DXF::BlockMap& bloc
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void DXFImporter::GenerateMaterials(aiScene* pScene, DXF::FileData& /*output*/) void DXFImporter::GenerateMaterials(aiScene* pScene, DXF::FileData& /*output*/)
{ {
@ -428,7 +432,6 @@ void DXFImporter::GenerateMaterials(aiScene* pScene, DXF::FileData& /*output*/)
pScene->mMaterials[0] = pcMat; pScene->mMaterials[0] = pcMat;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void DXFImporter::GenerateHierarchy(aiScene* pScene, DXF::FileData& /*output*/) void DXFImporter::GenerateHierarchy(aiScene* pScene, DXF::FileData& /*output*/)
{ {
@ -439,9 +442,7 @@ void DXFImporter::GenerateHierarchy(aiScene* pScene, DXF::FileData& /*output*/)
if (1 == pScene->mNumMeshes) { if (1 == pScene->mNumMeshes) {
pScene->mRootNode->mMeshes = new unsigned int[ pScene->mRootNode->mNumMeshes = 1 ]; pScene->mRootNode->mMeshes = new unsigned int[ pScene->mRootNode->mNumMeshes = 1 ];
pScene->mRootNode->mMeshes[0] = 0; pScene->mRootNode->mMeshes[0] = 0;
} } else {
else
{
pScene->mRootNode->mChildren = new aiNode*[ pScene->mRootNode->mNumChildren = pScene->mNumMeshes ]; pScene->mRootNode->mChildren = new aiNode*[ pScene->mRootNode->mNumChildren = pScene->mNumMeshes ];
for (unsigned int m = 0; m < pScene->mRootNode->mNumChildren;++m) { for (unsigned int m = 0; m < pScene->mRootNode->mNumChildren;++m) {
aiNode* p = pScene->mRootNode->mChildren[m] = new aiNode(); aiNode* p = pScene->mRootNode->mChildren[m] = new aiNode();
@ -456,22 +457,17 @@ void DXFImporter::GenerateHierarchy(aiScene* pScene, DXF::FileData& /*output*/)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void DXFImporter::SkipSection(DXF::LineReader& reader) void DXFImporter::SkipSection(DXF::LineReader& reader) {
{
for( ;!reader.End() && !reader.Is(0,"ENDSEC"); reader++); for( ;!reader.End() && !reader.Is(0,"ENDSEC"); reader++);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void DXFImporter::ParseHeader(DXF::LineReader& reader, DXF::FileData& /*output*/) void DXFImporter::ParseHeader(DXF::LineReader& reader, DXF::FileData& ) {
{
for( ;!reader.End() && !reader.Is(0,"ENDSEC"); reader++); for( ;!reader.End() && !reader.Is(0,"ENDSEC"); reader++);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void DXFImporter::ParseBlocks(DXF::LineReader& reader, DXF::FileData& output) void DXFImporter::ParseBlocks(DXF::LineReader& reader, DXF::FileData& output) {
{
while( !reader.End() && !reader.Is(0,"ENDSEC")) { while( !reader.End() && !reader.Is(0,"ENDSEC")) {
if (reader.Is(0,"BLOCK")) { if (reader.Is(0,"BLOCK")) {
ParseBlock(++reader,output); ParseBlock(++reader,output);
@ -480,15 +476,11 @@ void DXFImporter::ParseBlocks(DXF::LineReader& reader, DXF::FileData& output)
++reader; ++reader;
} }
DefaultLogger::get()->debug((Formatter::format("DXF: got "), ASSIMP_LOG_DEBUG_F("DXF: got ", output.blocks.size()," entries in BLOCKS" );
output.blocks.size()," entries in BLOCKS"
));
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void DXFImporter::ParseBlock(DXF::LineReader& reader, DXF::FileData& output) void DXFImporter::ParseBlock(DXF::LineReader& reader, DXF::FileData& output) {
{
// push a new block onto the stack. // push a new block onto the stack.
output.blocks.push_back( DXF::Block() ); output.blocks.push_back( DXF::Block() );
DXF::Block& block = output.blocks.back(); DXF::Block& block = output.blocks.back();
@ -518,7 +510,7 @@ void DXFImporter::ParseBlock(DXF::LineReader& reader, DXF::FileData& output)
// XXX is this a valid case? // XXX is this a valid case?
if (reader.Is(0,"INSERT")) { if (reader.Is(0,"INSERT")) {
DefaultLogger::get()->warn("DXF: INSERT within a BLOCK not currently supported; skipping"); ASSIMP_LOG_WARN("DXF: INSERT within a BLOCK not currently supported; skipping");
for( ;!reader.End() && !reader.Is(0,"ENDBLK"); ++reader); for( ;!reader.End() && !reader.Is(0,"ENDBLK"); ++reader);
break; break;
} }
@ -532,7 +524,6 @@ void DXFImporter::ParseBlock(DXF::LineReader& reader, DXF::FileData& output)
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void DXFImporter::ParseEntities(DXF::LineReader& reader, DXF::FileData& output) void DXFImporter::ParseEntities(DXF::LineReader& reader, DXF::FileData& output)
{ {
@ -562,19 +553,16 @@ void DXFImporter::ParseEntities(DXF::LineReader& reader, DXF::FileData& output)
++reader; ++reader;
} }
DefaultLogger::get()->debug((Formatter::format("DXF: got "), ASSIMP_LOG_DEBUG_F( "DXF: got ", block.lines.size()," polylines and ", block.insertions.size(),
block.lines.size()," polylines and ", block.insertions.size() ," inserted blocks in ENTITIES" " inserted blocks in ENTITIES" );
));
} }
void DXFImporter::ParseInsertion(DXF::LineReader& reader, DXF::FileData& output) void DXFImporter::ParseInsertion(DXF::LineReader& reader, DXF::FileData& output)
{ {
output.blocks.back().insertions.push_back( DXF::InsertBlock() ); output.blocks.back().insertions.push_back( DXF::InsertBlock() );
DXF::InsertBlock& bl = output.blocks.back().insertions.back(); DXF::InsertBlock& bl = output.blocks.back().insertions.back();
while( !reader.End() && !reader.Is(0)) { while( !reader.End() && !reader.Is(0)) {
switch(reader.GroupCode()) switch(reader.GroupCode())
{ {
// name of referenced block // name of referenced block
@ -619,8 +607,7 @@ void DXFImporter::ParseInsertion(DXF::LineReader& reader, DXF::FileData& output)
#define DXF_POLYLINE_FLAG_POLYFACEMESH 0x40 #define DXF_POLYLINE_FLAG_POLYFACEMESH 0x40
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void DXFImporter::ParsePolyLine(DXF::LineReader& reader, DXF::FileData& output) void DXFImporter::ParsePolyLine(DXF::LineReader& reader, DXF::FileData& output) {
{
output.blocks.back().lines.push_back( std::shared_ptr<DXF::PolyLine>( new DXF::PolyLine() ) ); output.blocks.back().lines.push_back( std::shared_ptr<DXF::PolyLine>( new DXF::PolyLine() ) );
DXF::PolyLine& line = *output.blocks.back().lines.back(); DXF::PolyLine& line = *output.blocks.back().lines.back();
@ -673,16 +660,15 @@ void DXFImporter::ParsePolyLine(DXF::LineReader& reader, DXF::FileData& output)
//} //}
if (vguess && line.positions.size() != vguess) { if (vguess && line.positions.size() != vguess) {
DefaultLogger::get()->warn((Formatter::format("DXF: unexpected vertex count in polymesh: "), ASSIMP_LOG_WARN_F("DXF: unexpected vertex count in polymesh: ",
line.positions.size(),", expected ", vguess line.positions.size(),", expected ", vguess );
));
} }
if (line.flags & DXF_POLYLINE_FLAG_POLYFACEMESH ) { if (line.flags & DXF_POLYLINE_FLAG_POLYFACEMESH ) {
if (line.positions.size() < 3 || line.indices.size() < 3) { if (line.positions.size() < 3 || line.indices.size() < 3) {
DefaultLogger::get()->warn("DXF: not enough vertices for polymesh; ignoring"); ASSIMP_LOG_WARN("DXF: not enough vertices for polymesh; ignoring");
output.blocks.back().lines.pop_back(); output.blocks.back().lines.pop_back();
return; return;
} }
// if these numbers are wrong, parsing might have gone wild. // if these numbers are wrong, parsing might have gone wild.
@ -690,13 +676,11 @@ void DXFImporter::ParsePolyLine(DXF::LineReader& reader, DXF::FileData& output)
// to set the 71 and 72 fields, respectively, to valid values. // to set the 71 and 72 fields, respectively, to valid values.
// So just fire a warning. // So just fire a warning.
if (iguess && line.counts.size() != iguess) { if (iguess && line.counts.size() != iguess) {
DefaultLogger::get()->warn((Formatter::format("DXF: unexpected face count in polymesh: "), ASSIMP_LOG_WARN_F( "DXF: unexpected face count in polymesh: ", line.counts.size(),", expected ", iguess );
line.counts.size(),", expected ", iguess
));
} }
} }
else if (!line.indices.size() && !line.counts.size()) { else if (!line.indices.size() && !line.counts.size()) {
// a polyline - so there are no indices yet. // a poly-line - so there are no indices yet.
size_t guess = line.positions.size() + (line.flags & DXF_POLYLINE_FLAG_CLOSED ? 1 : 0); size_t guess = line.positions.size() + (line.flags & DXF_POLYLINE_FLAG_CLOSED ? 1 : 0);
line.indices.reserve(guess); line.indices.reserve(guess);
@ -738,10 +722,10 @@ void DXFImporter::ParsePolyLineVertex(DXF::LineReader& reader, DXF::PolyLine& li
{ {
case 8: case 8:
// layer to which the vertex belongs to - assume that // layer to which the vertex belongs to - assume that
// this is always the layer the top-level polyline // this is always the layer the top-level poly-line
// entity resides on as well. // entity resides on as well.
if(reader.Value() != line.layer) { if(reader.Value() != line.layer) {
DefaultLogger::get()->warn("DXF: expected vertex to be part of a polyface but the 0x128 flag isn't set"); ASSIMP_LOG_WARN("DXF: expected vertex to be part of a poly-face but the 0x128 flag isn't set");
} }
break; break;
@ -760,7 +744,7 @@ void DXFImporter::ParsePolyLineVertex(DXF::LineReader& reader, DXF::PolyLine& li
case 73: case 73:
case 74: case 74:
if (cnti == 4) { if (cnti == 4) {
DefaultLogger::get()->warn("DXF: more than 4 indices per face not supported; ignoring"); ASSIMP_LOG_WARN("DXF: more than 4 indices per face not supported; ignoring");
break; break;
} }
indices[cnti++] = reader.ValueAsUnsignedInt(); indices[cnti++] = reader.ValueAsUnsignedInt();
@ -776,7 +760,7 @@ void DXFImporter::ParsePolyLineVertex(DXF::LineReader& reader, DXF::PolyLine& li
} }
if (line.flags & DXF_POLYLINE_FLAG_POLYFACEMESH && !(flags & DXF_VERTEX_FLAG_PART_OF_POLYFACE)) { if (line.flags & DXF_POLYLINE_FLAG_POLYFACEMESH && !(flags & DXF_VERTEX_FLAG_PART_OF_POLYFACE)) {
DefaultLogger::get()->warn("DXF: expected vertex to be part of a polyface but the 0x128 flag isn't set"); ASSIMP_LOG_WARN("DXF: expected vertex to be part of a polyface but the 0x128 flag isn't set");
} }
if (cnti) { if (cnti) {
@ -784,14 +768,13 @@ void DXFImporter::ParsePolyLineVertex(DXF::LineReader& reader, DXF::PolyLine& li
for (unsigned int i = 0; i < cnti; ++i) { for (unsigned int i = 0; i < cnti; ++i) {
// IMPORTANT NOTE: POLYMESH indices are ONE-BASED // IMPORTANT NOTE: POLYMESH indices are ONE-BASED
if (indices[i] == 0) { if (indices[i] == 0) {
DefaultLogger::get()->warn("DXF: invalid vertex index, indices are one-based."); ASSIMP_LOG_WARN("DXF: invalid vertex index, indices are one-based.");
--line.counts.back(); --line.counts.back();
continue; continue;
} }
line.indices.push_back(indices[i]-1); line.indices.push_back(indices[i]-1);
} }
} } else {
else {
line.positions.push_back(out); line.positions.push_back(out);
line.colors.push_back(clr); line.colors.push_back(clr);
} }
@ -901,7 +884,7 @@ void DXFImporter::Parse3DFace(DXF::LineReader& reader, DXF::FileData& output)
// sanity checks to see if we got something meaningful // sanity checks to see if we got something meaningful
if ((b[1] && !b[0]) || !b[2] || !b[3]) { if ((b[1] && !b[0]) || !b[2] || !b[3]) {
DefaultLogger::get()->warn("DXF: unexpected vertex setup in 3DFACE/LINE/FACE entity; ignoring"); ASSIMP_LOG_WARN("DXF: unexpected vertex setup in 3DFACE/LINE/FACE entity; ignoring");
output.blocks.back().lines.pop_back(); output.blocks.back().lines.pop_back();
return; return;
} }
@ -917,4 +900,3 @@ void DXFImporter::Parse3DFace(DXF::LineReader& reader, DXF::FileData& output)
} }
#endif // !! ASSIMP_BUILD_NO_DXF_IMPORTER #endif // !! ASSIMP_BUILD_NO_DXF_IMPORTER

View File

@ -91,7 +91,7 @@ void DeboneProcess::SetupProperties(const Importer* pImp)
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void DeboneProcess::Execute( aiScene* pScene) void DeboneProcess::Execute( aiScene* pScene)
{ {
DefaultLogger::get()->debug("DeboneProcess begin"); ASSIMP_LOG_DEBUG("DeboneProcess begin");
if(!pScene->mNumMeshes) { if(!pScene->mNumMeshes) {
return; return;
@ -148,9 +148,7 @@ void DeboneProcess::Execute( aiScene* pScene)
} }
if(!DefaultLogger::isNullLogger()) { if(!DefaultLogger::isNullLogger()) {
char buffer[1024]; ASSIMP_LOG_INFO_F("Removed %u bones. Input bones:", in - out, ". Output bones: ", out);
::ai_snprintf(buffer,1024,"Removed %u bones. Input bones: %u. Output bones: %u",in-out,in,out);
DefaultLogger::get()->info(buffer);
} }
// and destroy the source mesh. It should be completely contained inside the new submeshes // and destroy the source mesh. It should be completely contained inside the new submeshes
@ -173,7 +171,7 @@ void DeboneProcess::Execute( aiScene* pScene)
UpdateNode( pScene->mRootNode); UpdateNode( pScene->mRootNode);
} }
DefaultLogger::get()->debug("DeboneProcess end"); ASSIMP_LOG_DEBUG("DeboneProcess end");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -209,7 +207,7 @@ bool DeboneProcess::ConsiderMesh(const aiMesh* pMesh)
if(vertexBones[vid]!=cUnowned) { if(vertexBones[vid]!=cUnowned) {
if(vertexBones[vid]==i) //double entry if(vertexBones[vid]==i) //double entry
{ {
DefaultLogger::get()->warn("Encountered double entry in bone weights"); ASSIMP_LOG_WARN("Encountered double entry in bone weights");
} }
else //TODO: track attraction in order to break tie else //TODO: track attraction in order to break tie
{ {
@ -281,7 +279,7 @@ void DeboneProcess::SplitMesh( const aiMesh* pMesh, std::vector< std::pair< aiMe
if(vertexBones[vid]!=cUnowned) { if(vertexBones[vid]!=cUnowned) {
if(vertexBones[vid]==i) //double entry if(vertexBones[vid]==i) //double entry
{ {
//DefaultLogger::get()->warn("Encountered double entry in bone weights"); ASSIMP_LOG_WARN("Encountered double entry in bone weights");
} }
else //TODO: track attraction in order to break tie else //TODO: track attraction in order to break tie
{ {

View File

@ -76,11 +76,11 @@ 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) != 0;
if (isUnicode) { if (isUnicode) {
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, pFile, -1, fileName16, PATHLIMIT); MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, pFile, -1, fileName16, PATHLIMIT);
struct _stat64 filestat; struct __stat64 filestat;
if (0 != _wstat64(fileName16, &filestat)) { if (0 != _wstat64(fileName16, &filestat)) {
return false; return false;
} }
@ -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) != 0;
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) != 0;
if (isUnicode) { if (isUnicode) {
wchar_t out16[PATHLIMIT]; wchar_t out16[PATHLIMIT];
wchar_t in16[PATHLIMIT]; wchar_t in16[PATHLIMIT];
@ -170,7 +170,7 @@ inline static void MakeAbsolutePath (const char* in, char* _out)
if (!ret) { if (!ret) {
// preserve the input path, maybe someone else is able to fix // preserve the input path, maybe someone else is able to fix
// the path before it is accessed (e.g. our file system filter) // the path before it is accessed (e.g. our file system filter)
DefaultLogger::get()->warn("Invalid path: " + std::string(in)); ASSIMP_LOG_WARN_F("Invalid path: ", std::string(in));
strcpy(_out, in); strcpy(_out, in);
} }
@ -179,7 +179,7 @@ inline static void MakeAbsolutePath (const char* in, char* _out)
if (!ret) { if (!ret) {
// preserve the input path, maybe someone else is able to fix // preserve the input path, maybe someone else is able to fix
// the path before it is accessed (e.g. our file system filter) // the path before it is accessed (e.g. our file system filter)
DefaultLogger::get()->warn("Invalid path: " + std::string(in)); ASSIMP_LOG_WARN_F("Invalid path: ", std::string(in));
strcpy(_out, in); strcpy(_out, in);
} }
} }
@ -189,7 +189,7 @@ inline static void MakeAbsolutePath (const char* in, char* _out)
if(!ret) { if(!ret) {
// preserve the input path, maybe someone else is able to fix // preserve the input path, maybe someone else is able to fix
// the path before it is accessed (e.g. our file system filter) // the path before it is accessed (e.g. our file system filter)
DefaultLogger::get()->warn("Invalid path: "+std::string(in)); ASSIMP_LOG_WARN_F("Invalid path: ", std::string(in));
strcpy(_out,in); strcpy(_out,in);
} }
#endif #endif

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

View File

@ -93,29 +93,27 @@ void EmbedTexturesProcess::Execute(aiScene* pScene) {
} }
} }
char stringBuffer[128]; ASSIMP_LOG_INFO_F("EmbedTexturesProcess finished. Embedded ", embeddedTexturesCount, " textures." );
::ai_snprintf(stringBuffer, 128, "EmbedTexturesProcess finished. Embedded %u textures.", embeddedTexturesCount);
DefaultLogger::get()->info(stringBuffer);
} }
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."); ASSIMP_LOG_WARN_F("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 + "."); ASSIMP_LOG_ERROR_F("EmbedTexturesProcess: Unable to embed texture: ", path, ".");
return false; return false;
} }
} }
@ -134,7 +132,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

@ -62,6 +62,7 @@ Here we implement only the C++ interface (Assimp::Exporter).
#include "JoinVerticesProcess.h" #include "JoinVerticesProcess.h"
#include "MakeVerboseFormat.h" #include "MakeVerboseFormat.h"
#include "ConvertToLHProcess.h" #include "ConvertToLHProcess.h"
#include "PretransformVertices.h"
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
#include "ScenePrivate.h" #include "ScenePrivate.h"
#include <memory> #include <memory>
@ -97,6 +98,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* );
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -151,9 +154,9 @@ Exporter::ExportFormatEntry gExporters[] =
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB, Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
Exporter::ExportFormatEntry( "gltf2", "GL Transmission Format v. 2", "gltf2", &ExportSceneGLTF2, Exporter::ExportFormatEntry( "gltf2", "GL Transmission Format v. 2", "gltf", &ExportSceneGLTF2,
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
Exporter::ExportFormatEntry( "glb2", "GL Transmission Format v. 2 (binary)", "glb2", &ExportSceneGLB2, Exporter::ExportFormatEntry( "glb2", "GL Transmission Format v. 2 (binary)", "glb", &ExportSceneGLB2,
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
#endif #endif
@ -169,6 +172,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 +309,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
@ -355,7 +364,7 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
} }
if (verbosify || (exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) { if (verbosify || (exp.mEnforcePP & aiProcess_JoinIdenticalVertices)) {
DefaultLogger::get()->debug("export: Scene data not in verbose format, applying MakeVerboseFormat step first"); ASSIMP_LOG_DEBUG("export: Scene data not in verbose format, applying MakeVerboseFormat step first");
MakeVerboseFormatProcess proc; MakeVerboseFormatProcess proc;
proc.Execute(scenecopy.get()); proc.Execute(scenecopy.get());
@ -389,6 +398,11 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
} }
} }
bool exportPointCloud(false);
if (nullptr != pProperties) {
exportPointCloud = pProperties->GetPropertyBool(AI_CONFIG_EXPORT_POINT_CLOUDS);
}
// dispatch other processes // dispatch other processes
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) { for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
BaseProcess* const p = pimpl->mPostProcessingSteps[a]; BaseProcess* const p = pimpl->mPostProcessingSteps[a];
@ -397,7 +411,9 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
&& !dynamic_cast<FlipUVsProcess*>(p) && !dynamic_cast<FlipUVsProcess*>(p)
&& !dynamic_cast<FlipWindingOrderProcess*>(p) && !dynamic_cast<FlipWindingOrderProcess*>(p)
&& !dynamic_cast<MakeLeftHandedProcess*>(p)) { && !dynamic_cast<MakeLeftHandedProcess*>(p)) {
if (dynamic_cast<PretransformVertices*>(p) && exportPointCloud) {
continue;
}
p->Execute(scenecopy.get()); p->Execute(scenecopy.get());
} }
} }
@ -433,7 +449,6 @@ const char* Exporter::GetErrorString() const {
return pimpl->mError.c_str(); return pimpl->mError.c_str();
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Exporter::FreeBlob() { void Exporter::FreeBlob() {
delete pimpl->blob; delete pimpl->blob;
@ -462,7 +477,7 @@ size_t Exporter::GetExportFormatCount() const {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const aiExportFormatDesc* Exporter::GetExportFormatDescription( size_t index ) const { const aiExportFormatDesc* Exporter::GetExportFormatDescription( size_t index ) const {
if (index >= GetExportFormatCount()) { if (index >= GetExportFormatCount()) {
return NULL; return nullptr;
} }
// Return from static storage if the requested index is built-in. // Return from static storage if the requested index is built-in.
@ -487,7 +502,8 @@ aiReturn Exporter::RegisterExporter(const ExportFormatEntry& desc) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Exporter::UnregisterExporter(const char* id) { void Exporter::UnregisterExporter(const char* id) {
for(std::vector<ExportFormatEntry>::iterator it = pimpl->mExporters.begin(); it != pimpl->mExporters.end(); ++it) { for(std::vector<ExportFormatEntry>::iterator it = pimpl->mExporters.begin();
it != pimpl->mExporters.end(); ++it) {
if (!strcmp((*it).mDescription.id,id)) { if (!strcmp((*it).mDescription.id,id)) {
pimpl->mExporters.erase(it); pimpl->mExporters.erase(it);
break; break;
@ -523,8 +539,7 @@ bool ExportProperties::SetPropertyFloat(const char* szName, ai_real iValue) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Set a configuration property // Set a configuration property
bool ExportProperties :: SetPropertyString(const char* szName, const std::string& value) bool ExportProperties::SetPropertyString(const char* szName, const std::string& value) {
{
return SetGenericProperty<std::string>(mStringProperties, szName,value); return SetGenericProperty<std::string>(mStringProperties, szName,value);
} }

View File

@ -448,8 +448,8 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int le
/*Result ignored*/ ReadByte(input, cursor, input + length); /*Result ignored*/ ReadByte(input, cursor, input + length);
const uint32_t version = ReadWord(input, cursor, input + length); const uint32_t version = ReadWord(input, cursor, input + length);
const bool is64bits = version >= 7500; const bool is64bits = version >= 7500;
while (cursor < input + length) const char *end = input + length;
{ while (cursor < end ) {
if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) { if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) {
break; break;
} }

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,17 +624,25 @@ bool Converter::NeedsComplexTransformationChain( const Model& model )
bool ok; bool ok;
const float zero_epsilon = 1e-6f; const float zero_epsilon = 1e-6f;
const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
for ( size_t i = 0; i < TransformationComp_MAXIMUM; ++i ) { for ( size_t i = 0; i < TransformationComp_MAXIMUM; ++i ) {
const TransformationComp comp = static_cast< TransformationComp >( i ); const TransformationComp comp = static_cast< TransformationComp >( i );
if ( comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation || if ( comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation ) {
comp == TransformationComp_GeometricScaling || comp == TransformationComp_GeometricRotation || comp == TransformationComp_GeometricTranslation ) {
continue; continue;
} }
bool scale_compare = ( comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling );
const aiVector3D& v = PropertyGet<aiVector3D>( props, NameTransformationCompProperty( comp ), ok ); const aiVector3D& v = PropertyGet<aiVector3D>( props, NameTransformationCompProperty( comp ), ok );
if ( ok && v.SquareLength() > zero_epsilon ) { if ( ok && scale_compare ) {
return true; if ( (v - all_ones).SquareLength() > zero_epsilon ) {
return true;
}
} else if ( ok ) {
if ( v.SquareLength() > zero_epsilon ) {
return true;
}
} }
} }
@ -570,7 +654,7 @@ std::string Converter::NameTransformationChainNode( const std::string& name, Tra
return name + std::string( MAGIC_NODE_TAG ) + "_" + NameTransformationComp( comp ); return name + std::string( MAGIC_NODE_TAG ) + "_" + NameTransformationComp( comp );
} }
void Converter::GenerateTransformationNodeChain( const Model& model, std::vector<aiNode*>& output_nodes ) void Converter::GenerateTransformationNodeChain( const Model& model, std::vector<aiNode*>& output_nodes, std::vector<aiNode*>& post_output_nodes )
{ {
const PropertyTable& props = model.Props(); const PropertyTable& props = model.Props();
const Model::RotOrder rot = model.RotationOrder(); const Model::RotOrder rot = model.RotationOrder();
@ -582,20 +666,21 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
// generate transformation matrices for all the different transformation components // generate transformation matrices for all the different transformation components
const float zero_epsilon = 1e-6f; const float zero_epsilon = 1e-6f;
const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
bool is_complex = false; bool is_complex = false;
const aiVector3D& PreRotation = PropertyGet<aiVector3D>( props, "PreRotation", ok ); const aiVector3D& PreRotation = PropertyGet<aiVector3D>( props, "PreRotation", ok );
if ( ok && PreRotation.SquareLength() > zero_epsilon ) { if ( ok && PreRotation.SquareLength() > zero_epsilon ) {
is_complex = true; is_complex = true;
GetRotationMatrix( rot, PreRotation, chain[ TransformationComp_PreRotation ] ); GetRotationMatrix( Model::RotOrder::RotOrder_EulerXYZ, PreRotation, chain[ TransformationComp_PreRotation ] );
} }
const aiVector3D& PostRotation = PropertyGet<aiVector3D>( props, "PostRotation", ok ); const aiVector3D& PostRotation = PropertyGet<aiVector3D>( props, "PostRotation", ok );
if ( ok && PostRotation.SquareLength() > zero_epsilon ) { if ( ok && PostRotation.SquareLength() > zero_epsilon ) {
is_complex = true; is_complex = true;
GetRotationMatrix( rot, PostRotation, chain[ TransformationComp_PostRotation ] ); GetRotationMatrix( Model::RotOrder::RotOrder_EulerXYZ, PostRotation, chain[ TransformationComp_PostRotation ] );
} }
const aiVector3D& RotationPivot = PropertyGet<aiVector3D>( props, "RotationPivot", ok ); const aiVector3D& RotationPivot = PropertyGet<aiVector3D>( props, "RotationPivot", ok );
@ -634,7 +719,7 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
} }
const aiVector3D& Scaling = PropertyGet<aiVector3D>( props, "Lcl Scaling", ok ); const aiVector3D& Scaling = PropertyGet<aiVector3D>( props, "Lcl Scaling", ok );
if ( ok && std::fabs( Scaling.SquareLength() - 1.0f ) > zero_epsilon ) { if ( ok && (Scaling - all_ones).SquareLength() > zero_epsilon ) {
aiMatrix4x4::Scaling( Scaling, chain[ TransformationComp_Scaling ] ); aiMatrix4x4::Scaling( Scaling, chain[ TransformationComp_Scaling ] );
} }
@ -644,18 +729,38 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
} }
const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>( props, "GeometricScaling", ok ); const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>( props, "GeometricScaling", ok );
if ( ok && std::fabs( GeometricScaling.SquareLength() - 1.0f ) > zero_epsilon ) { if ( ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon ) {
is_complex = true;
aiMatrix4x4::Scaling( GeometricScaling, chain[ TransformationComp_GeometricScaling ] ); aiMatrix4x4::Scaling( GeometricScaling, chain[ TransformationComp_GeometricScaling ] );
aiVector3D GeometricScalingInverse = GeometricScaling;
bool canscale = true;
for (unsigned int i = 0; i < 3; ++i) {
if ( std::fabs( GeometricScalingInverse[i] ) > zero_epsilon ) {
GeometricScalingInverse[i] = 1.0f / GeometricScaling[i];
} else {
FBXImporter::LogError( "cannot invert geometric scaling matrix with a 0.0 scale component" );
canscale = false;
break;
}
}
if (canscale) {
aiMatrix4x4::Scaling( GeometricScalingInverse, chain[ TransformationComp_GeometricScalingInverse ] );
}
} }
const aiVector3D& GeometricRotation = PropertyGet<aiVector3D>( props, "GeometricRotation", ok ); const aiVector3D& GeometricRotation = PropertyGet<aiVector3D>( props, "GeometricRotation", ok );
if ( ok && GeometricRotation.SquareLength() > zero_epsilon ) { if ( ok && GeometricRotation.SquareLength() > zero_epsilon ) {
is_complex = true;
GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotation ] ); GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotation ] );
GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotationInverse ] );
chain[ TransformationComp_GeometricRotationInverse ].Inverse();
} }
const aiVector3D& GeometricTranslation = PropertyGet<aiVector3D>( props, "GeometricTranslation", ok ); const aiVector3D& GeometricTranslation = PropertyGet<aiVector3D>( props, "GeometricTranslation", ok );
if ( ok && GeometricTranslation.SquareLength() > zero_epsilon ) { if ( ok && GeometricTranslation.SquareLength() > zero_epsilon ) {
is_complex = true;
aiMatrix4x4::Translation( GeometricTranslation, chain[ TransformationComp_GeometricTranslation ] ); aiMatrix4x4::Translation( GeometricTranslation, chain[ TransformationComp_GeometricTranslation ] );
aiMatrix4x4::Translation( -GeometricTranslation, chain[ TransformationComp_GeometricTranslationInverse ] );
} }
// is_complex needs to be consistent with NeedsComplexTransformationChain() // is_complex needs to be consistent with NeedsComplexTransformationChain()
@ -663,7 +768,7 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
// not be guaranteed. // not be guaranteed.
ai_assert( NeedsComplexTransformationChain( model ) == is_complex ); ai_assert( NeedsComplexTransformationChain( model ) == is_complex );
const std::string& name = FixNodeName( model.Name() ); std::string name = FixNodeName( model.Name() );
// now, if we have more than just Translation, Scaling and Rotation, // now, if we have more than just Translation, Scaling and Rotation,
// we need to generate a full node chain to accommodate for assimp's // we need to generate a full node chain to accommodate for assimp's
@ -690,10 +795,18 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
} }
aiNode* nd = new aiNode(); aiNode* nd = new aiNode();
output_nodes.push_back( nd );
nd->mName.Set( NameTransformationChainNode( name, comp ) ); nd->mName.Set( NameTransformationChainNode( name, comp ) );
nd->mTransformation = chain[ i ]; nd->mTransformation = chain[ i ];
// geometric inverses go in a post-node chain
if ( comp == TransformationComp_GeometricScalingInverse ||
comp == TransformationComp_GeometricRotationInverse ||
comp == TransformationComp_GeometricTranslationInverse
) {
post_output_nodes.push_back( nd );
} else {
output_nodes.push_back( nd );
}
} }
ai_assert( output_nodes.size() ); ai_assert( output_nodes.size() );
@ -703,8 +816,10 @@ void Converter::GenerateTransformationNodeChain( const Model& model, std::vector
// else, we can just multiply the matrices together // else, we can just multiply the matrices together
aiNode* nd = new aiNode(); aiNode* nd = new aiNode();
output_nodes.push_back( nd ); output_nodes.push_back( nd );
std::string uniqueName;
GetUniqueName( name, uniqueName );
nd->mName.Set( name ); nd->mName.Set( uniqueName );
for (const auto &transform : chain) { for (const auto &transform : chain) {
nd->mTransformation = nd->mTransformation * transform; nd->mTransformation = nd->mTransformation * transform;
@ -759,7 +874,7 @@ void Converter::ConvertModel( const Model& model, aiNode& nd, const aiMatrix4x4&
const MeshGeometry* const mesh = dynamic_cast< const MeshGeometry* >( geo ); const MeshGeometry* const mesh = dynamic_cast< const MeshGeometry* >( geo );
if ( mesh ) { if ( mesh ) {
const std::vector<unsigned int>& indices = ConvertMesh( *mesh, model, node_global_transform ); const std::vector<unsigned int>& indices = ConvertMesh( *mesh, model, node_global_transform, nd);
std::copy( indices.begin(), indices.end(), std::back_inserter( meshes ) ); std::copy( indices.begin(), indices.end(), std::back_inserter( meshes ) );
} }
else { else {
@ -776,7 +891,7 @@ void Converter::ConvertModel( const Model& model, aiNode& nd, const aiMatrix4x4&
} }
std::vector<unsigned int> Converter::ConvertMesh( const MeshGeometry& mesh, const Model& model, std::vector<unsigned int> Converter::ConvertMesh( const MeshGeometry& mesh, const Model& model,
const aiMatrix4x4& node_global_transform ) const aiMatrix4x4& node_global_transform, aiNode& nd)
{ {
std::vector<unsigned int> temp; std::vector<unsigned int> temp;
@ -800,17 +915,17 @@ std::vector<unsigned int> Converter::ConvertMesh( const MeshGeometry& mesh, cons
const MatIndexArray::value_type base = mindices[ 0 ]; const MatIndexArray::value_type base = mindices[ 0 ];
for( MatIndexArray::value_type index : mindices ) { for( MatIndexArray::value_type index : mindices ) {
if ( index != base ) { if ( index != base ) {
return ConvertMeshMultiMaterial( mesh, model, node_global_transform ); return ConvertMeshMultiMaterial( mesh, model, node_global_transform, nd);
} }
} }
} }
// faster code-path, just copy the data // faster code-path, just copy the data
temp.push_back( ConvertMeshSingleMaterial( mesh, model, node_global_transform ) ); temp.push_back( ConvertMeshSingleMaterial( mesh, model, node_global_transform, nd) );
return temp; return temp;
} }
aiMesh* Converter::SetupEmptyMesh( const MeshGeometry& mesh ) aiMesh* Converter::SetupEmptyMesh( const MeshGeometry& mesh, aiNode& nd)
{ {
aiMesh* const out_mesh = new aiMesh(); aiMesh* const out_mesh = new aiMesh();
meshes.push_back( out_mesh ); meshes.push_back( out_mesh );
@ -825,15 +940,19 @@ aiMesh* Converter::SetupEmptyMesh( const MeshGeometry& mesh )
if ( name.length() ) { if ( name.length() ) {
out_mesh->mName.Set( name ); out_mesh->mName.Set( name );
} }
else
{
out_mesh->mName = nd.mName;
}
return out_mesh; return out_mesh;
} }
unsigned int Converter::ConvertMeshSingleMaterial( const MeshGeometry& mesh, const Model& model, unsigned int Converter::ConvertMeshSingleMaterial( const MeshGeometry& mesh, const Model& model,
const aiMatrix4x4& node_global_transform ) const aiMatrix4x4& node_global_transform, aiNode& nd)
{ {
const MatIndexArray& mindices = mesh.GetMaterialIndices(); const MatIndexArray& mindices = mesh.GetMaterialIndices();
aiMesh* const out_mesh = SetupEmptyMesh( mesh ); aiMesh* const out_mesh = SetupEmptyMesh(mesh, nd);
const std::vector<aiVector3D>& vertices = mesh.GetVertices(); const std::vector<aiVector3D>& vertices = mesh.GetVertices();
const std::vector<unsigned int>& faces = mesh.GetFaceIndexCounts(); const std::vector<unsigned int>& faces = mesh.GetFaceIndexCounts();
@ -957,7 +1076,7 @@ unsigned int Converter::ConvertMeshSingleMaterial( const MeshGeometry& mesh, con
} }
std::vector<unsigned int> Converter::ConvertMeshMultiMaterial( const MeshGeometry& mesh, const Model& model, std::vector<unsigned int> Converter::ConvertMeshMultiMaterial( const MeshGeometry& mesh, const Model& model,
const aiMatrix4x4& node_global_transform ) const aiMatrix4x4& node_global_transform, aiNode& nd)
{ {
const MatIndexArray& mindices = mesh.GetMaterialIndices(); const MatIndexArray& mindices = mesh.GetMaterialIndices();
ai_assert( mindices.size() ); ai_assert( mindices.size() );
@ -968,7 +1087,7 @@ std::vector<unsigned int> Converter::ConvertMeshMultiMaterial( const MeshGeometr
for( MatIndexArray::value_type index : mindices ) { for( MatIndexArray::value_type index : mindices ) {
if ( had.find( index ) == had.end() ) { if ( had.find( index ) == had.end() ) {
indices.push_back( ConvertMeshMultiMaterial( mesh, model, index, node_global_transform ) ); indices.push_back( ConvertMeshMultiMaterial( mesh, model, index, node_global_transform, nd) );
had.insert( index ); had.insert( index );
} }
} }
@ -978,9 +1097,10 @@ std::vector<unsigned int> Converter::ConvertMeshMultiMaterial( const MeshGeometr
unsigned int Converter::ConvertMeshMultiMaterial( const MeshGeometry& mesh, const Model& model, unsigned int Converter::ConvertMeshMultiMaterial( const MeshGeometry& mesh, const Model& model,
MatIndexArray::value_type index, MatIndexArray::value_type index,
const aiMatrix4x4& node_global_transform ) const aiMatrix4x4& node_global_transform,
aiNode& nd)
{ {
aiMesh* const out_mesh = SetupEmptyMesh( mesh ); aiMesh* const out_mesh = SetupEmptyMesh(mesh, nd);
const MatIndexArray& mindices = mesh.GetMaterialIndices(); const MatIndexArray& mindices = mesh.GetMaterialIndices();
const std::vector<aiVector3D>& vertices = mesh.GetVertices(); const std::vector<aiVector3D>& vertices = mesh.GetVertices();
@ -1406,6 +1526,46 @@ unsigned int Converter::ConvertVideo( const Video& video )
return static_cast<unsigned int>( textures.size() - 1 ); return static_cast<unsigned int>( textures.size() - 1 );
} }
aiString Converter::GetTexturePath(const Texture* tex)
{
aiString path;
path.Set(tex->RelativeFilename());
const Video* media = tex->Media();
if (media != nullptr) {
bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
unsigned int index;
VideoMap::const_iterator it = textures_converted.find(media);
if (it != textures_converted.end()) {
index = (*it).second;
textureReady = true;
}
else {
if (media->ContentLength() > 0) {
index = ConvertVideo(*media);
textures_converted[media] = index;
textureReady = true;
}
}
// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready
if (doc.Settings().useLegacyEmbeddedTextureNaming) {
if (textureReady) {
// TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING"
// In FBX files textures are now stored internally by Assimp with their filename included
// Now Assimp can lookup through the loaded textures after all data is processed
// We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it
// This may occur on this case too, it has to be studied
path.data[0] = '*';
path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
}
}
}
return path;
}
void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap& textures, void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap& textures,
const std::string& propName, const std::string& propName,
aiTextureType target, const MeshGeometry* const mesh ) aiTextureType target, const MeshGeometry* const mesh )
@ -1418,41 +1578,7 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap&
const Texture* const tex = ( *it ).second; const Texture* const tex = ( *it ).second;
if ( tex != 0 ) if ( tex != 0 )
{ {
aiString path; aiString path = GetTexturePath(tex);
path.Set( tex->RelativeFilename() );
const Video* media = tex->Media();
if (media != 0) {
bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
unsigned int index;
VideoMap::const_iterator it = textures_converted.find(media);
if (it != textures_converted.end()) {
index = (*it).second;
textureReady = true;
}
else {
if (media->ContentLength() > 0) {
index = ConvertVideo(*media);
textures_converted[media] = index;
textureReady = true;
}
}
// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready
if (doc.Settings().useLegacyEmbeddedTextureNaming) {
if (textureReady) {
// TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING"
// In FBX files textures are now stored internally by Assimp with their filename included
// Now Assimp can lookup thru the loaded textures after all data is processed
// We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it
// This may occur on this case too, it has to be studied
path.data[0] = '*';
path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index);
}
}
}
out_mat->AddProperty( &path, _AI_MATKEY_TEXTURE_BASE, target, 0 ); out_mat->AddProperty( &path, _AI_MATKEY_TEXTURE_BASE, target, 0 );
aiUVTransform uvTrafo; aiUVTransform uvTrafo;
@ -1559,9 +1685,8 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap&
} }
void Converter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, void Converter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextureMap& layeredTextures,
const std::string& propName, const std::string& propName,
aiTextureType target, const MeshGeometry* const mesh ) aiTextureType target, const MeshGeometry* const mesh ) {
{
LayeredTextureMap::const_iterator it = layeredTextures.find( propName ); LayeredTextureMap::const_iterator it = layeredTextures.find( propName );
if ( it == layeredTextures.end() ) { if ( it == layeredTextures.end() ) {
return; return;
@ -1577,9 +1702,7 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextu
const Texture* const tex = ( *it ).second->getTexture(texIndex); const Texture* const tex = ( *it ).second->getTexture(texIndex);
aiString path; aiString path = GetTexturePath(tex);
path.Set( tex->RelativeFilename() );
out_mat->AddProperty( &path, _AI_MATKEY_TEXTURE_BASE, target, texIndex ); out_mat->AddProperty( &path, _AI_MATKEY_TEXTURE_BASE, target, texIndex );
aiUVTransform uvTrafo; aiUVTransform uvTrafo;
@ -1805,11 +1928,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 +2046,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 +2268,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);
@ -164,23 +172,23 @@ private:
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed // MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed
std::vector<unsigned int> ConvertMesh(const MeshGeometry& mesh, const Model& model, std::vector<unsigned int> ConvertMesh(const MeshGeometry& mesh, const Model& model,
const aiMatrix4x4& node_global_transform); const aiMatrix4x4& node_global_transform, aiNode& nd);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
aiMesh* SetupEmptyMesh(const MeshGeometry& mesh); aiMesh* SetupEmptyMesh(const MeshGeometry& mesh, aiNode& nd);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
unsigned int ConvertMeshSingleMaterial(const MeshGeometry& mesh, const Model& model, unsigned int ConvertMeshSingleMaterial(const MeshGeometry& mesh, const Model& model,
const aiMatrix4x4& node_global_transform); const aiMatrix4x4& node_global_transform, aiNode& nd);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::vector<unsigned int> ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model, std::vector<unsigned int> ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model,
const aiMatrix4x4& node_global_transform); const aiMatrix4x4& node_global_transform, aiNode& nd);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
unsigned int ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model, unsigned int ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model,
MatIndexArray::value_type index, MatIndexArray::value_type index,
const aiMatrix4x4& node_global_transform); const aiMatrix4x4& node_global_transform, aiNode& nd);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
static const unsigned int NO_MATERIAL_SEPARATION = /* std::numeric_limits<unsigned int>::max() */ static const unsigned int NO_MATERIAL_SEPARATION = /* std::numeric_limits<unsigned int>::max() */
@ -220,6 +228,10 @@ private:
// Video -> aiTexture // Video -> aiTexture
unsigned int ConvertVideo(const Video& video); unsigned int ConvertVideo(const Video& video);
// ------------------------------------------------------------------------------------------------
// convert embedded texture if necessary and return actual texture path
aiString GetTexturePath(const Texture* tex);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, void TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures,
const std::string& propName, const std::string& propName,
@ -255,18 +267,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 +278,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 +428,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

@ -214,7 +214,7 @@ const Object* LazyObject::Get(bool dieOnError)
// note: the error message is already formatted, so raw logging is ok // note: the error message is already formatted, so raw logging is ok
if(!DefaultLogger::isNullLogger()) { if(!DefaultLogger::isNullLogger()) {
DefaultLogger::get()->error(ex.what()); ASSIMP_LOG_ERROR(ex.what());
} }
return NULL; return NULL;
} }
@ -575,11 +575,11 @@ std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bo
ai_assert( count != 0 ); ai_assert( count != 0 );
ai_assert( count <= MAX_CLASSNAMES); ai_assert( count <= MAX_CLASSNAMES);
size_t lenghts[MAX_CLASSNAMES]; size_t lengths[MAX_CLASSNAMES];
const size_t c = count; const size_t c = count;
for (size_t i = 0; i < c; ++i) { for (size_t i = 0; i < c; ++i) {
lenghts[ i ] = strlen(classnames[i]); lengths[ i ] = strlen(classnames[i]);
} }
std::vector<const Connection*> temp; std::vector<const Connection*> temp;
@ -597,7 +597,7 @@ std::vector<const Connection*> Document::GetConnectionsSequenced(uint64_t id, bo
for (size_t i = 0; i < c; ++i) { for (size_t i = 0; i < c; ++i) {
ai_assert(classnames[i]); ai_assert(classnames[i]);
if(static_cast<size_t>(std::distance(key.begin(),key.end())) == lenghts[i] && !strncmp(classnames[i],obtype,lenghts[i])) { if(static_cast<size_t>(std::distance(key.begin(),key.end())) == lengths[i] && !strncmp(classnames[i],obtype,lengths[i])) {
obtype = NULL; obtype = NULL;
break; break;
} }

View File

@ -79,7 +79,7 @@ void DOMError(const std::string& message, const Element* element /*= NULL*/)
void DOMWarning(const std::string& message, const Token& token) void DOMWarning(const std::string& message, const Token& token)
{ {
if(DefaultLogger::get()) { if(DefaultLogger::get()) {
DefaultLogger::get()->warn(Util::AddTokenText("FBX-DOM",message,&token)); ASSIMP_LOG_WARN(Util::AddTokenText("FBX-DOM",message,&token));
} }
} }
@ -91,7 +91,7 @@ void DOMWarning(const std::string& message, const Element* element /*= NULL*/)
return; return;
} }
if(DefaultLogger::get()) { if(DefaultLogger::get()) {
DefaultLogger::get()->warn("FBX-DOM: " + message); ASSIMP_LOG_WARN("FBX-DOM: " + message);
} }
} }
@ -115,7 +115,7 @@ std::shared_ptr<const PropertyTable> GetPropertyTable(const Document& doc,
} }
} }
if(!Properties70) { if(!Properties70 || !Properties70->Compound()) {
if(!no_warn) { if(!no_warn) {
DOMWarning("property table (Properties70) not found",&element); DOMWarning("property table (Properties70) not found",&element);
} }

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

2479
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; // connection 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 {
@ -299,7 +302,7 @@ Video::Video(uint64_t id, const Element& element, const Document& doc, const std
} }
if(Content) { if(Content) {
//this field is ommited when the embedded texture is already loaded, let's ignore if it's not found //this field is omitted when the embedded texture is already loaded, let's ignore if it's not found
try { try {
const Token& token = GetRequiredToken(*Content, 0); const Token& token = GetRequiredToken(*Content, 0);
const char* data = token.begin(); const char* data = token.begin();

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,9 +495,14 @@ void ResolveVertexDataArray(std::vector<T>& data_out, const Scope& source,
return; return;
} }
const T empty;
unsigned int next = 0; unsigned int next = 0;
for(int i : uvIndices) { for(int i : uvIndices) {
if (static_cast<size_t>(i) >= tempData.size()) { if ( -1 == i ) {
data_out[ next++ ] = empty;
continue;
}
if (static_cast<size_t>(i) >= tempData.size()) {
DOMError("index out of range",&GetRequiredElement(source,indexDataElementName)); DOMError("index out of range",&GetRequiredElement(source,indexDataElementName));
} }
@ -528,7 +529,6 @@ void MeshGeometry::ReadVertexDataNormals(std::vector<aiVector3D>& normals_out, c
m_mappings); m_mappings);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source, void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope& source,
const std::string& MappingInformationType, const std::string& MappingInformationType,
@ -543,7 +543,6 @@ void MeshGeometry::ReadVertexDataUV(std::vector<aiVector2D>& uv_out, const Scope
m_mappings); m_mappings);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, const Scope& source, void MeshGeometry::ReadVertexDataColors(std::vector<aiColor4D>& colors_out, const Scope& source,
const std::string& MappingInformationType, const std::string& MappingInformationType,

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

@ -54,6 +54,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
//remove mesh at position 'index' from the scene
static void removeMesh(aiScene* pScene, unsigned const index);
//correct node indices to meshes and remove references to deleted mesh
static void updateSceneGraph(aiNode* pNode, unsigned const index);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
FindDegeneratesProcess::FindDegeneratesProcess() FindDegeneratesProcess::FindDegeneratesProcess()
@ -85,11 +90,50 @@ void FindDegeneratesProcess::SetupProperties(const Importer* pImp) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void FindDegeneratesProcess::Execute( aiScene* pScene) { void FindDegeneratesProcess::Execute( aiScene* pScene) {
DefaultLogger::get()->debug("FindDegeneratesProcess begin"); ASSIMP_LOG_DEBUG("FindDegeneratesProcess begin");
for (unsigned int i = 0; i < pScene->mNumMeshes;++i){ for (unsigned int i = 0; i < pScene->mNumMeshes;++i){
ExecuteOnMesh( pScene->mMeshes[ i ] ); if (ExecuteOnMesh(pScene->mMeshes[i])) {
removeMesh(pScene, i);
--i; //the current i is removed, do not skip the next one
}
}
ASSIMP_LOG_DEBUG("FindDegeneratesProcess finished");
}
static void removeMesh(aiScene* pScene, unsigned const index) {
//we start at index and copy the pointers one position forward
//save the mesh pointer to delete it later
auto delete_me = pScene->mMeshes[index];
for (unsigned i = index; i < pScene->mNumMeshes - 1; ++i) {
pScene->mMeshes[i] = pScene->mMeshes[i+1];
}
pScene->mMeshes[pScene->mNumMeshes - 1] = nullptr;
--(pScene->mNumMeshes);
delete delete_me;
//removing a mesh also requires updating all references to it in the scene graph
updateSceneGraph(pScene->mRootNode, index);
}
static void updateSceneGraph(aiNode* pNode, unsigned const index) {
for (unsigned i = 0; i < pNode->mNumMeshes; ++i) {
if (pNode->mMeshes[i] > index) {
--(pNode->mMeshes[i]);
continue;
}
if (pNode->mMeshes[i] == index) {
for (unsigned j = i; j < pNode->mNumMeshes -1; ++j) {
pNode->mMeshes[j] = pNode->mMeshes[j+1];
}
--(pNode->mNumMeshes);
--i;
continue;
}
}
//recurse to all children
for (unsigned i = 0; i < pNode->mNumChildren; ++i) {
updateSceneGraph(pNode->mChildren[i], index);
} }
DefaultLogger::get()->debug("FindDegeneratesProcess finished");
} }
static ai_real heron( ai_real a, ai_real b, ai_real c ) { static ai_real heron( ai_real a, ai_real b, ai_real c ) {
@ -125,7 +169,7 @@ static ai_real calculateAreaOfTriangle( const aiFace& face, aiMesh* mesh ) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported mesh // Executes the post processing step on the given imported mesh
void FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) { bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
mesh->mPrimitiveTypes = 0; mesh->mPrimitiveTypes = 0;
std::vector<bool> remove_me; std::vector<bool> remove_me;
@ -161,7 +205,7 @@ void FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) {
// NOTE: we set the removed vertex index to an unique value // NOTE: we set the removed vertex index to an unique value
// to make sure the developer gets notified when his // to make sure the developer gets notified when his
// application attemps to access this data. // application attempts to access this data.
face.mIndices[ face.mNumIndices ] = 0xdeadbeef; face.mIndices[ face.mNumIndices ] = 0xdeadbeef;
if(first) { if(first) {
@ -227,33 +271,28 @@ evil_jump_outside:
if (&face_src != &face_dest) { if (&face_src != &face_dest) {
// clear source // clear source
face_src.mNumIndices = 0; face_src.mNumIndices = 0;
face_src.mIndices = NULL; face_src.mIndices = nullptr;
} }
} }
else { else {
// Otherwise delete it if we don't need this face // Otherwise delete it if we don't need this face
delete[] face_src.mIndices; delete[] face_src.mIndices;
face_src.mIndices = NULL; face_src.mIndices = nullptr;
face_src.mNumIndices = 0; face_src.mNumIndices = 0;
} }
} }
// Just leave the rest of the array unreferenced, we don't care for now // Just leave the rest of the array unreferenced, we don't care for now
mesh->mNumFaces = n; mesh->mNumFaces = n;
if (!mesh->mNumFaces) { if (!mesh->mNumFaces) {
// WTF!? //The whole mesh consists of degenerated faces
// OK ... for completeness and because I'm not yet tired, //signal upward, that this mesh should be deleted.
// let's write code that willl hopefully never be called ASSIMP_LOG_DEBUG("FindDegeneratesProcess removed a mesh full of degenerated primitives");
// (famous last words) return true;
// OK ... bad idea.
throw DeadlyImportError("Mesh is empty after removal of degenerated primitives ... WTF!?");
} }
} }
if (deg && !DefaultLogger::isNullLogger()) if (deg && !DefaultLogger::isNullLogger()) {
{ ASSIMP_LOG_WARN_F( "Found ", deg, " degenerated primitives");
char s[64];
ASSIMP_itoa10(s,deg);
DefaultLogger::get()->warn(std::string("Found ") + s + " degenerated primitives");
} }
return false;
} }

View File

@ -74,7 +74,8 @@ public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Execute step on a given mesh // Execute step on a given mesh
void ExecuteOnMesh( aiMesh* mesh); ///@returns true if the current mesh should be deleted, false otherwise
bool ExecuteOnMesh( aiMesh* mesh);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/// @brief Enable the instant removal of degenerated primitives /// @brief Enable the instant removal of degenerated primitives

View File

@ -119,7 +119,7 @@ void UpdateMeshIndices(aiNode* node, unsigned int* lookup)
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void FindInstancesProcess::Execute( aiScene* pScene) void FindInstancesProcess::Execute( aiScene* pScene)
{ {
DefaultLogger::get()->debug("FindInstancesProcess begin"); ASSIMP_LOG_DEBUG("FindInstancesProcess begin");
if (pScene->mNumMeshes) { if (pScene->mNumMeshes) {
// use a pseudo hash for all meshes in the scene to quickly find // use a pseudo hash for all meshes in the scene to quickly find
@ -267,13 +267,11 @@ void FindInstancesProcess::Execute( aiScene* pScene)
// write to log // write to log
if (!DefaultLogger::isNullLogger()) { if (!DefaultLogger::isNullLogger()) {
ASSIMP_LOG_INFO_F( "FindInstancesProcess finished. Found ", (pScene->mNumMeshes - numMeshesOut), " instances" );
char buffer[512];
::ai_snprintf(buffer,512,"FindInstancesProcess finished. Found %i instances",pScene->mNumMeshes-numMeshesOut);
DefaultLogger::get()->info(buffer);
} }
pScene->mNumMeshes = numMeshesOut; pScene->mNumMeshes = numMeshesOut;
} else {
ASSIMP_LOG_DEBUG("FindInstancesProcess finished. No instanced meshes found");
} }
else DefaultLogger::get()->debug("FindInstancesProcess finished. No instanced meshes found");
} }
} }

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

@ -118,7 +118,7 @@ void UpdateMeshReferences(aiNode* node, const std::vector<unsigned int>& meshMap
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void FindInvalidDataProcess::Execute( aiScene* pScene) void FindInvalidDataProcess::Execute( aiScene* pScene)
{ {
DefaultLogger::get()->debug("FindInvalidDataProcess begin"); ASSIMP_LOG_DEBUG("FindInvalidDataProcess begin");
bool out = false; bool out = false;
std::vector<unsigned int> meshMapping(pScene->mNumMeshes); std::vector<unsigned int> meshMapping(pScene->mNumMeshes);
@ -163,9 +163,10 @@ void FindInvalidDataProcess::Execute( aiScene* pScene)
pScene->mNumMeshes = real; pScene->mNumMeshes = real;
} }
DefaultLogger::get()->info("FindInvalidDataProcess finished. Found issues ..."); ASSIMP_LOG_INFO("FindInvalidDataProcess finished. Found issues ...");
} else {
ASSIMP_LOG_DEBUG("FindInvalidDataProcess finished. Everything seems to be OK.");
} }
else DefaultLogger::get()->debug("FindInvalidDataProcess finished. Everything seems to be OK.");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -212,8 +213,7 @@ inline bool ProcessArray(T*& in, unsigned int num,const char* name,
{ {
const char* err = ValidateArrayContents(in,num,dirtyMask,mayBeIdentical,mayBeZero); const char* err = ValidateArrayContents(in,num,dirtyMask,mayBeIdentical,mayBeZero);
if (err) { if (err) {
DefaultLogger::get()->error(std::string("FindInvalidDataProcess fails on mesh ") + name + ": " + err); ASSIMP_LOG_ERROR_F( "FindInvalidDataProcess fails on mesh ", name, ": ", err);
delete[] in; delete[] in;
in = NULL; in = NULL;
return true; return true;
@ -332,7 +332,7 @@ void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim)
i = 1; i = 1;
} }
if (1 == i) if (1 == i)
DefaultLogger::get()->warn("Simplified dummy tracks with just one key"); ASSIMP_LOG_WARN("Simplified dummy tracks with just one key");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -354,7 +354,7 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh)
// Process vertex positions // Process vertex positions
if (pMesh->mVertices && ProcessArray(pMesh->mVertices, pMesh->mNumVertices, "positions", dirtyMask)) { if (pMesh->mVertices && ProcessArray(pMesh->mVertices, pMesh->mNumVertices, "positions", dirtyMask)) {
DefaultLogger::get()->error("Deleting mesh: Unable to continue without vertex positions"); ASSIMP_LOG_ERROR("Deleting mesh: Unable to continue without vertex positions");
return 2; return 2;
} }

View File

@ -82,28 +82,35 @@ bool FixInfacingNormalsProcess::IsActive( unsigned int pFlags) const
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void FixInfacingNormalsProcess::Execute( aiScene* pScene) void FixInfacingNormalsProcess::Execute( aiScene* pScene)
{ {
DefaultLogger::get()->debug("FixInfacingNormalsProcess begin"); ASSIMP_LOG_DEBUG("FixInfacingNormalsProcess begin");
bool bHas = false; bool bHas( false );
for( unsigned int a = 0; a < pScene->mNumMeshes; a++) for (unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
if(ProcessMesh( pScene->mMeshes[a],a))bHas = true; if (ProcessMesh(pScene->mMeshes[a], a)) {
bHas = true;
}
}
if (bHas) if (bHas) {
DefaultLogger::get()->debug("FixInfacingNormalsProcess finished. Found issues."); ASSIMP_LOG_DEBUG("FixInfacingNormalsProcess finished. Found issues.");
else DefaultLogger::get()->debug("FixInfacingNormalsProcess finished. No changes to the scene."); } else {
ASSIMP_LOG_DEBUG("FixInfacingNormalsProcess finished. No changes to the scene.");
}
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Apply the step to the mesh // Apply the step to the mesh
bool FixInfacingNormalsProcess::ProcessMesh( aiMesh* pcMesh, unsigned int index) bool FixInfacingNormalsProcess::ProcessMesh( aiMesh* pcMesh, unsigned int index)
{ {
ai_assert(NULL != pcMesh); ai_assert(nullptr != pcMesh);
// Nothing to do if there are no model normals // Nothing to do if there are no model normals
if (!pcMesh->HasNormals())return false; if (!pcMesh->HasNormals()) {
return false;
}
// Compute the bounding box of both the model vertices + normals and // Compute the bounding box of both the model vertices + normals and
// the umodified model vertices. Then check whether the first BB // the unmodified model vertices. Then check whether the first BB
// is smaller than the second. In this case we can assume that the // is smaller than the second. In this case we can assume that the
// normals need to be flipped, although there are a few special cases .. // normals need to be flipped, although there are a few special cases ..
// convex, concave, planar models ... // convex, concave, planar models ...
@ -155,14 +162,9 @@ bool FixInfacingNormalsProcess::ProcessMesh( aiMesh* pcMesh, unsigned int index)
if (fDelta1_z < 0.05f * std::sqrt( fDelta1_y * fDelta1_x ))return false; if (fDelta1_z < 0.05f * std::sqrt( fDelta1_y * fDelta1_x ))return false;
// now compare the volumes of the bounding boxes // now compare the volumes of the bounding boxes
if (std::fabs(fDelta0_x * fDelta0_y * fDelta0_z) < if (std::fabs(fDelta0_x * fDelta0_y * fDelta0_z) < std::fabs(fDelta1_x * fDelta1_yz)) {
std::fabs(fDelta1_x * fDelta1_yz)) if (!DefaultLogger::isNullLogger()) {
{ ASSIMP_LOG_INFO_F("Mesh ", index, ": Normals are facing inwards (or the mesh is planar)", index);
if (!DefaultLogger::isNullLogger())
{
char buffer[128]; // should be sufficiently large
ai_snprintf(buffer,128,"Mesh %u: Normals are facing inwards (or the mesh is planar)",index);
DefaultLogger::get()->info(buffer);
} }
// Invert normals // Invert normals

View File

@ -72,16 +72,15 @@ GenFaceNormalsProcess::~GenFaceNormalsProcess()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool GenFaceNormalsProcess::IsActive( unsigned int pFlags) const bool GenFaceNormalsProcess::IsActive( unsigned int pFlags) const {
{ force_ = (pFlags & aiProcess_ForceGenNormals) != 0;
return (pFlags & aiProcess_GenNormals) != 0; return (pFlags & aiProcess_GenNormals) != 0;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void GenFaceNormalsProcess::Execute( aiScene* pScene) void GenFaceNormalsProcess::Execute( aiScene* pScene) {
{ ASSIMP_LOG_DEBUG("GenFaceNormalsProcess begin");
DefaultLogger::get()->debug("GenFaceNormalsProcess begin");
if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) { if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here"); throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
@ -94,11 +93,12 @@ void GenFaceNormalsProcess::Execute( aiScene* pScene)
} }
} }
if (bHas) { if (bHas) {
DefaultLogger::get()->info("GenFaceNormalsProcess finished. " ASSIMP_LOG_INFO("GenFaceNormalsProcess finished. "
"Face normals have been calculated"); "Face normals have been calculated");
} else {
ASSIMP_LOG_DEBUG("GenFaceNormalsProcess finished. "
"Normals are already there");
} }
else DefaultLogger::get()->debug("GenFaceNormalsProcess finished. "
"Normals are already there");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -106,14 +106,15 @@ void GenFaceNormalsProcess::Execute( aiScene* pScene)
bool GenFaceNormalsProcess::GenMeshFaceNormals (aiMesh* pMesh) bool GenFaceNormalsProcess::GenMeshFaceNormals (aiMesh* pMesh)
{ {
if (NULL != pMesh->mNormals) { if (NULL != pMesh->mNormals) {
return false; if (force_) delete[] pMesh->mNormals;
else return false;
} }
// If the mesh consists of lines and/or points but not of // If the mesh consists of lines and/or points but not of
// triangles or higher-order polygons the normal vectors // triangles or higher-order polygons the normal vectors
// are undefined. // are undefined.
if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) { if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) {
DefaultLogger::get()->info("Normal vectors are undefined for line and point meshes"); ASSIMP_LOG_INFO("Normal vectors are undefined for line and point meshes");
return false; return false;
} }
@ -135,7 +136,7 @@ bool GenFaceNormalsProcess::GenMeshFaceNormals (aiMesh* pMesh)
const aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]]; const aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]];
const aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]]; const aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]];
const aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]]; const aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]];
const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).Normalize(); const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe();
for (unsigned int i = 0;i < face.mNumIndices;++i) { for (unsigned int i = 0;i < face.mNumIndices;++i) {
pMesh->mNormals[face.mIndices[i]] = vNor; pMesh->mNormals[face.mIndices[i]] = vNor;

View File

@ -78,7 +78,8 @@ public:
private: private:
bool GenMeshFaceNormals (aiMesh* pcMesh); bool GenMeshFaceNormals(aiMesh* pcMesh);
mutable bool force_ = false;
}; };
} // end of namespace Assimp } // end of namespace Assimp

View File

@ -72,6 +72,7 @@ GenVertexNormalsProcess::~GenVertexNormalsProcess() {
// Returns whether the processing step is present in the given flag field. // Returns whether the processing step is present in the given flag field.
bool GenVertexNormalsProcess::IsActive( unsigned int pFlags) const bool GenVertexNormalsProcess::IsActive( unsigned int pFlags) const
{ {
force_ = (pFlags & aiProcess_ForceGenNormals) != 0;
return (pFlags & aiProcess_GenSmoothNormals) != 0; return (pFlags & aiProcess_GenSmoothNormals) != 0;
} }
@ -88,39 +89,42 @@ void GenVertexNormalsProcess::SetupProperties(const Importer* pImp)
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
void GenVertexNormalsProcess::Execute( aiScene* pScene) void GenVertexNormalsProcess::Execute( aiScene* pScene)
{ {
DefaultLogger::get()->debug("GenVertexNormalsProcess begin"); ASSIMP_LOG_DEBUG("GenVertexNormalsProcess begin");
if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) {
throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here"); throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here");
}
bool bHas = false; bool bHas = false;
for( unsigned int a = 0; a < pScene->mNumMeshes; a++) for( unsigned int a = 0; a < pScene->mNumMeshes; ++a) {
{
if(GenMeshVertexNormals( pScene->mMeshes[a],a)) if(GenMeshVertexNormals( pScene->mMeshes[a],a))
bHas = true; bHas = true;
} }
if (bHas) { if (bHas) {
DefaultLogger::get()->info("GenVertexNormalsProcess finished. " ASSIMP_LOG_INFO("GenVertexNormalsProcess finished. "
"Vertex normals have been calculated"); "Vertex normals have been calculated");
} else {
ASSIMP_LOG_DEBUG("GenVertexNormalsProcess finished. "
"Normals are already there");
} }
else DefaultLogger::get()->debug("GenVertexNormalsProcess finished. "
"Normals are already there");
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Executes the post processing step on the given imported data. // Executes the post processing step on the given imported data.
bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int meshIndex) bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int meshIndex)
{ {
if (NULL != pMesh->mNormals) if (NULL != pMesh->mNormals) {
return false; if (force_) delete[] pMesh->mNormals;
else return false;
}
// If the mesh consists of lines and/or points but not of // If the mesh consists of lines and/or points but not of
// triangles or higher-order polygons the normal vectors // triangles or higher-order polygons the normal vectors
// are undefined. // are undefined.
if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON)))
{ {
DefaultLogger::get()->info("Normal vectors are undefined for line and point meshes"); ASSIMP_LOG_INFO("Normal vectors are undefined for line and point meshes");
return false; return false;
} }
@ -145,7 +149,7 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
const aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]]; const aiVector3D* pV1 = &pMesh->mVertices[face.mIndices[0]];
const aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]]; const aiVector3D* pV2 = &pMesh->mVertices[face.mIndices[1]];
const aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]]; const aiVector3D* pV3 = &pMesh->mVertices[face.mIndices[face.mNumIndices-1]];
const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)); const aiVector3D vNor = ((*pV2 - *pV1) ^ (*pV3 - *pV1)).NormalizeSafe();
for (unsigned int i = 0;i < face.mNumIndices;++i) { for (unsigned int i = 0;i < face.mNumIndices;++i) {
pMesh->mNormals[face.mIndices[i]] = vNor; pMesh->mNormals[face.mIndices[i]] = vNor;
@ -213,17 +217,15 @@ bool GenVertexNormalsProcess::GenMeshVertexNormals (aiMesh* pMesh, unsigned int
vertexFinder->FindPositions( pMesh->mVertices[i] , posEpsilon, verticesFound); vertexFinder->FindPositions( pMesh->mVertices[i] , posEpsilon, verticesFound);
aiVector3D vr = pMesh->mNormals[i]; aiVector3D vr = pMesh->mNormals[i];
ai_real vrlen = vr.Length();
aiVector3D pcNor; aiVector3D pcNor;
for (unsigned int a = 0; a < verticesFound.size(); ++a) { for (unsigned int a = 0; a < verticesFound.size(); ++a) {
aiVector3D v = pMesh->mNormals[verticesFound[a]]; aiVector3D v = pMesh->mNormals[verticesFound[a]];
// check whether the angle between the two normals is not too large // Check whether the angle between the two normals is not too large.
// HACK: if v.x is qnan the dot product will become qnan, too // Skip the angle check on our own normal to avoid false negatives
// therefore the comparison against fLimit should be false // (v*v is not guaranteed to be 1.0 for all unit vectors v)
// in every case. if (is_not_qnan(v.x) && (verticesFound[a] == i || (v * vr >= fLimit)))
if (v * vr >= fLimit * vrlen * v.Length())
pcNor += v; pcNor += v;
} }
pcNew[i] = pcNor.NormalizeSafe(); pcNew[i] = pcNor.NormalizeSafe();

View File

@ -107,6 +107,7 @@ private:
/** Configuration option: maximum smoothing angle, in radians*/ /** Configuration option: maximum smoothing angle, in radians*/
ai_real configMaxAngle; ai_real configMaxAngle;
mutable bool force_ = false;
}; };
} // end of namespace Assimp } // end of namespace Assimp

View File

@ -141,21 +141,21 @@ void HMPImporter::InternReadFile( const std::string& pFile,
if (AI_HMP_MAGIC_NUMBER_LE_4 == iMagic || if (AI_HMP_MAGIC_NUMBER_LE_4 == iMagic ||
AI_HMP_MAGIC_NUMBER_BE_4 == iMagic) AI_HMP_MAGIC_NUMBER_BE_4 == iMagic)
{ {
DefaultLogger::get()->debug("HMP subtype: 3D GameStudio A4, magic word is HMP4"); ASSIMP_LOG_DEBUG("HMP subtype: 3D GameStudio A4, magic word is HMP4");
InternReadFile_HMP4(); InternReadFile_HMP4();
} }
// HMP5 format // HMP5 format
else if (AI_HMP_MAGIC_NUMBER_LE_5 == iMagic || else if (AI_HMP_MAGIC_NUMBER_LE_5 == iMagic ||
AI_HMP_MAGIC_NUMBER_BE_5 == iMagic) AI_HMP_MAGIC_NUMBER_BE_5 == iMagic)
{ {
DefaultLogger::get()->debug("HMP subtype: 3D GameStudio A5, magic word is HMP5"); ASSIMP_LOG_DEBUG("HMP subtype: 3D GameStudio A5, magic word is HMP5");
InternReadFile_HMP5(); InternReadFile_HMP5();
} }
// HMP7 format // HMP7 format
else if (AI_HMP_MAGIC_NUMBER_LE_7 == iMagic || else if (AI_HMP_MAGIC_NUMBER_LE_7 == iMagic ||
AI_HMP_MAGIC_NUMBER_BE_7 == iMagic) AI_HMP_MAGIC_NUMBER_BE_7 == iMagic)
{ {
DefaultLogger::get()->debug("HMP subtype: 3D GameStudio A7, magic word is HMP7"); ASSIMP_LOG_DEBUG("HMP subtype: 3D GameStudio A7, magic word is HMP7");
InternReadFile_HMP7(); InternReadFile_HMP7();
} }
else else

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;
} }
@ -135,7 +131,7 @@ void IRRImporter::SetupProperties(const Importer* pImp)
// read the output frame rate of all node animation channels // read the output frame rate of all node animation channels
fps = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_IRR_ANIM_FPS,100); fps = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_IRR_ANIM_FPS,100);
if (fps < 10.) { if (fps < 10.) {
DefaultLogger::get()->error("IRR: Invalid FPS configuration"); ASSIMP_LOG_ERROR("IRR: Invalid FPS configuration");
fps = 100; fps = 100;
} }
@ -285,7 +281,7 @@ void IRRImporter::CopyMaterial(std::vector<aiMaterial*>& materials,
return; return;
} }
else if (inmaterials.size() > 1) { else if (inmaterials.size() > 1) {
DefaultLogger::get()->info("IRR: Skipping additional materials"); ASSIMP_LOG_INFO("IRR: Skipping additional materials");
} }
mesh->mMaterialIndex = (unsigned int)materials.size(); mesh->mMaterialIndex = (unsigned int)materials.size();
@ -323,17 +319,18 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
if (root->animators.empty()) { if (root->animators.empty()) {
return; return;
} }
unsigned int total = 0; unsigned int total( 0 );
for (std::list<Animator>::iterator it = root->animators.begin();it != root->animators.end(); ++it) { for (std::list<Animator>::iterator it = root->animators.begin();it != root->animators.end(); ++it) {
if ((*it).type == Animator::UNKNOWN || (*it).type == Animator::OTHER) { if ((*it).type == Animator::UNKNOWN || (*it).type == Animator::OTHER) {
DefaultLogger::get()->warn("IRR: Skipping unknown or unsupported animator"); ASSIMP_LOG_WARN("IRR: Skipping unknown or unsupported animator");
continue; continue;
} }
++total; ++total;
} }
if (!total)return; if (!total) {
else if (1 == total) { return;
DefaultLogger::get()->warn("IRR: Adding dummy nodes to simulate multiple animators"); } else if (1 == total) {
ASSIMP_LOG_WARN("IRR: Adding dummy nodes to simulate multiple animators");
} }
// NOTE: 1 tick == i millisecond // NOTE: 1 tick == i millisecond
@ -522,9 +519,9 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector<aiNode
const int size = (int)in.splineKeys.size(); const int size = (int)in.splineKeys.size();
if (!size) { if (!size) {
// We have no point in the spline. That's bad. Really bad. // We have no point in the spline. That's bad. Really bad.
DefaultLogger::get()->warn("IRR: Spline animators with no points defined"); ASSIMP_LOG_WARN("IRR: Spline animators with no points defined");
delete anim;anim = NULL; delete anim;anim = nullptr;
break; break;
} }
else if (size == 1) { else if (size == 1) {
@ -676,7 +673,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
// graph we're currently building // graph we're currently building
aiScene* scene = batch.GetImport(root->id); aiScene* scene = batch.GetImport(root->id);
if (!scene) { if (!scene) {
DefaultLogger::get()->error("IRR: Unable to load external file: " + root->meshPath); ASSIMP_LOG_ERROR("IRR: Unable to load external file: " + root->meshPath);
break; break;
} }
attach.push_back(AttachmentInfo(scene,rootOut)); attach.push_back(AttachmentInfo(scene,rootOut));
@ -687,7 +684,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
// should be equal. If they are not, we can impossibly // should be equal. If they are not, we can impossibly
// do this ... // do this ...
if (root->materials.size() != (unsigned int)scene->mNumMaterials) { if (root->materials.size() != (unsigned int)scene->mNumMaterials) {
DefaultLogger::get()->warn("IRR: Failed to match imported materials " ASSIMP_LOG_WARN("IRR: Failed to match imported materials "
"with the materials found in the IRR scene file"); "with the materials found in the IRR scene file");
break; break;
@ -726,7 +723,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
} }
} }
if (bdo) { if (bdo) {
DefaultLogger::get()->info("IRR: Replacing mesh vertex alpha with common opacity"); ASSIMP_LOG_INFO("IRR: Replacing mesh vertex alpha with common opacity");
for (unsigned int a = 0; a < mesh->mNumVertices;++a) for (unsigned int a = 0; a < mesh->mNumVertices;++a)
mesh->mColors[0][a].a = 1.f; mesh->mColors[0][a].a = 1.f;
@ -810,7 +807,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
{ {
// A skybox is defined by six materials // A skybox is defined by six materials
if (root->materials.size() < 6) { if (root->materials.size() < 6) {
DefaultLogger::get()->error("IRR: There should be six materials for a skybox"); ASSIMP_LOG_ERROR("IRR: There should be six materials for a skybox");
break; break;
} }
@ -827,7 +824,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
// for IRR skyboxes. We add a 'IRR.SkyBox_' prefix to the node. // for IRR skyboxes. We add a 'IRR.SkyBox_' prefix to the node.
// ************************************************************* // *************************************************************
root->name = "IRR.SkyBox_" + root->name; root->name = "IRR.SkyBox_" + root->name;
DefaultLogger::get()->info("IRR: Loading skybox, this will " ASSIMP_LOG_INFO("IRR: Loading skybox, this will "
"require special handling to be displayed correctly"); "require special handling to be displayed correctly");
} }
break; break;
@ -835,7 +832,7 @@ void IRRImporter::GenerateGraph(Node* root,aiNode* rootOut ,aiScene* scene,
case Node::TERRAIN: case Node::TERRAIN:
{ {
// to support terrains, we'd need to have a texture decoder // to support terrains, we'd need to have a texture decoder
DefaultLogger::get()->error("IRR: Unsupported node - TERRAIN"); ASSIMP_LOG_ERROR("IRR: Unsupported node - TERRAIN");
} }
break; break;
default: default:
@ -1014,11 +1011,11 @@ void IRRImporter::InternReadFile( const std::string& pFile,
} }
else if (!ASSIMP_stricmp(sz,"billBoard")) { else if (!ASSIMP_stricmp(sz,"billBoard")) {
// We don't support billboards, so ignore them // We don't support billboards, so ignore them
DefaultLogger::get()->error("IRR: Billboards are not supported by Assimp"); ASSIMP_LOG_ERROR("IRR: Billboards are not supported by Assimp");
nd = new Node(Node::DUMMY); nd = new Node(Node::DUMMY);
} }
else { else {
DefaultLogger::get()->warn("IRR: Found unknown node: " + std::string(sz)); ASSIMP_LOG_WARN("IRR: Found unknown node: " + std::string(sz));
/* We skip the contents of nodes we don't know. /* We skip the contents of nodes we don't know.
* We parse the transformation and all animators * We parse the transformation and all animators
@ -1045,7 +1042,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
*/ */
if (!curNode) { if (!curNode) {
#if 0 #if 0
DefaultLogger::get()->error("IRR: Encountered <attributes> element, but " ASSIMP_LOG_ERROR("IRR: Encountered <attributes> element, but "
"there is no node active"); "there is no node active");
#endif #endif
continue; continue;
@ -1273,7 +1270,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
lights.pop_back(); lights.pop_back();
curNode->type = Node::DUMMY; curNode->type = Node::DUMMY;
DefaultLogger::get()->error("Ignoring light of unknown type: " + prop.value); ASSIMP_LOG_ERROR("Ignoring light of unknown type: " + prop.value);
} }
} }
else if ((prop.name == "Mesh" && Node::MESH == curNode->type) || else if ((prop.name == "Mesh" && Node::MESH == curNode->type) ||
@ -1281,7 +1278,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
{ {
/* This is the file name of the mesh - either /* This is the file name of the mesh - either
* animated or not. We need to make sure we setup * animated or not. We need to make sure we setup
* the correct postprocessing settings here. * the correct post-processing settings here.
*/ */
unsigned int pp = 0; unsigned int pp = 0;
BatchLoader::PropertyMap map; BatchLoader::PropertyMap map;
@ -1303,7 +1300,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
const std::string extension = GetExtension(prop.value); const std::string extension = GetExtension(prop.value);
if ("irr" == extension) { if ("irr" == extension) {
DefaultLogger::get()->error("IRR: Can't load another IRR file recursively"); ASSIMP_LOG_ERROR("IRR: Can't load another IRR file recursively");
} }
else else
{ {
@ -1327,7 +1324,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
curAnim->type = Animator::FOLLOW_SPLINE; curAnim->type = Animator::FOLLOW_SPLINE;
} }
else { else {
DefaultLogger::get()->warn("IRR: Ignoring unknown animator: " ASSIMP_LOG_WARN("IRR: Ignoring unknown animator: "
+ prop.value); + prop.value);
curAnim->type = Animator::UNKNOWN; curAnim->type = Animator::UNKNOWN;
@ -1352,7 +1349,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
// back in the node hierarchy // back in the node hierarchy
if (!curParent) { if (!curParent) {
curParent = root; curParent = root;
DefaultLogger::get()->error("IRR: Too many closing <node> elements"); ASSIMP_LOG_ERROR("IRR: Too many closing <node> elements");
} }
else curParent = curParent->parent; else curParent = curParent->parent;
} }
@ -1373,15 +1370,14 @@ void IRRImporter::InternReadFile( const std::string& pFile,
} }
} }
/* Now iterate through all cameras and compute their final (horizontal) FOV // Now iterate through all cameras and compute their final (horizontal) FOV
*/
for (aiCamera *cam : cameras) { for (aiCamera *cam : cameras) {
// screen aspect could be missing // screen aspect could be missing
if (cam->mAspect) { if (cam->mAspect) {
cam->mHorizontalFOV *= cam->mAspect; cam->mHorizontalFOV *= cam->mAspect;
} else {
ASSIMP_LOG_WARN("IRR: Camera aspect is not given, can't compute horizontal FOV");
} }
else DefaultLogger::get()->warn("IRR: Camera aspect is not given, can't compute horizontal FOV");
} }
batch.LoadAll(); batch.LoadAll();
@ -1476,7 +1472,7 @@ void IRRImporter::InternReadFile( const std::string& pFile,
* models from external files * models from external files
*/ */
if (!pScene->mNumMeshes || !pScene->mNumMaterials) { if (!pScene->mNumMeshes || !pScene->mNumMaterials) {
DefaultLogger::get()->warn("IRR: No meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE"); ASSIMP_LOG_WARN("IRR: No meshes loaded, setting AI_SCENE_FLAGS_INCOMPLETE");
pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
} }

View File

@ -175,7 +175,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
if (!ASSIMP_stricmp(reader->getNodeName(),"buffer") && (curMat || curMesh)) { if (!ASSIMP_stricmp(reader->getNodeName(),"buffer") && (curMat || curMesh)) {
// end of previous buffer. A material and a mesh should be there // end of previous buffer. A material and a mesh should be there
if ( !curMat || !curMesh) { if ( !curMat || !curMesh) {
DefaultLogger::get()->error("IRRMESH: A buffer must contain a mesh and a material"); ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
releaseMaterial( &curMat ); releaseMaterial( &curMat );
releaseMesh( &curMesh ); releaseMesh( &curMesh );
} else { } else {
@ -197,7 +197,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
if (!ASSIMP_stricmp(reader->getNodeName(),"material")) { if (!ASSIMP_stricmp(reader->getNodeName(),"material")) {
if (curMat) { if (curMat) {
DefaultLogger::get()->warn("IRRMESH: Only one material description per buffer, please"); ASSIMP_LOG_WARN("IRRMESH: Only one material description per buffer, please");
releaseMaterial( &curMat ); releaseMaterial( &curMat );
} }
curMat = ParseMaterial(curMatFlags); curMat = ParseMaterial(curMatFlags);
@ -208,7 +208,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
if (!num) { if (!num) {
// This is possible ... remove the mesh from the list and skip further reading // This is possible ... remove the mesh from the list and skip further reading
DefaultLogger::get()->warn("IRRMESH: Found mesh with zero vertices"); ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero vertices");
releaseMaterial( &curMat ); releaseMaterial( &curMat );
releaseMesh( &curMesh ); releaseMesh( &curMesh );
@ -255,7 +255,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
} }
else if (ASSIMP_stricmp("standard", t)) { else if (ASSIMP_stricmp("standard", t)) {
releaseMaterial( &curMat ); releaseMaterial( &curMat );
DefaultLogger::get()->warn("IRRMESH: Unknown vertex format"); ASSIMP_LOG_WARN("IRRMESH: Unknown vertex format");
} }
else vertexFormat = 0; else vertexFormat = 0;
textMeaning = 1; textMeaning = 1;
@ -275,7 +275,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
curMesh->mNumVertices = reader->getAttributeValueAsInt("indexCount"); curMesh->mNumVertices = reader->getAttributeValueAsInt("indexCount");
if (!curMesh->mNumVertices) { if (!curMesh->mNumVertices) {
// This is possible ... remove the mesh from the list and skip further reading // This is possible ... remove the mesh from the list and skip further reading
DefaultLogger::get()->warn("IRRMESH: Found mesh with zero indices"); ASSIMP_LOG_WARN("IRRMESH: Found mesh with zero indices");
// mesh - away // mesh - away
releaseMesh( &curMesh ); releaseMesh( &curMesh );
@ -288,7 +288,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
} }
if (curMesh->mNumVertices % 3) { if (curMesh->mNumVertices % 3) {
DefaultLogger::get()->warn("IRRMESH: Number if indices isn't divisible by 3"); ASSIMP_LOG_WARN("IRRMESH: Number if indices isn't divisible by 3");
} }
curMesh->mNumFaces = curMesh->mNumVertices / 3; curMesh->mNumFaces = curMesh->mNumVertices / 3;
@ -439,7 +439,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
unsigned int total = 0; unsigned int total = 0;
while(SkipSpacesAndLineEnd(&sz)) { while(SkipSpacesAndLineEnd(&sz)) {
if (curFace >= faceEnd) { if (curFace >= faceEnd) {
DefaultLogger::get()->error("IRRMESH: Too many indices"); ASSIMP_LOG_ERROR("IRRMESH: Too many indices");
break; break;
} }
if (!curIdx) { if (!curIdx) {
@ -449,7 +449,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
unsigned int idx = strtoul10(sz,&sz); unsigned int idx = strtoul10(sz,&sz);
if (idx >= curVertices.size()) { if (idx >= curVertices.size()) {
DefaultLogger::get()->error("IRRMESH: Index out of range"); ASSIMP_LOG_ERROR("IRRMESH: Index out of range");
idx = 0; idx = 0;
} }
@ -470,7 +470,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
} }
if (curFace != faceEnd) if (curFace != faceEnd)
DefaultLogger::get()->error("IRRMESH: Not enough indices"); ASSIMP_LOG_ERROR("IRRMESH: Not enough indices");
// Finish processing the mesh - do some small material workarounds // Finish processing the mesh - do some small material workarounds
if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) { if (curMatFlags & AI_IRRMESH_MAT_trans_vertex_alpha && !useColors) {
@ -492,7 +492,7 @@ void IRRMeshImporter::InternReadFile( const std::string& pFile,
// End of the last buffer. A material and a mesh should be there // End of the last buffer. A material and a mesh should be there
if (curMat || curMesh) { if (curMat || curMesh) {
if ( !curMat || !curMesh) { if ( !curMat || !curMesh) {
DefaultLogger::get()->error("IRRMESH: A buffer must contain a mesh and a material"); ASSIMP_LOG_ERROR("IRRMESH: A buffer must contain a mesh and a material");
releaseMaterial( &curMat ); releaseMaterial( &curMat );
releaseMesh( &curMesh ); releaseMesh( &curMesh );
} }

View File

@ -179,14 +179,14 @@ void IrrlichtBase::ReadVectorProperty (VectorProperty& out)
SkipSpaces(&ptr); SkipSpaces(&ptr);
if (',' != *ptr) if (',' != *ptr)
{ {
DefaultLogger::get()->error("IRR(MESH): Expected comma in vector definition"); ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
} }
else SkipSpaces(ptr+1,&ptr); else SkipSpaces(ptr+1,&ptr);
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.y ); ptr = fast_atoreal_move<float>( ptr,(float&)out.value.y );
SkipSpaces(&ptr); SkipSpaces(&ptr);
if (',' != *ptr) if (',' != *ptr)
{ {
DefaultLogger::get()->error("IRR(MESH): Expected comma in vector definition"); ASSIMP_LOG_ERROR("IRR(MESH): Expected comma in vector definition");
} }
else SkipSpaces(ptr+1,&ptr); else SkipSpaces(ptr+1,&ptr);
ptr = fast_atoreal_move<float>( ptr,(float&)out.value.z ); ptr = fast_atoreal_move<float>( ptr,(float&)out.value.z );
@ -360,7 +360,7 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags)
matFlags = AI_IRRMESH_MAT_normalmap_ta; matFlags = AI_IRRMESH_MAT_normalmap_ta;
} }
else { else {
DefaultLogger::get()->warn("IRRMat: Unrecognized material type: " + prop.value); ASSIMP_LOG_WARN("IRRMat: Unrecognized material type: " + prop.value);
} }
} }
@ -391,9 +391,7 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags)
// set the corresponding material flag // set the corresponding material flag
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE; matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
} } else if (matFlags & AI_IRRMESH_MAT_solid_2layer) {// or just as second diffuse texture
// or just as second diffuse texture
else if (matFlags & AI_IRRMESH_MAT_solid_2layer) {
++cnt; ++cnt;
s.Set(prop.value); s.Set(prop.value);
mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(1)); mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(1));
@ -401,19 +399,15 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags)
// set the corresponding material flag // set the corresponding material flag
matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE; matFlags |= AI_IRRMESH_EXTRA_2ND_TEXTURE;
} else {
ASSIMP_LOG_WARN("IRRmat: Skipping second texture");
} }
else DefaultLogger::get()->warn("IRRmat: Skipping second texture"); } else if (prop.name == "Texture3" && cnt == 2) {
}
else if (prop.name == "Texture3" && cnt == 2)
{
// Irrlicht does not seem to use these channels. // Irrlicht does not seem to use these channels.
++cnt; ++cnt;
s.Set(prop.value); s.Set(prop.value);
mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(nd+1)); mat->AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(nd+1));
} } else if (prop.name == "Texture4" && cnt == 3) {
else if (prop.name == "Texture4" && cnt == 3)
{
// Irrlicht does not seem to use these channels. // Irrlicht does not seem to use these channels.
++cnt; ++cnt;
s.Set(prop.value); s.Set(prop.value);
@ -499,7 +493,8 @@ aiMaterial* IrrlichtBase::ParseMaterial(unsigned int& matFlags)
break; break;
} }
} }
DefaultLogger::get()->error("IRRMESH: Unexpected end of file. Material is not complete"); ASSIMP_LOG_ERROR("IRRMESH: Unexpected end of file. Material is not complete");
return mat; return mat;
} }

View File

@ -91,7 +91,7 @@ protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Read a property of the specified type from the current XML element. /** Read a property of the specified type from the current XML element.
* @param out Recives output data * @param out Receives output data
*/ */
void ReadHexProperty (HexProperty& out); void ReadHexProperty (HexProperty& out);
void ReadStringProperty (StringProperty& out); void ReadStringProperty (StringProperty& out);

View File

@ -147,10 +147,7 @@ void AllocateFromAssimpHeap::operator delete[] ( void* data) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Importer constructor. // Importer constructor.
Importer::Importer() Importer::Importer()
: pimpl( NULL ) { : pimpl( new ImporterPimpl ) {
// allocate the pimpl first
pimpl = new ImporterPimpl();
pimpl->mScene = NULL; pimpl->mScene = NULL;
pimpl->mErrorString = ""; pimpl->mErrorString = "";
@ -190,7 +187,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 +197,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)
@ -220,7 +205,7 @@ aiReturn Importer::RegisterPPStep(BaseProcess* pImp)
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
pimpl->mPostProcessingSteps.push_back(pImp); pimpl->mPostProcessingSteps.push_back(pImp);
DefaultLogger::get()->info("Registering custom post-processing step"); ASSIMP_LOG_INFO("Registering custom post-processing step");
ASSIMP_END_EXCEPTION_REGION(aiReturn); ASSIMP_END_EXCEPTION_REGION(aiReturn);
return AI_SUCCESS; return AI_SUCCESS;
@ -247,7 +232,7 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp)
#ifdef ASSIMP_BUILD_DEBUG #ifdef ASSIMP_BUILD_DEBUG
if (IsExtensionSupported(*it)) { if (IsExtensionSupported(*it)) {
DefaultLogger::get()->warn("The file extension " + *it + " is already in use"); ASSIMP_LOG_WARN_F("The file extension ", *it, " is already in use");
} }
#endif #endif
baked += *it; baked += *it;
@ -255,7 +240,7 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp)
// add the loader // add the loader
pimpl->mImporter.push_back(pImp); pimpl->mImporter.push_back(pImp);
DefaultLogger::get()->info("Registering custom importer for these file extensions: " + baked); ASSIMP_LOG_INFO_F("Registering custom importer for these file extensions: ", baked);
ASSIMP_END_EXCEPTION_REGION(aiReturn); ASSIMP_END_EXCEPTION_REGION(aiReturn);
return AI_SUCCESS; return AI_SUCCESS;
} }
@ -275,10 +260,10 @@ aiReturn Importer::UnregisterLoader(BaseImporter* pImp)
if (it != pimpl->mImporter.end()) { if (it != pimpl->mImporter.end()) {
pimpl->mImporter.erase(it); pimpl->mImporter.erase(it);
DefaultLogger::get()->info("Unregistering custom importer: "); ASSIMP_LOG_INFO("Unregistering custom importer: ");
return AI_SUCCESS; return AI_SUCCESS;
} }
DefaultLogger::get()->warn("Unable to remove custom importer: I can't find you ..."); ASSIMP_LOG_WARN("Unable to remove custom importer: I can't find you ...");
ASSIMP_END_EXCEPTION_REGION(aiReturn); ASSIMP_END_EXCEPTION_REGION(aiReturn);
return AI_FAILURE; return AI_FAILURE;
} }
@ -298,10 +283,10 @@ aiReturn Importer::UnregisterPPStep(BaseProcess* pImp)
if (it != pimpl->mPostProcessingSteps.end()) { if (it != pimpl->mPostProcessingSteps.end()) {
pimpl->mPostProcessingSteps.erase(it); pimpl->mPostProcessingSteps.erase(it);
DefaultLogger::get()->info("Unregistering custom post-processing step"); ASSIMP_LOG_INFO("Unregistering custom post-processing step");
return AI_SUCCESS; return AI_SUCCESS;
} }
DefaultLogger::get()->warn("Unable to remove custom post-processing step: I can't find you .."); ASSIMP_LOG_WARN("Unable to remove custom post-processing step: I can't find you ..");
ASSIMP_END_EXCEPTION_REGION(aiReturn); ASSIMP_END_EXCEPTION_REGION(aiReturn);
return AI_FAILURE; return AI_FAILURE;
} }
@ -383,11 +368,11 @@ bool Importer::IsDefaultProgressHandler() const
bool _ValidateFlags(unsigned int pFlags) bool _ValidateFlags(unsigned int pFlags)
{ {
if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals) { if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals) {
DefaultLogger::get()->error("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible"); ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible");
return false; return false;
} }
if (pFlags & aiProcess_OptimizeGraph && pFlags & aiProcess_PreTransformVertices) { if (pFlags & aiProcess_OptimizeGraph && pFlags & aiProcess_PreTransformVertices) {
DefaultLogger::get()->error("#aiProcess_OptimizeGraph and #aiProcess_PreTransformVertices are incompatible"); ASSIMP_LOG_ERROR("#aiProcess_OptimizeGraph and #aiProcess_PreTransformVertices are incompatible");
return false; return false;
} }
return true; return true;
@ -519,26 +504,15 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void WriteLogOpening(const std::string& file) void WriteLogOpening(const std::string& file)
{ {
Logger* l = DefaultLogger::get(); ASSIMP_LOG_INFO_F("Load ", file);
if (!l) {
return;
}
l->info("Load " + file);
// print a full version dump. This is nice because we don't // print a full version dump. This is nice because we don't
// need to ask the authors of incoming bug reports for // need to ask the authors of incoming bug reports for
// the library version they're using - a log dump is // the library version they're using - a log dump is
// sufficient. // sufficient.
const unsigned int flags = aiGetCompileFlags(); const unsigned int flags( aiGetCompileFlags() );
l->debug(format() std::stringstream stream;
<< "Assimp " stream << "Assimp " << aiGetVersionMajor() << "." << aiGetVersionMinor() << "." << aiGetVersionRevision() << " "
<< aiGetVersionMajor()
<< "."
<< aiGetVersionMinor()
<< "."
<< aiGetVersionRevision()
<< " "
#if defined(ASSIMP_BUILD_ARCHITECTURE) #if defined(ASSIMP_BUILD_ARCHITECTURE)
<< ASSIMP_BUILD_ARCHITECTURE << ASSIMP_BUILD_ARCHITECTURE
#elif defined(_M_IX86) || defined(__x86_32__) || defined(__i386__) #elif defined(_M_IX86) || defined(__x86_32__) || defined(__i386__)
@ -554,12 +528,11 @@ void WriteLogOpening(const std::string& file)
#elif defined(__arm__) #elif defined(__arm__)
<< "arm" << "arm"
#else #else
<< "<unknown architecture>" << "<unknown architecture>"
#endif #endif
<< " " << " "
#if defined(ASSIMP_BUILD_COMPILER) #if defined(ASSIMP_BUILD_COMPILER)
<< ASSIMP_BUILD_COMPILER << ( ASSIMP_BUILD_COMPILER )
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
<< "msvc" << "msvc"
#elif defined(__GNUC__) #elif defined(__GNUC__)
@ -574,8 +547,9 @@ void WriteLogOpening(const std::string& file)
<< (flags & ASSIMP_CFLAGS_NOBOOST ? " noboost" : "") << (flags & ASSIMP_CFLAGS_NOBOOST ? " noboost" : "")
<< (flags & ASSIMP_CFLAGS_SHARED ? " shared" : "") << (flags & ASSIMP_CFLAGS_SHARED ? " shared" : "")
<< (flags & ASSIMP_CFLAGS_SINGLETHREADED ? " singlethreaded" : "") << (flags & ASSIMP_CFLAGS_SINGLETHREADED ? " singlethreaded" : "");
);
ASSIMP_LOG_DEBUG(stream.str());
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -601,7 +575,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
// a scene. In this case we need to delete the old one // a scene. In this case we need to delete the old one
if (pimpl->mScene) { if (pimpl->mScene) {
DefaultLogger::get()->debug("(Deleting previous scene)"); ASSIMP_LOG_DEBUG("(Deleting previous scene)");
FreeScene(); FreeScene();
} }
@ -609,7 +583,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
if( !pimpl->mIOHandler->Exists( pFile)) { if( !pimpl->mIOHandler->Exists( pFile)) {
pimpl->mErrorString = "Unable to open file \"" + pFile + "\"."; pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
DefaultLogger::get()->error(pimpl->mErrorString); ASSIMP_LOG_ERROR(pimpl->mErrorString);
return NULL; return NULL;
} }
@ -632,9 +606,8 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
// not so bad yet ... try format auto detection. // not so bad yet ... try format auto detection.
const std::string::size_type s = pFile.find_last_of('.'); const std::string::size_type s = pFile.find_last_of('.');
if (s != std::string::npos) { if (s != std::string::npos) {
DefaultLogger::get()->info("File extension not known, trying signature-based detection"); ASSIMP_LOG_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;
@ -644,7 +617,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
// Put a proper error message if no suitable importer was found // Put a proper error message if no suitable importer was found
if( !imp) { if( !imp) {
pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\"."; pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
DefaultLogger::get()->error(pimpl->mErrorString); ASSIMP_LOG_ERROR(pimpl->mErrorString);
return NULL; return NULL;
} }
} }
@ -664,7 +637,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
if ( NULL != desc ) { if ( NULL != desc ) {
ext = desc->mName; ext = desc->mName;
} }
DefaultLogger::get()->info("Found a matching importer for this file format: " + ext + "." ); ASSIMP_LOG_INFO("Found a matching importer for this file format: " + ext + "." );
pimpl->mProgressHandler->UpdateFileRead( 0, fileSize ); pimpl->mProgressHandler->UpdateFileRead( 0, fileSize );
if (profiler) { if (profiler) {
@ -732,7 +705,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
pimpl->mErrorString = std::string("std::exception: ") + e.what(); pimpl->mErrorString = std::string("std::exception: ") + e.what();
#endif #endif
DefaultLogger::get()->error(pimpl->mErrorString); ASSIMP_LOG_ERROR(pimpl->mErrorString);
delete pimpl->mScene; pimpl->mScene = NULL; delete pimpl->mScene; pimpl->mScene = NULL;
} }
#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS #endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
@ -760,7 +733,7 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
// In debug builds: run basic flag validation // In debug builds: run basic flag validation
ai_assert(_ValidateFlags(pFlags)); ai_assert(_ValidateFlags(pFlags));
DefaultLogger::get()->info("Entering post processing pipeline"); ASSIMP_LOG_INFO("Entering post processing pipeline");
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
// The ValidateDS process plays an exceptional role. It isn't contained in the global // The ValidateDS process plays an exceptional role. It isn't contained in the global
@ -778,13 +751,13 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
if (pimpl->bExtraVerbose) if (pimpl->bExtraVerbose)
{ {
#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS #ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
DefaultLogger::get()->error("Verbose Import is not available due to build settings"); ASSIMP_LOG_ERROR("Verbose Import is not available due to build settings");
#endif // no validation #endif // no validation
pFlags |= aiProcess_ValidateDataStructure; pFlags |= aiProcess_ValidateDataStructure;
} }
#else #else
if (pimpl->bExtraVerbose) { if (pimpl->bExtraVerbose) {
DefaultLogger::get()->warn("Not a debug build, ignoring extra verbose setting"); ASSIMP_LOG_WARN("Not a debug build, ignoring extra verbose setting");
} }
#endif // ! DEBUG #endif // ! DEBUG
@ -816,18 +789,19 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
// If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step
if (pimpl->bExtraVerbose) { if (pimpl->bExtraVerbose) {
DefaultLogger::get()->debug("Verbose Import: revalidating data structures"); ASSIMP_LOG_DEBUG("Verbose Import: re-validating data structures");
ValidateDSProcess ds; ValidateDSProcess ds;
ds.ExecuteOnScene (this); ds.ExecuteOnScene (this);
if( !pimpl->mScene) { if( !pimpl->mScene) {
DefaultLogger::get()->error("Verbose Import: failed to revalidate data structures"); ASSIMP_LOG_ERROR("Verbose Import: failed to re-validate data structures");
break; break;
} }
} }
#endif // ! DEBUG #endif // ! DEBUG
} }
pimpl->mProgressHandler->UpdatePostProcess( static_cast<int>(pimpl->mPostProcessingSteps.size()), static_cast<int>(pimpl->mPostProcessingSteps.size()) ); pimpl->mProgressHandler->UpdatePostProcess( static_cast<int>(pimpl->mPostProcessingSteps.size()),
static_cast<int>(pimpl->mPostProcessingSteps.size()) );
// update private scene flags // update private scene flags
if( pimpl->mScene ) if( pimpl->mScene )
@ -835,7 +809,7 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
// clear any data allocated by post-process steps // clear any data allocated by post-process steps
pimpl->mPPShared->Clean(); pimpl->mPPShared->Clean();
DefaultLogger::get()->info("Leaving post processing pipeline"); ASSIMP_LOG_INFO("Leaving post processing pipeline");
ASSIMP_END_EXCEPTION_REGION(const aiScene*); ASSIMP_END_EXCEPTION_REGION(const aiScene*);
return pimpl->mScene; return pimpl->mScene;
@ -856,7 +830,7 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess
} }
// In debug builds: run basic flag validation // In debug builds: run basic flag validation
DefaultLogger::get()->info( "Entering customized post processing pipeline" ); ASSIMP_LOG_INFO( "Entering customized post processing pipeline" );
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
// The ValidateDS process plays an exceptional role. It isn't contained in the global // The ValidateDS process plays an exceptional role. It isn't contained in the global
@ -874,12 +848,12 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess
if ( pimpl->bExtraVerbose ) if ( pimpl->bExtraVerbose )
{ {
#ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS #ifdef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
DefaultLogger::get()->error( "Verbose Import is not available due to build settings" ); ASSIMP_LOG_ERROR( "Verbose Import is not available due to build settings" );
#endif // no validation #endif // no validation
} }
#else #else
if ( pimpl->bExtraVerbose ) { if ( pimpl->bExtraVerbose ) {
DefaultLogger::get()->warn( "Not a debug build, ignoring extra verbose setting" ); ASSIMP_LOG_WARN( "Not a debug build, ignoring extra verbose setting" );
} }
#endif // ! DEBUG #endif // ! DEBUG
@ -897,18 +871,18 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess
// If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step // If the extra verbose mode is active, execute the ValidateDataStructureStep again - after each step
if ( pimpl->bExtraVerbose || requestValidation ) { if ( pimpl->bExtraVerbose || requestValidation ) {
DefaultLogger::get()->debug( "Verbose Import: revalidating data structures" ); ASSIMP_LOG_DEBUG( "Verbose Import: revalidating data structures" );
ValidateDSProcess ds; ValidateDSProcess ds;
ds.ExecuteOnScene( this ); ds.ExecuteOnScene( this );
if ( !pimpl->mScene ) { if ( !pimpl->mScene ) {
DefaultLogger::get()->error( "Verbose Import: failed to revalidate data structures" ); ASSIMP_LOG_ERROR( "Verbose Import: failed to revalidate data structures" );
} }
} }
// clear any data allocated by post-process steps // clear any data allocated by post-process steps
pimpl->mPPShared->Clean(); pimpl->mPPShared->Clean();
DefaultLogger::get()->info( "Leaving customized post processing pipeline" ); ASSIMP_LOG_INFO( "Leaving customized post processing pipeline" );
ASSIMP_END_EXCEPTION_REGION( const aiScene* ); ASSIMP_END_EXCEPTION_REGION( const aiScene* );
@ -919,7 +893,7 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess
// Helper function to check whether an extension is supported by ASSIMP // Helper function to check whether an extension is supported by ASSIMP
bool Importer::IsExtensionSupported(const char* szExtension) const bool Importer::IsExtensionSupported(const char* szExtension) const
{ {
return NULL != GetImporter(szExtension); return nullptr != GetImporter(szExtension);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -959,6 +933,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 --
@ -995,15 +970,18 @@ void Importer::GetExtensionList(aiString& szOut) const
(*i)->GetExtensionList(str); (*i)->GetExtensionList(str);
} }
for (std::set<std::string>::const_iterator it = str.begin();; ) { // List can be empty
szOut.Append("*."); if( !str.empty() ) {
szOut.Append((*it).c_str()); for (std::set<std::string>::const_iterator it = str.begin();; ) {
szOut.Append("*.");
szOut.Append((*it).c_str());
if (++it == str.end()) { if (++it == str.end()) {
break; break;
} }
szOut.Append(";"); szOut.Append(";");
} }
}
ASSIMP_END_EXCEPTION_REGION(void); ASSIMP_END_EXCEPTION_REGION(void);
} }
@ -1022,33 +1000,33 @@ bool Importer::SetPropertyInteger(const char* szName, int iValue)
// Set a configuration property // Set a configuration property
bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) bool Importer::SetPropertyFloat(const char* szName, ai_real iValue)
{ {
bool exising; bool existing;
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
exising = SetGenericProperty<ai_real>(pimpl->mFloatProperties, szName,iValue); existing = SetGenericProperty<ai_real>(pimpl->mFloatProperties, szName,iValue);
ASSIMP_END_EXCEPTION_REGION(bool); ASSIMP_END_EXCEPTION_REGION(bool);
return exising; return existing;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Set a configuration property // Set a configuration property
bool Importer::SetPropertyString(const char* szName, const std::string& value) bool Importer::SetPropertyString(const char* szName, const std::string& value)
{ {
bool exising; bool existing;
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
exising = SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value); existing = SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value);
ASSIMP_END_EXCEPTION_REGION(bool); ASSIMP_END_EXCEPTION_REGION(bool);
return exising; return existing;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Set a configuration property // Set a configuration property
bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value)
{ {
bool exising; bool existing;
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
exising = SetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties, szName,value); existing = SetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties, szName,value);
ASSIMP_END_EXCEPTION_REGION(bool); ASSIMP_END_EXCEPTION_REGION(bool);
return exising; return existing;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -68,10 +68,8 @@ namespace Assimp {
* std::vector and std::map in the public headers. Furthermore we are dropping * std::vector and std::map in the public headers. Furthermore we are dropping
* any STL interface problems caused by mismatching STL settings. All * any STL interface problems caused by mismatching STL settings. All
* size calculation are now done by us, not the app heap. */ * size calculation are now done by us, not the app heap. */
class ImporterPimpl class ImporterPimpl {
{
public: public:
// Data type to store the key hash // Data type to store the key hash
typedef unsigned int KeyType; typedef unsigned int KeyType;
@ -82,8 +80,6 @@ public:
typedef std::map<KeyType, std::string> StringPropertyMap; typedef std::map<KeyType, std::string> StringPropertyMap;
typedef std::map<KeyType, aiMatrix4x4> MatrixPropertyMap; typedef std::map<KeyType, aiMatrix4x4> MatrixPropertyMap;
public:
/** IO handler to use for all file accesses. */ /** IO handler to use for all file accesses. */
IOSystem* mIOHandler; IOSystem* mIOHandler;
bool mIsDefaultHandler; bool mIsDefaultHandler;
@ -117,12 +113,34 @@ public:
MatrixPropertyMap mMatrixProperties; MatrixPropertyMap mMatrixProperties;
/** Used for testing - extra verbose mode causes the ValidateDataStructure-Step /** Used for testing - extra verbose mode causes the ValidateDataStructure-Step
* to be executed before and after every single postprocess step */ * to be executed before and after every single post-process step */
bool bExtraVerbose; bool bExtraVerbose;
/** Used by post-process steps to share data */ /** Used by post-process steps to share data */
SharedPostProcessInfo* mPPShared; SharedPostProcessInfo* mPPShared;
/// The default class constructor.
ImporterPimpl();
}; };
inline
ImporterPimpl::ImporterPimpl()
: mIOHandler( nullptr )
, mIsDefaultHandler( false )
, mProgressHandler( nullptr )
, mIsDefaultProgressHandler( false )
, mImporter()
, mPostProcessingSteps()
, mScene( nullptr )
, mErrorString()
, mIntProperties()
, mFloatProperties()
, mStringProperties()
, mMatrixProperties()
, bExtraVerbose( false )
, mPPShared( nullptr ) {
// empty
}
//! @endcond //! @endcond

View File

@ -728,7 +728,7 @@ void ProcessSweptAreaSolid(const Schema_2x3::IfcSweptAreaSolid& swept, TempMesh&
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool ProcessGeometricItem(const Schema_2x3::IfcRepresentationItem& geo, unsigned int matid, std::vector<unsigned int>& mesh_indices, bool ProcessGeometricItem(const Schema_2x3::IfcRepresentationItem& geo, unsigned int matid, std::set<unsigned int>& mesh_indices,
ConversionData& conv) ConversionData& conv)
{ {
bool fix_orientation = false; bool fix_orientation = false;
@ -810,7 +810,7 @@ bool ProcessGeometricItem(const Schema_2x3::IfcRepresentationItem& geo, unsigned
aiMesh* const mesh = meshtmp->ToMesh(); aiMesh* const mesh = meshtmp->ToMesh();
if(mesh) { if(mesh) {
mesh->mMaterialIndex = matid; mesh->mMaterialIndex = matid;
mesh_indices.push_back(static_cast<unsigned int>(conv.meshes.size())); mesh_indices.insert(static_cast<unsigned int>(conv.meshes.size()));
conv.meshes.push_back(mesh); conv.meshes.push_back(mesh);
return true; return true;
} }
@ -818,33 +818,31 @@ bool ProcessGeometricItem(const Schema_2x3::IfcRepresentationItem& geo, unsigned
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void AssignAddedMeshes(std::vector<unsigned int>& mesh_indices,aiNode* nd, void AssignAddedMeshes(std::set<unsigned int>& mesh_indices,aiNode* nd,
ConversionData& /*conv*/) ConversionData& /*conv*/)
{ {
if (!mesh_indices.empty()) { if (!mesh_indices.empty()) {
std::set<unsigned int>::const_iterator it = mesh_indices.cbegin();
std::set<unsigned int>::const_iterator end = mesh_indices.cend();
// make unique nd->mNumMeshes = static_cast<unsigned int>(mesh_indices.size());
std::sort(mesh_indices.begin(),mesh_indices.end());
std::vector<unsigned int>::iterator it_end = std::unique(mesh_indices.begin(),mesh_indices.end());
nd->mNumMeshes = static_cast<unsigned int>(std::distance(mesh_indices.begin(),it_end));
nd->mMeshes = new unsigned int[nd->mNumMeshes]; nd->mMeshes = new unsigned int[nd->mNumMeshes];
for(unsigned int i = 0; i < nd->mNumMeshes; ++i) { for(unsigned int i = 0; it != end && i < nd->mNumMeshes; ++i, ++it) {
nd->mMeshes[i] = mesh_indices[i]; nd->mMeshes[i] = *it;
} }
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool TryQueryMeshCache(const Schema_2x3::IfcRepresentationItem& item, bool TryQueryMeshCache(const Schema_2x3::IfcRepresentationItem& item,
std::vector<unsigned int>& mesh_indices, unsigned int mat_index, std::set<unsigned int>& mesh_indices, unsigned int mat_index,
ConversionData& conv) ConversionData& conv)
{ {
ConversionData::MeshCacheIndex idx(&item, mat_index); ConversionData::MeshCacheIndex idx(&item, mat_index);
ConversionData::MeshCache::const_iterator it = conv.cached_meshes.find(idx); ConversionData::MeshCache::const_iterator it = conv.cached_meshes.find(idx);
if (it != conv.cached_meshes.end()) { if (it != conv.cached_meshes.end()) {
std::copy((*it).second.begin(),(*it).second.end(),std::back_inserter(mesh_indices)); std::copy((*it).second.begin(),(*it).second.end(),std::inserter(mesh_indices, mesh_indices.end()));
return true; return true;
} }
return false; return false;
@ -852,7 +850,7 @@ bool TryQueryMeshCache(const Schema_2x3::IfcRepresentationItem& item,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void PopulateMeshCache(const Schema_2x3::IfcRepresentationItem& item, void PopulateMeshCache(const Schema_2x3::IfcRepresentationItem& item,
const std::vector<unsigned int>& mesh_indices, unsigned int mat_index, const std::set<unsigned int>& mesh_indices, unsigned int mat_index,
ConversionData& conv) ConversionData& conv)
{ {
ConversionData::MeshCacheIndex idx(&item, mat_index); ConversionData::MeshCacheIndex idx(&item, mat_index);
@ -861,7 +859,7 @@ void PopulateMeshCache(const Schema_2x3::IfcRepresentationItem& item,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool ProcessRepresentationItem(const Schema_2x3::IfcRepresentationItem& item, unsigned int matid, bool ProcessRepresentationItem(const Schema_2x3::IfcRepresentationItem& item, unsigned int matid,
std::vector<unsigned int>& mesh_indices, std::set<unsigned int>& mesh_indices,
ConversionData& conv) ConversionData& conv)
{ {
// determine material // determine material

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;
} }
@ -434,7 +435,7 @@ bool ProcessMappedItem(const Schema_2x3::IfcMappedItem& mapped, aiNode* nd_src,
msrc = m*msrc; msrc = m*msrc;
std::vector<unsigned int> meshes; std::set<unsigned int> meshes;
const size_t old_openings = conv.collect_openings ? conv.collect_openings->size() : 0; const size_t old_openings = conv.collect_openings ? conv.collect_openings->size() : 0;
if (conv.apply_openings) { if (conv.apply_openings) {
IfcMatrix4 minv = msrc; IfcMatrix4 minv = msrc;
@ -549,7 +550,7 @@ void ProcessProductRepresentation(const Schema_2x3::IfcProduct& el, aiNode* nd,
// extract Color from metadata, if present // extract Color from metadata, if present
unsigned int matid = ProcessMaterials( el.GetID(), std::numeric_limits<uint32_t>::max(), conv, false); unsigned int matid = ProcessMaterials( el.GetID(), std::numeric_limits<uint32_t>::max(), conv, false);
std::vector<unsigned int> meshes; std::set<unsigned int> meshes;
// we want only one representation type, so bring them in a suitable order (i.e try those // we want only one representation type, so bring them in a suitable order (i.e try those
// that look as if we could read them quickly at first). This way of reading // that look as if we could read them quickly at first). This way of reading
@ -582,9 +583,8 @@ typedef std::map<std::string, std::string> Metadata;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ProcessMetadata(const Schema_2x3::ListOf< Schema_2x3::Lazy< Schema_2x3::IfcProperty >, 1, 0 >& set, ConversionData& conv, Metadata& properties, void ProcessMetadata(const Schema_2x3::ListOf< Schema_2x3::Lazy< Schema_2x3::IfcProperty >, 1, 0 >& set, ConversionData& conv, Metadata& properties,
const std::string& prefix = "", const std::string& prefix = "",
unsigned int nest = 0) unsigned int nest = 0) {
{
for(const Schema_2x3::IfcProperty& property : set) { for(const Schema_2x3::IfcProperty& property : set) {
const std::string& key = prefix.length() > 0 ? (prefix + "." + property.Name) : property.Name; const std::string& key = prefix.length() > 0 ? (prefix + "." + property.Name) : property.Name;
if (const Schema_2x3::IfcPropertySingleValue* const singleValue = property.ToPtr<Schema_2x3::IfcPropertySingleValue>()) { if (const Schema_2x3::IfcPropertySingleValue* const singleValue = property.ToPtr<Schema_2x3::IfcPropertySingleValue>()) {

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