Merge pull request #16 from assimp/master

Update
pull/4057/head
Madrich 2019-11-25 14:09:26 +01:00 committed by GitHub
commit a413774e24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
271 changed files with 19728 additions and 9552 deletions

127
.clang-format 100644
View File

@ -0,0 +1,127 @@
# Commented out parameters are those with the same value as base LLVM style
# We can uncomment them if we want to change their value, or enforce the
# chosen value in case the base style changes (last sync: Clang 6.0.1).
---
### General config, applies to all languages ###
BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: DontAlign
# AlignConsecutiveAssignments: false
# AlignConsecutiveDeclarations: false
# AlignEscapedNewlines: Right
# AlignOperands: true
AlignTrailingComments: false
AllowAllParametersOfDeclarationOnNextLine: false
# AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Inline
AllowShortIfStatementsOnASingleLine: true
# AllowShortLoopsOnASingleLine: false
# AlwaysBreakAfterDefinitionReturnType: None
# AlwaysBreakAfterReturnType: None
# AlwaysBreakBeforeMultilineStrings: false
# AlwaysBreakTemplateDeclarations: false
# BinPackArguments: true
# BinPackParameters: true
# BraceWrapping:
# AfterClass: false
# AfterControlStatement: false
# AfterEnum: false
# AfterFunction: false
# AfterNamespace: false
# AfterObjCDeclaration: false
# AfterStruct: false
# AfterUnion: false
# AfterExternBlock: false
# BeforeCatch: false
# BeforeElse: false
# IndentBraces: false
# SplitEmptyFunction: true
# SplitEmptyRecord: true
# SplitEmptyNamespace: true
# BreakBeforeBinaryOperators: None
# BreakBeforeBraces: Attach
# BreakBeforeInheritanceComma: false
BreakBeforeTernaryOperators: false
# BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: AfterColon
# BreakStringLiterals: true
ColumnLimit: 0
# CommentPragmas: '^ IWYU pragma:'
# CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 8
ContinuationIndentWidth: 8
Cpp11BracedListStyle: false
# DerivePointerAlignment: false
# DisableFormat: false
# ExperimentalAutoDetectBinPacking: false
# FixNamespaceComments: true
# ForEachMacros:
# - foreach
# - Q_FOREACH
# - BOOST_FOREACH
# IncludeBlocks: Preserve
IncludeCategories:
- Regex: '".*"'
Priority: 1
- Regex: '^<.*\.h>'
Priority: 2
- Regex: '^<.*'
Priority: 3
# IncludeIsMainRegex: '(Test)?$'
IndentCaseLabels: true
# IndentPPDirectives: None
IndentWidth: 4
# IndentWrappedFunctionNames: false
# JavaScriptQuotes: Leave
# JavaScriptWrapImports: true
# KeepEmptyLinesAtTheStartOfBlocks: true
# MacroBlockBegin: ''
# MacroBlockEnd: ''
# MaxEmptyLinesToKeep: 1
# NamespaceIndentation: None
# PenaltyBreakAssignment: 2
# PenaltyBreakBeforeFirstCallParameter: 19
# PenaltyBreakComment: 300
# PenaltyBreakFirstLessLess: 120
# PenaltyBreakString: 1000
# PenaltyExcessCharacter: 1000000
# PenaltyReturnTypeOnItsOwnLine: 60
# PointerAlignment: Right
# RawStringFormats:
# - Delimiter: pb
# Language: TextProto
# BasedOnStyle: google
# ReflowComments: true
# SortIncludes: true
# SortUsingDeclarations: true
# SpaceAfterCStyleCast: false
# SpaceAfterTemplateKeyword: true
# SpaceBeforeAssignmentOperators: true
# SpaceBeforeParens: ControlStatements
# SpaceInEmptyParentheses: false
# SpacesBeforeTrailingComments: 1
# SpacesInAngles: false
# SpacesInContainerLiterals: true
# SpacesInCStyleCastParentheses: false
# SpacesInParentheses: false
# SpacesInSquareBrackets: false
TabWidth: 4
UseTab: Always
---
### C++ specific config ###
Language: Cpp
Standard: Cpp11
---
### ObjC specific config ###
Language: ObjC
Standard: Cpp11
ObjCBlockIndentWidth: 4
# ObjCSpaceAfterProperty: false
# ObjCSpaceBeforeProtocolList: true
---
### Java specific config ###
Language: Java
# BreakAfterJavaFieldAnnotations: false
...

2
.github/FUNDING.yml vendored 100644
View File

@ -0,0 +1,2 @@
patreon: assimp
ko_fi: kimkulling

5
.gitignore vendored
View File

@ -2,6 +2,11 @@
build build
.project .project
*.kdev4* *.kdev4*
.DS_Store
# build artefacts
*.o
*.a
# Visual Studio # Visual Studio
*.sln *.sln

View File

@ -7,6 +7,7 @@
# #
function generate() { function generate() {
OPTIONS="-DASSIMP_WERROR=ON" OPTIONS="-DASSIMP_WERROR=ON"
OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=NO"
if [ "$DISABLE_EXPORTERS" = "YES" ] ; then if [ "$DISABLE_EXPORTERS" = "YES" ] ; then
OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=YES" OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=YES"

View File

@ -0,0 +1,26 @@
:: This is an example file to generate binaries using Windows Operating System
:: This script is configured to be executed from the source directory
:: Compiled binaries will be placed in BINARIES_DIR\code\CONFIG
:: NOTE
:: The build process will generate a config.h file that is placed in BINARIES_DIR\include
:: This file must be merged with SOURCE_DIR\include
:: You should write yourself a script that copies the files where you want them.
:: Also see: https://github.com/assimp/assimp/pull/2646
SET SOURCE_DIR=.
:: For generators see "cmake --help"
SET GENERATOR=Visual Studio 15 2017
SET BINARIES_DIR="./BINARIES/Win32"
cmake CMakeLists.txt -G "%GENERATOR%" -S %SOURCE_DIR% -B %BINARIES_DIR%
cmake --build %BINARIES_DIR% --config release
SET BINARIES_DIR="./BINARIES/x64"
cmake CMakeLists.txt -G "%GENERATOR% Win64" -S %SOURCE_DIR% -B %BINARIES_DIR%
cmake --build %BINARIES_DIR% --config debug
cmake --build %BINARIES_DIR% --config release
PAUSE

View File

@ -1,17 +1,31 @@
# Build Instructions # Build Instructions
## Install CMake
## Build on all platforms using vcpkg
You can download and install assimp using the [vcpkg](https://github.com/Microsoft/vcpkg/) dependency manager:
```bash
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
vcpkg install assimp
```
The assimp port in vcpkg is kept up to date by Microsoft team members and community contributors. If the version is out of date, please [create an issue or pull request](https://github.com/Microsoft/vcpkg) on the vcpkg repository.
## Manual build instructions
### Install CMake
Asset-Importer-Lib can be build for a lot of different platforms. We are using cmake to generate the build environment for these via cmake. So you have to make sure that you have a working cmake-installation on your system. You can download it at https://cmake.org/ or for linux install it via Asset-Importer-Lib can be build for a lot of different platforms. We are using cmake to generate the build environment for these via cmake. So you have to make sure that you have a working cmake-installation on your system. You can download it at https://cmake.org/ or for linux install it via
```bash ```bash
sudo apt-get install cmake sudo apt-get install cmake
``` ```
## Get the source ### Get the source
Make sure you have a working git-installation. Open a command prompt and clone the Asset-Importer-Lib via: Make sure you have a working git-installation. Open a command prompt and clone the Asset-Importer-Lib via:
```bash ```bash
git clone https://github.com/assimp/assimp.git git clone https://github.com/assimp/assimp.git
``` ```
## Build instructions for Windows with Visual-Studio ### Build instructions for Windows with Visual-Studio
First you have to install Visual-Studio on your windows-system. You can get the Community-Version for free here: https://visualstudio.microsoft.com/de/downloads/ First you have to install Visual-Studio on your windows-system. You can get the Community-Version for free here: https://visualstudio.microsoft.com/de/downloads/
To generate the build environment for your IDE open a command prompt, navigate to your repo and type: To generate the build environment for your IDE open a command prompt, navigate to your repo and type:
@ -20,10 +34,10 @@ cmake CMakeLists.txt
``` ```
This will generate the project files for the visual studio. All dependencies used to build Asset-IMporter-Lib shall be part of the repo. If you want to use you own zlib.installation this is possible as well. Check the options for it. This will generate the project files for the visual studio. All dependencies used to build Asset-IMporter-Lib shall be part of the repo. If you want to use you own zlib.installation this is possible as well. Check the options for it.
## Build instructions for Windows with UWP ### Build instructions for Windows with UWP
See <https://stackoverflow.com/questions/40803170/cmake-uwp-using-cmake-to-build-universal-windows-app> See <https://stackoverflow.com/questions/40803170/cmake-uwp-using-cmake-to-build-universal-windows-app>
## Build instructions for Linux / Unix ### Build instructions for Linux / Unix
Open a terminal and got to your repository. You can generate the makefiles and build the library via: Open a terminal and got to your repository. You can generate the makefiles and build the library via:
```bash ```bash
@ -34,7 +48,7 @@ The option -j descripes the number of parallel processes for the build. In this
If you want to use a IDE for linux you can try QTCreator for instance. If you want to use a IDE for linux you can try QTCreator for instance.
## Build instructions for MinGW ### Build instructions for MinGW
Older versions of MinGW's compiler (e.g. 5.1.0) do not support the -mbig_obj flag Older versions of MinGW's compiler (e.g. 5.1.0) do not support the -mbig_obj flag
required to compile some of assimp's files, especially for debug builds. required to compile some of assimp's files, especially for debug builds.
Version 7.3.0 of g++-mingw-w64 & gcc-mingw-w64 appears to work. Version 7.3.0 of g++-mingw-w64 & gcc-mingw-w64 appears to work.
@ -50,7 +64,7 @@ The following toolchain may or may not be helpful for building assimp using MinG
Besides the toolchain, compilation should be the same as for Linux / Unix. Besides the toolchain, compilation should be the same as for Linux / Unix.
## CMake build options ### CMake build options
The cmake-build-environment provides options to configure the build. The following options can be used: The cmake-build-environment provides options to configure the build. The following options can be used:
- **BUILD_SHARED_LIBS ( default ON )**: Generation of shared libs ( dll for windows, so for Linux ). Set this to OFF to get a static lib. - **BUILD_SHARED_LIBS ( default ON )**: Generation of shared libs ( dll for windows, so for Linux ). Set this to OFF to get a static lib.
- **BUILD_FRAMEWORK ( default OFF, MacOnly)**: Build package as Mac OS X Framework bundle - **BUILD_FRAMEWORK ( default OFF, MacOnly)**: Build package as Mac OS X Framework bundle

View File

@ -173,7 +173,6 @@ SET (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VER
SET (ASSIMP_SOVERSION 5) SET (ASSIMP_SOVERSION 5)
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" )
if(NOT HUNTER_ENABLED) if(NOT HUNTER_ENABLED)
# Enable C++11 support globally # Enable C++11 support globally
set_property( GLOBAL PROPERTY CXX_STANDARD 11 ) set_property( GLOBAL PROPERTY CXX_STANDARD 11 )
@ -254,6 +253,7 @@ ELSEIF(MSVC)
IF(MSVC12) IF(MSVC12)
ADD_COMPILE_OPTIONS(/wd4351) ADD_COMPILE_OPTIONS(/wd4351)
ENDIF() ENDIF()
SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Ob2 /Zi")
ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
IF(NOT HUNTER_ENABLED) IF(NOT HUNTER_ENABLED)
SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}") SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")
@ -271,22 +271,20 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW )
SET(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") SET(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
ENDIF() ENDIF()
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -Wa,-mbig-obj ${CMAKE_CXX_FLAGS}") SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -Wa,-mbig-obj -O3 ${CMAKE_CXX_FLAGS}")
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}") SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
ADD_DEFINITIONS( -U__STRICT_ANSI__ ) ADD_DEFINITIONS( -U__STRICT_ANSI__ )
ENDIF() ENDIF()
IF ( IOS AND NOT HUNTER_ENABLED) IF ( IOS AND NOT HUNTER_ENABLED)
IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -Og") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -Og")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -Og") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -Og")
ELSE() ELSE()
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3") SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3") SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3")
# Experimental for pdb generation # Experimental for pdb generation
ENDIF() ENDIF()
ENDIF( IOS AND NOT HUNTER_ENABLED) ENDIF( IOS AND NOT HUNTER_ENABLED)
IF (ASSIMP_COVERALLS) IF (ASSIMP_COVERALLS)
@ -341,7 +339,7 @@ SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG) get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
IF (is_multi_config OR (CMAKE_BUILD_TYPE STREQUAL "Debug")) IF (INJECT_DEBUG_POSTFIX AND (is_multi_config OR CMAKE_BUILD_TYPE STREQUAL "Debug"))
SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfix for lib, samples and tools") SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfix for lib, samples and tools")
ELSE() ELSE()
SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Debug Postfix for lib, samples and tools") SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Debug Postfix for lib, samples and tools")
@ -393,6 +391,11 @@ IF(HUNTER_ENABLED)
) )
ELSE(HUNTER_ENABLED) ELSE(HUNTER_ENABLED)
# cmake configuration files # cmake configuration files
if(${BUILD_SHARED_LIBS})
set(BUILD_LIB_TYPE SHARED)
else()
set(BUILD_LIB_TYPE STATIC)
endif()
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE) CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE)
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE) CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE)
IF (is_multi_config) IF (is_multi_config)
@ -559,17 +562,15 @@ ENDIF(NOT HUNTER_ENABLED)
ADD_SUBDIRECTORY( code/ ) ADD_SUBDIRECTORY( code/ )
IF ( ASSIMP_BUILD_ASSIMP_TOOLS ) IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
# The viewer for windows only
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 )
# Te command line tool
ADD_SUBDIRECTORY( tools/assimp_cmd/ ) ADD_SUBDIRECTORY( tools/assimp_cmd/ )
IF (NOT IOS)
ADD_SUBDIRECTORY( tools/assimp_qt_viewer/ )
ENDIF (NOT IOS)
ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS ) ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS )
IF ( ASSIMP_BUILD_SAMPLES) IF ( ASSIMP_BUILD_SAMPLES)

View File

@ -60,13 +60,19 @@ __Importers__:
- ENFF - ENFF
- [FBX](https://en.wikipedia.org/wiki/FBX) - [FBX](https://en.wikipedia.org/wiki/FBX)
- [glTF 1.0](https://en.wikipedia.org/wiki/GlTF#glTF_1.0) + GLB - [glTF 1.0](https://en.wikipedia.org/wiki/GlTF#glTF_1.0) + GLB
- [glTF 2.0](https://en.wikipedia.org/wiki/GlTF#glTF_2.0) - [glTF 2.0](https://en.wikipedia.org/wiki/GlTF#glTF_2.0):
At the moment for glTF2.0 the following extensions are supported:
+ KHR_lights_punctual ( 5.0 )
+ KHR_materials_pbrSpecularGlossiness ( 5.0 )
+ KHR_materials_unlit ( 5.0 )
+ KHR_texture_transform ( 5.1 under test )
- HMB - HMB
- IFC-STEP - IFC-STEP
- IRR / IRRMESH - IRR / IRRMESH
- [LWO](https://en.wikipedia.org/wiki/LightWave_3D) - [LWO](https://en.wikipedia.org/wiki/LightWave_3D)
- LWS - LWS
- LXO - LXO
- [M3D](https://bztsrc.gitlab.io/model3d)
- MD2 - MD2
- MD3 - MD3
- MD5 - MD5
@ -120,7 +126,7 @@ __Exporters__:
- FBX ( experimental ) - FBX ( experimental )
### Building ### ### Building ###
Take a look into the https://github.com/assimp/assimp/blob/master/Build.md 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 https://github.com/assimp/assimp/blob/master/Build.md file. We are available in vcpkg, and our build system is CMake; if you used CMake before there is a good chance you know what to do.
### Ports ### ### Ports ###
* [Android](port/AndroidJNI/README.md) * [Android](port/AndroidJNI/README.md)

View File

@ -17,6 +17,8 @@ image:
- Visual Studio 2013 - Visual Studio 2013
- Visual Studio 2015 - Visual Studio 2015
- Visual Studio 2017 - Visual Studio 2017
- Visual Studio 2019
- MinGW
platform: platform:
- Win32 - Win32
@ -27,11 +29,15 @@ configuration: Release
install: install:
- set PATH=C:\Ruby24-x64\bin;%PATH% - set PATH=C:\Ruby24-x64\bin;%PATH%
- set CMAKE_DEFINES -DASSIMP_WERROR=ON - set CMAKE_DEFINES -DASSIMP_WERROR=ON
- if [%COMPILER%]==[MinGW] set PATH=C:\MinGW\bin;%PATH%
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2013" set CMAKE_GENERATOR_NAME=Visual Studio 12 2013 - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2013" set CMAKE_GENERATOR_NAME=Visual Studio 12 2013
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015 - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015
- 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 "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2019" set CMAKE_GENERATOR_NAME=Visual Studio 16 2019
- cmake %CMAKE_DEFINES% -G "%CMAKE_GENERATOR_NAME%" . - cmake %CMAKE_DEFINES% -G "%CMAKE_GENERATOR_NAME%" -A %platform% .
# Rename sh.exe as sh.exe in PATH interferes with MinGW - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015
- rename "C:\Program Files\Git\usr\bin\sh.exe" "sh2.exe"
- set PATH=%PATH%;"C:\\Program Files (x86)\\Inno Setup 5" - 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/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 - 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

View File

@ -35,6 +35,8 @@ if(MSVC)
endif() endif()
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" ) set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
file(TO_NATIVE_PATH ${_IMPORT_PREFIX} _IMPORT_PREFIX)
if(ASSIMP_BUILD_SHARED_LIBS) if(ASSIMP_BUILD_SHARED_LIBS)
set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@") set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@")
set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_IMPORT_LIBRARY_SUFFIX@") set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_IMPORT_LIBRARY_SUFFIX@")
@ -63,7 +65,14 @@ if(MSVC)
else() else()
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" ) set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" )
if(ASSIMP_BUILD_SHARED_LIBS) if(ASSIMP_BUILD_SHARED_LIBS)
if(WIN32)
# Handle MinGW compiler.
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
elseif(APPLE)
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@")
else()
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@") set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
endif()
set_target_properties(assimp::assimp PROPERTIES set_target_properties(assimp::assimp PROPERTIES
IMPORTED_SONAME_DEBUG "${sharedLibraryName}" IMPORTED_SONAME_DEBUG "${sharedLibraryName}"
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${sharedLibraryName}"

View File

@ -35,6 +35,8 @@ if(MSVC)
endif() endif()
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" ) set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" )
file(TO_NATIVE_PATH ${_IMPORT_PREFIX} _IMPORT_PREFIX)
if(ASSIMP_BUILD_SHARED_LIBS) if(ASSIMP_BUILD_SHARED_LIBS)
set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@") set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@")
set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_IMPORT_LIBRARY_SUFFIX@") set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_IMPORT_LIBRARY_SUFFIX@")
@ -63,9 +65,17 @@ if(MSVC)
else() else()
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" ) set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" )
if(ASSIMP_BUILD_SHARED_LIBS) if(ASSIMP_BUILD_SHARED_LIBS)
if(WIN32)
# Handle MinGW compiler.
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
elseif(APPLE)
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@")
else()
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@") set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
endif()
set_target_properties(assimp::assimp PROPERTIES set_target_properties(assimp::assimp PROPERTIES
IMPORTED_SONAME_RELEASE "${sharedLibraryName}" IMPORTED_SONAME_RELEASE "${sharedLibraryName}"
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${sharedLibraryName}"
) )
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )

View File

@ -5,6 +5,9 @@ if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5)
endif() endif()
cmake_policy(PUSH) cmake_policy(PUSH)
cmake_policy(VERSION 2.6) cmake_policy(VERSION 2.6)
# Required for the evaluation of "if(@BUILD_SHARED_LIBS@)" below to function
cmake_policy(SET CMP0012 NEW)
#---------------------------------------------------------------- #----------------------------------------------------------------
# Generated CMake target import file. # Generated CMake target import file.
#---------------------------------------------------------------- #----------------------------------------------------------------
@ -51,11 +54,7 @@ if(_IMPORT_PREFIX STREQUAL "/")
endif() endif()
# Create imported target assimp::assimp # Create imported target assimp::assimp
if(@BUILD_SHARED_LIBS@) add_library(assimp::assimp @BUILD_LIB_TYPE@ IMPORTED)
add_library(assimp::assimp SHARED IMPORTED)
else()
add_library(assimp::assimp STATIC IMPORTED)
endif()
set_target_properties(assimp::assimp PROPERTIES set_target_properties(assimp::assimp PROPERTIES
COMPATIBLE_INTERFACE_STRING "assimp_MAJOR_VERSION" COMPATIBLE_INTERFACE_STRING "assimp_MAJOR_VERSION"

View File

@ -54,14 +54,18 @@ else(WIN32)
find_path( find_path(
assimp_INCLUDE_DIRS assimp_INCLUDE_DIRS
NAMES postprocess.h scene.h version.h config.h cimport.h NAMES assimp/postprocess.h assimp/scene.h assimp/version.h assimp/config.h assimp/cimport.h
PATHS /usr/local/include/ PATHS /usr/local/include
PATHS /usr/include/
) )
find_library( find_library(
assimp_LIBRARIES assimp_LIBRARIES
NAMES assimp NAMES assimp
PATHS /usr/local/lib/ PATHS /usr/local/lib/
PATHS /usr/lib64/
PATHS /usr/lib/
) )
if (assimp_INCLUDE_DIRS AND assimp_LIBRARIES) if (assimp_INCLUDE_DIRS AND assimp_LIBRARIES)

View File

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

View File

@ -50,9 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER
// internal headers
#include "3DSLoader.h" #include "3DSLoader.h"
#include <assimp/Macros.h>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>

View File

@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <assimp/StringComparison.h> #include <assimp/StringComparison.h>
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <string> #include <string>
#include <vector> #include <vector>
@ -58,11 +59,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory> #include <memory>
#include "D3MFOpcPackage.h" #include "D3MFOpcPackage.h"
#ifdef ASSIMP_USE_HUNTER
# include <minizip/unzip.h>
#else
# include <unzip.h>
#endif
#include <assimp/irrXMLWrapper.h> #include <assimp/irrXMLWrapper.h>
#include "3MFXmlTags.h" #include "3MFXmlTags.h"
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
@ -453,7 +449,7 @@ bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bo
if ( nullptr == pIOHandler ) { if ( nullptr == pIOHandler ) {
return false; return false;
} }
if ( !D3MF::D3MFOpcPackage::isZipArchive( pIOHandler, filename ) ) { if ( !ZipArchiveIOSystem::isZipArchive( pIOHandler, filename ) ) {
return false; return false;
} }
D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename ); D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename );

View File

@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <cstdlib> #include <cstdlib>
#include <memory> #include <memory>
@ -56,344 +57,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <map> #include <map>
#include <algorithm> #include <algorithm>
#include <cassert> #include <cassert>
#ifdef ASSIMP_USE_HUNTER
# include <minizip/unzip.h>
#else
# include <unzip.h>
#endif
#include "3MFXmlTags.h" #include "3MFXmlTags.h"
namespace Assimp { namespace Assimp {
namespace D3MF { namespace D3MF {
class IOSystem2Unzip {
public:
static voidpf open(voidpf opaque, const char* filename, int mode);
static uLong read(voidpf opaque, voidpf stream, void* buf, uLong size);
static uLong write(voidpf opaque, voidpf stream, const void* buf, uLong size);
static long tell(voidpf opaque, voidpf stream);
static long seek(voidpf opaque, voidpf stream, uLong offset, int origin);
static int close(voidpf opaque, voidpf stream);
static int testerror(voidpf opaque, voidpf stream);
static zlib_filefunc_def get(IOSystem* pIOHandler);
};
voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) {
IOSystem* io_system = reinterpret_cast<IOSystem*>(opaque);
const char* mode_fopen = NULL;
if((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) {
mode_fopen = "rb";
} else {
if(mode & ZLIB_FILEFUNC_MODE_EXISTING) {
mode_fopen = "r+b";
} else {
if(mode & ZLIB_FILEFUNC_MODE_CREATE) {
mode_fopen = "wb";
}
}
}
return (voidpf) io_system->Open(filename, mode_fopen);
}
uLong IOSystem2Unzip::read(voidpf /*opaque*/, voidpf stream, void* buf, uLong size) {
IOStream* io_stream = (IOStream*) stream;
return static_cast<uLong>(io_stream->Read(buf, 1, size));
}
uLong IOSystem2Unzip::write(voidpf /*opaque*/, voidpf stream, const void* buf, uLong size) {
IOStream* io_stream = (IOStream*) stream;
return static_cast<uLong>(io_stream->Write(buf, 1, size));
}
long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) {
IOStream* io_stream = (IOStream*) stream;
return static_cast<long>(io_stream->Tell());
}
long IOSystem2Unzip::seek(voidpf /*opaque*/, voidpf stream, uLong offset, int origin) {
IOStream* io_stream = (IOStream*) stream;
aiOrigin assimp_origin;
switch (origin) {
default:
case ZLIB_FILEFUNC_SEEK_CUR:
assimp_origin = aiOrigin_CUR;
break;
case ZLIB_FILEFUNC_SEEK_END:
assimp_origin = aiOrigin_END;
break;
case ZLIB_FILEFUNC_SEEK_SET:
assimp_origin = aiOrigin_SET;
break;
}
return (io_stream->Seek(offset, assimp_origin) == aiReturn_SUCCESS ? 0 : -1);
}
int IOSystem2Unzip::close(voidpf opaque, voidpf stream) {
IOSystem* io_system = (IOSystem*) opaque;
IOStream* io_stream = (IOStream*) stream;
io_system->Close(io_stream);
return 0;
}
int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) {
return 0;
}
zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) {
zlib_filefunc_def mapping;
#ifdef ASSIMP_USE_HUNTER
mapping.zopen_file = (open_file_func)open;
mapping.zread_file = (read_file_func)read;
mapping.zwrite_file = (write_file_func)write;
mapping.ztell_file = (tell_file_func)tell;
mapping.zseek_file = (seek_file_func)seek;
mapping.zclose_file = (close_file_func)close;
mapping.zerror_file = (error_file_func)testerror;
#else
mapping.zopen_file = open;
mapping.zread_file = read;
mapping.zwrite_file = write;
mapping.ztell_file = tell;
mapping.zseek_file = seek;
mapping.zclose_file = close;
mapping.zerror_file = testerror;
#endif
mapping.opaque = reinterpret_cast<voidpf>(pIOHandler);
return mapping;
}
class ZipFile : public IOStream {
friend class D3MFZipArchive;
public:
explicit ZipFile(size_t size);
virtual ~ZipFile();
size_t Read(void* pvBuffer, size_t pSize, size_t pCount );
size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/);
size_t FileSize() const;
aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/);
size_t Tell() const;
void Flush();
private:
void *m_Buffer;
size_t m_Size;
};
ZipFile::ZipFile(size_t size)
: m_Buffer( nullptr )
, m_Size(size) {
ai_assert(m_Size != 0);
m_Buffer = ::malloc(m_Size);
}
ZipFile::~ZipFile() {
::free(m_Buffer);
m_Buffer = NULL;
}
size_t ZipFile::Read(void* pvBuffer, size_t pSize, size_t pCount) {
const size_t size = pSize * pCount;
ai_assert(size <= m_Size);
std::memcpy(pvBuffer, m_Buffer, size);
return size;
}
size_t ZipFile::Write(const void* pvBuffer, size_t size, size_t pCount ) {
const size_t size_to_write( size * pCount );
if ( 0 == size_to_write ) {
return 0U;
}
return 0U;
}
size_t ZipFile::FileSize() const {
return m_Size;
}
aiReturn ZipFile::Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) {
return aiReturn_FAILURE;
}
size_t ZipFile::Tell() const {
return 0;
}
void ZipFile::Flush() {
// empty
}
class D3MFZipArchive : public IOSystem {
public:
static const unsigned int FileNameSize = 256;
D3MFZipArchive(IOSystem* pIOHandler, const std::string & rFile);
~D3MFZipArchive();
bool Exists(const char* pFile) const;
char getOsSeparator() const;
IOStream* Open(const char* pFile, const char* pMode = "rb");
void Close(IOStream* pFile);
bool isOpen() const;
void getFileList(std::vector<std::string> &rFileList);
private:
bool mapArchive();
private:
unzFile m_ZipFileHandle;
std::map<std::string, ZipFile*> m_ArchiveMap;
};
// ------------------------------------------------------------------------------------------------
// Constructor.
D3MFZipArchive::D3MFZipArchive(IOSystem* pIOHandler, const std::string& rFile)
: m_ZipFileHandle( nullptr )
, m_ArchiveMap() {
if (! rFile.empty()) {
zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);
m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping);
if(m_ZipFileHandle != nullptr ) {
mapArchive();
}
}
}
// ------------------------------------------------------------------------------------------------
// Destructor.
D3MFZipArchive::~D3MFZipArchive() {
for(auto &file : m_ArchiveMap) {
delete file.second;
}
m_ArchiveMap.clear();
if(m_ZipFileHandle != nullptr) {
unzClose(m_ZipFileHandle);
m_ZipFileHandle = nullptr;
}
}
// ------------------------------------------------------------------------------------------------
// Returns true, if the archive is already open.
bool D3MFZipArchive::isOpen() const {
return (m_ZipFileHandle != nullptr );
}
// ------------------------------------------------------------------------------------------------
// Returns true, if the filename is part of the archive.
bool D3MFZipArchive::Exists(const char* pFile) const {
ai_assert(pFile != nullptr );
if ( pFile == nullptr ) {
return false;
}
std::string filename(pFile);
std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(filename);
bool exist( false );
if(it != m_ArchiveMap.end()) {
exist = true;
}
return exist;
}
// ------------------------------------------------------------------------------------------------
// Returns the separator delimiter.
char D3MFZipArchive::getOsSeparator() const {
#ifndef _WIN32
return '/';
#else
return '\\';
#endif
}
// ------------------------------------------------------------------------------------------------
// Opens a file, which is part of the archive.
IOStream *D3MFZipArchive::Open(const char* pFile, const char* /*pMode*/) {
ai_assert(pFile != NULL);
IOStream* result = NULL;
std::map<std::string, ZipFile*>::iterator it = m_ArchiveMap.find(pFile);
if(it != m_ArchiveMap.end()) {
result = static_cast<IOStream*>(it->second);
}
return result;
}
// ------------------------------------------------------------------------------------------------
// Close a filestream.
void D3MFZipArchive::Close(IOStream *pFile) {
(void)(pFile);
ai_assert(pFile != NULL);
// We don't do anything in case the file would be opened again in the future
}
// ------------------------------------------------------------------------------------------------
// Returns the file-list of the archive.
void D3MFZipArchive::getFileList(std::vector<std::string> &rFileList) {
rFileList.clear();
for(const auto &file : m_ArchiveMap) {
rFileList.push_back(file.first);
}
}
// ------------------------------------------------------------------------------------------------
// Maps the archive content.
bool D3MFZipArchive::mapArchive() {
bool success = false;
if(m_ZipFileHandle != NULL) {
if(m_ArchiveMap.empty()) {
// At first ensure file is already open
if(unzGoToFirstFile(m_ZipFileHandle) == UNZ_OK) {
// Loop over all files
do {
char filename[FileNameSize];
unz_file_info fileInfo;
if(unzGetCurrentFileInfo(m_ZipFileHandle, &fileInfo, filename, FileNameSize, NULL, 0, NULL, 0) == UNZ_OK) {
// The file has EXACTLY the size of uncompressed_size. In C
// you need to mark the last character with '\0', so add
// another character
if(fileInfo.uncompressed_size != 0 && unzOpenCurrentFile(m_ZipFileHandle) == UNZ_OK) {
std::pair<std::map<std::string, ZipFile*>::iterator, bool> result = m_ArchiveMap.insert(std::make_pair(filename, new ZipFile(fileInfo.uncompressed_size)));
if(unzReadCurrentFile(m_ZipFileHandle, result.first->second->m_Buffer, fileInfo.uncompressed_size) == (long int) fileInfo.uncompressed_size) {
if(unzCloseCurrentFile(m_ZipFileHandle) == UNZ_OK) {
// Nothing to do anymore...
}
}
}
}
} while(unzGoToNextFile(m_ZipFileHandle) != UNZ_END_OF_LIST_OF_FILE);
}
}
success = true;
}
return success;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
typedef std::shared_ptr<OpcPackageRelationship> OpcPackageRelationshipPtr; typedef std::shared_ptr<OpcPackageRelationship> OpcPackageRelationshipPtr;
@ -453,7 +121,7 @@ public:
D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile) D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
: mRootStream(nullptr) : mRootStream(nullptr)
, mZipArchive() { , mZipArchive() {
mZipArchive.reset( new D3MF::D3MFZipArchive( pIOHandler, rFile ) ); mZipArchive.reset( new ZipArchiveIOSystem( pIOHandler, rFile ) );
if(!mZipArchive->isOpen()) { if(!mZipArchive->isOpen()) {
throw DeadlyImportError("Failed to open file " + rFile+ "."); throw DeadlyImportError("Failed to open file " + rFile+ ".");
} }
@ -481,14 +149,14 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
ASSIMP_LOG_DEBUG(rootFile); ASSIMP_LOG_DEBUG(rootFile);
mZipArchive->Close(fileStream);
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 root-file in archive : " + rootFile ); throw DeadlyExportError( "Cannot open root-file in archive : " + rootFile );
} }
mZipArchive->Close( fileStream );
} else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) { } else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) {
ASSIMP_LOG_WARN_F("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES",file); ASSIMP_LOG_WARN_F("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES",file);
} else { } else {
@ -499,7 +167,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
} }
D3MFOpcPackage::~D3MFOpcPackage() { D3MFOpcPackage::~D3MFOpcPackage() {
// empty mZipArchive->Close(mRootStream);
} }
IOStream* D3MFOpcPackage::RootStream() const { IOStream* D3MFOpcPackage::RootStream() const {
@ -516,15 +184,6 @@ bool D3MFOpcPackage::validate() {
return mZipArchive->Exists( ModelRef.c_str() ); 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()));

View File

@ -49,6 +49,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/irrXMLWrapper.h> #include <assimp/irrXMLWrapper.h>
namespace Assimp { namespace Assimp {
class ZipArchiveIOSystem;
namespace D3MF { namespace D3MF {
using XmlReader = irr::io::IrrXMLReader ; using XmlReader = irr::io::IrrXMLReader ;
@ -60,22 +62,19 @@ struct OpcPackageRelationship {
std::string target; std::string target;
}; };
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(); bool validate();
static bool isZipArchive( IOSystem* pIOHandler, const std::string& rFile );
protected: protected:
std::string ReadPackageRootRelationship(IOStream* stream); std::string ReadPackageRootRelationship(IOStream* stream);
private: private:
IOStream* mRootStream; IOStream* mRootStream;
std::unique_ptr<D3MFZipArchive> mZipArchive; std::unique_ptr<ZipArchiveIOSystem> mZipArchive;
}; };
} // Namespace D3MF } // Namespace D3MF

View File

@ -83,7 +83,7 @@ void AMFImporter::Clear()
mMaterial_Converted.clear(); mMaterial_Converted.clear();
mTexture_Converted.clear(); mTexture_Converted.clear();
// Delete all elements // Delete all elements
if(mNodeElement_List.size()) if(!mNodeElement_List.empty())
{ {
for(CAMFImporter_NodeElement* ne: mNodeElement_List) { delete ne; } for(CAMFImporter_NodeElement* ne: mNodeElement_List) { delete ne; }

View File

@ -66,7 +66,7 @@ aiColor4D AMFImporter::SPP_Material::GetColor(const float /*pX*/, const float /*
aiColor4D tcol; aiColor4D tcol;
// Check if stored data are supported. // Check if stored data are supported.
if(Composition.size() != 0) if(!Composition.empty())
{ {
throw DeadlyImportError("IME. GetColor for composition"); throw DeadlyImportError("IME. GetColor for composition");
} }
@ -321,7 +321,7 @@ void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace
}; };
pOutputList_Separated.clear(); pOutputList_Separated.clear();
if(pInputList.size() == 0) return; if(pInputList.empty()) return;
do do
{ {
@ -334,19 +334,19 @@ void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace
{ {
auto it_old = it; auto it_old = it;
it++; ++it;
face_list_cur.push_back(*it_old); face_list_cur.push_back(*it_old);
pInputList.erase(it_old); pInputList.erase(it_old);
} }
else else
{ {
it++; ++it;
} }
} }
if(face_list_cur.size() > 0) pOutputList_Separated.push_back(face_list_cur); if(!face_list_cur.empty()) pOutputList_Separated.push_back(face_list_cur);
} while(pInputList.size() > 0); } while(!pInputList.empty());
} }
void AMFImporter::Postprocess_AddMetadata(const std::list<CAMFImporter_NodeElement_Metadata*>& metadataList, aiNode& sceneNode) const void AMFImporter::Postprocess_AddMetadata(const std::list<CAMFImporter_NodeElement_Metadata*>& metadataList, aiNode& sceneNode) const
@ -712,7 +712,7 @@ std::list<unsigned int> mesh_idx;
}// for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child) }// for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child)
// if meshes was created then assign new indices with current aiNode // if meshes was created then assign new indices with current aiNode
if(mesh_idx.size() > 0) if(!mesh_idx.empty())
{ {
std::list<unsigned int>::const_iterator mit = mesh_idx.begin(); std::list<unsigned int>::const_iterator mit = mesh_idx.begin();
@ -787,7 +787,7 @@ std::list<aiNode*> ch_node;
}// for(const CAMFImporter_NodeElement* ne: pConstellation.Child) }// for(const CAMFImporter_NodeElement* ne: pConstellation.Child)
// copy found aiNode's as children // copy found aiNode's as children
if(ch_node.size() == 0) throw DeadlyImportError("<constellation> must have at least one <instance>."); if(ch_node.empty()) throw DeadlyImportError("<constellation> must have at least one <instance>.");
size_t ch_idx = 0; size_t ch_idx = 0;
@ -883,13 +883,13 @@ nl_clean_loop:
if(node_list.size() > 1) if(node_list.size() > 1)
{ {
// walk through all nodes // walk through all nodes
for(std::list<aiNode*>::iterator nl_it = node_list.begin(); nl_it != node_list.end(); nl_it++) for(std::list<aiNode*>::iterator nl_it = node_list.begin(); nl_it != node_list.end(); ++nl_it)
{ {
// and try to find them in another top nodes. // and try to find them in another top nodes.
std::list<aiNode*>::const_iterator next_it = nl_it; std::list<aiNode*>::const_iterator next_it = nl_it;
next_it++; ++next_it;
for(; next_it != node_list.end(); next_it++) for(; next_it != node_list.end(); ++next_it)
{ {
if((*next_it)->FindNode((*nl_it)->mName) != nullptr) if((*next_it)->FindNode((*nl_it)->mName) != nullptr)
{ {
@ -907,7 +907,7 @@ nl_clean_loop:
// //
// //
// Nodes // Nodes
if(node_list.size() > 0) if(!node_list.empty())
{ {
std::list<aiNode*>::const_iterator nl_it = node_list.begin(); std::list<aiNode*>::const_iterator nl_it = node_list.begin();
@ -924,7 +924,7 @@ nl_clean_loop:
// //
// Meshes // Meshes
if(mesh_list.size() > 0) if(!mesh_list.empty())
{ {
std::list<aiMesh*>::const_iterator ml_it = mesh_list.begin(); std::list<aiMesh*>::const_iterator ml_it = mesh_list.begin();

View File

@ -34,15 +34,6 @@ namespace Assimp {
void ExportAssimp2Json(const char*, Assimp::IOSystem*, const aiScene*, const Assimp::ExportProperties*); void ExportAssimp2Json(const char*, Assimp::IOSystem*, const aiScene*, const Assimp::ExportProperties*);
Exporter::ExportFormatEntry Assimp2Json_desc = Assimp::Exporter::ExportFormatEntry(
"json",
"Plain JSON representation of the Assimp scene data structure",
"json",
&ExportAssimp2Json,
0u
);
// small utility class to simplify serializing the aiScene to Json // small utility class to simplify serializing the aiScene to Json
class JSONWriter { class JSONWriter {
public: public:

View File

@ -104,6 +104,7 @@ SET( PUBLIC_HEADERS
${HEADER_PATH}/Exporter.hpp ${HEADER_PATH}/Exporter.hpp
${HEADER_PATH}/DefaultIOStream.h ${HEADER_PATH}/DefaultIOStream.h
${HEADER_PATH}/DefaultIOSystem.h ${HEADER_PATH}/DefaultIOSystem.h
${HEADER_PATH}/ZipArchiveIOSystem.h
${HEADER_PATH}/SceneCombiner.h ${HEADER_PATH}/SceneCombiner.h
${HEADER_PATH}/fast_atof.h ${HEADER_PATH}/fast_atof.h
${HEADER_PATH}/qnan.h ${HEADER_PATH}/qnan.h
@ -136,7 +137,6 @@ SET( PUBLIC_HEADERS
${HEADER_PATH}/irrXMLWrapper.h ${HEADER_PATH}/irrXMLWrapper.h
${HEADER_PATH}/BlobIOSystem.h ${HEADER_PATH}/BlobIOSystem.h
${HEADER_PATH}/MathFunctions.h ${HEADER_PATH}/MathFunctions.h
${HEADER_PATH}/Macros.h
${HEADER_PATH}/Exceptional.h ${HEADER_PATH}/Exceptional.h
${HEADER_PATH}/ByteSwapper.h ${HEADER_PATH}/ByteSwapper.h
) )
@ -172,6 +172,7 @@ SET( Common_SRCS
Common/DefaultProgressHandler.h Common/DefaultProgressHandler.h
Common/DefaultIOStream.cpp Common/DefaultIOStream.cpp
Common/DefaultIOSystem.cpp Common/DefaultIOSystem.cpp
Common/ZipArchiveIOSystem.cpp
Common/PolyTools.h Common/PolyTools.h
Common/Importer.cpp Common/Importer.cpp
Common/IFF.h Common/IFF.h
@ -406,6 +407,18 @@ ADD_ASSIMP_IMPORTER( LWS
LWS/LWSLoader.h LWS/LWSLoader.h
) )
ADD_ASSIMP_IMPORTER( M3D
M3D/M3DMaterials.h
M3D/M3DImporter.h
M3D/M3DImporter.cpp
M3D/m3d.h
)
ADD_ASSIMP_EXPORTER( M3D
M3D/M3DExporter.h
M3D/M3DExporter.cpp
)
ADD_ASSIMP_IMPORTER( MD2 ADD_ASSIMP_IMPORTER( MD2
MD2/MD2FileData.h MD2/MD2FileData.h
MD2/MD2Loader.cpp MD2/MD2Loader.cpp
@ -669,6 +682,8 @@ SET( PostProcessing_SRCS
PostProcessing/MakeVerboseFormat.h PostProcessing/MakeVerboseFormat.h
PostProcessing/ScaleProcess.cpp PostProcessing/ScaleProcess.cpp
PostProcessing/ScaleProcess.h PostProcessing/ScaleProcess.h
PostProcessing/ArmaturePopulate.cpp
PostProcessing/ArmaturePopulate.h
PostProcessing/GenBoundingBoxesProcess.cpp PostProcessing/GenBoundingBoxesProcess.cpp
PostProcessing/GenBoundingBoxesProcess.h PostProcessing/GenBoundingBoxesProcess.h
) )
@ -688,8 +703,6 @@ ADD_ASSIMP_IMPORTER( Q3BSP
Q3BSP/Q3BSPFileParser.cpp Q3BSP/Q3BSPFileParser.cpp
Q3BSP/Q3BSPFileImporter.h Q3BSP/Q3BSPFileImporter.h
Q3BSP/Q3BSPFileImporter.cpp Q3BSP/Q3BSPFileImporter.cpp
Q3BSP/Q3BSPZipArchive.h
Q3BSP/Q3BSPZipArchive.cpp
) )
ADD_ASSIMP_IMPORTER( RAW ADD_ASSIMP_IMPORTER( RAW
@ -766,6 +779,8 @@ ADD_ASSIMP_EXPORTER( X3D
) )
ADD_ASSIMP_IMPORTER( GLTF ADD_ASSIMP_IMPORTER( GLTF
glTF/glTFCommon.h
glTF/glTFCommon.cpp
glTF/glTFAsset.h glTF/glTFAsset.h
glTF/glTFAsset.inl glTF/glTFAsset.inl
glTF/glTFAssetWriter.h glTF/glTFAssetWriter.h
@ -810,7 +825,7 @@ ADD_ASSIMP_IMPORTER( MMD
MMD/MMDVmdParser.h MMD/MMDVmdParser.h
) )
ADD_ASSIMP_EXPORTER( Assjson ADD_ASSIMP_EXPORTER( ASSJSON
Assjson/cencode.c Assjson/cencode.c
Assjson/cencode.h Assjson/cencode.h
Assjson/json_exporter.cpp Assjson/json_exporter.cpp
@ -1057,6 +1072,8 @@ MESSAGE(STATUS "Disabled importer formats:${ASSIMP_IMPORTERS_DISABLED}")
MESSAGE(STATUS "Enabled exporter formats:${ASSIMP_EXPORTERS_ENABLED}") MESSAGE(STATUS "Enabled exporter formats:${ASSIMP_EXPORTERS_ENABLED}")
MESSAGE(STATUS "Disabled exporter formats:${ASSIMP_EXPORTERS_DISABLED}") MESSAGE(STATUS "Disabled exporter formats:${ASSIMP_EXPORTERS_DISABLED}")
SOURCE_GROUP( include\\assimp FILES ${PUBLIC_HEADERS} )
SET( assimp_src SET( assimp_src
# Assimp Files # Assimp Files
${Core_SRCS} ${Core_SRCS}

View File

@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "ColladaExporter.h" #include "ColladaExporter.h"
#include <assimp/Bitmap.h> #include <assimp/Bitmap.h>
#include <assimp/MathFunctions.h>
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include <assimp/SceneCombiner.h> #include <assimp/SceneCombiner.h>
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
@ -91,6 +92,36 @@ void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* p
} // end of namespace Assimp } // end of namespace Assimp
// ------------------------------------------------------------------------------------------------
// Encodes a string into a valid XML ID using the xsd:ID schema qualifications.
static const std::string XMLIDEncode(const std::string& name) {
const char XML_ID_CHARS[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.";
const unsigned int XML_ID_CHARS_COUNT = sizeof(XML_ID_CHARS) / sizeof(char);
if (name.length() == 0) {
return name;
}
std::stringstream idEncoded;
// xsd:ID must start with letter or underscore
if (!((name[0] >= 'A' && name[0] <= 'z') || name[0] == '_')) {
idEncoded << '_';
}
for (std::string::const_iterator it = name.begin(); it != name.end(); ++it) {
// xsd:ID can only contain letters, digits, underscores, hyphens and periods
if (strchr(XML_ID_CHARS, *it) != nullptr) {
idEncoded << *it;
} else {
// Select placeholder character based on invalid character to prevent name collisions
idEncoded << XML_ID_CHARS[(*it) % XML_ID_CHARS_COUNT];
}
}
return idEncoded.str();
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor for a specific scene to export // Constructor for a specific scene to export
ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file) ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file)
@ -145,7 +176,7 @@ void ColladaExporter::WriteFile() {
// useless Collada fu at the end, just in case we haven't had enough indirections, yet. // useless Collada fu at the end, just in case we haven't had enough indirections, yet.
mOutput << startstr << "<scene>" << endstr; mOutput << startstr << "<scene>" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<instance_visual_scene url=\"#" + XMLEscape(mScene->mRootNode->mName.C_Str()) + "\" />" << endstr; mOutput << startstr << "<instance_visual_scene url=\"#" + XMLIDEncode(mScene->mRootNode->mName.C_Str()) + "\" />" << endstr;
PopTag(); PopTag();
mOutput << startstr << "</scene>" << endstr; mOutput << startstr << "</scene>" << endstr;
PopTag(); PopTag();
@ -155,7 +186,7 @@ void ColladaExporter::WriteFile() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Writes the asset header // Writes the asset header
void ColladaExporter::WriteHeader() { void ColladaExporter::WriteHeader() {
static const ai_real epsilon = ai_real( 0.00001 ); static const ai_real epsilon = Math::getEpsilon<ai_real>();
static const aiQuaternion x_rot(aiMatrix3x3( static const aiQuaternion x_rot(aiMatrix3x3(
0, -1, 0, 0, -1, 0,
1, 0, 0, 1, 0, 0,
@ -317,7 +348,7 @@ void ColladaExporter::WriteTextures() {
std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char*) texture->achFormatHint); std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char*) texture->achFormatHint);
std::unique_ptr<IOStream> outfile(mIOSystem->Open(mPath + name, "wb")); std::unique_ptr<IOStream> outfile(mIOSystem->Open(mPath + mIOSystem->getOsSeparator() + name, "wb"));
if(outfile == NULL) { if(outfile == NULL) {
throw DeadlyExportError("could not open output texture file: " + mPath + name); throw DeadlyExportError("could not open output texture file: " + mPath + name);
} }
@ -355,9 +386,10 @@ void ColladaExporter::WriteCamerasLibrary() {
void ColladaExporter::WriteCamera(size_t pIndex){ void ColladaExporter::WriteCamera(size_t pIndex){
const aiCamera *cam = mScene->mCameras[pIndex]; const aiCamera *cam = mScene->mCameras[pIndex];
const std::string idstrEscaped = XMLEscape(cam->mName.C_Str()); const std::string cameraName = XMLEscape(cam->mName.C_Str());
const std::string cameraId = XMLIDEncode(cam->mName.C_Str());
mOutput << startstr << "<camera id=\"" << idstrEscaped << "-camera\" name=\"" << idstrEscaped << "_name\" >" << endstr; mOutput << startstr << "<camera id=\"" << cameraId << "-camera\" name=\"" << cameraName << "\" >" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<optics>" << endstr; mOutput << startstr << "<optics>" << endstr;
PushTag(); PushTag();
@ -411,10 +443,11 @@ void ColladaExporter::WriteLightsLibrary() {
void ColladaExporter::WriteLight(size_t pIndex){ void ColladaExporter::WriteLight(size_t pIndex){
const aiLight *light = mScene->mLights[pIndex]; const aiLight *light = mScene->mLights[pIndex];
const std::string idstrEscaped = XMLEscape(light->mName.C_Str()); const std::string lightName = XMLEscape(light->mName.C_Str());
const std::string lightId = XMLIDEncode(light->mName.C_Str());
mOutput << startstr << "<light id=\"" << idstrEscaped << "-light\" name=\"" mOutput << startstr << "<light id=\"" << lightId << "-light\" name=\""
<< idstrEscaped << "_name\" >" << endstr; << lightName << "\" >" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<technique_common>" << endstr; mOutput << startstr << "<technique_common>" << endstr;
PushTag(); PushTag();
@ -585,7 +618,7 @@ static bool isalnum_C(char c) {
void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd) { void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd) {
if( !pSurface.texture.empty() ) if( !pSurface.texture.empty() )
{ {
mOutput << startstr << "<image id=\"" << XMLEscape(pNameAdd) << "\">" << endstr; mOutput << startstr << "<image id=\"" << XMLIDEncode(pNameAdd) << "\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<init_from>"; mOutput << startstr << "<init_from>";
@ -618,7 +651,7 @@ void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std
} }
else else
{ {
mOutput << startstr << "<texture texture=\"" << XMLEscape(pImageName) << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr; mOutput << startstr << "<texture texture=\"" << XMLIDEncode(pImageName) << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
} }
PopTag(); PopTag();
mOutput << startstr << "</" << pTypeName << ">" << endstr; mOutput << startstr << "</" << pTypeName << ">" << endstr;
@ -632,21 +665,21 @@ void ColladaExporter::WriteTextureParamEntry( const Surface& pSurface, const std
// if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture // if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture
if( !pSurface.texture.empty() ) if( !pSurface.texture.empty() )
{ {
mOutput << startstr << "<newparam sid=\"" << XMLEscape(pMatName) << "-" << pTypeName << "-surface\">" << endstr; mOutput << startstr << "<newparam sid=\"" << XMLIDEncode(pMatName) << "-" << pTypeName << "-surface\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<surface type=\"2D\">" << endstr; mOutput << startstr << "<surface type=\"2D\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<init_from>" << XMLEscape(pMatName) << "-" << pTypeName << "-image</init_from>" << endstr; mOutput << startstr << "<init_from>" << XMLIDEncode(pMatName) << "-" << pTypeName << "-image</init_from>" << endstr;
PopTag(); PopTag();
mOutput << startstr << "</surface>" << endstr; mOutput << startstr << "</surface>" << endstr;
PopTag(); PopTag();
mOutput << startstr << "</newparam>" << endstr; mOutput << startstr << "</newparam>" << endstr;
mOutput << startstr << "<newparam sid=\"" << XMLEscape(pMatName) << "-" << pTypeName << "-sampler\">" << endstr; mOutput << startstr << "<newparam sid=\"" << XMLIDEncode(pMatName) << "-" << pTypeName << "-sampler\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<sampler2D>" << endstr; mOutput << startstr << "<sampler2D>" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<source>" << XMLEscape(pMatName) << "-" << pTypeName << "-surface</source>" << endstr; mOutput << startstr << "<source>" << XMLIDEncode(pMatName) << "-" << pTypeName << "-surface</source>" << endstr;
PopTag(); PopTag();
mOutput << startstr << "</sampler2D>" << endstr; mOutput << startstr << "</sampler2D>" << endstr;
PopTag(); PopTag();
@ -698,11 +731,6 @@ void ColladaExporter::WriteMaterials()
materials[a].name = std::string(name.C_Str()) + to_string(materialCountWithThisName); materials[a].name = std::string(name.C_Str()) + to_string(materialCountWithThisName);
} }
} }
for( std::string::iterator it = materials[a].name.begin(); it != materials[a].name.end(); ++it ) {
if( !isalnum_C( *it ) ) {
*it = '_';
}
}
aiShadingMode shading = aiShadingMode_Flat; aiShadingMode shading = aiShadingMode_Flat;
materials[a].shading_model = "phong"; materials[a].shading_model = "phong";
@ -767,7 +795,7 @@ void ColladaExporter::WriteMaterials()
{ {
const Material& mat = *it; const Material& mat = *it;
// this is so ridiculous it must be right // this is so ridiculous it must be right
mOutput << startstr << "<effect id=\"" << XMLEscape(mat.name) << "-fx\" name=\"" << XMLEscape(mat.name) << "\">" << endstr; mOutput << startstr << "<effect id=\"" << XMLIDEncode(mat.name) << "-fx\" name=\"" << XMLEscape(mat.name) << "\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<profile_COMMON>" << endstr; mOutput << startstr << "<profile_COMMON>" << endstr;
PushTag(); PushTag();
@ -818,9 +846,9 @@ void ColladaExporter::WriteMaterials()
for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it ) for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it )
{ {
const Material& mat = *it; const Material& mat = *it;
mOutput << startstr << "<material id=\"" << XMLEscape(mat.name) << "\" name=\"" << mat.name << "\">" << endstr; mOutput << startstr << "<material id=\"" << XMLIDEncode(mat.name) << "\" name=\"" << XMLEscape(mat.name) << "\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<instance_effect url=\"#" << XMLEscape(mat.name) << "-fx\"/>" << endstr; mOutput << startstr << "<instance_effect url=\"#" << XMLIDEncode(mat.name) << "-fx\"/>" << endstr;
PopTag(); PopTag();
mOutput << startstr << "</material>" << endstr; mOutput << startstr << "</material>" << endstr;
} }
@ -849,8 +877,8 @@ void ColladaExporter::WriteControllerLibrary()
void ColladaExporter::WriteController( size_t pIndex) void ColladaExporter::WriteController( size_t pIndex)
{ {
const aiMesh* mesh = mScene->mMeshes[pIndex]; const aiMesh* mesh = mScene->mMeshes[pIndex];
const std::string idstr = GetMeshId( pIndex); const std::string idstr = mesh->mName.length == 0 ? GetMeshId(pIndex) : mesh->mName.C_Str();
const std::string idstrEscaped = XMLEscape(idstr); const std::string idstrEscaped = XMLIDEncode(idstr);
if ( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) if ( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
return; return;
@ -885,7 +913,7 @@ void ColladaExporter::WriteController( size_t pIndex)
mOutput << startstr << "<Name_array id=\"" << idstrEscaped << "-skin-joints-array\" count=\"" << mesh->mNumBones << "\">"; mOutput << startstr << "<Name_array id=\"" << idstrEscaped << "-skin-joints-array\" count=\"" << mesh->mNumBones << "\">";
for( size_t i = 0; i < mesh->mNumBones; ++i ) for( size_t i = 0; i < mesh->mNumBones; ++i )
mOutput << XMLEscape(mesh->mBones[i]->mName.C_Str()) << " "; mOutput << XMLIDEncode(mesh->mBones[i]->mName.C_Str()) << " ";
mOutput << "</Name_array>" << endstr; mOutput << "</Name_array>" << endstr;
@ -1020,14 +1048,15 @@ void ColladaExporter::WriteGeometryLibrary()
void ColladaExporter::WriteGeometry( size_t pIndex) void ColladaExporter::WriteGeometry( size_t pIndex)
{ {
const aiMesh* mesh = mScene->mMeshes[pIndex]; const aiMesh* mesh = mScene->mMeshes[pIndex];
const std::string idstr = GetMeshId( pIndex); const std::string idstr = mesh->mName.length == 0 ? GetMeshId(pIndex) : mesh->mName.C_Str();
const std::string idstrEscaped = XMLEscape(idstr); const std::string geometryName = XMLEscape(idstr);
const std::string geometryId = XMLIDEncode(idstr);
if ( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) if ( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
return; return;
// opening tag // opening tag
mOutput << startstr << "<geometry id=\"" << idstrEscaped << "\" name=\"" << idstrEscaped << "_name\" >" << endstr; mOutput << startstr << "<geometry id=\"" << geometryId << "\" name=\"" << geometryName << "\" >" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<mesh>" << endstr; mOutput << startstr << "<mesh>" << endstr;
@ -1058,9 +1087,9 @@ void ColladaExporter::WriteGeometry( size_t pIndex)
// assemble vertex structure // assemble vertex structure
// Only write input for POSITION since we will write other as shared inputs in polygon definition // Only write input for POSITION since we will write other as shared inputs in polygon definition
mOutput << startstr << "<vertices id=\"" << idstrEscaped << "-vertices" << "\">" << endstr; mOutput << startstr << "<vertices id=\"" << geometryId << "-vertices" << "\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<input semantic=\"POSITION\" source=\"#" << idstrEscaped << "-positions\" />" << endstr; mOutput << startstr << "<input semantic=\"POSITION\" source=\"#" << geometryId << "-positions\" />" << endstr;
PopTag(); PopTag();
mOutput << startstr << "</vertices>" << endstr; mOutput << startstr << "</vertices>" << endstr;
@ -1078,18 +1107,18 @@ void ColladaExporter::WriteGeometry( size_t pIndex)
{ {
mOutput << startstr << "<lines count=\"" << countLines << "\" material=\"defaultMaterial\">" << endstr; mOutput << startstr << "<lines count=\"" << countLines << "\" material=\"defaultMaterial\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstrEscaped << "-vertices\" />" << endstr; mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << geometryId << "-vertices\" />" << endstr;
if( mesh->HasNormals() ) if( mesh->HasNormals() )
mOutput << startstr << "<input semantic=\"NORMAL\" source=\"#" << idstrEscaped << "-normals\" />" << endstr; mOutput << startstr << "<input semantic=\"NORMAL\" source=\"#" << geometryId << "-normals\" />" << endstr;
for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
{ {
if( mesh->HasTextureCoords(static_cast<unsigned int>(a)) ) if( mesh->HasTextureCoords(static_cast<unsigned int>(a)) )
mOutput << startstr << "<input semantic=\"TEXCOORD\" source=\"#" << idstrEscaped << "-tex" << a << "\" " << "set=\"" << a << "\"" << " />" << endstr; mOutput << startstr << "<input semantic=\"TEXCOORD\" source=\"#" << geometryId << "-tex" << a << "\" " << "set=\"" << a << "\"" << " />" << endstr;
} }
for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a )
{ {
if( mesh->HasVertexColors(static_cast<unsigned int>(a) ) ) if( mesh->HasVertexColors(static_cast<unsigned int>(a) ) )
mOutput << startstr << "<input semantic=\"COLOR\" source=\"#" << idstrEscaped << "-color" << a << "\" " << "set=\"" << a << "\"" << " />" << endstr; mOutput << startstr << "<input semantic=\"COLOR\" source=\"#" << geometryId << "-color" << a << "\" " << "set=\"" << a << "\"" << " />" << endstr;
} }
mOutput << startstr << "<p>"; mOutput << startstr << "<p>";
@ -1112,18 +1141,18 @@ void ColladaExporter::WriteGeometry( size_t pIndex)
{ {
mOutput << startstr << "<polylist count=\"" << countPoly << "\" material=\"defaultMaterial\">" << endstr; mOutput << startstr << "<polylist count=\"" << countPoly << "\" material=\"defaultMaterial\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstrEscaped << "-vertices\" />" << endstr; mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << geometryId << "-vertices\" />" << endstr;
if( mesh->HasNormals() ) if( mesh->HasNormals() )
mOutput << startstr << "<input offset=\"0\" semantic=\"NORMAL\" source=\"#" << idstrEscaped << "-normals\" />" << endstr; mOutput << startstr << "<input offset=\"0\" semantic=\"NORMAL\" source=\"#" << geometryId << "-normals\" />" << endstr;
for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
{ {
if( mesh->HasTextureCoords(static_cast<unsigned int>(a)) ) if( mesh->HasTextureCoords(static_cast<unsigned int>(a)) )
mOutput << startstr << "<input offset=\"0\" semantic=\"TEXCOORD\" source=\"#" << idstrEscaped << "-tex" << a << "\" " << "set=\"" << a << "\"" << " />" << endstr; mOutput << startstr << "<input offset=\"0\" semantic=\"TEXCOORD\" source=\"#" << geometryId << "-tex" << a << "\" " << "set=\"" << a << "\"" << " />" << endstr;
} }
for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a )
{ {
if( mesh->HasVertexColors(static_cast<unsigned int>(a) ) ) if( mesh->HasVertexColors(static_cast<unsigned int>(a) ) )
mOutput << startstr << "<input offset=\"0\" semantic=\"COLOR\" source=\"#" << idstrEscaped << "-color" << a << "\" " << "set=\"" << a << "\"" << " />" << endstr; mOutput << startstr << "<input offset=\"0\" semantic=\"COLOR\" source=\"#" << geometryId << "-color" << a << "\" " << "set=\"" << a << "\"" << " />" << endstr;
} }
mOutput << startstr << "<vcount>"; mOutput << startstr << "<vcount>";
@ -1172,13 +1201,13 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy
return; return;
} }
std::string arrayId = pIdString + "-array"; std::string arrayId = XMLIDEncode(pIdString) + "-array";
mOutput << startstr << "<source id=\"" << XMLEscape(pIdString) << "\" name=\"" << XMLEscape(pIdString) << "\">" << endstr; mOutput << startstr << "<source id=\"" << XMLIDEncode(pIdString) << "\" name=\"" << XMLEscape(pIdString) << "\">" << endstr;
PushTag(); PushTag();
// source array // source array
mOutput << startstr << "<float_array id=\"" << XMLEscape(arrayId) << "\" count=\"" << pElementCount * floatsPerElement << "\"> "; mOutput << startstr << "<float_array id=\"" << arrayId << "\" count=\"" << pElementCount * floatsPerElement << "\"> ";
PushTag(); PushTag();
if( pType == FloatType_TexCoord2 ) if( pType == FloatType_TexCoord2 )
@ -1264,11 +1293,12 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy
// Writes the scene library // Writes the scene library
void ColladaExporter::WriteSceneLibrary() void ColladaExporter::WriteSceneLibrary()
{ {
const std::string scene_name_escaped = XMLEscape(mScene->mRootNode->mName.C_Str()); const std::string sceneName = XMLEscape(mScene->mRootNode->mName.C_Str());
const std::string sceneId = XMLIDEncode(mScene->mRootNode->mName.C_Str());
mOutput << startstr << "<library_visual_scenes>" << endstr; mOutput << startstr << "<library_visual_scenes>" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<visual_scene id=\"" + scene_name_escaped + "\" name=\"" + scene_name_escaped + "\">" << endstr; mOutput << startstr << "<visual_scene id=\"" + sceneId + "\" name=\"" + sceneName + "\">" << endstr;
PushTag(); PushTag();
// start recursive write at the root node // start recursive write at the root node
@ -1299,7 +1329,7 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
idstr = idstr + ending; idstr = idstr + ending;
} }
const std::string idstrEscaped = XMLEscape(idstr); const std::string idstrEscaped = XMLIDEncode(idstr);
mOutput << startstr << "<animation id=\"" + idstrEscaped + "\" name=\"" + animation_name_escaped + "\">" << endstr; mOutput << startstr << "<animation id=\"" + idstrEscaped + "\" name=\"" + animation_name_escaped + "\">" << endstr;
PushTag(); PushTag();
@ -1371,13 +1401,13 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
} }
const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-interpolation"); const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-interpolation");
std::string arrayId = node_idstr + "-array"; std::string arrayId = XMLIDEncode(node_idstr) + "-array";
mOutput << startstr << "<source id=\"" << XMLEscape(node_idstr) << "\">" << endstr; mOutput << startstr << "<source id=\"" << XMLIDEncode(node_idstr) << "\">" << endstr;
PushTag(); PushTag();
// source array // source array
mOutput << startstr << "<Name_array id=\"" << XMLEscape(arrayId) << "\" count=\"" << names.size() << "\"> "; mOutput << startstr << "<Name_array id=\"" << arrayId << "\" count=\"" << names.size() << "\"> ";
for( size_t a = 0; a < names.size(); ++a ) { for( size_t a = 0; a < names.size(); ++a ) {
mOutput << names[a] << " "; mOutput << names[a] << " ";
} }
@ -1386,7 +1416,7 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
mOutput << startstr << "<technique_common>" << endstr; mOutput << startstr << "<technique_common>" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<accessor source=\"#" << XMLEscape(arrayId) << "\" count=\"" << names.size() << "\" stride=\"" << 1 << "\">" << endstr; mOutput << startstr << "<accessor source=\"#" << arrayId << "\" count=\"" << names.size() << "\" stride=\"" << 1 << "\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<param name=\"INTERPOLATION\" type=\"name\"></param>" << endstr; mOutput << startstr << "<param name=\"INTERPOLATION\" type=\"name\"></param>" << endstr;
@ -1408,12 +1438,12 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
{ {
// samplers // samplers
const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-sampler"); const std::string node_idstr = nodeAnim->mNodeName.data + std::string("_matrix-sampler");
mOutput << startstr << "<sampler id=\"" << XMLEscape(node_idstr) << "\">" << endstr; mOutput << startstr << "<sampler id=\"" << XMLIDEncode(node_idstr) << "\">" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<input semantic=\"INPUT\" source=\"#" << XMLEscape( nodeAnim->mNodeName.data + std::string("_matrix-input") ) << "\"/>" << endstr; mOutput << startstr << "<input semantic=\"INPUT\" source=\"#" << XMLIDEncode( nodeAnim->mNodeName.data + std::string("_matrix-input") ) << "\"/>" << endstr;
mOutput << startstr << "<input semantic=\"OUTPUT\" source=\"#" << XMLEscape( nodeAnim->mNodeName.data + std::string("_matrix-output") ) << "\"/>" << endstr; mOutput << startstr << "<input semantic=\"OUTPUT\" source=\"#" << XMLIDEncode( nodeAnim->mNodeName.data + std::string("_matrix-output") ) << "\"/>" << endstr;
mOutput << startstr << "<input semantic=\"INTERPOLATION\" source=\"#" << XMLEscape( nodeAnim->mNodeName.data + std::string("_matrix-interpolation") ) << "\"/>" << endstr; mOutput << startstr << "<input semantic=\"INTERPOLATION\" source=\"#" << XMLIDEncode( nodeAnim->mNodeName.data + std::string("_matrix-interpolation") ) << "\"/>" << endstr;
PopTag(); PopTag();
mOutput << startstr << "</sampler>" << endstr; mOutput << startstr << "</sampler>" << endstr;
@ -1425,7 +1455,7 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
{ {
// channels // channels
mOutput << startstr << "<channel source=\"#" << XMLEscape( nodeAnim->mNodeName.data + std::string("_matrix-sampler") ) << "\" target=\"" << XMLEscape(nodeAnim->mNodeName.data) << "/matrix\"/>" << endstr; mOutput << startstr << "<channel source=\"#" << XMLIDEncode( nodeAnim->mNodeName.data + std::string("_matrix-sampler") ) << "\" target=\"" << XMLIDEncode(nodeAnim->mNodeName.data) << "/matrix\"/>" << endstr;
} }
} }
@ -1436,8 +1466,6 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ColladaExporter::WriteAnimationsLibrary() void ColladaExporter::WriteAnimationsLibrary()
{ {
const std::string scene_name_escaped = XMLEscape(mScene->mRootNode->mName.C_Str());
if ( mScene->mNumAnimations > 0 ) { if ( mScene->mNumAnimations > 0 ) {
mOutput << startstr << "<library_animations>" << endstr; mOutput << startstr << "<library_animations>" << endstr;
PushTag(); PushTag();
@ -1545,16 +1573,17 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
} }
} }
const std::string node_name_escaped = XMLEscape(pNode->mName.data); const std::string node_id = XMLIDEncode(pNode->mName.data);
const std::string node_name = XMLEscape(pNode->mName.data);
mOutput << startstr << "<node "; mOutput << startstr << "<node ";
if(is_skeleton_root) { if(is_skeleton_root) {
mOutput << "id=\"" << node_name_escaped << "\" " << (is_joint ? "sid=\"" + node_name_escaped +"\"" : "") ; // For now, only support one skeleton in a scene. mOutput << "id=\"" << node_id << "\" " << (is_joint ? "sid=\"" + node_id +"\"" : "") ; // For now, only support one skeleton in a scene.
mFoundSkeletonRootNodeID = node_name_escaped; mFoundSkeletonRootNodeID = node_id;
} else { } else {
mOutput << "id=\"" << node_name_escaped << "\" " << (is_joint ? "sid=\"" + node_name_escaped +"\"": "") ; mOutput << "id=\"" << node_id << "\" " << (is_joint ? "sid=\"" + node_id +"\"": "") ;
} }
mOutput << " name=\"" << node_name_escaped mOutput << " name=\"" << node_name
<< "\" type=\"" << node_type << "\" type=\"" << node_type
<< "\">" << endstr; << "\">" << endstr;
PushTag(); PushTag();
@ -1593,14 +1622,14 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
//check if it is a camera node //check if it is a camera node
for(size_t i=0; i<mScene->mNumCameras; i++){ for(size_t i=0; i<mScene->mNumCameras; i++){
if(mScene->mCameras[i]->mName == pNode->mName){ if(mScene->mCameras[i]->mName == pNode->mName){
mOutput << startstr <<"<instance_camera url=\"#" << node_name_escaped << "-camera\"/>" << endstr; mOutput << startstr <<"<instance_camera url=\"#" << node_id << "-camera\"/>" << endstr;
break; break;
} }
} }
//check if it is a light node //check if it is a light node
for(size_t i=0; i<mScene->mNumLights; i++){ for(size_t i=0; i<mScene->mNumLights; i++){
if(mScene->mLights[i]->mName == pNode->mName){ if(mScene->mLights[i]->mName == pNode->mName){
mOutput << startstr <<"<instance_light url=\"#" << node_name_escaped << "-light\"/>" << endstr; mOutput << startstr <<"<instance_light url=\"#" << node_id << "-light\"/>" << endstr;
break; break;
} }
} }
@ -1614,15 +1643,17 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
continue; continue;
const std::string meshName = mesh->mName.length == 0 ? GetMeshId(pNode->mMeshes[a]) : mesh->mName.C_Str();
if( mesh->mNumBones == 0 ) if( mesh->mNumBones == 0 )
{ {
mOutput << startstr << "<instance_geometry url=\"#" << XMLEscape(GetMeshId( pNode->mMeshes[a])) << "\">" << endstr; mOutput << startstr << "<instance_geometry url=\"#" << XMLIDEncode(meshName) << "\">" << endstr;
PushTag(); PushTag();
} }
else else
{ {
mOutput << startstr mOutput << startstr
<< "<instance_controller url=\"#" << XMLEscape(GetMeshId( pNode->mMeshes[a])) << "-skin\">" << "<instance_controller url=\"#" << XMLIDEncode(meshName) << "-skin\">"
<< endstr; << endstr;
PushTag(); PushTag();
@ -1630,7 +1661,7 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
// use the first bone to find skeleton root // use the first bone to find skeleton root
const aiNode * skeletonRootBoneNode = findSkeletonRootNode( pScene, mesh ); const aiNode * skeletonRootBoneNode = findSkeletonRootNode( pScene, mesh );
if ( skeletonRootBoneNode ) { if ( skeletonRootBoneNode ) {
mFoundSkeletonRootNodeID = XMLEscape( skeletonRootBoneNode->mName.C_Str() ); mFoundSkeletonRootNodeID = XMLIDEncode( skeletonRootBoneNode->mName.C_Str() );
} }
mOutput << startstr << "<skeleton>#" << mFoundSkeletonRootNodeID << "</skeleton>" << endstr; mOutput << startstr << "<skeleton>#" << mFoundSkeletonRootNodeID << "</skeleton>" << endstr;
} }
@ -1638,7 +1669,7 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
PushTag(); PushTag();
mOutput << startstr << "<technique_common>" << endstr; mOutput << startstr << "<technique_common>" << endstr;
PushTag(); PushTag();
mOutput << startstr << "<instance_material symbol=\"defaultMaterial\" target=\"#" << XMLEscape(materials[mesh->mMaterialIndex].name) << "\">" << endstr; mOutput << startstr << "<instance_material symbol=\"defaultMaterial\" target=\"#" << XMLIDEncode(materials[mesh->mMaterialIndex].name) << "\">" << endstr;
PushTag(); PushTag();
for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
{ {

View File

@ -580,15 +580,11 @@ struct Image
{ {
std::string mFileName; std::string mFileName;
/** If image file name is zero, embedded image data /** Embedded image data */
*/
std::vector<uint8_t> mImageData; std::vector<uint8_t> mImageData;
/** If image file name is zero, file format of /** File format hint of embedded image data */
* embedded image data.
*/
std::string mEmbeddedFormat; std::string mEmbeddedFormat;
}; };
/** An animation channel. */ /** An animation channel. */

File diff suppressed because it is too large Load Diff

View File

@ -94,20 +94,20 @@ public:
public: public:
/** Returns whether the class can handle the format of the given file. /** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details. */ * See BaseImporter::CanRead() for details. */
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; bool CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const override;
protected: protected:
/** Return importer meta information. /** Return importer meta information.
* See #BaseImporter::GetInfo for the details * See #BaseImporter::GetInfo for the details
*/ */
const aiImporterDesc* GetInfo () const; const aiImporterDesc* GetInfo () const override;
void SetupProperties(const Importer* pImp); void SetupProperties(const Importer* pImp) override;
/** Imports the given file into the given scene structure. /** Imports the given file into the given scene structure.
* See BaseImporter::InternReadFile() for details * See BaseImporter::InternReadFile() for details
*/ */
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) override;
/** Recursively constructs a scene node for the given parser node and returns it. */ /** Recursively constructs a scene node for the given parser node and returns it. */
aiNode* BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode); aiNode* BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode);
@ -120,7 +120,7 @@ protected:
void BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode, void BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode,
aiNode* pTarget); aiNode* pTarget);
aiMesh *findMesh(std::string meshid); aiMesh *findMesh(const std::string& meshid);
/** Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh */ /** Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh */
aiMesh* CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh, aiMesh* CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
@ -184,9 +184,6 @@ protected:
aiString FindFilenameForEffectTexture( const ColladaParser& pParser, aiString FindFilenameForEffectTexture( const ColladaParser& pParser,
const Collada::Effect& pEffect, const std::string& pName); const Collada::Effect& pEffect, const std::string& pName);
/** Converts a path read from a collada file to the usual representation */
void ConvertPath( aiString& ss);
/** Reads a float value from an accessor and its data array. /** Reads a float value from an accessor and its data array.
* @param pAccessor The accessor to use for reading * @param pAccessor The accessor to use for reading
* @param pData The data array to read from * @param pData The data array to read from

File diff suppressed because it is too large Load Diff

View File

@ -54,6 +54,7 @@
namespace Assimp namespace Assimp
{ {
class ZipArchiveIOSystem;
// ------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------
/** Parser helper class for the Collada loader. /** Parser helper class for the Collada loader.
@ -65,16 +66,22 @@ namespace Assimp
{ {
friend class ColladaLoader; friend class ColladaLoader;
/** Converts a path read from a collada file to the usual representation */
static void UriDecodePath(aiString& ss);
protected: protected:
/** Map for generic metadata as aiString */ /** Map for generic metadata as aiString */
typedef std::map<std::string, aiString> StringMetaData; typedef std::map<std::string, aiString> StringMetaData;
/** Constructor from XML file */ /** Constructor from XML file */
ColladaParser( IOSystem* pIOHandler, const std::string& pFile); ColladaParser(IOSystem* pIOHandler, const std::string& pFile);
/** Destructor */ /** Destructor */
~ColladaParser(); ~ColladaParser();
/** Attempts to read the ZAE manifest and returns the DAE to open */
static std::string ReadZaeManifest(ZipArchiveIOSystem &zip_archive);
/** Reads the contents of the file */ /** Reads the contents of the file */
void ReadContents(); void ReadContents();
@ -235,6 +242,9 @@ namespace Assimp
// Processes bind_vertex_input and bind elements // Processes bind_vertex_input and bind elements
void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl); void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl);
/** Reads embedded textures from a ZAE archive*/
void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive);
protected: protected:
/** Aborts the file reading with an exception */ /** Aborts the file reading with an exception */
AI_WONT_RETURN void ThrowException( const std::string& pError) const AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void ThrowException( const std::string& pError) const AI_WONT_RETURN_SUFFIX;

View File

@ -67,7 +67,20 @@ using namespace Assimp;
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
BaseImporter::BaseImporter() AI_NO_EXCEPT BaseImporter::BaseImporter() AI_NO_EXCEPT
: m_progress() { : m_progress() {
// nothing to do here /**
* Assimp Importer
* unit conversions available
* if you need another measurment unit add it below.
* it's currently defined in assimp that we prefer meters.
*
* NOTE: Initialised here rather than in the header file
* to workaround a VS2013 bug with brace initialisers
* */
importerUnits[ImporterUnits::M] = 1.0;
importerUnits[ImporterUnits::CM] = 0.01;
importerUnits[ImporterUnits::MM] = 0.001;
importerUnits[ImporterUnits::INCHES] = 0.0254;
importerUnits[ImporterUnits::FEET] = 0.3048;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -76,9 +89,25 @@ BaseImporter::~BaseImporter() {
// nothing to do here // nothing to do here
} }
void BaseImporter::UpdateImporterScale( Importer* pImp )
{
ai_assert(pImp != nullptr);
ai_assert(importerScale != 0.0);
ai_assert(fileScale != 0.0);
double activeScale = importerScale * fileScale;
// Set active scaling
pImp->SetPropertyFloat( AI_CONFIG_APP_SCALE_KEY, static_cast<float>( activeScale) );
ASSIMP_LOG_DEBUG_F("UpdateImporterScale scale set: %f", activeScale );
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// 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(Importer* pImp, const std::string& pFile, IOSystem* pIOHandler) {
m_progress = pImp->GetProgressHandler(); m_progress = pImp->GetProgressHandler();
if (nullptr == m_progress) { if (nullptr == m_progress) {
return nullptr; return nullptr;
@ -100,6 +129,11 @@ aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile,
{ {
InternReadFile( pFile, sc.get(), &filter); InternReadFile( pFile, sc.get(), &filter);
// Calculate import scale hook - required because pImp not available anywhere else
// passes scale into ScaleProcess
UpdateImporterScale(pImp);
} catch( const std::exception& err ) { } catch( const std::exception& err ) {
// extract error description // extract error description
m_ErrorText = err.what(); m_ErrorText = err.what();
@ -112,7 +146,7 @@ aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile,
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void BaseImporter::SetupProperties(const Importer* /*pImp*/) void BaseImporter::SetupProperties(const Importer* pImp)
{ {
// the default implementation does nothing // the default implementation does nothing
} }
@ -588,6 +622,8 @@ aiScene* BatchLoader::GetImport( unsigned int which )
return nullptr; return nullptr;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void BatchLoader::LoadAll() void BatchLoader::LoadAll()
{ {

View File

@ -52,6 +52,35 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
namespace
{
template<size_t sizeOfPointer>
size_t select_ftell(FILE* file)
{
return ::ftell(file);
}
template<size_t sizeOfPointer>
int select_fseek(FILE* file, int64_t offset, int origin)
{
return ::fseek(file, static_cast<long>(offset), origin);
}
#if defined _WIN32 && (!defined __GNUC__ || __MSVCRT_VERSION__ >= 0x0601)
template<>
size_t select_ftell<8>(FILE* file)
{
return ::_ftelli64(file);
}
template<>
int select_fseek<8>(FILE* file, int64_t offset, int origin)
{
return ::_fseeki64(file, offset, origin);
}
#endif
}
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
DefaultIOStream::~DefaultIOStream() DefaultIOStream::~DefaultIOStream()
{ {
@ -93,7 +122,7 @@ aiReturn DefaultIOStream::Seek(size_t pOffset,
aiOrigin_END == SEEK_END && aiOrigin_SET == SEEK_SET"); aiOrigin_END == SEEK_END && aiOrigin_SET == SEEK_SET");
// do the seek // do the seek
return (0 == ::fseek(mFile, (long)pOffset,(int)pOrigin) ? AI_SUCCESS : AI_FAILURE); return (0 == select_fseek<sizeof(void*)>(mFile, (int64_t)pOffset,(int)pOrigin) ? AI_SUCCESS : AI_FAILURE);
} }
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------
@ -102,7 +131,7 @@ size_t DefaultIOStream::Tell() const
if (!mFile) { if (!mFile) {
return 0; return 0;
} }
return ::ftell(mFile); return select_ftell<sizeof(void*)>(mFile);
} }
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------

View File

@ -61,83 +61,66 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
// maximum path length #ifdef _WIN32
// XXX http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html static std::wstring Utf8ToWide(const char* in)
#ifdef PATH_MAX {
# define PATHLIMIT PATH_MAX int size = MultiByteToWideChar(CP_UTF8, 0, in, -1, nullptr, 0);
#else // size includes terminating null; std::wstring adds null automatically
# define PATHLIMIT 4096 std::wstring out(static_cast<size_t>(size) - 1, L'\0');
MultiByteToWideChar(CP_UTF8, 0, in, -1, &out[0], size);
return out;
}
static std::string WideToUtf8(const wchar_t* in)
{
int size = WideCharToMultiByte(CP_UTF8, 0, in, -1, nullptr, 0, nullptr, nullptr);
// size includes terminating null; std::string adds null automatically
std::string out(static_cast<size_t>(size) - 1, '\0');
WideCharToMultiByte(CP_UTF8, 0, in, -1, &out[0], size, nullptr, nullptr);
return out;
}
#endif #endif
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Tests for the existence of a file at the given path. // Tests for the existence of a file at the given path.
bool DefaultIOSystem::Exists( const char* pFile) const bool DefaultIOSystem::Exists(const char* pFile) const
{ {
#ifdef _WIN32 #ifdef _WIN32
wchar_t fileName16[PATHLIMIT];
#ifndef WindowsStore
bool isUnicode = IsTextUnicode(pFile, static_cast<int>(strlen(pFile)), NULL) != 0;
if (isUnicode) {
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, pFile, -1, fileName16, PATHLIMIT);
struct __stat64 filestat; struct __stat64 filestat;
if (0 != _wstat64(fileName16, &filestat)) { if (_wstat64(Utf8ToWide(pFile).c_str(), &filestat) != 0) {
return false; return false;
} }
} else { #else
#endif
FILE* file = ::fopen(pFile, "rb"); FILE* file = ::fopen(pFile, "rb");
if (!file) if (!file)
return false; return false;
::fclose(file); ::fclose(file);
#ifndef WindowsStore
}
#endif
#else
FILE* file = ::fopen( pFile, "rb");
if( !file)
return false;
::fclose( file);
#endif #endif
return true; return true;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Open a new file with a given path. // Open a new file with a given path.
IOStream* DefaultIOSystem::Open( const char* strFile, const char* strMode) IOStream* DefaultIOSystem::Open(const char* strFile, const char* strMode)
{ {
ai_assert(NULL != strFile); ai_assert(strFile != nullptr);
ai_assert(NULL != strMode); ai_assert(strMode != nullptr);
FILE* file; FILE* file;
#ifdef _WIN32 #ifdef _WIN32
wchar_t fileName16[PATHLIMIT]; file = ::_wfopen(Utf8ToWide(strFile).c_str(), Utf8ToWide(strMode).c_str());
#ifndef WindowsStore
bool isUnicode = IsTextUnicode(strFile, static_cast<int>(strlen(strFile)), NULL) != 0;
if (isUnicode) {
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, strFile, -1, fileName16, PATHLIMIT);
std::string mode8(strMode);
file = ::_wfopen(fileName16, std::wstring(mode8.begin(), mode8.end()).c_str());
} else {
#endif
file = ::fopen(strFile, strMode);
#ifndef WindowsStore
}
#endif
#else #else
file = ::fopen(strFile, strMode); file = ::fopen(strFile, strMode);
#endif #endif
if (nullptr == file) if (!file)
return nullptr; return nullptr;
return new DefaultIOStream(file, (std::string) strFile); return new DefaultIOStream(file, strFile);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Closes the given file and releases all resources associated with it. // Closes the given file and releases all resources associated with it.
void DefaultIOSystem::Close( IOStream* pFile) void DefaultIOSystem::Close(IOStream* pFile)
{ {
delete pFile; delete pFile;
} }
@ -155,78 +138,56 @@ char DefaultIOSystem::getOsSeparator() const
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// IOSystem default implementation (ComparePaths isn't a pure virtual function) // IOSystem default implementation (ComparePaths isn't a pure virtual function)
bool IOSystem::ComparePaths (const char* one, const char* second) const bool IOSystem::ComparePaths(const char* one, const char* second) const
{ {
return !ASSIMP_stricmp(one,second); return !ASSIMP_stricmp(one, second);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Convert a relative path into an absolute path // Convert a relative path into an absolute path
inline static void MakeAbsolutePath (const char* in, char* _out) inline static std::string MakeAbsolutePath(const char* in)
{ {
ai_assert(in && _out); ai_assert(in);
#if defined( _MSC_VER ) || defined( __MINGW32__ ) std::string out;
#ifndef WindowsStore #ifdef _WIN32
bool isUnicode = IsTextUnicode(in, static_cast<int>(strlen(in)), NULL) != 0; wchar_t* ret = ::_wfullpath(nullptr, Utf8ToWide(in).c_str(), 0);
if (isUnicode) {
wchar_t out16[PATHLIMIT];
wchar_t in16[PATHLIMIT];
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, in, -1, out16, PATHLIMIT);
wchar_t* ret = ::_wfullpath(out16, in16, PATHLIMIT);
if (ret) { if (ret) {
WideCharToMultiByte(CP_UTF8, MB_PRECOMPOSED, out16, -1, _out, PATHLIMIT, nullptr, nullptr); out = WideToUtf8(ret);
free(ret);
} }
if (!ret) {
// preserve the input path, maybe someone else is able to fix
// the path before it is accessed (e.g. our file system filter)
ASSIMP_LOG_WARN_F("Invalid path: ", std::string(in));
strcpy(_out, in);
}
} else {
#endif
char* ret = :: _fullpath(_out, in, PATHLIMIT);
if (!ret) {
// preserve the input path, maybe someone else is able to fix
// the path before it is accessed (e.g. our file system filter)
ASSIMP_LOG_WARN_F("Invalid path: ", std::string(in));
strcpy(_out, in);
}
#ifndef WindowsStore
}
#endif
#else #else
// use realpath char* ret = realpath(in, nullptr);
char* ret = realpath(in, _out); if (ret) {
if(!ret) { out = ret;
free(ret);
}
#endif
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)
ASSIMP_LOG_WARN_F("Invalid path: ", std::string(in)); ASSIMP_LOG_WARN_F("Invalid path: ", std::string(in));
strcpy(_out,in); out = in;
} }
#endif return out;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// DefaultIOSystem's more specialized implementation // DefaultIOSystem's more specialized implementation
bool DefaultIOSystem::ComparePaths (const char* one, const char* second) const bool DefaultIOSystem::ComparePaths(const char* one, const char* second) const
{ {
// chances are quite good both paths are formatted identically, // chances are quite good both paths are formatted identically,
// so we can hopefully return here already // so we can hopefully return here already
if( !ASSIMP_stricmp(one,second) ) if (!ASSIMP_stricmp(one, second))
return true; return true;
char temp1[PATHLIMIT]; std::string temp1 = MakeAbsolutePath(one);
char temp2[PATHLIMIT]; std::string temp2 = MakeAbsolutePath(second);
MakeAbsolutePath (one, temp1); return !ASSIMP_stricmp(temp1, temp2);
MakeAbsolutePath (second, temp2);
return !ASSIMP_stricmp(temp1,temp2);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::string DefaultIOSystem::fileName( const std::string &path ) std::string DefaultIOSystem::fileName(const std::string& path)
{ {
std::string ret = path; std::string ret = path;
std::size_t last = ret.find_last_of("\\/"); std::size_t last = ret.find_last_of("\\/");
@ -235,16 +196,16 @@ std::string DefaultIOSystem::fileName( const std::string &path )
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::string DefaultIOSystem::completeBaseName( const std::string &path ) std::string DefaultIOSystem::completeBaseName(const std::string& path)
{ {
std::string ret = fileName(path); std::string ret = fileName(path);
std::size_t pos = ret.find_last_of('.'); std::size_t pos = ret.find_last_of('.');
if(pos != ret.npos) ret = ret.substr(0, pos); if (pos != std::string::npos) ret = ret.substr(0, pos);
return ret; return ret;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::string DefaultIOSystem::absolutePath( const std::string &path ) std::string DefaultIOSystem::absolutePath(const std::string& path)
{ {
std::string ret = path; std::string ret = path;
std::size_t last = ret.find_last_of("\\/"); std::size_t last = ret.find_last_of("\\/");
@ -253,5 +214,3 @@ std::string DefaultIOSystem::absolutePath( const std::string &path )
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
#undef PATHLIMIT

View File

@ -121,7 +121,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams,
}; };
// For compilers without dead code path detection // For compilers without dead code path detection
return NULL; return nullptr;
} }
// ---------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------

View File

@ -102,94 +102,92 @@ void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperti
void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneFBX(const char*, IOSystem*, const aiScene*, const ExportProperties*);
void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneFBXA(const char*, IOSystem*, const aiScene*, const ExportProperties*);
void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* ); void ExportScene3MF( const char*, IOSystem*, const aiScene*, const ExportProperties* );
void ExportSceneM3D(const char*, IOSystem*, const aiScene*, const ExportProperties*);
void ExportSceneA3D(const char*, IOSystem*, const aiScene*, const ExportProperties*);
void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*); void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*);
// ------------------------------------------------------------------------------------------------
// global array of all export formats which Assimp supports in its current build static void setupExporterArray(std::vector<Exporter::ExportFormatEntry> &exporters) {
Exporter::ExportFormatEntry gExporters[] =
{
#ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER
Exporter::ExportFormatEntry( "collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada ), exporters.push_back(Exporter::ExportFormatEntry("collada", "COLLADA - Digital Asset Exchange Schema", "dae", &ExportSceneCollada));
#endif #endif
#ifndef ASSIMP_BUILD_NO_X_EXPORTER #ifndef ASSIMP_BUILD_NO_X_EXPORTER
Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile, exporters.push_back(Exporter::ExportFormatEntry("x", "X Files", "x", &ExportSceneXFile,
aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs ), aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs));
#endif #endif
#ifndef ASSIMP_BUILD_NO_STEP_EXPORTER #ifndef ASSIMP_BUILD_NO_STEP_EXPORTER
Exporter::ExportFormatEntry( "stp", "Step Files", "stp", &ExportSceneStep, 0 ), exporters.push_back(Exporter::ExportFormatEntry("stp", "Step Files", "stp", &ExportSceneStep, 0));
#endif #endif
#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER #ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
Exporter::ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj, exporters.push_back(Exporter::ExportFormatEntry("obj", "Wavefront OBJ format", "obj", &ExportSceneObj,
aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */ ), aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */));
Exporter::ExportFormatEntry( "objnomtl", "Wavefront OBJ format without material file", "obj", &ExportSceneObjNoMtl, exporters.push_back(Exporter::ExportFormatEntry("objnomtl", "Wavefront OBJ format without material file", "obj", &ExportSceneObjNoMtl,
aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */ ), aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */));
#endif #endif
#ifndef ASSIMP_BUILD_NO_STL_EXPORTER #ifndef ASSIMP_BUILD_NO_STL_EXPORTER
Exporter::ExportFormatEntry( "stl", "Stereolithography", "stl" , &ExportSceneSTL, exporters.push_back(Exporter::ExportFormatEntry("stl", "Stereolithography", "stl", &ExportSceneSTL,
aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices));
), exporters.push_back(Exporter::ExportFormatEntry("stlb", "Stereolithography (binary)", "stl", &ExportSceneSTLBinary,
Exporter::ExportFormatEntry( "stlb", "Stereolithography (binary)", "stl" , &ExportSceneSTLBinary, aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices));
aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
),
#endif #endif
#ifndef ASSIMP_BUILD_NO_PLY_EXPORTER #ifndef ASSIMP_BUILD_NO_PLY_EXPORTER
Exporter::ExportFormatEntry( "ply", "Stanford Polygon Library", "ply" , &ExportScenePly, exporters.push_back(Exporter::ExportFormatEntry("ply", "Stanford Polygon Library", "ply", &ExportScenePly,
aiProcess_PreTransformVertices aiProcess_PreTransformVertices));
), exporters.push_back(Exporter::ExportFormatEntry("plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary,
Exporter::ExportFormatEntry( "plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary, aiProcess_PreTransformVertices));
aiProcess_PreTransformVertices
),
#endif #endif
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER #ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
Exporter::ExportFormatEntry( "3ds", "Autodesk 3DS (legacy)", "3ds" , &ExportScene3DS, exporters.push_back(Exporter::ExportFormatEntry("3ds", "Autodesk 3DS (legacy)", "3ds", &ExportScene3DS,
aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices ), aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices));
#endif #endif
#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER #ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER
Exporter::ExportFormatEntry( "gltf2", "GL Transmission Format v. 2", "gltf", &ExportSceneGLTF2, exporters.push_back(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)", "glb", &ExportSceneGLB2, exporters.push_back(Exporter::ExportFormatEntry("glb2", "GL Transmission Format v. 2 (binary)", "glb", &ExportSceneGLB2,
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType));
Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF, exporters.push_back(Exporter::ExportFormatEntry("gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF,
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType));
Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB, exporters.push_back(Exporter::ExportFormatEntry("glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ), aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType));
#endif #endif
#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0 ), exporters.push_back(Exporter::ExportFormatEntry("assbin", "Assimp Binary File", "assbin", &ExportSceneAssbin, 0));
#endif #endif
#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER #ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
Exporter::ExportFormatEntry( "assxml", "Assxml Document", "assxml" , &ExportSceneAssxml, 0 ), exporters.push_back(Exporter::ExportFormatEntry("assxml", "Assimp XML Document", "assxml", &ExportSceneAssxml, 0));
#endif #endif
#ifndef ASSIMP_BUILD_NO_X3D_EXPORTER #ifndef ASSIMP_BUILD_NO_X3D_EXPORTER
Exporter::ExportFormatEntry( "x3d", "Extensible 3D", "x3d" , &ExportSceneX3D, 0 ), exporters.push_back(Exporter::ExportFormatEntry("x3d", "Extensible 3D", "x3d", &ExportSceneX3D, 0));
#endif #endif
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER #ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
Exporter::ExportFormatEntry( "fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0 ), exporters.push_back(Exporter::ExportFormatEntry("fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0));
Exporter::ExportFormatEntry( "fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0 ), exporters.push_back(Exporter::ExportFormatEntry("fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0));
#endif
#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER
exporters.push_back(Exporter::ExportFormatEntry("m3d", "Model 3D (binary)", "m3d", &ExportSceneM3D, 0));
exporters.push_back(Exporter::ExportFormatEntry("a3d", "Model 3D (ascii)", "m3d", &ExportSceneA3D, 0));
#endif #endif
#ifndef ASSIMP_BUILD_NO_3MF_EXPORTER #ifndef ASSIMP_BUILD_NO_3MF_EXPORTER
Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 ), exporters.push_back(Exporter::ExportFormatEntry("3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0));
#endif #endif
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER #ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
Exporter::ExportFormatEntry("json", "Plain JSON representation of the Assimp scene data structure", "json", &ExportAssimp2Json, 0) exporters.push_back(Exporter::ExportFormatEntry("assjson", "Assimp JSON Document", "json", &ExportAssimp2Json, 0));
#endif #endif
}; }
#define ASSIMP_NUM_EXPORTERS (sizeof(gExporters)/sizeof(gExporters[0]))
class ExporterPimpl { class ExporterPimpl {
public: public:
@ -205,10 +203,7 @@ public:
GetPostProcessingStepInstanceList(mPostProcessingSteps); GetPostProcessingStepInstanceList(mPostProcessingSteps);
// grab all built-in exporters // grab all built-in exporters
if ( 0 != ( ASSIMP_NUM_EXPORTERS ) ) { setupExporterArray(mExporters);
mExporters.resize( ASSIMP_NUM_EXPORTERS );
std::copy( gExporters, gExporters + ASSIMP_NUM_EXPORTERS, mExporters.begin() );
}
} }
~ExporterPimpl() { ~ExporterPimpl() {
@ -252,23 +247,27 @@ Exporter :: Exporter()
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Exporter::~Exporter() { Exporter::~Exporter() {
ai_assert(nullptr != pimpl);
FreeBlob(); FreeBlob();
delete pimpl; delete pimpl;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Exporter::SetIOHandler( IOSystem* pIOHandler) { void Exporter::SetIOHandler( IOSystem* pIOHandler) {
ai_assert(nullptr != pimpl);
pimpl->mIsDefaultIOHandler = !pIOHandler; pimpl->mIsDefaultIOHandler = !pIOHandler;
pimpl->mIOSystem.reset(pIOHandler); pimpl->mIOSystem.reset(pIOHandler);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
IOSystem* Exporter::GetIOHandler() const { IOSystem* Exporter::GetIOHandler() const {
ai_assert(nullptr != pimpl);
return pimpl->mIOSystem.get(); return pimpl->mIOSystem.get();
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
bool Exporter::IsDefaultIOHandler() const { bool Exporter::IsDefaultIOHandler() const {
ai_assert(nullptr != pimpl);
return pimpl->mIsDefaultIOHandler; return pimpl->mIsDefaultIOHandler;
} }
@ -295,6 +294,7 @@ void Exporter::SetProgressHandler(ProgressHandler* pHandler) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const char* pFormatId, const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const char* pFormatId,
unsigned int pPreprocessing, const ExportProperties* pProperties) { unsigned int pPreprocessing, const ExportProperties* pProperties) {
ai_assert(nullptr != pimpl);
if (pimpl->blob) { if (pimpl->blob) {
delete pimpl->blob; delete pimpl->blob;
pimpl->blob = nullptr; pimpl->blob = nullptr;
@ -315,44 +315,16 @@ const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const cha
return pimpl->blob; return pimpl->blob;
} }
// ------------------------------------------------------------------------------------------------
bool IsVerboseFormat(const aiMesh* mesh) {
// avoid slow vector<bool> specialization
std::vector<unsigned int> seen(mesh->mNumVertices,0);
for(unsigned int i = 0; i < mesh->mNumFaces; ++i) {
const aiFace& f = mesh->mFaces[i];
for(unsigned int j = 0; j < f.mNumIndices; ++j) {
if(++seen[f.mIndices[j]] == 2) {
// found a duplicate index
return false;
}
}
}
return true;
}
// ------------------------------------------------------------------------------------------------
bool IsVerboseFormat(const aiScene* pScene) {
for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
if(!IsVerboseFormat(pScene->mMeshes[i])) {
return false;
}
}
return true;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath, aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath,
unsigned int pPreprocessing, const ExportProperties* pProperties) { unsigned int pPreprocessing, const ExportProperties* pProperties) {
ASSIMP_BEGIN_EXCEPTION_REGION(); ASSIMP_BEGIN_EXCEPTION_REGION();
ai_assert(nullptr != pimpl);
// 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
// format. They will likely not be aware that there is a flag in the scene to indicate // format. They will likely not be aware that there is a flag in the scene to indicate
// this, however. To avoid surprises and bug reports, we check for duplicates in // this, however. To avoid surprises and bug reports, we check for duplicates in
// meshes upfront. // meshes upfront.
const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || IsVerboseFormat(pScene); const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || MakeVerboseFormatProcess::IsVerboseFormat(pScene);
pimpl->mProgressHandler->UpdateFileWrite(0, 4); pimpl->mProgressHandler->UpdateFileWrite(0, 4);
@ -472,7 +444,10 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
} }
ExportProperties emptyProperties; // Never pass NULL ExportProperties so Exporters don't have to worry. ExportProperties emptyProperties; // Never pass NULL ExportProperties so Exporters don't have to worry.
exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProperties ? pProperties : &emptyProperties); ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties;
pProp->SetPropertyBool("bJoinIdenticalVertices", must_join_again);
exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp);
exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp);
pimpl->mProgressHandler->UpdateFileWrite(4, 4); pimpl->mProgressHandler->UpdateFileWrite(4, 4);
} catch (DeadlyExportError& err) { } catch (DeadlyExportError& err) {
@ -491,11 +466,13 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const char* Exporter::GetErrorString() const { const char* Exporter::GetErrorString() const {
ai_assert(nullptr != pimpl);
return pimpl->mError.c_str(); return pimpl->mError.c_str();
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void Exporter::FreeBlob() { void Exporter::FreeBlob() {
ai_assert(nullptr != pimpl);
delete pimpl->blob; delete pimpl->blob;
pimpl->blob = nullptr; pimpl->blob = nullptr;
@ -504,30 +481,34 @@ void Exporter::FreeBlob() {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const aiExportDataBlob* Exporter::GetBlob() const { const aiExportDataBlob* Exporter::GetBlob() const {
ai_assert(nullptr != pimpl);
return pimpl->blob; return pimpl->blob;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const aiExportDataBlob* Exporter::GetOrphanedBlob() const { const aiExportDataBlob* Exporter::GetOrphanedBlob() const {
const aiExportDataBlob* tmp = pimpl->blob; ai_assert(nullptr != pimpl);
const aiExportDataBlob *tmp = pimpl->blob;
pimpl->blob = nullptr; pimpl->blob = nullptr;
return tmp; return tmp;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
size_t Exporter::GetExportFormatCount() const { size_t Exporter::GetExportFormatCount() const {
ai_assert(nullptr != pimpl);
return pimpl->mExporters.size(); return pimpl->mExporters.size();
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
const aiExportFormatDesc* Exporter::GetExportFormatDescription( size_t index ) const { const aiExportFormatDesc* Exporter::GetExportFormatDescription( size_t index ) const {
ai_assert(nullptr != pimpl);
if (index >= GetExportFormatCount()) { if (index >= GetExportFormatCount()) {
return nullptr; return nullptr;
} }
// Return from static storage if the requested index is built-in. // Return from static storage if the requested index is built-in.
if (index < sizeof(gExporters) / sizeof(gExporters[0])) { if (index < pimpl->mExporters.size()) {
return &gExporters[index].mDescription; return &pimpl->mExporters[index].mDescription;
} }
return &pimpl->mExporters[index].mDescription; return &pimpl->mExporters[index].mDescription;
@ -535,7 +516,8 @@ const aiExportFormatDesc* Exporter::GetExportFormatDescription( size_t index ) c
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
aiReturn Exporter::RegisterExporter(const ExportFormatEntry& desc) { aiReturn Exporter::RegisterExporter(const ExportFormatEntry& desc) {
for(const ExportFormatEntry& e : pimpl->mExporters) { ai_assert(nullptr != pimpl);
for (const ExportFormatEntry &e : pimpl->mExporters) {
if (!strcmp(e.mDescription.id,desc.mDescription.id)) { if (!strcmp(e.mDescription.id,desc.mDescription.id)) {
return aiReturn_FAILURE; return aiReturn_FAILURE;
} }
@ -547,7 +529,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(); ai_assert(nullptr != pimpl);
for (std::vector<ExportFormatEntry>::iterator it = pimpl->mExporters.begin();
it != pimpl->mExporters.end(); ++it) { 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);

View File

@ -197,6 +197,9 @@ corresponding preprocessor flag to selectively disable formats.
#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER #ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
# include "MMD/MMDImporter.h" # include "MMD/MMDImporter.h"
#endif #endif
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
# include "M3D/M3DImporter.h"
#endif
#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER #ifndef ASSIMP_BUILD_NO_STEP_IMPORTER
# include "Importer/StepFile/StepFileImporter.h" # include "Importer/StepFile/StepFileImporter.h"
#endif #endif
@ -223,6 +226,9 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out)
#if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER) #if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER)
out.push_back( new Discreet3DSImporter()); out.push_back( new Discreet3DSImporter());
#endif #endif
#if (!defined ASSIMP_BUILD_NO_M3D_IMPORTER)
out.push_back( new M3DImporter());
#endif
#if (!defined ASSIMP_BUILD_NO_MD3_IMPORTER) #if (!defined ASSIMP_BUILD_NO_MD3_IMPORTER)
out.push_back( new MD3Importer()); out.push_back( new MD3Importer());
#endif #endif

View File

@ -131,11 +131,15 @@ corresponding preprocessor flag to selectively disable steps.
#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS) #if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
# include "PostProcessing/ScaleProcess.h" # include "PostProcessing/ScaleProcess.h"
#endif #endif
#if (!defined ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS)
# include "PostProcessing/ArmaturePopulate.h"
#endif
#if (!defined ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS) #if (!defined ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS)
# include "PostProcessing/GenBoundingBoxesProcess.h" # include "PostProcessing/GenBoundingBoxesProcess.h"
#endif #endif
namespace Assimp { namespace Assimp {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -180,6 +184,9 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS) #if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
out.push_back( new ScaleProcess()); out.push_back( new ScaleProcess());
#endif #endif
#if (!defined ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS)
out.push_back( new ArmaturePopulate());
#endif
#if (!defined ASSIMP_BUILD_NO_PRETRANSFORMVERTICES_PROCESS) #if (!defined ASSIMP_BUILD_NO_PRETRANSFORMVERTICES_PROCESS)
out.push_back( new PretransformVertices()); out.push_back( new PretransformVertices());
#endif #endif

View File

@ -1091,6 +1091,35 @@ void SceneCombiner::Copy( aiMesh** _dest, const aiMesh* src ) {
aiFace& f = dest->mFaces[i]; aiFace& f = dest->mFaces[i];
GetArrayCopy(f.mIndices,f.mNumIndices); GetArrayCopy(f.mIndices,f.mNumIndices);
} }
// make a deep copy of all blend shapes
CopyPtrArray(dest->mAnimMeshes, dest->mAnimMeshes, dest->mNumAnimMeshes);
}
// ------------------------------------------------------------------------------------------------
void SceneCombiner::Copy(aiAnimMesh** _dest, const aiAnimMesh* src) {
if (nullptr == _dest || nullptr == src) {
return;
}
aiAnimMesh* dest = *_dest = new aiAnimMesh();
// get a flat copy
::memcpy(dest, src, sizeof(aiAnimMesh));
// and reallocate all arrays
GetArrayCopy(dest->mVertices, dest->mNumVertices);
GetArrayCopy(dest->mNormals, dest->mNumVertices);
GetArrayCopy(dest->mTangents, dest->mNumVertices);
GetArrayCopy(dest->mBitangents, dest->mNumVertices);
unsigned int n = 0;
while (dest->HasTextureCoords(n))
GetArrayCopy(dest->mTextureCoords[n++], dest->mNumVertices);
n = 0;
while (dest->HasVertexColors(n))
GetArrayCopy(dest->mColors[n++], dest->mNumVertices);
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1167,6 +1196,7 @@ void SceneCombiner::Copy( aiAnimation** _dest, const aiAnimation* src ) {
// and reallocate all arrays // and reallocate all arrays
CopyPtrArray( dest->mChannels, src->mChannels, dest->mNumChannels ); CopyPtrArray( dest->mChannels, src->mChannels, dest->mNumChannels );
CopyPtrArray( dest->mMorphMeshChannels, src->mMorphMeshChannels, dest->mNumMorphMeshChannels );
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -1186,6 +1216,26 @@ void SceneCombiner::Copy(aiNodeAnim** _dest, const aiNodeAnim* src) {
GetArrayCopy( dest->mRotationKeys, dest->mNumRotationKeys ); GetArrayCopy( dest->mRotationKeys, dest->mNumRotationKeys );
} }
void SceneCombiner::Copy(aiMeshMorphAnim** _dest, const aiMeshMorphAnim* src) {
if ( nullptr == _dest || nullptr == src ) {
return;
}
aiMeshMorphAnim* dest = *_dest = new aiMeshMorphAnim();
// get a flat copy
::memcpy(dest,src,sizeof(aiMeshMorphAnim));
// and reallocate all arrays
GetArrayCopy( dest->mKeys, dest->mNumKeys );
for (ai_uint i = 0; i < dest->mNumKeys;++i) {
dest->mKeys[i].mValues = new unsigned int[dest->mKeys[i].mNumValuesAndWeights];
dest->mKeys[i].mWeights = new double[dest->mKeys[i].mNumValuesAndWeights];
::memcpy(dest->mKeys[i].mValues, src->mKeys[i].mValues, dest->mKeys[i].mNumValuesAndWeights * sizeof(unsigned int));
::memcpy(dest->mKeys[i].mWeights, src->mKeys[i].mWeights, dest->mKeys[i].mNumValuesAndWeights * sizeof(double));
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void SceneCombiner::Copy( aiCamera** _dest,const aiCamera* src) { void SceneCombiner::Copy( aiCamera** _dest,const aiCamera* src) {
if ( nullptr == _dest || nullptr == src ) { if ( nullptr == _dest || nullptr == src ) {

View File

@ -46,8 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/scene.h> #include <assimp/scene.h>
#include "ScenePrivate.h" #include "ScenePrivate.h"
static const unsigned int MajorVersion = 4; #include "revision.h"
static const unsigned int MinorVersion = 1;
// -------------------------------------------------------------------------------- // --------------------------------------------------------------------------------
// Legal information string - don't remove this. // Legal information string - don't remove this.
@ -56,9 +55,9 @@ static const char* LEGAL_INFORMATION =
"Open Asset Import Library (Assimp).\n" "Open Asset Import Library (Assimp).\n"
"A free C/C++ library to import various 3D file formats into applications\n\n" "A free C/C++ library to import various 3D file formats into applications\n\n"
"(c) 2008-2017, assimp team\n" "(c) 2006-2019, assimp team\n"
"License under the terms and conditions of the 3-clause BSD license\n" "License under the terms and conditions of the 3-clause BSD license\n"
"http://assimp.sourceforge.net\n" "http://assimp.org\n"
; ;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -67,16 +66,22 @@ ASSIMP_API const char* aiGetLegalString () {
return LEGAL_INFORMATION; return LEGAL_INFORMATION;
} }
// ------------------------------------------------------------------------------------------------
// Get Assimp patch version
ASSIMP_API unsigned int aiGetVersionPatch() {
return VER_PATCH;
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get Assimp minor version // Get Assimp minor version
ASSIMP_API unsigned int aiGetVersionMinor () { ASSIMP_API unsigned int aiGetVersionMinor () {
return MinorVersion; return VER_MINOR;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Get Assimp major version // Get Assimp major version
ASSIMP_API unsigned int aiGetVersionMajor () { ASSIMP_API unsigned int aiGetVersionMajor () {
return MajorVersion; return VER_MAJOR;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
@ -104,9 +109,6 @@ ASSIMP_API unsigned int aiGetCompileFlags () {
return flags; return flags;
} }
// include current build revision, which is even updated from time to time -- :-)
#include "revision.h"
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
ASSIMP_API unsigned int aiGetVersionRevision() { ASSIMP_API unsigned int aiGetVersionRevision() {
return GitVersion; return GitVersion;

View File

@ -0,0 +1,539 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, 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 ZipArchiveIOSystem.cpp
* @brief Zip File I/O implementation for #Importer
*/
#include <assimp/ZipArchiveIOSystem.h>
#include <assimp/BaseImporter.h>
#include <assimp/ai_assert.h>
#include <map>
#include <memory>
#ifdef ASSIMP_USE_HUNTER
# include <minizip/unzip.h>
#else
# include <unzip.h>
#endif
namespace Assimp {
// ----------------------------------------------------------------
// Wraps an existing Assimp::IOSystem for unzip
class IOSystem2Unzip {
public:
static voidpf open(voidpf opaque, const char* filename, int mode);
static uLong read(voidpf opaque, voidpf stream, void* buf, uLong size);
static uLong write(voidpf opaque, voidpf stream, const void* buf, uLong size);
static long tell(voidpf opaque, voidpf stream);
static long seek(voidpf opaque, voidpf stream, uLong offset, int origin);
static int close(voidpf opaque, voidpf stream);
static int testerror(voidpf opaque, voidpf stream);
static zlib_filefunc_def get(IOSystem* pIOHandler);
};
voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) {
IOSystem* io_system = reinterpret_cast<IOSystem*>(opaque);
const char* mode_fopen = nullptr;
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) {
mode_fopen = "rb";
}
else {
if (mode & ZLIB_FILEFUNC_MODE_EXISTING) {
mode_fopen = "r+b";
}
else {
if (mode & ZLIB_FILEFUNC_MODE_CREATE) {
mode_fopen = "wb";
}
}
}
return (voidpf)io_system->Open(filename, mode_fopen);
}
uLong IOSystem2Unzip::read(voidpf /*opaque*/, voidpf stream, void* buf, uLong size) {
IOStream* io_stream = (IOStream*)stream;
return static_cast<uLong>(io_stream->Read(buf, 1, size));
}
uLong IOSystem2Unzip::write(voidpf /*opaque*/, voidpf stream, const void* buf, uLong size) {
IOStream* io_stream = (IOStream*)stream;
return static_cast<uLong>(io_stream->Write(buf, 1, size));
}
long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) {
IOStream* io_stream = (IOStream*)stream;
return static_cast<long>(io_stream->Tell());
}
long IOSystem2Unzip::seek(voidpf /*opaque*/, voidpf stream, uLong offset, int origin) {
IOStream* io_stream = (IOStream*)stream;
aiOrigin assimp_origin;
switch (origin) {
default:
case ZLIB_FILEFUNC_SEEK_CUR:
assimp_origin = aiOrigin_CUR;
break;
case ZLIB_FILEFUNC_SEEK_END:
assimp_origin = aiOrigin_END;
break;
case ZLIB_FILEFUNC_SEEK_SET:
assimp_origin = aiOrigin_SET;
break;
}
return (io_stream->Seek(offset, assimp_origin) == aiReturn_SUCCESS ? 0 : -1);
}
int IOSystem2Unzip::close(voidpf opaque, voidpf stream) {
IOSystem* io_system = (IOSystem*)opaque;
IOStream* io_stream = (IOStream*)stream;
io_system->Close(io_stream);
return 0;
}
int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) {
return 0;
}
zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) {
zlib_filefunc_def mapping;
#ifdef ASSIMP_USE_HUNTER
mapping.zopen_file = (open_file_func)open;
mapping.zread_file = (read_file_func)read;
mapping.zwrite_file = (write_file_func)write;
mapping.ztell_file = (tell_file_func)tell;
mapping.zseek_file = (seek_file_func)seek;
mapping.zclose_file = (close_file_func)close;
mapping.zerror_file = (error_file_func)testerror;
#else
mapping.zopen_file = open;
mapping.zread_file = read;
mapping.zwrite_file = write;
mapping.ztell_file = tell;
mapping.zseek_file = seek;
mapping.zclose_file = close;
mapping.zerror_file = testerror;
#endif
mapping.opaque = reinterpret_cast<voidpf>(pIOHandler);
return mapping;
}
// ----------------------------------------------------------------
// A read-only file inside a ZIP
class ZipFile : public IOStream {
friend class ZipFileInfo;
explicit ZipFile(size_t size);
public:
virtual ~ZipFile();
// IOStream interface
size_t Read(void* pvBuffer, size_t pSize, size_t pCount) override;
size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) override { return 0; }
size_t FileSize() const override;
aiReturn Seek(size_t pOffset, aiOrigin pOrigin) override;
size_t Tell() const override;
void Flush() override {}
private:
size_t m_Size = 0;
size_t m_SeekPtr = 0;
std::unique_ptr<uint8_t[]> m_Buffer;
};
// ----------------------------------------------------------------
// Info about a read-only file inside a ZIP
class ZipFileInfo
{
public:
explicit ZipFileInfo(unzFile zip_handle, size_t size);
// Allocate and Extract data from the ZIP
ZipFile * Extract(unzFile zip_handle) const;
private:
size_t m_Size = 0;
unz_file_pos_s m_ZipFilePos;
};
ZipFileInfo::ZipFileInfo(unzFile zip_handle, size_t size)
: m_Size(size) {
ai_assert(m_Size != 0);
// Workaround for MSVC 2013 - C2797
m_ZipFilePos.num_of_file = 0;
m_ZipFilePos.pos_in_zip_directory = 0;
unzGetFilePos(zip_handle, &(m_ZipFilePos));
}
ZipFile * ZipFileInfo::Extract(unzFile zip_handle) const {
// Find in the ZIP. This cannot fail
unz_file_pos_s *filepos = const_cast<unz_file_pos_s*>(&(m_ZipFilePos));
if (unzGoToFilePos(zip_handle, filepos) != UNZ_OK)
return nullptr;
if (unzOpenCurrentFile(zip_handle) != UNZ_OK)
return nullptr;
ZipFile *zip_file = new ZipFile(m_Size);
if (unzReadCurrentFile(zip_handle, zip_file->m_Buffer.get(), static_cast<unsigned int>(m_Size)) != static_cast<int>(m_Size))
{
// Failed, release the memory
delete zip_file;
zip_file = nullptr;
}
ai_assert(unzCloseCurrentFile(zip_handle) == UNZ_OK);
return zip_file;
}
ZipFile::ZipFile(size_t size)
: m_Size(size) {
ai_assert(m_Size != 0);
m_Buffer = std::unique_ptr<uint8_t[]>(new uint8_t[m_Size]);
}
ZipFile::~ZipFile() {
}
size_t ZipFile::Read(void* pvBuffer, size_t pSize, size_t pCount) {
// Should be impossible
ai_assert(m_Buffer != nullptr);
ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount);
// Clip down to file size
size_t byteSize = pSize * pCount;
if ((byteSize + m_SeekPtr) > m_Size)
{
pCount = (m_Size - m_SeekPtr) / pSize;
byteSize = pSize * pCount;
if (byteSize == 0)
return 0;
}
std::memcpy(pvBuffer, m_Buffer.get() + m_SeekPtr, byteSize);
m_SeekPtr += byteSize;
return pCount;
}
size_t ZipFile::FileSize() const {
return m_Size;
}
aiReturn ZipFile::Seek(size_t pOffset, aiOrigin pOrigin) {
switch (pOrigin)
{
case aiOrigin_SET: {
if (pOffset > m_Size) return aiReturn_FAILURE;
m_SeekPtr = pOffset;
return aiReturn_SUCCESS;
}
case aiOrigin_CUR: {
if ((pOffset + m_SeekPtr) > m_Size) return aiReturn_FAILURE;
m_SeekPtr += pOffset;
return aiReturn_SUCCESS;
}
case aiOrigin_END: {
if (pOffset > m_Size) return aiReturn_FAILURE;
m_SeekPtr = m_Size - pOffset;
return aiReturn_SUCCESS;
}
default:;
}
return aiReturn_FAILURE;
}
size_t ZipFile::Tell() const {
return m_SeekPtr;
}
// ----------------------------------------------------------------
// pImpl of the Zip Archive IO
class ZipArchiveIOSystem::Implement {
public:
static const unsigned int FileNameSize = 256;
Implement(IOSystem* pIOHandler, const char* pFilename, const char* pMode);
~Implement();
bool isOpen() const;
void getFileList(std::vector<std::string>& rFileList);
void getFileListExtension(std::vector<std::string>& rFileList, const std::string& extension);
bool Exists(std::string& filename);
IOStream* OpenFile(std::string& filename);
static void SimplifyFilename(std::string& filename);
private:
void MapArchive();
private:
typedef std::map<std::string, ZipFileInfo> ZipFileInfoMap;
unzFile m_ZipFileHandle = nullptr;
ZipFileInfoMap m_ArchiveMap;
};
ZipArchiveIOSystem::Implement::Implement(IOSystem* pIOHandler, const char* pFilename, const char* pMode) {
ai_assert(strcmp(pMode, "r") == 0);
ai_assert(pFilename != nullptr);
if (pFilename[0] == 0)
return;
zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);
m_ZipFileHandle = unzOpen2(pFilename, &mapping);
}
ZipArchiveIOSystem::Implement::~Implement() {
m_ArchiveMap.clear();
if (m_ZipFileHandle != nullptr) {
unzClose(m_ZipFileHandle);
m_ZipFileHandle = nullptr;
}
}
void ZipArchiveIOSystem::Implement::MapArchive() {
if (m_ZipFileHandle == nullptr)
return;
if (!m_ArchiveMap.empty())
return;
// At first ensure file is already open
if (unzGoToFirstFile(m_ZipFileHandle) != UNZ_OK)
return;
// Loop over all files
do {
char filename[FileNameSize];
unz_file_info fileInfo;
if (unzGetCurrentFileInfo(m_ZipFileHandle, &fileInfo, filename, FileNameSize, nullptr, 0, nullptr, 0) == UNZ_OK) {
if (fileInfo.uncompressed_size != 0) {
std::string filename_string(filename, fileInfo.size_filename);
SimplifyFilename(filename_string);
m_ArchiveMap.emplace(filename_string, ZipFileInfo(m_ZipFileHandle, fileInfo.uncompressed_size));
}
}
} while (unzGoToNextFile(m_ZipFileHandle) != UNZ_END_OF_LIST_OF_FILE);
}
bool ZipArchiveIOSystem::Implement::isOpen() const {
return (m_ZipFileHandle != nullptr);
}
void ZipArchiveIOSystem::Implement::getFileList(std::vector<std::string>& rFileList) {
MapArchive();
rFileList.clear();
for (const auto &file : m_ArchiveMap) {
rFileList.push_back(file.first);
}
}
void ZipArchiveIOSystem::Implement::getFileListExtension(std::vector<std::string>& rFileList, const std::string& extension) {
MapArchive();
rFileList.clear();
for (const auto &file : m_ArchiveMap) {
if (extension == BaseImporter::GetExtension(file.first))
rFileList.push_back(file.first);
}
}
bool ZipArchiveIOSystem::Implement::Exists(std::string& filename) {
MapArchive();
ZipFileInfoMap::const_iterator it = m_ArchiveMap.find(filename);
return (it != m_ArchiveMap.end());
}
IOStream * ZipArchiveIOSystem::Implement::OpenFile(std::string& filename) {
MapArchive();
SimplifyFilename(filename);
// Find in the map
ZipFileInfoMap::const_iterator zip_it = m_ArchiveMap.find(filename);
if (zip_it == m_ArchiveMap.cend())
return nullptr;
const ZipFileInfo &zip_file = (*zip_it).second;
return zip_file.Extract(m_ZipFileHandle);
}
inline void ReplaceAll(std::string& data, const std::string& before, const std::string& after) {
size_t pos = data.find(before);
while (pos != std::string::npos)
{
data.replace(pos, before.size(), after);
pos = data.find(before, pos + after.size());
}
}
inline void ReplaceAllChar(std::string& data, const char before, const char after) {
size_t pos = data.find(before);
while (pos != std::string::npos)
{
data[pos] = after;
pos = data.find(before, pos + 1);
}
}
void ZipArchiveIOSystem::Implement::SimplifyFilename(std::string& filename)
{
ReplaceAllChar(filename, '\\', '/');
// Remove all . and / from the beginning of the path
size_t pos = filename.find_first_not_of("./");
if (pos != 0)
filename.erase(0, pos);
// Simplify "my/folder/../file.png" constructions, if any
static const std::string relative("/../");
const size_t relsize = relative.size() - 1;
pos = filename.find(relative);
while (pos != std::string::npos)
{
// Previous slash
size_t prevpos = filename.rfind('/', pos - 1);
if (prevpos == pos)
filename.erase(0, pos + relative.size());
else
filename.erase(prevpos, pos + relsize - prevpos);
pos = filename.find(relative);
}
}
ZipArchiveIOSystem::ZipArchiveIOSystem(IOSystem* pIOHandler, const char* pFilename, const char* pMode)
: pImpl(new Implement(pIOHandler, pFilename, pMode)) {
}
// ----------------------------------------------------------------
// The ZipArchiveIO
ZipArchiveIOSystem::ZipArchiveIOSystem(IOSystem* pIOHandler, const std::string& rFilename, const char* pMode)
: pImpl(new Implement(pIOHandler, rFilename.c_str(), pMode))
{
}
ZipArchiveIOSystem::~ZipArchiveIOSystem() {
delete pImpl;
}
bool ZipArchiveIOSystem::Exists(const char* pFilename) const {
ai_assert(pFilename != nullptr);
if (pFilename == nullptr) {
return false;
}
std::string filename(pFilename);
return pImpl->Exists(filename);
}
// This is always '/' in a ZIP
char ZipArchiveIOSystem::getOsSeparator() const {
return '/';
}
// Only supports Reading
IOStream * ZipArchiveIOSystem::Open(const char* pFilename, const char* pMode) {
ai_assert(pFilename != nullptr);
for (size_t i = 0; pMode[i] != 0; ++i)
{
ai_assert(pMode[i] != 'w');
if (pMode[i] == 'w')
return nullptr;
}
std::string filename(pFilename);
return pImpl->OpenFile(filename);
}
void ZipArchiveIOSystem::Close(IOStream* pFile) {
delete pFile;
}
bool ZipArchiveIOSystem::isOpen() const {
return (pImpl->isOpen());
}
void ZipArchiveIOSystem::getFileList(std::vector<std::string>& rFileList) const {
return pImpl->getFileList(rFileList);
}
void ZipArchiveIOSystem::getFileListExtension(std::vector<std::string>& rFileList, const std::string& extension) const {
return pImpl->getFileListExtension(rFileList, extension);
}
bool ZipArchiveIOSystem::isZipArchive(IOSystem* pIOHandler, const char* pFilename) {
Implement tmp(pIOHandler, pFilename, "r");
return tmp.isOpen();
}
bool ZipArchiveIOSystem::isZipArchive(IOSystem* pIOHandler, const std::string& rFilename) {
return isZipArchive(pIOHandler, rFilename.c_str());
}
}

View File

@ -44,23 +44,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
aiNode::aiNode() aiNode::aiNode()
: mName("") : mName("")
, mParent(NULL) , mParent(nullptr)
, mNumChildren(0) , mNumChildren(0)
, mChildren(NULL) , mChildren(nullptr)
, mNumMeshes(0) , mNumMeshes(0)
, mMeshes(NULL) , mMeshes(nullptr)
, mMetaData(NULL) { , mMetaData(nullptr) {
// empty // empty
} }
aiNode::aiNode(const std::string& name) aiNode::aiNode(const std::string& name)
: mName(name) : mName(name)
, mParent(NULL) , mParent(nullptr)
, mNumChildren(0) , mNumChildren(0)
, mChildren(NULL) , mChildren(nullptr)
, mNumMeshes(0) , mNumMeshes(0)
, mMeshes(NULL) , mMeshes(nullptr)
, mMetaData(NULL) { , mMetaData(nullptr) {
// empty // empty
} }
@ -68,7 +68,7 @@ aiNode::aiNode(const std::string& name)
aiNode::~aiNode() { aiNode::~aiNode() {
// delete all children recursively // delete all children recursively
// to make sure we won't crash if the data is invalid ... // to make sure we won't crash if the data is invalid ...
if (mChildren && mNumChildren) if (mNumChildren && mChildren)
{ {
for (unsigned int a = 0; a < mNumChildren; a++) for (unsigned int a = 0; a < mNumChildren; a++)
delete mChildren[a]; delete mChildren[a];

View File

@ -50,9 +50,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp { namespace Assimp {
namespace FBX namespace FBX
{ {
const std::string NULL_RECORD = { // 13 null bytes const std::string NULL_RECORD = { // 25 null bytes in 64-bit and 13 null bytes in 32-bit
'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0' '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0',
}; // who knows why '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'
}; // who knows why, it looks like two integers 32/64 bit (compressed and uncompressed sizes?) + 1 byte (might be compression type?)
const std::string SEPARATOR = {'\x00', '\x01'}; // for use inside strings const std::string SEPARATOR = {'\x00', '\x01'}; // for use inside strings
const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import const std::string MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
const int64_t SECOND = 46186158000; // FBX's kTime unit const int64_t SECOND = 46186158000; // FBX's kTime unit

View File

@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define INCLUDED_AI_FBX_COMPILECONFIG_H #define INCLUDED_AI_FBX_COMPILECONFIG_H
#include <map> #include <map>
#include <set>
// //
#if _MSC_VER > 1500 || (defined __GNUC___) #if _MSC_VER > 1500 || (defined __GNUC___)
@ -54,16 +55,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# else # else
# define fbx_unordered_map map # define fbx_unordered_map map
# define fbx_unordered_multimap multimap # define fbx_unordered_multimap multimap
# define fbx_unordered_set set
# define fbx_unordered_multiset multiset
#endif #endif
#ifdef ASSIMP_FBX_USE_UNORDERED_MULTIMAP #ifdef ASSIMP_FBX_USE_UNORDERED_MULTIMAP
# include <unordered_map> # include <unordered_map>
# include <unordered_set>
# if _MSC_VER > 1600 # if _MSC_VER > 1600
# define fbx_unordered_map unordered_map # define fbx_unordered_map unordered_map
# define fbx_unordered_multimap unordered_multimap # define fbx_unordered_multimap unordered_multimap
# define fbx_unordered_set unordered_set
# define fbx_unordered_multiset unordered_multiset
# else # else
# define fbx_unordered_map tr1::unordered_map # define fbx_unordered_map tr1::unordered_map
# define fbx_unordered_multimap tr1::unordered_multimap # define fbx_unordered_multimap tr1::unordered_multimap
# define fbx_unordered_set tr1::unordered_set
# define fbx_unordered_multiset tr1::unordered_multiset
# endif # endif
#endif #endif

View File

@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "FBXImporter.h" #include "FBXImporter.h"
#include <assimp/StringComparison.h> #include <assimp/StringComparison.h>
#include <assimp/MathFunctions.h>
#include <assimp/scene.h> #include <assimp/scene.h>
@ -66,7 +67,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <vector> #include <vector>
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <cstdint>
#include <iostream>
#include <stdlib.h>
namespace Assimp { namespace Assimp {
namespace FBX { namespace FBX {
@ -75,9 +78,9 @@ namespace Assimp {
#define MAGIC_NODE_TAG "_$AssimpFbx$" #define MAGIC_NODE_TAG "_$AssimpFbx$"
#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000L #define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
FBXConverter::FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit ) FBXConverter::FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones )
: defaultMaterialIndex() : defaultMaterialIndex()
, lights() , lights()
, cameras() , cameras()
@ -89,13 +92,19 @@ namespace Assimp {
, mNodeNames() , mNodeNames()
, anim_fps() , anim_fps()
, out(out) , out(out)
, doc(doc) , doc(doc) {
, mRemoveEmptyBones( removeEmptyBones )
, mCurrentUnit(FbxUnit::cm) {
// animations need to be converted first since this will // animations need to be converted first since this will
// populate the node_anim_chain_bits map, which is needed // populate the node_anim_chain_bits map, which is needed
// to determine which nodes need to be generated. // to determine which nodes need to be generated.
ConvertAnimations(); ConvertAnimations();
// Embedded textures in FBX could be connected to nothing but to itself,
// for instance Texture -> Video connection only but not to the main graph,
// The idea here is to traverse all objects to find these Textures and convert them,
// so later during material conversion it will find converted texture in the textures_converted array.
if (doc.Settings().readTextures)
{
ConvertOrphantEmbeddedTextures();
}
ConvertRootNode(); ConvertRootNode();
if (doc.Settings().readAllMaterials) { if (doc.Settings().readAllMaterials) {
@ -119,7 +128,6 @@ namespace Assimp {
ConvertGlobalSettings(); ConvertGlobalSettings();
TransferDataToScene(); TransferDataToScene();
ConvertToUnitScale(unit);
// if we didn't read any meshes set the AI_SCENE_FLAGS_INCOMPLETE // if we didn't read any meshes set the AI_SCENE_FLAGS_INCOMPLETE
// to make sure the scene passes assimp's validation. FBX files // to make sure the scene passes assimp's validation. FBX files
@ -146,7 +154,7 @@ namespace Assimp {
out->mRootNode->mName.Set(unique_name); out->mRootNode->mName.Set(unique_name);
// root has ID 0 // root has ID 0
ConvertNodes(0L, *out->mRootNode); ConvertNodes(0L, out->mRootNode, out->mRootNode);
} }
static std::string getAncestorBaseName(const aiNode* node) static std::string getAncestorBaseName(const aiNode* node)
@ -180,8 +188,11 @@ namespace Assimp {
GetUniqueName(original_name, unique_name); GetUniqueName(original_name, unique_name);
return unique_name; return unique_name;
} }
/// todo: pre-build node hierarchy
void FBXConverter::ConvertNodes(uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform) { /// todo: get bone from stack
/// todo: make map of aiBone* to aiNode*
/// then update convert clusters to the new format
void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) {
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;
@ -192,62 +203,69 @@ namespace Assimp {
try { try {
for (const Connection* con : conns) { for (const Connection* con : conns) {
// ignore object-property links // ignore object-property links
if (con->PropertyName().length()) { if (con->PropertyName().length()) {
continue; // really important we document why this is ignored.
FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored");
continue; //?
} }
// convert connection source object into Object base class
const Object* const object = con->SourceObject(); const Object* const object = con->SourceObject();
if (nullptr == object) { if (nullptr == object) {
FBXImporter::LogWarn("failed to convert source object for Model link"); FBXImporter::LogError("failed to convert source object for Model link");
continue; continue;
} }
// FBX Model::Cube, Model::Bone001, etc elements
// This detects if we can cast the object into this model structure.
const Model* const model = dynamic_cast<const Model*>(object); const Model* const model = dynamic_cast<const Model*>(object);
if (nullptr != model) { if (nullptr != model) {
nodes_chain.clear(); nodes_chain.clear();
post_nodes_chain.clear(); post_nodes_chain.clear();
aiMatrix4x4 new_abs_transform = parent_transform; aiMatrix4x4 new_abs_transform = parent->mTransformation;
std::string node_name = FixNodeName(model->Name());
std::string unique_name = MakeUniqueNodeName(model, parent);
// even though there is only a single input node, the design of // even though there is only a single input node, the design of
// 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.
const bool need_additional_node = GenerateTransformationNodeChain(*model, unique_name, nodes_chain, post_nodes_chain);
// generate node transforms - this includes pivot data
// if need_additional_node is true then you t
const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain);
// assert that for the current node we must have at least a single transform
ai_assert(nodes_chain.size()); ai_assert(nodes_chain.size());
if (need_additional_node) { if (need_additional_node) {
nodes_chain.push_back(new aiNode(unique_name)); nodes_chain.push_back(new aiNode(node_name));
} }
//setup metadata on newest node //setup metadata on newest node
SetupNodeMetadata(*model, *nodes_chain.back()); SetupNodeMetadata(*model, *nodes_chain.back());
// link all nodes in a row // link all nodes in a row
aiNode* last_parent = &parent; aiNode* last_parent = parent;
for (aiNode* prenode : nodes_chain) { for (aiNode* child : nodes_chain) {
ai_assert(prenode); ai_assert(child);
if (last_parent != &parent) { if (last_parent != parent) {
last_parent->mNumChildren = 1; last_parent->mNumChildren = 1;
last_parent->mChildren = new aiNode*[1]; last_parent->mChildren = new aiNode*[1];
last_parent->mChildren[0] = prenode; last_parent->mChildren[0] = child;
} }
prenode->mParent = last_parent; child->mParent = last_parent;
last_parent = prenode; last_parent = child;
new_abs_transform *= prenode->mTransformation; new_abs_transform *= child->mTransformation;
} }
// attach geometry // attach geometry
ConvertModel(*model, *nodes_chain.back(), new_abs_transform); ConvertModel(*model, nodes_chain.back(), root_node, new_abs_transform);
// check if there will be any child nodes // check if there will be any child nodes
const std::vector<const Connection*>& child_conns const std::vector<const Connection*>& child_conns
@ -259,7 +277,7 @@ namespace Assimp {
for (aiNode* postnode : post_nodes_chain) { for (aiNode* postnode : post_nodes_chain) {
ai_assert(postnode); ai_assert(postnode);
if (last_parent != &parent) { if (last_parent != parent) {
last_parent->mNumChildren = 1; last_parent->mNumChildren = 1;
last_parent->mChildren = new aiNode*[1]; last_parent->mChildren = new aiNode*[1];
last_parent->mChildren[0] = postnode; last_parent->mChildren[0] = postnode;
@ -281,15 +299,15 @@ namespace Assimp {
); );
} }
// attach sub-nodes (if any) // recursion call - child nodes
ConvertNodes(model->ID(), *last_parent, new_abs_transform); ConvertNodes(model->ID(), last_parent, root_node);
if (doc.Settings().readLights) { if (doc.Settings().readLights) {
ConvertLights(*model, unique_name); ConvertLights(*model, node_name);
} }
if (doc.Settings().readCameras) { if (doc.Settings().readCameras) {
ConvertCameras(*model, unique_name); ConvertCameras(*model, node_name);
} }
nodes.push_back(nodes_chain.front()); nodes.push_back(nodes_chain.front());
@ -298,11 +316,17 @@ namespace Assimp {
} }
if (nodes.size()) { if (nodes.size()) {
parent.mChildren = new aiNode*[nodes.size()](); parent->mChildren = new aiNode*[nodes.size()]();
parent.mNumChildren = static_cast<unsigned int>(nodes.size()); parent->mNumChildren = static_cast<unsigned int>(nodes.size());
std::swap_ranges(nodes.begin(), nodes.end(), parent.mChildren); std::swap_ranges(nodes.begin(), nodes.end(), parent->mChildren);
} }
else
{
parent->mNumChildren = 0;
parent->mChildren = nullptr;
}
} }
catch (std::exception&) { catch (std::exception&) {
Util::delete_fun<aiNode> deleter; Util::delete_fun<aiNode> deleter;
@ -555,7 +579,7 @@ namespace Assimp {
return; return;
} }
const float angle_epsilon = 1e-6f; const float angle_epsilon = Math::getEpsilon<float>();
out = aiMatrix4x4(); out = aiMatrix4x4();
@ -685,30 +709,37 @@ namespace Assimp {
bool ok; bool ok;
aiMatrix4x4 chain[TransformationComp_MAXIMUM]; aiMatrix4x4 chain[TransformationComp_MAXIMUM];
ai_assert(TransformationComp_MAXIMUM < 32);
std::uint32_t chainBits = 0;
// A node won't need a node chain if it only has these.
const std::uint32_t chainMaskSimple = (1 << TransformationComp_Translation) + (1 << TransformationComp_Scaling) + (1 << TransformationComp_Rotation);
// A node will need a node chain if it has any of these.
const std::uint32_t chainMaskComplex = ((1 << (TransformationComp_MAXIMUM)) - 1) - chainMaskSimple;
std::fill_n(chain, static_cast<unsigned int>(TransformationComp_MAXIMUM), aiMatrix4x4()); std::fill_n(chain, static_cast<unsigned int>(TransformationComp_MAXIMUM), aiMatrix4x4());
// 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 = Math::getEpsilon<float>();
const aiVector3D all_ones(1.0f, 1.0f, 1.0f); const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
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; chainBits = chainBits | (1 << TransformationComp_PreRotation);
GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, 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; chainBits = chainBits | (1 << TransformationComp_PostRotation);
GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, 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);
if (ok && RotationPivot.SquareLength() > zero_epsilon) { if (ok && RotationPivot.SquareLength() > zero_epsilon) {
is_complex = true; chainBits = chainBits | (1 << TransformationComp_RotationPivot) | (1 << TransformationComp_RotationPivotInverse);
aiMatrix4x4::Translation(RotationPivot, chain[TransformationComp_RotationPivot]); aiMatrix4x4::Translation(RotationPivot, chain[TransformationComp_RotationPivot]);
aiMatrix4x4::Translation(-RotationPivot, chain[TransformationComp_RotationPivotInverse]); aiMatrix4x4::Translation(-RotationPivot, chain[TransformationComp_RotationPivotInverse]);
@ -716,21 +747,21 @@ namespace Assimp {
const aiVector3D& RotationOffset = PropertyGet<aiVector3D>(props, "RotationOffset", ok); const aiVector3D& RotationOffset = PropertyGet<aiVector3D>(props, "RotationOffset", ok);
if (ok && RotationOffset.SquareLength() > zero_epsilon) { if (ok && RotationOffset.SquareLength() > zero_epsilon) {
is_complex = true; chainBits = chainBits | (1 << TransformationComp_RotationOffset);
aiMatrix4x4::Translation(RotationOffset, chain[TransformationComp_RotationOffset]); aiMatrix4x4::Translation(RotationOffset, chain[TransformationComp_RotationOffset]);
} }
const aiVector3D& ScalingOffset = PropertyGet<aiVector3D>(props, "ScalingOffset", ok); const aiVector3D& ScalingOffset = PropertyGet<aiVector3D>(props, "ScalingOffset", ok);
if (ok && ScalingOffset.SquareLength() > zero_epsilon) { if (ok && ScalingOffset.SquareLength() > zero_epsilon) {
is_complex = true; chainBits = chainBits | (1 << TransformationComp_ScalingOffset);
aiMatrix4x4::Translation(ScalingOffset, chain[TransformationComp_ScalingOffset]); aiMatrix4x4::Translation(ScalingOffset, chain[TransformationComp_ScalingOffset]);
} }
const aiVector3D& ScalingPivot = PropertyGet<aiVector3D>(props, "ScalingPivot", ok); const aiVector3D& ScalingPivot = PropertyGet<aiVector3D>(props, "ScalingPivot", ok);
if (ok && ScalingPivot.SquareLength() > zero_epsilon) { if (ok && ScalingPivot.SquareLength() > zero_epsilon) {
is_complex = true; chainBits = chainBits | (1 << TransformationComp_ScalingPivot) | (1 << TransformationComp_ScalingPivotInverse);
aiMatrix4x4::Translation(ScalingPivot, chain[TransformationComp_ScalingPivot]); aiMatrix4x4::Translation(ScalingPivot, chain[TransformationComp_ScalingPivot]);
aiMatrix4x4::Translation(-ScalingPivot, chain[TransformationComp_ScalingPivotInverse]); aiMatrix4x4::Translation(-ScalingPivot, chain[TransformationComp_ScalingPivotInverse]);
@ -738,22 +769,28 @@ namespace Assimp {
const aiVector3D& Translation = PropertyGet<aiVector3D>(props, "Lcl Translation", ok); const aiVector3D& Translation = PropertyGet<aiVector3D>(props, "Lcl Translation", ok);
if (ok && Translation.SquareLength() > zero_epsilon) { if (ok && Translation.SquareLength() > zero_epsilon) {
chainBits = chainBits | (1 << TransformationComp_Translation);
aiMatrix4x4::Translation(Translation, chain[TransformationComp_Translation]); aiMatrix4x4::Translation(Translation, chain[TransformationComp_Translation]);
} }
const aiVector3D& Scaling = PropertyGet<aiVector3D>(props, "Lcl Scaling", ok); const aiVector3D& Scaling = PropertyGet<aiVector3D>(props, "Lcl Scaling", ok);
if (ok && (Scaling - all_ones).SquareLength() > zero_epsilon) { if (ok && (Scaling - all_ones).SquareLength() > zero_epsilon) {
chainBits = chainBits | (1 << TransformationComp_Scaling);
aiMatrix4x4::Scaling(Scaling, chain[TransformationComp_Scaling]); aiMatrix4x4::Scaling(Scaling, chain[TransformationComp_Scaling]);
} }
const aiVector3D& Rotation = PropertyGet<aiVector3D>(props, "Lcl Rotation", ok); const aiVector3D& Rotation = PropertyGet<aiVector3D>(props, "Lcl Rotation", ok);
if (ok && Rotation.SquareLength() > zero_epsilon) { if (ok && Rotation.SquareLength() > zero_epsilon) {
chainBits = chainBits | (1 << TransformationComp_Rotation);
GetRotationMatrix(rot, Rotation, chain[TransformationComp_Rotation]); GetRotationMatrix(rot, Rotation, chain[TransformationComp_Rotation]);
} }
const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>(props, "GeometricScaling", ok); const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>(props, "GeometricScaling", ok);
if (ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon) { if (ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon) {
is_complex = true; chainBits = chainBits | (1 << TransformationComp_GeometricScaling);
aiMatrix4x4::Scaling(GeometricScaling, chain[TransformationComp_GeometricScaling]); aiMatrix4x4::Scaling(GeometricScaling, chain[TransformationComp_GeometricScaling]);
aiVector3D GeometricScalingInverse = GeometricScaling; aiVector3D GeometricScalingInverse = GeometricScaling;
bool canscale = true; bool canscale = true;
@ -768,13 +805,14 @@ namespace Assimp {
} }
} }
if (canscale) { if (canscale) {
chainBits = chainBits | (1 << TransformationComp_GeometricScalingInverse);
aiMatrix4x4::Scaling(GeometricScalingInverse, chain[TransformationComp_GeometricScalingInverse]); 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; chainBits = chainBits | (1 << TransformationComp_GeometricRotation) | (1 << TransformationComp_GeometricRotationInverse);
GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotation]); GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotation]);
GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotationInverse]); GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotationInverse]);
chain[TransformationComp_GeometricRotationInverse].Inverse(); chain[TransformationComp_GeometricRotationInverse].Inverse();
@ -782,7 +820,7 @@ namespace Assimp {
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; chainBits = chainBits | (1 << TransformationComp_GeometricTranslation) | (1 << TransformationComp_GeometricTranslationInverse);
aiMatrix4x4::Translation(GeometricTranslation, chain[TransformationComp_GeometricTranslation]); aiMatrix4x4::Translation(GeometricTranslation, chain[TransformationComp_GeometricTranslation]);
aiMatrix4x4::Translation(-GeometricTranslation, chain[TransformationComp_GeometricTranslationInverse]); aiMatrix4x4::Translation(-GeometricTranslation, chain[TransformationComp_GeometricTranslationInverse]);
} }
@ -790,12 +828,12 @@ namespace Assimp {
// is_complex needs to be consistent with NeedsComplexTransformationChain() // is_complex needs to be consistent with NeedsComplexTransformationChain()
// or the interplay between this code and the animation converter would // or the interplay between this code and the animation converter would
// not be guaranteed. // not be guaranteed.
ai_assert(NeedsComplexTransformationChain(model) == is_complex); //ai_assert(NeedsComplexTransformationChain(model) == ((chainBits & chainMaskComplex) != 0));
// 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
// lack to express pivots and offsets. // lack to express pivots and offsets.
if (is_complex && doc.Settings().preservePivots) { if ((chainBits & chainMaskComplex) && doc.Settings().preservePivots) {
FBXImporter::LogInfo("generating full transformation chain for node: " + name); FBXImporter::LogInfo("generating full transformation chain for node: " + name);
// query the anim_chain_bits dictionary to find out which chain elements // query the anim_chain_bits dictionary to find out which chain elements
@ -808,7 +846,7 @@ namespace Assimp {
for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) { for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) {
const TransformationComp comp = static_cast<TransformationComp>(i); const TransformationComp comp = static_cast<TransformationComp>(i);
if (chain[i].IsIdentity() && (anim_chain_bitmask & bit) == 0) { if ((chainBits & bit) == 0 && (anim_chain_bitmask & bit) == 0) {
continue; continue;
} }
@ -892,7 +930,8 @@ namespace Assimp {
} }
} }
void FBXConverter::ConvertModel(const Model& model, aiNode& nd, const aiMatrix4x4& node_global_transform) void FBXConverter::ConvertModel(const Model &model, aiNode *parent, aiNode *root_node,
const aiMatrix4x4 &absolute_transform)
{ {
const std::vector<const Geometry*>& geos = model.GetGeometry(); const std::vector<const Geometry*>& geos = model.GetGeometry();
@ -904,11 +943,12 @@ namespace Assimp {
const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*>(geo); const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*>(geo);
const LineGeometry* const line = dynamic_cast<const LineGeometry*>(geo); const LineGeometry* const line = dynamic_cast<const LineGeometry*>(geo);
if (mesh) { if (mesh) {
const std::vector<unsigned int>& indices = ConvertMesh(*mesh, model, node_global_transform, nd); const std::vector<unsigned int>& indices = ConvertMesh(*mesh, model, parent, root_node,
absolute_transform);
std::copy(indices.begin(), indices.end(), std::back_inserter(meshes)); std::copy(indices.begin(), indices.end(), std::back_inserter(meshes));
} }
else if (line) { else if (line) {
const std::vector<unsigned int>& indices = ConvertLine(*line, model, node_global_transform, nd); const std::vector<unsigned int>& indices = ConvertLine(*line, model, parent, root_node);
std::copy(indices.begin(), indices.end(), std::back_inserter(meshes)); std::copy(indices.begin(), indices.end(), std::back_inserter(meshes));
} }
else { else {
@ -917,15 +957,16 @@ namespace Assimp {
} }
if (meshes.size()) { if (meshes.size()) {
nd.mMeshes = new unsigned int[meshes.size()](); parent->mMeshes = new unsigned int[meshes.size()]();
nd.mNumMeshes = static_cast<unsigned int>(meshes.size()); parent->mNumMeshes = static_cast<unsigned int>(meshes.size());
std::swap_ranges(meshes.begin(), meshes.end(), nd.mMeshes); std::swap_ranges(meshes.begin(), meshes.end(), parent->mMeshes);
} }
} }
std::vector<unsigned int> FBXConverter::ConvertMesh(const MeshGeometry& mesh, const Model& model, std::vector<unsigned int>
const aiMatrix4x4& node_global_transform, aiNode& nd) FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node,
const aiMatrix4x4 &absolute_transform)
{ {
std::vector<unsigned int> temp; std::vector<unsigned int> temp;
@ -949,18 +990,18 @@ namespace Assimp {
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, nd); return ConvertMeshMultiMaterial(mesh, model, parent, root_node, absolute_transform);
} }
} }
} }
// faster code-path, just copy the data // faster code-path, just copy the data
temp.push_back(ConvertMeshSingleMaterial(mesh, model, node_global_transform, nd)); temp.push_back(ConvertMeshSingleMaterial(mesh, model, absolute_transform, parent, root_node));
return temp; return temp;
} }
std::vector<unsigned int> FBXConverter::ConvertLine(const LineGeometry& line, const Model& model, std::vector<unsigned int> FBXConverter::ConvertLine(const LineGeometry& line, const Model& model,
const aiMatrix4x4& node_global_transform, aiNode& nd) aiNode *parent, aiNode *root_node)
{ {
std::vector<unsigned int> temp; std::vector<unsigned int> temp;
@ -971,7 +1012,7 @@ namespace Assimp {
return temp; return temp;
} }
aiMesh* const out_mesh = SetupEmptyMesh(line, nd); aiMesh* const out_mesh = SetupEmptyMesh(line, root_node);
out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
// copy vertices // copy vertices
@ -1006,7 +1047,7 @@ namespace Assimp {
return temp; return temp;
} }
aiMesh* FBXConverter::SetupEmptyMesh(const Geometry& mesh, aiNode& nd) aiMesh* FBXConverter::SetupEmptyMesh(const Geometry& mesh, aiNode *parent)
{ {
aiMesh* const out_mesh = new aiMesh(); aiMesh* const out_mesh = new aiMesh();
meshes.push_back(out_mesh); meshes.push_back(out_mesh);
@ -1023,17 +1064,18 @@ namespace Assimp {
} }
else else
{ {
out_mesh->mName = nd.mName; out_mesh->mName = parent->mName;
} }
return out_mesh; return out_mesh;
} }
unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry& mesh, const Model& model, unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model,
const aiMatrix4x4& node_global_transform, aiNode& nd) const aiMatrix4x4 &absolute_transform, aiNode *parent,
aiNode *root_node)
{ {
const MatIndexArray& mindices = mesh.GetMaterialIndices(); const MatIndexArray& mindices = mesh.GetMaterialIndices();
aiMesh* const out_mesh = SetupEmptyMesh(mesh, nd); aiMesh* const out_mesh = SetupEmptyMesh(mesh, parent);
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();
@ -1100,7 +1142,7 @@ namespace Assimp {
binormals = &tempBinormals; binormals = &tempBinormals;
} }
else { else {
binormals = NULL; binormals = nullptr;
} }
} }
@ -1150,8 +1192,9 @@ namespace Assimp {
ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]); ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]);
} }
if (doc.Settings().readWeights && mesh.DeformerSkin() != NULL) { if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr) {
ConvertWeights(out_mesh, model, mesh, node_global_transform, NO_MATERIAL_SEPARATION); ConvertWeights(out_mesh, model, mesh, absolute_transform, parent, root_node, NO_MATERIAL_SEPARATION,
nullptr);
} }
std::vector<aiAnimMesh*> animMeshes; std::vector<aiAnimMesh*> animMeshes;
@ -1196,8 +1239,10 @@ namespace Assimp {
return static_cast<unsigned int>(meshes.size() - 1); return static_cast<unsigned int>(meshes.size() - 1);
} }
std::vector<unsigned int> FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model, std::vector<unsigned int>
const aiMatrix4x4& node_global_transform, aiNode& nd) FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent,
aiNode *root_node,
const aiMatrix4x4 &absolute_transform)
{ {
const MatIndexArray& mindices = mesh.GetMaterialIndices(); const MatIndexArray& mindices = mesh.GetMaterialIndices();
ai_assert(mindices.size()); ai_assert(mindices.size());
@ -1208,7 +1253,7 @@ namespace Assimp {
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, nd)); indices.push_back(ConvertMeshMultiMaterial(mesh, model, index, parent, root_node, absolute_transform));
had.insert(index); had.insert(index);
} }
} }
@ -1216,18 +1261,18 @@ namespace Assimp {
return indices; return indices;
} }
unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model, unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model,
MatIndexArray::value_type index, MatIndexArray::value_type index,
const aiMatrix4x4& node_global_transform, aiNode *parent, aiNode *root_node,
aiNode& nd) const aiMatrix4x4 &absolute_transform)
{ {
aiMesh* const out_mesh = SetupEmptyMesh(mesh, nd); aiMesh* const out_mesh = SetupEmptyMesh(mesh, parent);
const MatIndexArray& mindices = mesh.GetMaterialIndices(); const MatIndexArray& mindices = mesh.GetMaterialIndices();
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();
const bool process_weights = doc.Settings().readWeights && mesh.DeformerSkin() != NULL; const bool process_weights = doc.Settings().readWeights && mesh.DeformerSkin() != nullptr;
unsigned int count_faces = 0; unsigned int count_faces = 0;
unsigned int count_vertices = 0; unsigned int count_vertices = 0;
@ -1247,10 +1292,10 @@ namespace Assimp {
ai_assert(count_faces); ai_assert(count_faces);
ai_assert(count_vertices); ai_assert(count_vertices);
// mapping from output indices to DOM indexing, needed to resolve weights // mapping from output indices to DOM indexing, needed to resolve weights or blendshapes
std::vector<unsigned int> reverseMapping; std::vector<unsigned int> reverseMapping;
std::map<unsigned int, unsigned int> translateIndexMap; std::map<unsigned int, unsigned int> translateIndexMap;
if (process_weights) { if (process_weights || mesh.GetBlendShapes().size() > 0) {
reverseMapping.resize(count_vertices); reverseMapping.resize(count_vertices);
} }
@ -1287,7 +1332,7 @@ namespace Assimp {
binormals = &tempBinormals; binormals = &tempBinormals;
} }
else { else {
binormals = NULL; binormals = nullptr;
} }
} }
@ -1386,7 +1431,7 @@ namespace Assimp {
ConvertMaterialForMesh(out_mesh, model, mesh, index); ConvertMaterialForMesh(out_mesh, model, mesh, index);
if (process_weights) { if (process_weights) {
ConvertWeights(out_mesh, model, mesh, node_global_transform, index, &reverseMapping); ConvertWeights(out_mesh, model, mesh, absolute_transform, parent, root_node, index, &reverseMapping);
} }
std::vector<aiAnimMesh*> animMeshes; std::vector<aiAnimMesh*> animMeshes;
@ -1407,7 +1452,10 @@ namespace Assimp {
unsigned int count = 0; unsigned int count = 0;
const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count); const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count);
for (unsigned int k = 0; k < count; k++) { for (unsigned int k = 0; k < count; k++) {
unsigned int index = translateIndexMap[outIndices[k]]; unsigned int outIndex = outIndices[k];
if (translateIndexMap.find(outIndex) == translateIndexMap.end())
continue;
unsigned int index = translateIndexMap[outIndex];
animMesh->mVertices[index] += vertex; animMesh->mVertices[index] += vertex;
if (animMesh->mNormals != nullptr) { if (animMesh->mNormals != nullptr) {
animMesh->mNormals[index] += normal; animMesh->mNormals[index] += normal;
@ -1421,13 +1469,22 @@ namespace Assimp {
} }
} }
const size_t numAnimMeshes = animMeshes.size();
if (numAnimMeshes > 0) {
out_mesh->mNumAnimMeshes = static_cast<unsigned int>(numAnimMeshes);
out_mesh->mAnimMeshes = new aiAnimMesh*[numAnimMeshes];
for (size_t i = 0; i < numAnimMeshes; i++) {
out_mesh->mAnimMeshes[i] = animMeshes.at(i);
}
}
return static_cast<unsigned int>(meshes.size() - 1); return static_cast<unsigned int>(meshes.size() - 1);
} }
void FBXConverter::ConvertWeights(aiMesh* out, const Model& model, const MeshGeometry& geo, void FBXConverter::ConvertWeights(aiMesh *out, const Model &model, const MeshGeometry &geo,
const aiMatrix4x4& node_global_transform, const aiMatrix4x4 &absolute_transform,
unsigned int materialIndex, aiNode *parent, aiNode *root_node, unsigned int materialIndex,
std::vector<unsigned int>* outputVertStartIndices) std::vector<unsigned int> *outputVertStartIndices)
{ {
ai_assert(geo.DeformerSkin()); ai_assert(geo.DeformerSkin());
@ -1438,41 +1495,35 @@ namespace Assimp {
const Skin& sk = *geo.DeformerSkin(); const Skin& sk = *geo.DeformerSkin();
std::vector<aiBone*> bones; std::vector<aiBone*> bones;
bones.reserve(sk.Clusters().size());
const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION; const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION;
ai_assert(no_mat_check || outputVertStartIndices); ai_assert(no_mat_check || outputVertStartIndices);
try { try {
// iterate over the sub deformers
for (const Cluster* cluster : sk.Clusters()) { for (const Cluster* cluster : sk.Clusters()) {
ai_assert(cluster); ai_assert(cluster);
const WeightIndexArray& indices = cluster->GetIndices(); const WeightIndexArray& indices = cluster->GetIndices();
if (indices.empty() && mRemoveEmptyBones ) {
continue;
}
const MatIndexArray& mats = geo.GetMaterialIndices(); const MatIndexArray& mats = geo.GetMaterialIndices();
bool ok = false;
const size_t no_index_sentinel = std::numeric_limits<size_t>::max(); const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
count_out_indices.clear(); count_out_indices.clear();
index_out_indices.clear(); index_out_indices.clear();
out_indices.clear(); out_indices.clear();
// now check if *any* of these weights is contained in the output mesh, // now check if *any* of these weights is contained in the output mesh,
// taking notes so we don't need to do it twice. // taking notes so we don't need to do it twice.
for (WeightIndexArray::value_type index : indices) { for (WeightIndexArray::value_type index : indices) {
unsigned int count = 0; unsigned int count = 0;
const unsigned int* const out_idx = geo.ToOutputVertexIndex(index, count); const unsigned int* const out_idx = geo.ToOutputVertexIndex(index, count);
// ToOutputVertexIndex only returns NULL if index is out of bounds // ToOutputVertexIndex only returns nullptr if index is out of bounds
// which should never happen // which should never happen
ai_assert(out_idx != NULL); ai_assert(out_idx != nullptr);
index_out_indices.push_back(no_index_sentinel); index_out_indices.push_back(no_index_sentinel);
count_out_indices.push_back(0); count_out_indices.push_back(0);
@ -1498,7 +1549,6 @@ namespace Assimp {
} }
++count_out_indices.back(); ++count_out_indices.back();
ok = true;
} }
} }
} }
@ -1506,49 +1556,75 @@ namespace Assimp {
// if we found at least one, generate the output bones // if we found at least one, generate the output bones
// XXX this could be heavily simplified by collecting the bone // XXX this could be heavily simplified by collecting the bone
// data in a single step. // data in a single step.
if (ok && mRemoveEmptyBones) { ConvertCluster(bones, cluster, out_indices, index_out_indices,
ConvertCluster(bones, model, *cluster, out_indices, index_out_indices, count_out_indices, absolute_transform, parent, root_node);
count_out_indices, node_global_transform);
} }
bone_map.clear();
} }
} catch (std::exception&e) {
catch (std::exception&) {
std::for_each(bones.begin(), bones.end(), Util::delete_fun<aiBone>()); std::for_each(bones.begin(), bones.end(), Util::delete_fun<aiBone>());
throw; throw;
} }
if (bones.empty()) { if (bones.empty()) {
out->mBones = nullptr;
out->mNumBones = 0;
return; return;
} } else {
out->mBones = new aiBone *[bones.size()]();
out->mBones = new aiBone*[bones.size()]();
out->mNumBones = static_cast<unsigned int>(bones.size()); out->mNumBones = static_cast<unsigned int>(bones.size());
std::swap_ranges(bones.begin(), bones.end(), out->mBones); std::swap_ranges(bones.begin(), bones.end(), out->mBones);
} }
}
void FBXConverter::ConvertCluster(std::vector<aiBone*>& bones, const Model& /*model*/, const Cluster& cl, const aiNode* FBXConverter::GetNodeByName( const aiString& name, aiNode *current_node )
std::vector<size_t>& out_indices,
std::vector<size_t>& index_out_indices,
std::vector<size_t>& count_out_indices,
const aiMatrix4x4& node_global_transform)
{ {
aiNode * iter = current_node;
//printf("Child count: %d", iter->mNumChildren);
return iter;
}
aiBone* const bone = new aiBone(); void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
bones.push_back(bone); std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform,
aiNode *parent, aiNode *root_node) {
ai_assert(cl); // make sure cluster valid
std::string deformer_name = cl->TargetNode()->Name();
aiString bone_name = aiString(FixNodeName(deformer_name));
bone->mName = FixNodeName(cl.TargetNode()->Name()); aiBone *bone = nullptr;
bone->mOffsetMatrix = cl.TransformLink(); if (bone_map.count(deformer_name)) {
std::cout << "retrieved bone from lookup " << bone_name.C_Str() << ". Deformer: " << deformer_name
<< std::endl;
bone = bone_map[deformer_name];
} else {
std::cout << "created new bone " << bone_name.C_Str() << ". Deformer: " << deformer_name << std::endl;
bone = new aiBone();
bone->mName = bone_name;
// store local transform link for post processing
bone->mOffsetMatrix = cl->TransformLink();
bone->mOffsetMatrix.Inverse(); bone->mOffsetMatrix.Inverse();
bone->mOffsetMatrix = bone->mOffsetMatrix * node_global_transform; aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform;
bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset
//
// Now calculate the aiVertexWeights
//
aiVertexWeight *cursor = nullptr;
bone->mNumWeights = static_cast<unsigned int>(out_indices.size()); bone->mNumWeights = static_cast<unsigned int>(out_indices.size());
aiVertexWeight* cursor = bone->mWeights = new aiVertexWeight[out_indices.size()]; cursor = bone->mWeights = new aiVertexWeight[out_indices.size()];
const size_t no_index_sentinel = std::numeric_limits<size_t>::max(); const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
const WeightArray& weights = cl.GetWeights(); const WeightArray& weights = cl->GetWeights();
const size_t c = index_out_indices.size(); const size_t c = index_out_indices.size();
for (size_t i = 0; i < c; ++i) { for (size_t i = 0; i < c; ++i) {
@ -1560,12 +1636,23 @@ namespace Assimp {
const size_t cc = count_out_indices[i]; const size_t cc = count_out_indices[i];
for (size_t j = 0; j < cc; ++j) { for (size_t j = 0; j < cc; ++j) {
// cursor runs from first element relative to the start
// or relative to the start of the next indexes.
aiVertexWeight& out_weight = *cursor++; aiVertexWeight& out_weight = *cursor++;
out_weight.mVertexId = static_cast<unsigned int>(out_indices[index_index + j]); out_weight.mVertexId = static_cast<unsigned int>(out_indices[index_index + j]);
out_weight.mWeight = weights[i]; out_weight.mWeight = weights[i];
} }
} }
bone_map.insert(std::pair<const std::string, aiBone *>(deformer_name, bone));
}
std::cout << "bone research: Indicies size: " << out_indices.size() << std::endl;
// lookup must be populated in case something goes wrong
// this also allocates bones to mesh instance outside
local_mesh_bones.push_back(bone);
} }
void FBXConverter::ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, void FBXConverter::ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo,
@ -1695,7 +1782,7 @@ namespace Assimp {
bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found) bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
unsigned int index; unsigned int index;
VideoMap::const_iterator it = textures_converted.find(media); VideoMap::const_iterator it = textures_converted.find(*media);
if (it != textures_converted.end()) { if (it != textures_converted.end()) {
index = (*it).second; index = (*it).second;
textureReady = true; textureReady = true;
@ -1703,7 +1790,7 @@ namespace Assimp {
else { else {
if (media->ContentLength() > 0) { if (media->ContentLength() > 0) {
index = ConvertVideo(*media); index = ConvertVideo(*media);
textures_converted[media] = index; textures_converted[*media] = index;
textureReady = true; textureReady = true;
} }
} }
@ -1986,6 +2073,21 @@ namespace Assimp {
TrySetTextureProperties(out_mat, textures, "Maya|SpecularTexture", aiTextureType_SPECULAR, mesh); TrySetTextureProperties(out_mat, textures, "Maya|SpecularTexture", aiTextureType_SPECULAR, mesh);
TrySetTextureProperties(out_mat, textures, "Maya|FalloffTexture", aiTextureType_OPACITY, mesh); TrySetTextureProperties(out_mat, textures, "Maya|FalloffTexture", aiTextureType_OPACITY, mesh);
TrySetTextureProperties(out_mat, textures, "Maya|ReflectionMapTexture", aiTextureType_REFLECTION, mesh); TrySetTextureProperties(out_mat, textures, "Maya|ReflectionMapTexture", aiTextureType_REFLECTION, mesh);
// Maya PBR
TrySetTextureProperties(out_mat, textures, "Maya|baseColor|file", aiTextureType_BASE_COLOR, mesh);
TrySetTextureProperties(out_mat, textures, "Maya|normalCamera|file", aiTextureType_NORMAL_CAMERA, mesh);
TrySetTextureProperties(out_mat, textures, "Maya|emissionColor|file", aiTextureType_EMISSION_COLOR, mesh);
TrySetTextureProperties(out_mat, textures, "Maya|metalness|file", aiTextureType_METALNESS, mesh);
TrySetTextureProperties(out_mat, textures, "Maya|diffuseRoughness|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
// Maya stingray
TrySetTextureProperties(out_mat, textures, "Maya|TEX_color_map|file", aiTextureType_BASE_COLOR, mesh);
TrySetTextureProperties(out_mat, textures, "Maya|TEX_normal_map|file", aiTextureType_NORMAL_CAMERA, mesh);
TrySetTextureProperties(out_mat, textures, "Maya|TEX_emissive_map|file", aiTextureType_EMISSION_COLOR, mesh);
TrySetTextureProperties(out_mat, textures, "Maya|TEX_metallic_map|file", aiTextureType_METALNESS, mesh);
TrySetTextureProperties(out_mat, textures, "Maya|TEX_roughness_map|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
TrySetTextureProperties(out_mat, textures, "Maya|TEX_ao_map|file", aiTextureType_AMBIENT_OCCLUSION, mesh);
} }
void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh) void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh)
@ -2212,13 +2314,13 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
if (media != nullptr && media->ContentLength() > 0) { if (media != nullptr && media->ContentLength() > 0) {
unsigned int index; unsigned int index;
VideoMap::const_iterator it = textures_converted.find(media); VideoMap::const_iterator it = textures_converted.find(*media);
if (it != textures_converted.end()) { if (it != textures_converted.end()) {
index = (*it).second; index = (*it).second;
} }
else { else {
index = ConvertVideo(*media); index = ConvertVideo(*media);
textures_converted[media] = index; textures_converted[*media] = index;
} }
// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture) // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
@ -2646,7 +2748,7 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
// sanity check whether the input is ok // sanity check whether the input is ok
static void validateAnimCurveNodes(const std::vector<const AnimationCurveNode*>& curves, static void validateAnimCurveNodes(const std::vector<const AnimationCurveNode*>& curves,
bool strictMode) { bool strictMode) {
const Object* target(NULL); const Object* target(nullptr);
for (const AnimationCurveNode* node : curves) { for (const AnimationCurveNode* node : curves) {
if (!target) { if (!target) {
target = node->Target(); target = node->Target();
@ -2677,7 +2779,7 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
#ifdef ASSIMP_BUILD_DEBUG #ifdef ASSIMP_BUILD_DEBUG
validateAnimCurveNodes(curves, doc.Settings().strictMode); validateAnimCurveNodes(curves, doc.Settings().strictMode);
#endif #endif
const AnimationCurveNode* curve_node = NULL; const AnimationCurveNode* curve_node = nullptr;
for (const AnimationCurveNode* node : curves) { for (const AnimationCurveNode* node : curves) {
ai_assert(node); ai_assert(node);
@ -2937,7 +3039,7 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
TransformationCompDefaultValue(comp) TransformationCompDefaultValue(comp)
); );
const float epsilon = 1e-6f; const float epsilon = Math::getEpsilon<float>();
return (dyn_val - static_val).SquareLength() < epsilon; return (dyn_val - static_val).SquareLength() < epsilon;
} }
@ -3520,52 +3622,12 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
out->mMetaData->Set(14, "CustomFrameRate", doc.GlobalSettings().CustomFrameRate()); out->mMetaData->Set(14, "CustomFrameRate", doc.GlobalSettings().CustomFrameRate());
} }
void FBXConverter::ConvertToUnitScale( FbxUnit unit ) {
if (mCurrentUnit == unit) {
return;
}
ai_real scale = 1.0;
if (mCurrentUnit == FbxUnit::cm) {
if (unit == FbxUnit::m) {
scale = (ai_real)0.01;
} else if (unit == FbxUnit::km) {
scale = (ai_real)0.00001;
}
} else if (mCurrentUnit == FbxUnit::m) {
if (unit == FbxUnit::cm) {
scale = (ai_real)100.0;
} else if (unit == FbxUnit::km) {
scale = (ai_real)0.001;
}
} else if (mCurrentUnit == FbxUnit::km) {
if (unit == FbxUnit::cm) {
scale = (ai_real)100000.0;
} else if (unit == FbxUnit::m) {
scale = (ai_real)1000.0;
}
}
for (auto mesh : meshes) {
if (nullptr == mesh) {
continue;
}
if (mesh->HasPositions()) {
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
aiVector3D &pos = mesh->mVertices[i];
pos *= scale;
}
}
}
}
void FBXConverter::TransferDataToScene() void FBXConverter::TransferDataToScene()
{ {
ai_assert(!out->mMeshes); ai_assert(!out->mMeshes);
ai_assert(!out->mNumMeshes); ai_assert(!out->mNumMeshes);
// note: the trailing () ensures initialization with NULL - not // note: the trailing () ensures initialization with nullptr - not
// many C++ users seem to know this, so pointing it out to avoid // many C++ users seem to know this, so pointing it out to avoid
// confusion why this code works. // confusion why this code works.
@ -3612,10 +3674,51 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
} }
} }
// ------------------------------------------------------------------------------------------------ void FBXConverter::ConvertOrphantEmbeddedTextures()
void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit)
{ {
FBXConverter converter(out, doc, removeEmptyBones, unit); // in C++14 it could be:
// for (auto&& [id, object] : objects)
for (auto&& id_and_object : doc.Objects())
{
auto&& id = std::get<0>(id_and_object);
auto&& object = std::get<1>(id_and_object);
// If an object doesn't have parent
if (doc.ConnectionsBySource().count(id) == 0)
{
const Texture* realTexture = nullptr;
try
{
const auto& element = object->GetElement();
const Token& key = element.KeyToken();
const char* obtype = key.begin();
const size_t length = static_cast<size_t>(key.end() - key.begin());
if (strncmp(obtype, "Texture", length) == 0)
{
const Texture* texture = static_cast<const Texture*>(object->Get());
if (texture->Media() && texture->Media()->ContentLength() > 0)
{
realTexture = texture;
}
}
}
catch (...)
{
// do nothing
}
if (realTexture)
{
const Video* media = realTexture->Media();
unsigned int index = ConvertVideo(*media);
textures_converted[*media] = index;
}
}
}
}
// ------------------------------------------------------------------------------------------------
void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones)
{
FBXConverter converter(out, doc, removeEmptyBones);
} }
} // !FBX } // !FBX

View File

@ -76,23 +76,13 @@ namespace Assimp {
namespace FBX { namespace FBX {
class Document; class Document;
enum class FbxUnit {
cm = 0,
m,
km,
NumUnits,
Undefined
};
/** /**
* 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
* @param doc Parsed FBX document * @param doc Parsed FBX document
* @param removeEmptyBones Will remove bones, which do not have any references to vertices. * @param removeEmptyBones Will remove bones, which do not have any references to vertices.
*/ */
void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit); void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones);
/** Dummy class to encapsulate the conversion process */ /** Dummy class to encapsulate the conversion process */
class FBXConverter { class FBXConverter {
@ -123,7 +113,7 @@ public:
}; };
public: public:
FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit); FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones);
~FBXConverter(); ~FBXConverter();
private: private:
@ -133,7 +123,7 @@ private:
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// collect and assign child nodes // collect and assign child nodes
void ConvertNodes(uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform = aiMatrix4x4()); void ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertLights(const Model& model, const std::string &orig_name ); void ConvertLights(const Model& model, const std::string &orig_name );
@ -189,32 +179,35 @@ private:
void SetupNodeMetadata(const Model& model, aiNode& nd); void SetupNodeMetadata(const Model& model, aiNode& nd);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertModel(const Model& model, aiNode& nd, const aiMatrix4x4& node_global_transform); void ConvertModel(const Model &model, aiNode *parent, aiNode *root_node,
const aiMatrix4x4 &absolute_transform);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// 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>
const aiMatrix4x4& node_global_transform, aiNode& nd); ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node,
const aiMatrix4x4 &absolute_transform);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::vector<unsigned int> ConvertLine(const LineGeometry& line, const Model& model, std::vector<unsigned int> ConvertLine(const LineGeometry& line, const Model& model,
const aiMatrix4x4& node_global_transform, aiNode& nd); aiNode *parent, aiNode *root_node);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode& nd); aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode *parent);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
unsigned int ConvertMeshSingleMaterial(const MeshGeometry& mesh, const Model& model, unsigned int ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model,
const aiMatrix4x4& node_global_transform, aiNode& nd); const aiMatrix4x4 &absolute_transform, aiNode *parent,
aiNode *root_node);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
std::vector<unsigned int> ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model, std::vector<unsigned int>
const aiMatrix4x4& node_global_transform, aiNode& nd); ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node,
const aiMatrix4x4 &absolute_transform);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
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, aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_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() */
@ -227,17 +220,17 @@ private:
* - outputVertStartIndices is only used when a material index is specified, it gives for * - outputVertStartIndices is only used when a material index is specified, it gives for
* each output vertex the DOM index it maps to. * each output vertex the DOM index it maps to.
*/ */
void ConvertWeights(aiMesh* out, const Model& model, const MeshGeometry& geo, void ConvertWeights(aiMesh *out, const Model &model, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
const aiMatrix4x4& node_global_transform = aiMatrix4x4(), aiNode *parent = NULL, aiNode *root_node = NULL,
unsigned int materialIndex = NO_MATERIAL_SEPARATION, unsigned int materialIndex = NO_MATERIAL_SEPARATION,
std::vector<unsigned int>* outputVertStartIndices = NULL); std::vector<unsigned int> *outputVertStartIndices = NULL);
// lookup
static const aiNode* GetNodeByName( const aiString& name, aiNode *current_node );
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertCluster(std::vector<aiBone*>& bones, const Model& /*model*/, const Cluster& cl, void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
std::vector<size_t>& out_indices, std::vector<size_t> &out_indices, std::vector<size_t> &index_out_indices,
std::vector<size_t>& index_out_indices, std::vector<size_t> &count_out_indices, const aiMatrix4x4 &absolute_transform,
std::vector<size_t>& count_out_indices, aiNode *parent, aiNode *root_node);
const aiMatrix4x4& node_global_transform);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo,
@ -430,14 +423,14 @@ private:
void ConvertGlobalSettings(); void ConvertGlobalSettings();
// ------------------------------------------------------------------------------------------------
// Will perform the conversion from a given unit to the requested unit.
void ConvertToUnitScale(FbxUnit unit);
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// copy generated meshes, animations, lights, cameras and textures to the output scene // copy generated meshes, animations, lights, cameras and textures to the output scene
void TransferDataToScene(); void TransferDataToScene();
// ------------------------------------------------------------------------------------------------
// FBX file could have embedded textures not connected to anything
void ConvertOrphantEmbeddedTextures();
private: private:
// 0: not assigned yet, others: index is value - 1 // 0: not assigned yet, others: index is value - 1
unsigned int defaultMaterialIndex; unsigned int defaultMaterialIndex;
@ -449,31 +442,47 @@ private:
std::vector<aiCamera*> cameras; std::vector<aiCamera*> cameras;
std::vector<aiTexture*> textures; std::vector<aiTexture*> textures;
using MaterialMap = std::map<const Material*, unsigned int>; using MaterialMap = std::fbx_unordered_map<const Material*, unsigned int>;
MaterialMap materials_converted; MaterialMap materials_converted;
using VideoMap = std::map<const Video*, unsigned int>; using VideoMap = std::fbx_unordered_map<const Video, unsigned int>;
VideoMap textures_converted; VideoMap textures_converted;
using MeshMap = std::map<const Geometry*, std::vector<unsigned int> >; using MeshMap = std::fbx_unordered_map<const Geometry*, std::vector<unsigned int> >;
MeshMap meshes_converted; MeshMap meshes_converted;
// fixed node name -> which trafo chain components have animations? // fixed node name -> which trafo chain components have animations?
using NodeAnimBitMap = std::map<std::string, unsigned int> ; using NodeAnimBitMap = std::fbx_unordered_map<std::string, unsigned int> ;
NodeAnimBitMap node_anim_chain_bits; NodeAnimBitMap node_anim_chain_bits;
// number of nodes with the same name // number of nodes with the same name
using NodeNameCache = std::unordered_map<std::string, unsigned int>; using NodeNameCache = std::fbx_unordered_map<std::string, unsigned int>;
NodeNameCache mNodeNames; NodeNameCache mNodeNames;
// Deformer name is not the same as a bone name - it does contain the bone name though :)
// Deformer names in FBX are always unique in an FBX file.
std::map<const std::string, aiBone *> bone_map;
double anim_fps; double anim_fps;
aiScene* const out; aiScene* const out;
const FBX::Document& doc; const FBX::Document& doc;
bool mRemoveEmptyBones; static void BuildBoneList(aiNode *current_node, const aiNode *root_node, const aiScene *scene,
std::vector<aiBone*>& bones);
FbxUnit mCurrentUnit; void BuildBoneStack(aiNode *current_node, const aiNode *root_node, const aiScene *scene,
const std::vector<aiBone *> &bones,
std::map<aiBone *, aiNode *> &bone_stack,
std::vector<aiNode*> &node_stack );
static void BuildNodeList(aiNode *current_node, std::vector<aiNode *> &nodes);
static aiNode *GetNodeFromStack(const aiString &node_name, std::vector<aiNode *> &nodes);
static aiNode *GetArmatureRoot(aiNode *bone_node, std::vector<aiBone*> &bone_list);
static bool IsBoneNode(const aiString &bone_name, std::vector<aiBone *> &bones);
}; };
} }

View File

@ -90,14 +90,6 @@ const Object* LazyObject::Get(bool dieOnError)
return object.get(); return object.get();
} }
// if this is the root object, we return a dummy since there
// is no root object int he fbx file - it is just referenced
// with id 0.
if(id == 0L) {
object.reset(new Object(id, element, "Model::RootNode"));
return object.get();
}
const Token& key = element.KeyToken(); const Token& key = element.KeyToken();
const TokenList& tokens = element.Tokens(); const TokenList& tokens = element.Tokens();

View File

@ -637,6 +637,20 @@ public:
return ptr; return ptr;
} }
bool operator==(const Video& other) const
{
return (
type == other.type
&& relativeFileName == other.relativeFileName
&& fileName == other.fileName
);
}
bool operator<(const Video& other) const
{
return std::tie(type, relativeFileName, fileName) < std::tie(other.type, other.relativeFileName, other.fileName);
}
private: private:
std::string type; std::string type;
std::string relativeFileName; std::string relativeFileName;
@ -1005,10 +1019,10 @@ public:
// during their entire lifetime (Document). FBX files have // during their entire lifetime (Document). FBX files have
// up to many thousands of objects (most of which we never use), // up to many thousands of objects (most of which we never use),
// so the memory overhead for them should be kept at a minimum. // so the memory overhead for them should be kept at a minimum.
typedef std::map<uint64_t, LazyObject*> ObjectMap; typedef std::fbx_unordered_map<uint64_t, LazyObject*> ObjectMap;
typedef std::fbx_unordered_map<std::string, std::shared_ptr<const PropertyTable> > PropertyTemplateMap; typedef std::fbx_unordered_map<std::string, std::shared_ptr<const PropertyTable> > PropertyTemplateMap;
typedef std::multimap<uint64_t, const Connection*> ConnectionMap; typedef std::fbx_unordered_multimap<uint64_t, const Connection*> ConnectionMap;
/** DOM class for global document settings, a single instance per document can /** DOM class for global document settings, a single instance per document can
* be accessed via Document.Globals(). */ * be accessed via Document.Globals(). */
@ -1177,4 +1191,25 @@ private:
} // Namespace FBX } // Namespace FBX
} // Namespace Assimp } // Namespace Assimp
namespace std
{
template <>
struct hash<const Assimp::FBX::Video>
{
std::size_t operator()(const Assimp::FBX::Video& video) const
{
using std::size_t;
using std::hash;
using std::string;
size_t res = 17;
res = res * 31 + hash<string>()(video.Name());
res = res * 31 + hash<string>()(video.RelativeFilename());
res = res * 31 + hash<string>()(video.Type());
return res;
}
};
}
#endif // INCLUDED_AI_FBX_DOCUMENT_H #endif // INCLUDED_AI_FBX_DOCUMENT_H

View File

@ -325,9 +325,9 @@ void FBX::Node::BeginBinary(Assimp::StreamWriterLE &s)
this->start_pos = s.Tell(); this->start_pos = s.Tell();
// placeholders for end pos and property section info // placeholders for end pos and property section info
s.PutU4(0); // end pos s.PutU8(0); // end pos
s.PutU4(0); // number of properties s.PutU8(0); // number of properties
s.PutU4(0); // total property section length s.PutU8(0); // total property section length
// node name // node name
s.PutU1(uint8_t(name.size())); // length of node name s.PutU1(uint8_t(name.size())); // length of node name
@ -352,9 +352,9 @@ void FBX::Node::EndPropertiesBinary(
size_t pos = s.Tell(); size_t pos = s.Tell();
ai_assert(pos > property_start); ai_assert(pos > property_start);
size_t property_section_size = pos - property_start; size_t property_section_size = pos - property_start;
s.Seek(start_pos + 4); s.Seek(start_pos + 8); // 8 bytes of uint64_t of end_pos
s.PutU4(uint32_t(num_properties)); s.PutU8(num_properties);
s.PutU4(uint32_t(property_section_size)); s.PutU8(property_section_size);
s.Seek(pos); s.Seek(pos);
} }
@ -375,7 +375,7 @@ void FBX::Node::EndBinary(
// now go back and write initial pos // now go back and write initial pos
this->end_pos = s.Tell(); this->end_pos = s.Tell();
s.Seek(start_pos); s.Seek(start_pos);
s.PutU4(uint32_t(end_pos)); s.PutU8(end_pos);
s.Seek(end_pos); s.Seek(end_pos);
} }

View File

@ -59,11 +59,7 @@ namespace FBX {
FBXExportProperty::FBXExportProperty(bool v) FBXExportProperty::FBXExportProperty(bool v)
: type('C') : type('C')
, data(1) { , data(1, uint8_t(v)) {}
data = {
uint8_t(v)
};
}
FBXExportProperty::FBXExportProperty(int16_t v) FBXExportProperty::FBXExportProperty(int16_t v)
: type('Y') : type('Y')

View File

@ -67,6 +67,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <vector> #include <vector>
#include <array> #include <array>
#include <unordered_set> #include <unordered_set>
#include <numeric>
// RESOURCES: // RESOURCES:
// https://code.blender.org/2013/08/fbx-binary-file-format-specification/ // https://code.blender.org/2013/08/fbx-binary-file-format-specification/
@ -80,8 +81,8 @@ using namespace Assimp::FBX;
// some constants that we'll use for writing metadata // some constants that we'll use for writing metadata
namespace Assimp { namespace Assimp {
namespace FBX { namespace FBX {
const std::string EXPORT_VERSION_STR = "7.4.0"; const std::string EXPORT_VERSION_STR = "7.5.0";
const uint32_t EXPORT_VERSION_INT = 7400; // 7.4 == 2014/2015 const uint32_t EXPORT_VERSION_INT = 7500; // 7.5 == 2016+
// FBX files have some hashed values that depend on the creation time field, // FBX files have some hashed values that depend on the creation time field,
// but for now we don't actually know how to generate these. // but for now we don't actually know how to generate these.
// what we can do is set them to a known-working version. // what we can do is set them to a known-working version.
@ -1005,6 +1006,9 @@ void FBXExporter::WriteObjects ()
object_node.EndProperties(outstream, binary, indent); object_node.EndProperties(outstream, binary, indent);
object_node.BeginChildren(outstream, binary, indent); object_node.BeginChildren(outstream, binary, indent);
bool bJoinIdenticalVertices = mProperties->GetPropertyBool("bJoinIdenticalVertices", true);
std::vector<std::vector<int32_t>> vVertexIndice;//save vertex_indices as it is needed later
// geometry (aiMesh) // geometry (aiMesh)
mesh_uids.clear(); mesh_uids.clear();
indent = 1; indent = 1;
@ -1031,6 +1035,7 @@ void FBXExporter::WriteObjects ()
std::vector<int32_t> vertex_indices; std::vector<int32_t> vertex_indices;
// map of vertex value to its index in the data vector // map of vertex value to its index in the data vector
std::map<aiVector3D,size_t> index_by_vertex_value; std::map<aiVector3D,size_t> index_by_vertex_value;
if(bJoinIdenticalVertices){
int32_t index = 0; int32_t index = 0;
for (size_t vi = 0; vi < m->mNumVertices; ++vi) { for (size_t vi = 0; vi < m->mNumVertices; ++vi) {
aiVector3D vtx = m->mVertices[vi]; aiVector3D vtx = m->mVertices[vi];
@ -1046,6 +1051,19 @@ void FBXExporter::WriteObjects ()
vertex_indices.push_back(int32_t(elem->second)); vertex_indices.push_back(int32_t(elem->second));
} }
} }
}
else { // do not join vertex, respect the export flag
vertex_indices.resize(m->mNumVertices);
std::iota(vertex_indices.begin(), vertex_indices.end(), 0);
for(unsigned int v = 0; v < m->mNumVertices; ++ v) {
aiVector3D vtx = m->mVertices[v];
flattened_vertices.push_back(vtx.x);
flattened_vertices.push_back(vtx.y);
flattened_vertices.push_back(vtx.z);
}
}
vVertexIndice.push_back(vertex_indices);
FBX::Node::WritePropertyNode( FBX::Node::WritePropertyNode(
"Vertices", flattened_vertices, outstream, binary, indent "Vertices", flattened_vertices, outstream, binary, indent
); );
@ -1116,6 +1134,51 @@ void FBXExporter::WriteObjects ()
normals.End(outstream, binary, indent, true); normals.End(outstream, binary, indent, true);
} }
// colors, if any
// TODO only one color channel currently
const int32_t colorChannelIndex = 0;
if (m->HasVertexColors(colorChannelIndex)) {
FBX::Node vertexcolors("LayerElementColor", int32_t(colorChannelIndex));
vertexcolors.Begin(outstream, binary, indent);
vertexcolors.DumpProperties(outstream, binary, indent);
vertexcolors.EndProperties(outstream, binary, indent);
vertexcolors.BeginChildren(outstream, binary, indent);
indent = 3;
FBX::Node::WritePropertyNode(
"Version", int32_t(101), outstream, binary, indent
);
char layerName[8];
sprintf(layerName, "COLOR_%d", colorChannelIndex);
FBX::Node::WritePropertyNode(
"Name", (const char*)layerName, outstream, binary, indent
);
FBX::Node::WritePropertyNode(
"MappingInformationType", "ByPolygonVertex",
outstream, binary, indent
);
FBX::Node::WritePropertyNode(
"ReferenceInformationType", "Direct",
outstream, binary, indent
);
std::vector<double> color_data;
color_data.reserve(4 * polygon_data.size());
for (size_t fi = 0; fi < m->mNumFaces; ++fi) {
const aiFace &f = m->mFaces[fi];
for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) {
const aiColor4D &c = m->mColors[colorChannelIndex][f.mIndices[pvi]];
color_data.push_back(c.r);
color_data.push_back(c.g);
color_data.push_back(c.b);
color_data.push_back(c.a);
}
}
FBX::Node::WritePropertyNode(
"Colors", color_data, outstream, binary, indent
);
indent = 2;
vertexcolors.End(outstream, binary, indent, true);
}
// uvs, if any // uvs, if any
for (size_t uvi = 0; uvi < m->GetNumUVChannels(); ++uvi) { for (size_t uvi = 0; uvi < m->GetNumUVChannels(); ++uvi) {
if (m->mNumUVComponents[uvi] > 2) { if (m->mNumUVComponents[uvi] > 2) {
@ -1209,6 +1272,11 @@ void FBXExporter::WriteObjects ()
le.AddChild("Type", "LayerElementNormal"); le.AddChild("Type", "LayerElementNormal");
le.AddChild("TypedIndex", int32_t(0)); le.AddChild("TypedIndex", int32_t(0));
layer.AddChild(le); layer.AddChild(le);
// TODO only 1 color channel currently
le = FBX::Node("LayerElement");
le.AddChild("Type", "LayerElementColor");
le.AddChild("TypedIndex", int32_t(0));
layer.AddChild(le);
le = FBX::Node("LayerElement"); le = FBX::Node("LayerElement");
le.AddChild("Type", "LayerElementMaterial"); le.AddChild("Type", "LayerElementMaterial");
le.AddChild("TypedIndex", int32_t(0)); le.AddChild("TypedIndex", int32_t(0));
@ -1219,6 +1287,16 @@ void FBXExporter::WriteObjects ()
layer.AddChild(le); layer.AddChild(le);
layer.Dump(outstream, binary, indent); layer.Dump(outstream, binary, indent);
for(unsigned int lr = 1; lr < m->GetNumUVChannels(); ++ lr)
{
FBX::Node layerExtra("Layer", int32_t(lr));
layerExtra.AddChild("Version", int32_t(100));
FBX::Node leExtra("LayerElement");
leExtra.AddChild("Type", "LayerElementUV");
leExtra.AddChild("TypedIndex", int32_t(lr));
layerExtra.AddChild(leExtra);
layerExtra.Dump(outstream, binary, indent);
}
// finish the node record // finish the node record
indent = 1; indent = 1;
n.End(outstream, binary, indent, true); n.End(outstream, binary, indent, true);
@ -1617,6 +1695,17 @@ void FBXExporter::WriteObjects ()
// at the same time we can build a list of all the skeleton nodes, // at the same time we can build a list of all the skeleton nodes,
// which will be used later to mark them as type "limbNode". // which will be used later to mark them as type "limbNode".
std::unordered_set<const aiNode*> limbnodes; std::unordered_set<const aiNode*> limbnodes;
//actual bone nodes in fbx, without parenting-up
std::unordered_set<std::string> setAllBoneNamesInScene;
for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m)
{
aiMesh* pMesh = mScene->mMeshes[m];
for(unsigned int b = 0; b < pMesh->mNumBones; ++ b)
setAllBoneNamesInScene.insert(pMesh->mBones[b]->mName.data);
}
aiMatrix4x4 mxTransIdentity;
// and a map of nodes by bone name, as finding them is annoying. // and a map of nodes by bone name, as finding them is annoying.
std::map<std::string,aiNode*> node_by_bone; std::map<std::string,aiNode*> node_by_bone;
for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) { for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
@ -1660,6 +1749,11 @@ void FBXExporter::WriteObjects ()
if (node_name.find(MAGIC_NODE_TAG) != std::string::npos) { if (node_name.find(MAGIC_NODE_TAG) != std::string::npos) {
continue; continue;
} }
//not a bone in scene && no effect in transform
if(setAllBoneNamesInScene.find(node_name)==setAllBoneNamesInScene.end()
&& parent->mTransformation == mxTransIdentity) {
continue;
}
// otherwise check if this is the root of the skeleton // otherwise check if this is the root of the skeleton
bool end = false; bool end = false;
// is the mesh part of this node? // is the mesh part of this node?
@ -1680,8 +1774,7 @@ void FBXExporter::WriteObjects ()
} }
if (end) { break; } if (end) { break; }
} }
limbnodes.insert(parent);
skeleton.insert(parent);
// if it was the skeleton root we can finish here // if it was the skeleton root we can finish here
if (end) { break; } if (end) { break; }
} }
@ -1723,28 +1816,8 @@ void FBXExporter::WriteObjects ()
// connect it // connect it
connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mi]); connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mi]);
// we will be indexing by vertex... //computed before
// but there might be a different number of "vertices" std::vector<int32_t>& vertex_indices = vVertexIndice[mi];
// between assimp and our output FBX.
// this code is cut-and-pasted from the geometry section above...
// ideally this should not be so.
// ---
// index of original vertex in vertex data vector
std::vector<int32_t> vertex_indices;
// map of vertex value to its index in the data vector
std::map<aiVector3D,size_t> index_by_vertex_value;
int32_t index = 0;
for (size_t vi = 0; vi < m->mNumVertices; ++vi) {
aiVector3D vtx = m->mVertices[vi];
auto elem = index_by_vertex_value.find(vtx);
if (elem == index_by_vertex_value.end()) {
vertex_indices.push_back(index);
index_by_vertex_value[vtx] = index;
++index;
} else {
vertex_indices.push_back(int32_t(elem->second));
}
}
// TODO, FIXME: this won't work if anything is not in the bind pose. // TODO, FIXME: this won't work if anything is not in the bind pose.
// for now if such a situation is detected, we throw an exception. // for now if such a situation is detected, we throw an exception.
@ -1822,41 +1895,10 @@ void FBXExporter::WriteObjects ()
inverse_bone_xform.Inverse(); inverse_bone_xform.Inverse();
aiMatrix4x4 tr = inverse_bone_xform * mesh_xform; aiMatrix4x4 tr = inverse_bone_xform * mesh_xform;
// this should be the same as the bone's mOffsetMatrix.
// if it's not the same, the skeleton isn't in the bind pose.
const float epsilon = 1e-4f; // some error is to be expected
bool bone_xform_okay = true;
if (b && ! tr.Equal(b->mOffsetMatrix, epsilon)) {
not_in_bind_pose.insert(b);
bone_xform_okay = false;
}
// if we have a bone we should use the mOffsetMatrix,
// otherwise try to just use the calculated transform.
if (b) {
sdnode.AddChild("Transform", b->mOffsetMatrix);
} else {
sdnode.AddChild("Transform", tr); sdnode.AddChild("Transform", tr);
}
// note: it doesn't matter if we mix these,
// because if they disagree we'll throw an exception later.
// it could be that the skeleton is not in the bone pose
// but all bones are still defined,
// in which case this would use the mOffsetMatrix for everything
// and a correct skeleton would still be output.
// transformlink should be the position of the bone in world space.
// if the bone is in the bind pose (or nonexistent),
// we can just use the matrix we already calculated
if (bone_xform_okay) {
sdnode.AddChild("TransformLink", bone_xform); sdnode.AddChild("TransformLink", bone_xform);
// otherwise we can only work it out using the mesh position.
} else {
aiMatrix4x4 trl = b->mOffsetMatrix;
trl.Inverse();
trl *= mesh_xform;
sdnode.AddChild("TransformLink", trl);
}
// note: this means we ALWAYS rely on the mesh node transform // note: this means we ALWAYS rely on the mesh node transform
// being unchanged from the time the skeleton was bound. // being unchanged from the time the skeleton was bound.
// there's not really any way around this at the moment. // there's not really any way around this at the moment.
@ -2441,7 +2483,7 @@ void FBXExporter::WriteModelNodes(
void FBXExporter::WriteAnimationCurveNode( void FBXExporter::WriteAnimationCurveNode(
StreamWriterLE& outstream, StreamWriterLE& outstream,
int64_t uid, int64_t uid,
std::string name, // "T", "R", or "S" const std::string& name, // "T", "R", or "S"
aiVector3D default_value, aiVector3D default_value,
std::string property_name, // "Lcl Translation" etc std::string property_name, // "Lcl Translation" etc
int64_t layer_uid, int64_t layer_uid,

View File

@ -156,7 +156,7 @@ namespace Assimp
void WriteAnimationCurveNode( void WriteAnimationCurveNode(
StreamWriterLE& outstream, StreamWriterLE& outstream,
int64_t uid, int64_t uid,
std::string name, // "T", "R", or "S" const std::string& name, // "T", "R", or "S"
aiVector3D default_value, aiVector3D default_value,
std::string property_name, // "Lcl Translation" etc std::string property_name, // "Lcl Translation" etc
int64_t animation_layer_uid, int64_t animation_layer_uid,

View File

@ -48,26 +48,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "FBXImporter.h" #include "FBXImporter.h"
#include "FBXTokenizer.h"
#include "FBXParser.h"
#include "FBXUtil.h"
#include "FBXDocument.h"
#include "FBXConverter.h" #include "FBXConverter.h"
#include "FBXDocument.h"
#include "FBXParser.h"
#include "FBXTokenizer.h"
#include "FBXUtil.h"
#include <assimp/StreamReader.h>
#include <assimp/MemoryIOWrapper.h> #include <assimp/MemoryIOWrapper.h>
#include <assimp/Importer.hpp> #include <assimp/StreamReader.h>
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <assimp/Importer.hpp>
namespace Assimp { namespace Assimp {
template<> template <>
const char* LogFunctions<FBXImporter>::Prefix() { const char *LogFunctions<FBXImporter>::Prefix() {
static auto prefix = "FBX: "; static auto prefix = "FBX: ";
return prefix; return prefix;
} }
} } // namespace Assimp
using namespace Assimp; using namespace Assimp;
using namespace Assimp::Formatter; using namespace Assimp::Formatter;
@ -91,44 +91,39 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by #Importer // Constructor to be privately used by #Importer
FBXImporter::FBXImporter() FBXImporter::FBXImporter() {
{
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
FBXImporter::~FBXImporter() FBXImporter::~FBXImporter() {
{
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// 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 FBXImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const bool FBXImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
{ const std::string &extension = GetExtension(pFile);
const std::string& extension = GetExtension(pFile); if (extension == std::string(desc.mFileExtensions)) {
if (extension == std::string( desc.mFileExtensions ) ) {
return true; return true;
} }
else if ((!extension.length() || checkSig) && pIOHandler) { else if ((!extension.length() || checkSig) && pIOHandler) {
// at least ASCII-FBX files usually have a 'FBX' somewhere in their head // at least ASCII-FBX files usually have a 'FBX' somewhere in their head
const char* tokens[] = {"fbx"}; const char *tokens[] = { "fbx" };
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
} }
return false; return false;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// List all extensions handled by this loader // List all extensions handled by this loader
const aiImporterDesc* FBXImporter::GetInfo () const const aiImporterDesc *FBXImporter::GetInfo() const {
{
return &desc; return &desc;
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Setup configuration properties for the loader // Setup configuration properties for the loader
void FBXImporter::SetupProperties(const Importer* pImp) void FBXImporter::SetupProperties(const Importer *pImp) {
{
settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true); settings.readAllLayers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_GEOMETRY_LAYERS, true);
settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false); settings.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true); settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
@ -146,9 +141,8 @@ void FBXImporter::SetupProperties(const Importer* pImp)
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports the given file into the given scene structure. // Imports the given file into the given scene structure.
void FBXImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
{ std::unique_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
std::unique_ptr<IOStream> stream(pIOHandler->Open(pFile,"rb"));
if (!stream) { if (!stream) {
ThrowException("Could not open file for reading"); ThrowException("Could not open file for reading");
} }
@ -159,10 +153,10 @@ void FBXImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
// streaming for its output data structures so the net win with // streaming for its output data structures so the net win with
// streaming input data would be very low. // streaming input data would be very low.
std::vector<char> contents; std::vector<char> contents;
contents.resize(stream->FileSize()+1); contents.resize(stream->FileSize() + 1);
stream->Read( &*contents.begin(), 1, contents.size()-1 ); stream->Read(&*contents.begin(), 1, contents.size() - 1);
contents[ contents.size() - 1 ] = 0; contents[contents.size() - 1] = 0;
const char* const begin = &*contents.begin(); const char *const begin = &*contents.begin();
// broadphase tokenizing pass in which we identify the core // broadphase tokenizing pass in which we identify the core
// syntax elements of FBX (brackets, commas, key:value mappings) // syntax elements of FBX (brackets, commas, key:value mappings)
@ -170,12 +164,11 @@ void FBXImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
try { try {
bool is_binary = false; bool is_binary = false;
if (!strncmp(begin,"Kaydara FBX Binary",18)) { if (!strncmp(begin, "Kaydara FBX Binary", 18)) {
is_binary = true; is_binary = true;
TokenizeBinary(tokens,begin,contents.size()); TokenizeBinary(tokens, begin, contents.size());
} } else {
else { Tokenize(tokens, begin);
Tokenize(tokens,begin);
} }
// use this information to construct a very rudimentary // use this information to construct a very rudimentary
@ -183,19 +176,21 @@ void FBXImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
Parser parser(tokens, is_binary); Parser parser(tokens, is_binary);
// take the raw parse-tree and convert it to a FBX DOM // take the raw parse-tree and convert it to a FBX DOM
Document doc(parser,settings); Document doc(parser, settings);
FbxUnit unit(FbxUnit::cm);
if (settings.convertToMeters) {
unit = FbxUnit::m;
}
// convert the FBX DOM to aiScene // convert the FBX DOM to aiScene
ConvertToAssimpScene(pScene,doc, settings.removeEmptyBones, unit); ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones);
std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>()); // size relative to cm
} float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
catch(std::exception&) {
std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>()); // Set FBX file scale is relative to CM must be converted to M for
// assimp universal format (M)
SetFileScale(size_relative_to_cm * 0.01f);
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
} catch (std::exception &) {
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
throw; throw;
} }
} }

View File

@ -115,7 +115,6 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
if(tempVerts.empty()) { if(tempVerts.empty()) {
FBXImporter::LogWarn("encountered mesh with no vertices"); FBXImporter::LogWarn("encountered mesh with no vertices");
return;
} }
std::vector<int> tempFaces; std::vector<int> tempFaces;
@ -123,7 +122,6 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
if(tempFaces.empty()) { if(tempFaces.empty()) {
FBXImporter::LogWarn("encountered mesh with no faces"); FBXImporter::LogWarn("encountered mesh with no faces");
return;
} }
m_vertices.reserve(tempFaces.size()); m_vertices.reserve(tempFaces.size());
@ -612,7 +610,10 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, cons
const std::string& ReferenceInformationType) const std::string& ReferenceInformationType)
{ {
const size_t face_count = m_faces.size(); const size_t face_count = m_faces.size();
ai_assert(face_count); if( 0 == face_count )
{
return;
}
// materials are handled separately. First of all, they are assigned per-face // materials are handled separately. First of all, they are assigned per-face
// and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect // and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
@ -624,16 +625,14 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, cons
if (materials_out.empty()) { if (materials_out.empty()) {
FBXImporter::LogError(Formatter::format("expected material index, ignoring")); FBXImporter::LogError(Formatter::format("expected material index, ignoring"));
return; return;
} } else if (materials_out.size() > 1) {
else if (materials_out.size() > 1) {
FBXImporter::LogWarn(Formatter::format("expected only a single material index, ignoring all except the first one")); FBXImporter::LogWarn(Formatter::format("expected only a single material index, ignoring all except the first one"));
materials_out.clear(); materials_out.clear();
} }
materials_out.resize(m_vertices.size()); materials_out.resize(m_vertices.size());
std::fill(materials_out.begin(), materials_out.end(), materials_out.at(0)); std::fill(materials_out.begin(), materials_out.end(), materials_out.at(0));
} } else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") {
else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") {
materials_out.resize(face_count); materials_out.resize(face_count);
if(materials_out.size() != face_count) { if(materials_out.size() != face_count) {
@ -642,18 +641,16 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, cons
); );
return; return;
} }
} } else {
else {
FBXImporter::LogError(Formatter::format("ignoring material assignments, access type not implemented: ") FBXImporter::LogError(Formatter::format("ignoring material assignments, access type not implemented: ")
<< MappingInformationType << "," << ReferenceInformationType); << MappingInformationType << "," << ReferenceInformationType);
} }
} }
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
ShapeGeometry::ShapeGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) ShapeGeometry::ShapeGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
: Geometry(id, element, name, doc) : Geometry(id, element, name, doc) {
{ const Scope *sc = element.Compound();
const Scope* sc = element.Compound(); if (nullptr == sc) {
if (!sc) {
DOMError("failed to read Geometry object (class: Shape), no data scope found"); DOMError("failed to read Geometry object (class: Shape), no data scope found");
} }
const Element& Indexes = GetRequiredElement(*sc, "Indexes", &element); const Element& Indexes = GetRequiredElement(*sc, "Indexes", &element);

View File

@ -311,10 +311,9 @@ class TrimmedCurve : public BoundedCurve {
public: public:
// -------------------------------------------------- // --------------------------------------------------
TrimmedCurve(const Schema_2x3::IfcTrimmedCurve& entity, ConversionData& conv) TrimmedCurve(const Schema_2x3::IfcTrimmedCurve& entity, ConversionData& conv)
: BoundedCurve(entity,conv) : BoundedCurve(entity,conv),
base(std::shared_ptr<const Curve>(Curve::Convert(entity.BasisCurve,conv)))
{ {
base = std::shared_ptr<const Curve>(Curve::Convert(entity.BasisCurve,conv));
typedef std::shared_ptr<const STEP::EXPRESS::DataType> Entry; typedef std::shared_ptr<const STEP::EXPRESS::DataType> Entry;
// for some reason, trimmed curves can either specify a parametric value // for some reason, trimmed curves can either specify a parametric value
@ -500,7 +499,7 @@ bool Curve::InRange(IfcFloat u) const {
if (IsClosed()) { if (IsClosed()) {
return true; return true;
} }
const IfcFloat epsilon = 1e-5; const IfcFloat epsilon = Math::getEpsilon<float>();
return u - range.first > -epsilon && range.second - u > -epsilon; return u - range.first > -epsilon && range.second - u > -epsilon;
} }
#endif #endif

View File

@ -128,7 +128,7 @@ void ProcessPolygonBoundaries(TempMesh& result, const TempMesh& inmesh, size_t m
outer_polygon_it = begin + master_bounds; outer_polygon_it = begin + master_bounds;
} }
else { else {
for(iit = begin; iit != end; iit++) { for(iit = begin; iit != end; ++iit) {
// find the polygon with the largest area and take it as the outer bound. // find the polygon with the largest area and take it as the outer bound.
IfcVector3& n = normals[std::distance(begin,iit)]; IfcVector3& n = normals[std::distance(begin,iit)];
const IfcFloat area = n.SquareLength(); const IfcFloat area = n.SquareLength();

View File

@ -593,7 +593,7 @@ typedef std::vector<std::pair<
bool BoundingBoxesAdjacent(const BoundingBox& bb, const BoundingBox& ibb) bool BoundingBoxesAdjacent(const BoundingBox& bb, const BoundingBox& ibb)
{ {
// TODO: I'm pretty sure there is a much more compact way to check this // TODO: I'm pretty sure there is a much more compact way to check this
const IfcFloat epsilon = 1e-5f; const IfcFloat epsilon = Math::getEpsilon<float>();
return (std::fabs(bb.second.x - ibb.first.x) < epsilon && bb.first.y <= ibb.second.y && bb.second.y >= ibb.first.y) || return (std::fabs(bb.second.x - ibb.first.x) < epsilon && bb.first.y <= ibb.second.y && bb.second.y >= ibb.first.y) ||
(std::fabs(bb.first.x - ibb.second.x) < epsilon && ibb.first.y <= bb.second.y && ibb.second.y >= bb.first.y) || (std::fabs(bb.first.x - ibb.second.x) < epsilon && ibb.first.y <= bb.second.y && ibb.second.y >= bb.first.y) ||
(std::fabs(bb.second.y - ibb.first.y) < epsilon && bb.first.x <= ibb.second.x && bb.second.x >= ibb.first.x) || (std::fabs(bb.second.y - ibb.first.y) < epsilon && bb.first.x <= ibb.second.x && bb.second.x >= ibb.first.x) ||
@ -681,7 +681,7 @@ bool IntersectingLineSegments(const IfcVector2& n0, const IfcVector2& n1,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void FindAdjacentContours(ContourVector::iterator current, const ContourVector& contours) void FindAdjacentContours(ContourVector::iterator current, const ContourVector& contours)
{ {
const IfcFloat sqlen_epsilon = static_cast<IfcFloat>(1e-8); const IfcFloat sqlen_epsilon = static_cast<IfcFloat>(Math::getEpsilon<float>());
const BoundingBox& bb = (*current).bb; const BoundingBox& bb = (*current).bb;
// What is to be done here is to populate the skip lists for the contour // What is to be done here is to populate the skip lists for the contour
@ -758,7 +758,7 @@ void FindAdjacentContours(ContourVector::iterator current, const ContourVector&
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
AI_FORCE_INLINE bool LikelyBorder(const IfcVector2& vdelta) AI_FORCE_INLINE bool LikelyBorder(const IfcVector2& vdelta)
{ {
const IfcFloat dot_point_epsilon = static_cast<IfcFloat>(1e-5); const IfcFloat dot_point_epsilon = static_cast<IfcFloat>(Math::getEpsilon<float>());
return std::fabs(vdelta.x * vdelta.y) < dot_point_epsilon; return std::fabs(vdelta.x * vdelta.y) < dot_point_epsilon;
} }

View File

@ -57,7 +57,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/material.h> #include <assimp/material.h>
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <assimp/Macros.h>
using namespace Assimp; using namespace Assimp;
using namespace irr; using namespace irr;

View File

@ -0,0 +1,420 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
Copyright (c) 2019 bzt
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_M3D_EXPORTER
#define M3D_IMPLEMENTATION
#define M3D_NOIMPORTER
#define M3D_EXPORTER
#define M3D_ASCII
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
#define M3D_NODUP
#endif
// Header files, standard library.
#include <memory> // shared_ptr
#include <string>
#include <vector>
#include <assimp/version.h> // aiGetVersion
#include <assimp/IOSystem.hpp>
#include <assimp/Exporter.hpp>
#include <assimp/DefaultLogger.hpp>
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <assimp/Exceptional.h> // DeadlyExportError
#include <assimp/material.h> // aiTextureType
#include <assimp/scene.h>
#include <assimp/mesh.h>
#include "M3DExporter.h"
#include "M3DMaterials.h"
// RESOURCES:
// https://gitlab.com/bztsrc/model3d/blob/master/docs/m3d_format.md
// https://gitlab.com/bztsrc/model3d/blob/master/docs/a3d_format.md
/*
* Currently supports static meshes, vertex colors, materials, textures
*
* For animation, it would require the following conversions:
* - aiNode (bones) -> m3d_t.bone (with parent id, position vector and oriantation quaternion)
* - aiMesh.aiBone -> m3d_t.skin (per vertex, with bone id, weight pairs)
* - aiAnimation -> m3d_action (frame with timestamp and list of bone id, position, orientation
* triplets, instead of per bone timestamp + lists)
*/
using namespace Assimp;
namespace Assimp {
// ---------------------------------------------------------------------
// Worker function for exporting a scene to binary M3D.
// Prototyped and registered in Exporter.cpp
void ExportSceneM3D (
const char* pFile,
IOSystem* pIOSystem,
const aiScene* pScene,
const ExportProperties* pProperties
){
// initialize the exporter
M3DExporter exporter(pScene, pProperties);
// perform binary export
exporter.doExport(pFile, pIOSystem, false);
}
// ---------------------------------------------------------------------
// Worker function for exporting a scene to ASCII A3D.
// Prototyped and registered in Exporter.cpp
void ExportSceneA3D (
const char* pFile,
IOSystem* pIOSystem,
const aiScene* pScene,
const ExportProperties* pProperties
){
// initialize the exporter
M3DExporter exporter(pScene, pProperties);
// perform ascii export
exporter.doExport(pFile, pIOSystem, true);
}
} // end of namespace Assimp
// ------------------------------------------------------------------------------------------------
M3DExporter::M3DExporter ( const aiScene* pScene, const ExportProperties* pProperties )
: mScene(pScene)
, mProperties(pProperties)
, outfile()
, m3d(nullptr) { }
// ------------------------------------------------------------------------------------------------
void M3DExporter::doExport (
const char* pFile,
IOSystem* pIOSystem,
bool toAscii
){
// TODO: convert mProperties into M3D_EXP_* flags
(void)mProperties;
// open the indicated file for writing (in binary / ASCII mode)
outfile.reset(pIOSystem->Open(pFile, toAscii ? "wt" : "wb"));
if (!outfile) {
throw DeadlyExportError( "could not open output .m3d file: " + std::string(pFile) );
}
// use malloc() here because m3d_free() will call free()
m3d = (m3d_t*)calloc(1, sizeof(m3d_t));
if(!m3d) {
throw DeadlyExportError( "memory allocation error" );
}
m3d->name = _m3d_safestr((char*)&mScene->mRootNode->mName.data, 2);
// Create a model from assimp structures
aiMatrix4x4 m;
NodeWalk(mScene->mRootNode, m);
// serialize the structures
unsigned int size;
unsigned char *output = m3d_save(m3d, M3D_EXP_FLOAT,
M3D_EXP_EXTRA | (toAscii ? M3D_EXP_ASCII : 0), &size);
m3d_free(m3d);
if(!output || size < 8) {
throw DeadlyExportError( "unable to serialize into Model 3D" );
}
// Write out serialized model
outfile->Write(output, size, 1);
// explicitly release file pointer,
// so we don't have to rely on class destruction.
outfile.reset();
}
// ------------------------------------------------------------------------------------------------
// helper to add a vertex (private to NodeWalk)
m3dv_t *M3DExporter::AddVrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx)
{
if(v->x == (M3D_FLOAT)-0.0) v->x = (M3D_FLOAT)0.0;
if(v->y == (M3D_FLOAT)-0.0) v->y = (M3D_FLOAT)0.0;
if(v->z == (M3D_FLOAT)-0.0) v->z = (M3D_FLOAT)0.0;
if(v->w == (M3D_FLOAT)-0.0) v->w = (M3D_FLOAT)0.0;
vrtx = (m3dv_t*)M3D_REALLOC(vrtx, ((*numvrtx) + 1) * sizeof(m3dv_t));
memcpy(&vrtx[*numvrtx], v, sizeof(m3dv_t));
*idx = *numvrtx;
(*numvrtx)++;
return vrtx;
}
// ------------------------------------------------------------------------------------------------
// helper to add a tmap (private to NodeWalk)
m3dti_t *M3DExporter::AddTmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *ti, uint32_t *idx)
{
tmap = (m3dti_t*)M3D_REALLOC(tmap, ((*numtmap) + 1) * sizeof(m3dti_t));
memcpy(&tmap[*numtmap], ti, sizeof(m3dti_t));
*idx = *numtmap;
(*numtmap)++;
return tmap;
}
// ------------------------------------------------------------------------------------------------
// recursive node walker
void M3DExporter::NodeWalk(const aiNode* pNode, aiMatrix4x4 m)
{
aiMatrix4x4 nm = m * pNode->mTransformation;
for(unsigned int i = 0; i < pNode->mNumMeshes; i++) {
const aiMesh *mesh = mScene->mMeshes[pNode->mMeshes[i]];
unsigned int mi = (M3D_INDEX)-1U;
if(mScene->mMaterials) {
// get the material for this mesh
mi = addMaterial(mScene->mMaterials[mesh->mMaterialIndex]);
}
// iterate through the mesh faces
for(unsigned int j = 0; j < mesh->mNumFaces; j++) {
unsigned int n;
const aiFace* face = &(mesh->mFaces[j]);
// only triangle meshes supported for now
if(face->mNumIndices != 3) {
throw DeadlyExportError( "use aiProcess_Triangulate before export" );
}
// add triangle to the output
n = m3d->numface++;
m3d->face = (m3df_t*)M3D_REALLOC(m3d->face,
m3d->numface * sizeof(m3df_t));
if(!m3d->face) {
throw DeadlyExportError( "memory allocation error" );
}
/* set all index to -1 by default */
m3d->face[n].vertex[0] = m3d->face[n].vertex[1] = m3d->face[n].vertex[2] =
m3d->face[n].normal[0] = m3d->face[n].normal[1] = m3d->face[n].normal[2] =
m3d->face[n].texcoord[0] = m3d->face[n].texcoord[1] = m3d->face[n].texcoord[2] = -1U;
m3d->face[n].materialid = mi;
for(unsigned int k = 0; k < face->mNumIndices; k++) {
// get the vertex's index
unsigned int l = face->mIndices[k];
unsigned int idx;
m3dv_t vertex;
m3dti_t ti;
// multiply the position vector by the transformation matrix
aiVector3D v = mesh->mVertices[l];
v *= nm;
vertex.x = v.x;
vertex.y = v.y;
vertex.z = v.z;
vertex.w = 1.0;
vertex.color = 0;
vertex.skinid = -1U;
// add color if defined
if(mesh->HasVertexColors(0))
vertex.color = mkColor(&mesh->mColors[0][l]);
// save the vertex to the output
m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex,
&vertex, &idx);
m3d->face[n].vertex[k] = (M3D_INDEX)idx;
// do we have texture coordinates?
if(mesh->HasTextureCoords(0)) {
ti.u = mesh->mTextureCoords[0][l].x;
ti.v = mesh->mTextureCoords[0][l].y;
m3d->tmap = AddTmap(m3d->tmap, &m3d->numtmap, &ti, &idx);
m3d->face[n].texcoord[k] = (M3D_INDEX)idx;
}
// do we have normal vectors?
if(mesh->HasNormals()) {
vertex.x = mesh->mNormals[l].x;
vertex.y = mesh->mNormals[l].y;
vertex.z = mesh->mNormals[l].z;
vertex.color = 0;
m3d->vertex = AddVrtx(m3d->vertex, &m3d->numvertex, &vertex, &idx);
m3d->face[n].normal[k] = (M3D_INDEX)idx;
}
}
}
}
// repeat for the children nodes
for (unsigned int i = 0; i < pNode->mNumChildren; i++) {
NodeWalk(pNode->mChildren[i], nm);
}
}
// ------------------------------------------------------------------------------------------------
// convert aiColor4D into uint32_t
uint32_t M3DExporter::mkColor(aiColor4D* c)
{
return ((uint8_t)(c->a*255) << 24L) |
((uint8_t)(c->b*255) << 16L) |
((uint8_t)(c->g*255) << 8L) |
((uint8_t)(c->r*255) << 0L);
}
// ------------------------------------------------------------------------------------------------
// add a material to the output
M3D_INDEX M3DExporter::addMaterial(const aiMaterial *mat)
{
unsigned int mi = -1U;
aiColor4D c;
aiString name;
ai_real f;
char *fn;
if(mat && mat->Get(AI_MATKEY_NAME, name) == AI_SUCCESS && name.length &&
strcmp((char*)&name.data, AI_DEFAULT_MATERIAL_NAME)) {
// check if we have saved a material by this name. This has to be done
// because only the referenced materials should be added to the output
for(unsigned int i = 0; i < m3d->nummaterial; i++)
if(!strcmp((char*)&name.data, m3d->material[i].name)) {
mi = i;
break;
}
// if not found, add the material to the output
if(mi == -1U) {
unsigned int k;
mi = m3d->nummaterial++;
m3d->material = (m3dm_t*)M3D_REALLOC(m3d->material, m3d->nummaterial
* sizeof(m3dm_t));
if(!m3d->material) {
throw DeadlyExportError( "memory allocation error" );
}
m3d->material[mi].name = _m3d_safestr((char*)&name.data, 0);
m3d->material[mi].numprop = 0;
m3d->material[mi].prop = NULL;
// iterate through the material property table and see what we got
for(k = 0; k < 15; k++) {
unsigned int j;
if(m3d_propertytypes[k].format == m3dpf_map)
continue;
if(aiProps[k].pKey) {
switch(m3d_propertytypes[k].format) {
case m3dpf_color:
if(mat->Get(aiProps[k].pKey, aiProps[k].type,
aiProps[k].index, c) == AI_SUCCESS)
addProp(&m3d->material[mi],
m3d_propertytypes[k].id, mkColor(&c));
break;
case m3dpf_float:
if(mat->Get(aiProps[k].pKey, aiProps[k].type,
aiProps[k].index, f) == AI_SUCCESS)
addProp(&m3d->material[mi],
m3d_propertytypes[k].id,
/* not (uint32_t)f, because we don't want to convert
* it, we want to see it as 32 bits of memory */
*((uint32_t*)&f));
break;
case m3dpf_uint8:
if(mat->Get(aiProps[k].pKey, aiProps[k].type,
aiProps[k].index, j) == AI_SUCCESS) {
// special conversion for illumination model property
if(m3d_propertytypes[k].id == m3dp_il) {
switch(j) {
case aiShadingMode_NoShading: j = 0; break;
case aiShadingMode_Phong: j = 2; break;
default: j = 1; break;
}
}
addProp(&m3d->material[mi],
m3d_propertytypes[k].id, j);
}
break;
default:
if(mat->Get(aiProps[k].pKey, aiProps[k].type,
aiProps[k].index, j) == AI_SUCCESS)
addProp(&m3d->material[mi],
m3d_propertytypes[k].id, j);
break;
}
}
if(aiTxProps[k].pKey &&
mat->GetTexture((aiTextureType)aiTxProps[k].type,
aiTxProps[k].index, &name, NULL, NULL, NULL,
NULL, NULL) == AI_SUCCESS) {
unsigned int i;
for(j = name.length-1; j > 0 && name.data[j]!='.'; j++);
if(j && name.data[j]=='.' &&
(name.data[j+1]=='p' || name.data[j+1]=='P') &&
(name.data[j+1]=='n' || name.data[j+1]=='N') &&
(name.data[j+1]=='g' || name.data[j+1]=='G'))
name.data[j]=0;
// do we have this texture saved already?
fn = _m3d_safestr((char*)&name.data, 0);
for(j = 0, i = -1U; j < m3d->numtexture; j++)
if(!strcmp(fn, m3d->texture[j].name)) {
i = j;
free(fn);
break;
}
if(i == -1U) {
i = m3d->numtexture++;
m3d->texture = (m3dtx_t*)M3D_REALLOC(
m3d->texture,
m3d->numtexture * sizeof(m3dtx_t));
if(!m3d->texture) {
throw DeadlyExportError( "memory allocation error" );
}
// we don't need the texture itself, only its name
m3d->texture[i].name = fn;
m3d->texture[i].w = 0;
m3d->texture[i].h = 0;
m3d->texture[i].d = NULL;
}
addProp(&m3d->material[mi],
m3d_propertytypes[k].id + 128, i);
}
}
}
}
return mi;
}
// ------------------------------------------------------------------------------------------------
// add a material property to the output
void M3DExporter::addProp(m3dm_t *m, uint8_t type, uint32_t value)
{
unsigned int i;
i = m->numprop++;
m->prop = (m3dp_t*)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t));
if(!m->prop) { throw DeadlyExportError( "memory allocation error" ); }
m->prop[i].type = type;
m->prop[i].value.num = value;
}
#endif // ASSIMP_BUILD_NO_M3D_EXPORTER
#endif // ASSIMP_BUILD_NO_EXPORT

View File

@ -0,0 +1,100 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
Copyright (c) 2019 bzt
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 M3DExporter.h
* @brief Declares the exporter class to write a scene to a Model 3D file
*/
#ifndef AI_M3DEXPORTER_H_INC
#define AI_M3DEXPORTER_H_INC
#ifndef ASSIMP_BUILD_NO_M3D_EXPORTER
#include "m3d.h"
#include <assimp/types.h>
//#include <assimp/material.h>
#include <assimp/StreamWriter.h> // StreamWriterLE
#include <assimp/Exceptional.h> // DeadlyExportError
#include <memory> // shared_ptr
struct aiScene;
struct aiNode;
struct aiMaterial;
struct aiFace;
namespace Assimp
{
class IOSystem;
class IOStream;
class ExportProperties;
// ---------------------------------------------------------------------
/** Helper class to export a given scene to an M3D file. */
// ---------------------------------------------------------------------
class M3DExporter
{
public:
/// Constructor for a specific scene to export
M3DExporter(const aiScene* pScene, const ExportProperties* pProperties);
// call this to do the actual export
void doExport(const char* pFile, IOSystem* pIOSystem, bool toAscii);
private:
const aiScene* mScene; // the scene to export
const ExportProperties* mProperties; // currently unused
std::shared_ptr<IOStream> outfile; // file to write to
m3d_t *m3d; // model for the C library to convert to
// helper to do the recursive walking
void NodeWalk(const aiNode* pNode, aiMatrix4x4 m);
m3dv_t *AddVrtx(m3dv_t *vrtx, uint32_t *numvrtx, m3dv_t *v, uint32_t *idx);
m3dti_t *AddTmap(m3dti_t *tmap, uint32_t *numtmap, m3dti_t *ti, uint32_t *idx);
uint32_t mkColor(aiColor4D* c);
M3D_INDEX addMaterial(const aiMaterial *mat);
void addProp(m3dm_t *m, uint8_t type, uint32_t value);
};
}
#endif // ASSIMP_BUILD_NO_M3D_EXPORTER
#endif // AI_M3DEXPORTER_H_INC

View File

@ -0,0 +1,766 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
Copyright (c) 2019 bzt
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_M3D_IMPORTER
#define M3D_IMPLEMENTATION
#define M3D_ASCII
#define M3D_NONORMALS /* leave the post-processing to Assimp */
#define M3D_NOWEIGHTS
#define M3D_NOANIMATION
#include <assimp/IOStreamBuffer.h>
#include <memory>
#include <assimp/DefaultIOSystem.h>
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/ai_assert.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/importerdesc.h>
#include "M3DImporter.h"
#include "M3DMaterials.h"
// RESOURCES:
// https://gitlab.com/bztsrc/model3d/blob/master/docs/m3d_format.md
// https://gitlab.com/bztsrc/model3d/blob/master/docs/a3d_format.md
/*
Unfortunately aiNode has bone structures and meshes too, yet we can't assign
the mesh to a bone aiNode as a skin may refer to several aiNodes. Therefore
I've decided to import into this structure:
aiScene->mRootNode
| |->mMeshes (all the meshes)
| \->children (empty if there's no skeleton imported, no meshes)
| \->skeleton root aiNode*
| |->bone aiNode
| | \->subbone aiNode
| |->bone aiNode
| | ...
| \->bone aiNode
\->mMeshes[]
\->aiBone, referencing mesh-less aiNodes from above
* - normally one, but if a model has several skeleton roots, then all of them
are listed in aiScene->mRootNode->children, but all without meshes
*/
static const aiImporterDesc desc = {
"Model 3D Importer",
"",
"",
"",
aiImporterFlags_SupportBinaryFlavour,
0,
0,
0,
0,
"m3d a3d"
};
// workaround: the SDK expects a C callback, but we want to use Assimp::IOSystem to implement that
extern "C" {
void* m3dimporter_pIOHandler;
unsigned char *m3dimporter_readfile(char *fn, unsigned int *size) {
ai_assert( nullptr != fn );
ai_assert( nullptr != size );
std::string file(fn);
std::unique_ptr<Assimp::IOStream> pStream(
(reinterpret_cast<Assimp::IOSystem*>(m3dimporter_pIOHandler))->Open( file, "rb"));
size_t fileSize = 0;
unsigned char *data = NULL;
// sometimes pStream is nullptr for some reason (should be an empty object returning nothing I guess)
if(pStream) {
fileSize = pStream->FileSize();
// should be allocated with malloc(), because the library will call free() to deallocate
data = (unsigned char*)malloc(fileSize);
if( !data || !pStream.get() || !fileSize || fileSize != pStream->Read(data,1,fileSize)) {
pStream.reset();
*size = 0;
// don't throw a deadly exception, it's not fatal if we can't read an external asset
return nullptr;
}
pStream.reset();
}
*size = (int)fileSize;
return data;
}
}
namespace Assimp {
using namespace std;
// ------------------------------------------------------------------------------------------------
// Default constructor
M3DImporter::M3DImporter()
: mScene(nullptr)
, m3d(nullptr) { }
// ------------------------------------------------------------------------------------------------
// Destructor.
M3DImporter::~M3DImporter() {}
// ------------------------------------------------------------------------------------------------
// Returns true, if file is a binary or ASCII Model 3D file.
bool M3DImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler , bool checkSig) const {
const std::string extension = GetExtension(pFile);
if (extension == "m3d" || extension == "a3d")
return true;
else if (!extension.length() || checkSig) {
if (!pIOHandler) {
return true;
}
/*
* don't use CheckMagicToken because that checks with swapped bytes too, leading to false
* positives. This magic is not uint32_t, but char[4], so memcmp is the best way
const char* tokens[] = {"3DMO", "3dmo"};
return CheckMagicToken(pIOHandler,pFile,tokens,2,0,4);
*/
std::unique_ptr<IOStream> pStream (pIOHandler->Open(pFile, "rb"));
unsigned char data[4];
if(4 != pStream->Read(data,1,4)) {
return false;
}
return !memcmp(data, "3DMO", 4) /* bin */ || !memcmp(data, "3dmo", 4) /* ASCII */;
}
return false;
}
// ------------------------------------------------------------------------------------------------
const aiImporterDesc* M3DImporter::GetInfo() const {
return &desc;
}
// ------------------------------------------------------------------------------------------------
// Model 3D import implementation
void M3DImporter::InternReadFile( const std::string &file, aiScene* pScene, IOSystem* pIOHandler) {
// Read file into memory
std::unique_ptr<IOStream> pStream( pIOHandler->Open( file, "rb"));
if( !pStream.get() ) {
throw DeadlyImportError( "Failed to open file " + file + "." );
}
// Get the file-size and validate it, throwing an exception when fails
size_t fileSize = pStream->FileSize();
if( fileSize < 8 ) {
throw DeadlyImportError( "M3D-file " + file + " is too small." );
}
std::unique_ptr<unsigned char[]> _buffer (new unsigned char[fileSize]);
unsigned char *data( _buffer.get() );
if(fileSize != pStream->Read(data,1,fileSize)) {
throw DeadlyImportError( "Failed to read the file " + file + "." );
}
// Get the path for external assets
std::string folderName( "./" );
std::string::size_type pos = file.find_last_of( "\\/" );
if ( pos != std::string::npos ) {
folderName = file.substr( 0, pos );
if ( !folderName.empty() ) {
pIOHandler->PushDirectory( folderName );
}
}
// pass this IOHandler to the C callback
m3dimporter_pIOHandler = pIOHandler;
//DefaultLogger::create("/dev/stderr", Logger::VERBOSE);
ASSIMP_LOG_DEBUG_F("M3D: loading ", file);
// let the C SDK do the hard work for us
m3d = m3d_load(&data[0], m3dimporter_readfile, free, nullptr);
m3dimporter_pIOHandler = nullptr;
if( !m3d ) {
throw DeadlyImportError( "Unable to parse " + file + " as M3D." );
}
// create the root node
pScene->mRootNode = new aiNode;
pScene->mRootNode->mName = aiString(std::string(std::string(m3d->name)));
pScene->mRootNode->mTransformation = aiMatrix4x4();
pScene->mRootNode->mNumChildren = 0;
mScene = pScene;
ASSIMP_LOG_DEBUG("M3D: root node " + std::string(m3d->name));
// now we just have to fill up the Assimp structures in pScene
importMaterials();
importTextures();
importBones(-1U, pScene->mRootNode);
importMeshes();
importAnimations();
// we don't need the SDK's version any more
m3d_free(m3d);
// Pop directory stack
if ( pIOHandler->StackSize() > 0 ) {
pIOHandler->PopDirectory();
}
}
// ------------------------------------------------------------------------------------------------
// convert materials. properties are converted using a static table in M3DMaterials.h
void M3DImporter::importMaterials()
{
unsigned int i, j, k, l, n;
m3dm_t *m;
aiString name = aiString(AI_DEFAULT_MATERIAL_NAME);
aiColor4D c;
ai_real f;
ai_assert(mScene != nullptr);
ai_assert(m3d != nullptr);
mScene->mNumMaterials = m3d->nummaterial + 1;
mScene->mMaterials = new aiMaterial*[ m3d->nummaterial + 1 ];
ASSIMP_LOG_DEBUG_F("M3D: importMaterials ", mScene->mNumMaterials);
// add a default material as first
aiMaterial* mat = new aiMaterial;
mat->AddProperty( &name, AI_MATKEY_NAME );
c.a = 1.0; c.b = c.g = c.r = 0.6;
mat->AddProperty( &c, 1, AI_MATKEY_COLOR_DIFFUSE);
mScene->mMaterials[0] = mat;
for(i = 0; i < m3d->nummaterial; i++) {
m = &m3d->material[i];
aiMaterial* mat = new aiMaterial;
name.Set(std::string(m->name));
mat->AddProperty( &name, AI_MATKEY_NAME );
for(j = 0; j < m->numprop; j++) {
// look up property type
// 0 - 127 scalar values,
// 128 - 255 the same properties but for texture maps
k = 256;
for(l = 0; l < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); l++)
if(m->prop[j].type == m3d_propertytypes[l].id ||
m->prop[j].type == m3d_propertytypes[l].id + 128) {
k = l;
break;
}
// should never happen, but be safe than sorry
if(k == 256) continue;
// scalar properties
if(m->prop[j].type < 128 && aiProps[k].pKey) {
switch(m3d_propertytypes[k].format) {
case m3dpf_color:
c = mkColor(m->prop[j].value.color);
mat->AddProperty(&c, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index);
break;
case m3dpf_float:
f = m->prop[j].value.fnum;
mat->AddProperty(&f, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index);
break;
default:
n = m->prop[j].value.num;
if(m->prop[j].type == m3dp_il) {
switch(n) {
case 0: n = aiShadingMode_NoShading; break;
case 2: n = aiShadingMode_Phong; break;
default: n = aiShadingMode_Gouraud; break;
}
}
mat->AddProperty(&n, 1, aiProps[k].pKey, aiProps[k].type, aiProps[k].index);
break;
}
}
// texture map properties
if(m->prop[j].type >= 128 && aiTxProps[k].pKey &&
// extra check, should never happen, do we have the refered texture?
m->prop[j].value.textureid < m3d->numtexture &&
m3d->texture[m->prop[j].value.textureid].name) {
name.Set(std::string(std::string(m3d->texture[m->prop[j].value.textureid].name) + ".png"));
mat->AddProperty(&name, aiTxProps[k].pKey, aiTxProps[k].type, aiTxProps[k].index);
n = 0;
mat->AddProperty(&n, 1, _AI_MATKEY_UVWSRC_BASE, aiProps[k].type, aiProps[k].index);
}
}
mScene->mMaterials[i + 1] = mat;
}
}
// ------------------------------------------------------------------------------------------------
// import textures, this is the simplest of all
void M3DImporter::importTextures()
{
unsigned int i;
const char *formatHint[] = { "rgba0800", "rgba0808", "rgba8880", "rgba8888" };
m3dtx_t *t;
ai_assert(mScene != nullptr);
ai_assert(m3d != nullptr);
mScene->mNumTextures = m3d->numtexture;
ASSIMP_LOG_DEBUG_F("M3D: importTextures ", mScene->mNumTextures);
if(!m3d->numtexture)
return;
mScene->mTextures = new aiTexture*[m3d->numtexture];
for(i = 0; i < m3d->numtexture; i++) {
unsigned int j, k;
t = &m3d->texture[i];
if(!t->w || !t->h || !t->f || !t->d) continue;
aiTexture *tx = new aiTexture;
strcpy(tx->achFormatHint, formatHint[t->f - 1]);
tx->mFilename = aiString(std::string(t->name) + ".png");
tx->mWidth = t->w;
tx->mHeight = t->h;
tx->pcData = new aiTexel[ tx->mWidth*tx->mHeight ];
for(j = k = 0; j < tx->mWidth*tx->mHeight; j++) {
switch(t->f) {
case 1: tx->pcData[j].g = t->d[k++]; break;
case 2: tx->pcData[j].g = t->d[k++]; tx->pcData[j].a = t->d[k++]; break;
case 3:
tx->pcData[j].r = t->d[k++]; tx->pcData[j].g = t->d[k++];
tx->pcData[j].b = t->d[k++]; tx->pcData[j].a = 255;
break;
case 4:
tx->pcData[j].r = t->d[k++]; tx->pcData[j].g = t->d[k++];
tx->pcData[j].b = t->d[k++]; tx->pcData[j].a = t->d[k++];
break;
}
}
mScene->mTextures[i] = tx;
}
}
// ------------------------------------------------------------------------------------------------
// this is tricky. M3D has a global vertex and UV list, and faces are indexing them
// individually. In assimp there're per mesh vertex and UV lists, and they must be
// indexed simultaneously.
void M3DImporter::importMeshes()
{
unsigned int i, j, k, l, numpoly = 3, lastMat = -2U;
std::vector<aiMesh*> *meshes = new std::vector<aiMesh*>();
std::vector<aiFace> *faces = nullptr;
std::vector<aiVector3D> *vertices = nullptr;
std::vector<aiVector3D> *normals = nullptr;
std::vector<aiVector3D> *texcoords = nullptr;
std::vector<aiColor4D> *colors = nullptr;
std::vector<unsigned int> *vertexids = nullptr;
aiMesh *pMesh = nullptr;
ai_assert(mScene != nullptr);
ai_assert(m3d != nullptr);
ai_assert(mScene->mRootNode != nullptr);
ASSIMP_LOG_DEBUG_F("M3D: importMeshes ", m3d->numface);
for(i = 0; i < m3d->numface; i++) {
// we must switch mesh if material changes
if(lastMat != m3d->face[i].materialid) {
lastMat = m3d->face[i].materialid;
if(pMesh && vertices && vertices->size() && faces && faces->size()) {
populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids);
meshes->push_back(pMesh);
delete faces;
delete vertices;
delete normals;
delete texcoords;
delete colors;
delete vertexids; // this is not stored in pMesh, just to collect bone vertices
}
pMesh = new aiMesh;
pMesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
pMesh->mMaterialIndex = lastMat + 1;
faces = new std::vector<aiFace>();
vertices = new std::vector<aiVector3D>();
normals = new std::vector<aiVector3D>();
texcoords = new std::vector<aiVector3D>();
colors = new std::vector<aiColor4D>();
vertexids = new std::vector<unsigned int>();
}
// add a face to temporary vector
aiFace *pFace = new aiFace;
pFace->mNumIndices = numpoly;
pFace->mIndices = new unsigned int[numpoly];
for(j = 0; j < numpoly; j++) {
aiVector3D pos, uv, norm;
k = vertices->size();
pFace->mIndices[j] = k;
l = m3d->face[i].vertex[j];
pos.x = m3d->vertex[l].x;
pos.y = m3d->vertex[l].y;
pos.z = m3d->vertex[l].z;
vertices->push_back(pos);
colors->push_back(mkColor(m3d->vertex[l].color));
// add a bone to temporary vector
if(m3d->vertex[l].skinid != -1U &&m3d->vertex[l].skinid != -2U && m3d->skin && m3d->bone) {
// this is complicated, because M3D stores a list of bone id / weight pairs per
// vertex but assimp uses lists of local vertex id/weight pairs per local bone list
vertexids->push_back(l);
}
l = m3d->face[i].texcoord[j];
if(l != -1U) {
uv.x = m3d->tmap[l].u;
uv.y = m3d->tmap[l].v;
uv.z = 0.0;
texcoords->push_back(uv);
}
l = m3d->face[i].normal[j];
if(l != -1U) {
norm.x = m3d->vertex[l].x;
norm.y = m3d->vertex[l].y;
norm.z = m3d->vertex[l].z;
normals->push_back(norm);
}
}
faces->push_back(*pFace);
delete pFace;
}
// if there's data left in the temporary vectors, flush them
if(pMesh && vertices->size() && faces->size()) {
populateMesh(pMesh, faces, vertices, normals, texcoords, colors, vertexids);
meshes->push_back(pMesh);
}
// create global mesh list in scene
mScene->mNumMeshes = meshes->size();
mScene->mMeshes = new aiMesh*[mScene->mNumMeshes];
std::copy(meshes->begin(), meshes->end(), mScene->mMeshes);
// create mesh indeces in root node
mScene->mRootNode->mNumMeshes = meshes->size();
mScene->mRootNode->mMeshes = new unsigned int[meshes->size()];
for(i = 0; i < meshes->size(); i++) {
mScene->mRootNode->mMeshes[i] = i;
}
delete meshes;
if(faces) delete faces;
if(vertices) delete vertices;
if(normals) delete normals;
if(texcoords) delete texcoords;
if(colors) delete colors;
if(vertexids) delete vertexids;
}
// ------------------------------------------------------------------------------------------------
// a reentrant node parser. Otherwise this is simple
void M3DImporter::importBones(unsigned int parentid, aiNode *pParent)
{
unsigned int i, n;
ai_assert(pParent != nullptr);
ai_assert(mScene != nullptr);
ai_assert(m3d != nullptr);
ASSIMP_LOG_DEBUG_F("M3D: importBones ", m3d->numbone, " parentid ", (int)parentid);
for(n = 0, i = parentid + 1; i < m3d->numbone; i++)
if(m3d->bone[i].parent == parentid) n++;
pParent->mChildren = new aiNode*[n];
for(i = parentid + 1; i < m3d->numbone; i++) {
if(m3d->bone[i].parent == parentid) {
aiNode *pChild = new aiNode;
pChild->mParent = pParent;
pChild->mName = aiString(std::string(m3d->bone[i].name));
convertPose(&pChild->mTransformation, m3d->bone[i].pos, m3d->bone[i].ori);
pChild->mNumChildren = 0;
pParent->mChildren[pParent->mNumChildren] = pChild;
pParent->mNumChildren++;
importBones(i, pChild);
}
}
}
// ------------------------------------------------------------------------------------------------
// this is another headache. M3D stores list of changed bone id/position/orientation triplets and
// a timestamp per frame, but assimp needs timestamp and lists of position, orientation lists per
// bone, so we have to convert between the two conceptually different representation forms
void M3DImporter::importAnimations()
{
unsigned int i, j, k, l, pos, ori;
double t;
m3da_t *a;
ai_assert(mScene != nullptr);
ai_assert(m3d != nullptr);
mScene->mNumAnimations = m3d->numaction;
ASSIMP_LOG_DEBUG_F("M3D: importAnimations ", mScene->mNumAnimations);
if(!m3d->numaction || !m3d->numbone)
return;
mScene->mAnimations = new aiAnimation*[m3d->numaction];
for(i = 0; i < m3d->numaction; i++) {
a = &m3d->action[i];
aiAnimation *pAnim = new aiAnimation;
pAnim->mName = aiString(std::string(a->name));
pAnim->mDuration = ((double)a->durationmsec) / 10;
pAnim->mTicksPerSecond = 100;
// now we know how many bones are referenced in this animation
pAnim->mNumChannels = m3d->numbone;
pAnim->mChannels = new aiNodeAnim*[pAnim->mNumChannels];
for(l = 0; l < m3d->numbone; l++) {
unsigned int n;
pAnim->mChannels[l] = new aiNodeAnim;
pAnim->mChannels[l]->mNodeName = aiString(std::string(m3d->bone[l].name));
// now n is the size of positions / orientations arrays
pAnim->mChannels[l]->mNumPositionKeys = pAnim->mChannels[l]->mNumRotationKeys = a->numframe;
pAnim->mChannels[l]->mPositionKeys = new aiVectorKey[a->numframe];
pAnim->mChannels[l]->mRotationKeys = new aiQuatKey[a->numframe];
pos = m3d->bone[l].pos;
ori = m3d->bone[l].ori;
for(j = n = 0; j < a->numframe; j++) {
t = ((double)a->frame[j].msec) / 10;
for(k = 0; k < a->frame[j].numtransform; k++) {
if(a->frame[j].transform[k].boneid == l) {
pos = a->frame[j].transform[k].pos;
ori = a->frame[j].transform[k].ori;
}
}
m3dv_t *v = &m3d->vertex[pos];
m3dv_t *q = &m3d->vertex[ori];
pAnim->mChannels[l]->mPositionKeys[j].mTime = t;
pAnim->mChannels[l]->mPositionKeys[j].mValue.x = v->x;
pAnim->mChannels[l]->mPositionKeys[j].mValue.y = v->y;
pAnim->mChannels[l]->mPositionKeys[j].mValue.z = v->z;
pAnim->mChannels[l]->mRotationKeys[j].mTime = t;
pAnim->mChannels[l]->mRotationKeys[j].mValue.w = q->w;
pAnim->mChannels[l]->mRotationKeys[j].mValue.x = q->x;
pAnim->mChannels[l]->mRotationKeys[j].mValue.y = q->y;
pAnim->mChannels[l]->mRotationKeys[j].mValue.z = q->z;
}// foreach frame
}// foreach bones
mScene->mAnimations[i] = pAnim;
}
}
// ------------------------------------------------------------------------------------------------
// convert uint32_t into aiColor4D
aiColor4D M3DImporter::mkColor(uint32_t c) {
aiColor4D color;
color.a = ((float)((c >> 24)&0xff)) / 255;
color.b = ((float)((c >> 16)&0xff)) / 255;
color.g = ((float)((c >> 8)&0xff)) / 255;
color.r = ((float)((c >> 0)&0xff)) / 255;
return color;
}
// ------------------------------------------------------------------------------------------------
// convert a position id and orientation id into a 4 x 4 transformation matrix
void M3DImporter::convertPose(aiMatrix4x4 *m, unsigned int posid, unsigned int orientid)
{
ai_assert(m != nullptr);
ai_assert(m3d != nullptr);
ai_assert(posid != -1U && posid < m3d->numvertex);
ai_assert(orientid != -1U && orientid < m3d->numvertex);
m3dv_t *p = &m3d->vertex[posid];
m3dv_t *q = &m3d->vertex[orientid];
/* quaternion to matrix. Do NOT use aiQuaternion to aiMatrix3x3, gives bad results */
if(q->x == 0.0 && q->y == 0.0 && q->z >= 0.7071065 && q->z <= 0.7071075 && q->w == 0.0) {
m->a2 = m->a3 = m->b1 = m->b3 = m->c1 = m->c2 = 0.0;
m->a1 = m->b2 = m->c3 = -1.0;
} else {
m->a1 = 1 - 2 * (q->y * q->y + q->z * q->z); if(m->a1 > -M3D_EPSILON && m->a1 < M3D_EPSILON) m->a1 = 0.0;
m->a2 = 2 * (q->x * q->y - q->z * q->w); if(m->a2 > -M3D_EPSILON && m->a2 < M3D_EPSILON) m->a2 = 0.0;
m->a3 = 2 * (q->x * q->z + q->y * q->w); if(m->a3 > -M3D_EPSILON && m->a3 < M3D_EPSILON) m->a3 = 0.0;
m->b1 = 2 * (q->x * q->y + q->z * q->w); if(m->b1 > -M3D_EPSILON && m->b1 < M3D_EPSILON) m->b1 = 0.0;
m->b2 = 1 - 2 * (q->x * q->x + q->z * q->z); if(m->b2 > -M3D_EPSILON && m->b2 < M3D_EPSILON) m->b2 = 0.0;
m->b3 = 2 * (q->y * q->z - q->x * q->w); if(m->b3 > -M3D_EPSILON && m->b3 < M3D_EPSILON) m->b3 = 0.0;
m->c1 = 2 * (q->x * q->z - q->y * q->w); if(m->c1 > -M3D_EPSILON && m->c1 < M3D_EPSILON) m->c1 = 0.0;
m->c2 = 2 * (q->y * q->z + q->x * q->w); if(m->c2 > -M3D_EPSILON && m->c2 < M3D_EPSILON) m->c2 = 0.0;
m->c3 = 1 - 2 * (q->x * q->x + q->y * q->y); if(m->c3 > -M3D_EPSILON && m->c3 < M3D_EPSILON) m->c3 = 0.0;
}
/* set translation */
m->a4 = p->x; m->b4 = p->y; m->c4 = p->z;
m->d1 = 0; m->d2 = 0; m->d3 = 0; m->d4 = 1;
}
// ------------------------------------------------------------------------------------------------
// find a node by name
aiNode *M3DImporter::findNode(aiNode *pNode, aiString name)
{
unsigned int i;
ai_assert(pNode != nullptr);
ai_assert(mScene != nullptr);
if(pNode->mName == name)
return pNode;
for(i = 0; i < pNode->mNumChildren; i++) {
aiNode *pChild = findNode(pNode->mChildren[i], name);
if(pChild) return pChild;
}
return nullptr;
}
// ------------------------------------------------------------------------------------------------
// fills up offsetmatrix in mBones
void M3DImporter::calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m)
{
ai_assert(pNode != nullptr);
ai_assert(mScene != nullptr);
if(pNode->mParent) {
calculateOffsetMatrix(pNode->mParent, m);
*m *= pNode->mTransformation;
} else {
*m = pNode->mTransformation;
}
}
// ------------------------------------------------------------------------------------------------
// because M3D has a global mesh, global vertex ids and stores materialid on the face, we need
// temporary lists to collect data for an aiMesh, which requires local arrays and local indeces
// this function fills up an aiMesh with those temporary lists
void M3DImporter::populateMesh(aiMesh *pMesh, std::vector<aiFace> *faces, std::vector<aiVector3D> *vertices,
std::vector<aiVector3D> *normals, std::vector<aiVector3D> *texcoords, std::vector<aiColor4D> *colors,
std::vector<unsigned int> *vertexids) {
ai_assert(pMesh != nullptr);
ai_assert(faces != nullptr);
ai_assert(vertices != nullptr);
ai_assert(normals != nullptr);
ai_assert(texcoords != nullptr);
ai_assert(colors != nullptr);
ai_assert(vertexids != nullptr);
ai_assert(m3d != nullptr);
ASSIMP_LOG_DEBUG_F("M3D: populateMesh numvertices ", vertices->size(), " numfaces ", faces->size(),
" numnormals ", normals->size(), " numtexcoord ", texcoords->size(), " numbones ", m3d->numbone);
if(vertices->size() && faces->size()) {
pMesh->mNumFaces = faces->size();
pMesh->mFaces = new aiFace[pMesh->mNumFaces];
std::copy(faces->begin(), faces->end(), pMesh->mFaces);
pMesh->mNumVertices = vertices->size();
pMesh->mVertices = new aiVector3D[pMesh->mNumVertices];
std::copy(vertices->begin(), vertices->end(), pMesh->mVertices);
if(normals->size() == vertices->size()) {
pMesh->mNormals = new aiVector3D[pMesh->mNumVertices];
std::copy(normals->begin(), normals->end(), pMesh->mNormals);
}
if(texcoords->size() == vertices->size()) {
pMesh->mTextureCoords[0] = new aiVector3D[pMesh->mNumVertices];
std::copy(texcoords->begin(), texcoords->end(), pMesh->mTextureCoords[0]);
pMesh->mNumUVComponents[0] = 2;
}
if(colors->size() == vertices->size()) {
pMesh->mColors[0] = new aiColor4D[pMesh->mNumVertices];
std::copy(colors->begin(), colors->end(), pMesh->mColors[0]);
}
// this is complicated, because M3D stores a list of bone id / weight pairs per
// vertex but assimp uses lists of local vertex id/weight pairs per local bone list
pMesh->mNumBones = m3d->numbone;
/* we need aiBone with mOffsetMatrix for bones without weights as well */
if(pMesh->mNumBones) {
pMesh->mBones = new aiBone*[pMesh->mNumBones];
for(unsigned int i = 0; i < m3d->numbone; i++) {
aiNode *pNode;
pMesh->mBones[i] = new aiBone;
pMesh->mBones[i]->mName = aiString(std::string(m3d->bone[i].name));
pMesh->mBones[i]->mNumWeights = 0;
pNode = findNode(mScene->mRootNode, pMesh->mBones[i]->mName);
if(pNode) {
calculateOffsetMatrix(pNode, &pMesh->mBones[i]->mOffsetMatrix);
pMesh->mBones[i]->mOffsetMatrix.Inverse();
} else
pMesh->mBones[i]->mOffsetMatrix = aiMatrix4x4();
}
if(vertexids->size()) {
unsigned int i, j;
// first count how many vertices we have per bone
for(i = 0; i < vertexids->size(); i++) {
unsigned int s = m3d->vertex[vertexids->at(i)].skinid;
if(s != -1U && s!= -2U) {
for(unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) {
aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name));
for(j = 0; j < pMesh->mNumBones; j++) {
if(pMesh->mBones[j]->mName == name) {
pMesh->mBones[j]->mNumWeights++;
break;
}
}
}
}
}
// allocate mWeights
for(j = 0; j < pMesh->mNumBones; j++) {
aiBone *pBone = pMesh->mBones[j];
if(pBone->mNumWeights) {
pBone->mWeights = new aiVertexWeight[pBone->mNumWeights];
pBone->mNumWeights = 0;
}
}
// fill up with data
for(i = 0; i < vertexids->size(); i++) {
unsigned int s = m3d->vertex[vertexids->at(i)].skinid;
if(s != -1U && s!= -2U) {
for(unsigned int k = 0; k < M3D_NUMBONE && m3d->skin[s].weight[k] > 0.0; k++) {
aiString name = aiString(std::string(m3d->bone[m3d->skin[s].boneid[k]].name));
for(j = 0; j < pMesh->mNumBones; j++) {
if(pMesh->mBones[j]->mName == name) {
aiBone *pBone = pMesh->mBones[j];
pBone->mWeights[pBone->mNumWeights].mVertexId = i;
pBone->mWeights[pBone->mNumWeights].mWeight = m3d->skin[s].weight[k];
pBone->mNumWeights++;
break;
}
}
} // foreach skin
}
} // foreach vertexids
}
}
}
}
// ------------------------------------------------------------------------------------------------
} // Namespace Assimp
#endif // !! ASSIMP_BUILD_NO_M3D_IMPORTER

View File

@ -0,0 +1,106 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
Copyright (c) 2019 bzt
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 M3DImporter.h
* @brief Declares the importer class to read a scene from a Model 3D file
*/
#ifndef AI_M3DIMPORTER_H_INC
#define AI_M3DIMPORTER_H_INC
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
#include "m3d.h"
#include <assimp/BaseImporter.h>
#include <assimp/material.h>
#include <vector>
struct aiMesh;
struct aiNode;
struct aiMaterial;
struct aiFace;
namespace Assimp {
class M3DImporter : public BaseImporter {
public:
/// \brief Default constructor
M3DImporter();
/// \brief Destructor
~M3DImporter();
public:
/// \brief Returns whether the class can handle the format of the given file.
/// \remark See BaseImporter::CanRead() for details.
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
private:
aiScene* mScene; // the scene to import to
m3d_t *m3d; // model for the C library to convert from
//! \brief Appends the supported extension.
const aiImporterDesc* GetInfo () const;
//! \brief File import implementation.
void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
void importMaterials();
void importTextures();
void importMeshes();
void importBones(unsigned int parentid, aiNode *pParent);
void importAnimations();
// helper functions
aiColor4D mkColor(uint32_t c);
void convertPose(aiMatrix4x4 *m, unsigned int posid, unsigned int orientid);
aiNode *findNode(aiNode *pNode, aiString name);
void calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m);
void populateMesh(aiMesh *pMesh, std::vector<aiFace> *faces, std::vector<aiVector3D> *verteces,
std::vector<aiVector3D> *normals, std::vector<aiVector3D> *texcoords, std::vector<aiColor4D> *colors,
std::vector<unsigned int> *vertexids);
};
} // Namespace Assimp
#endif // ASSIMP_BUILD_NO_M3D_IMPORTER
#endif // AI_M3DIMPORTER_H_INC

View File

@ -0,0 +1,106 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
Copyright (c) 2019 bzt
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 M3DMaterials.h
* @brief Declares the Assimp and Model 3D file material type relations
*/
#ifndef AI_M3DMATERIALS_H_INC
#define AI_M3DMATERIALS_H_INC
/*
* In the m3d.h header, there's a static array which defines the material
* properties, called m3d_propertytypes. These must have the same size, and
* list the matching Assimp materials for those properties. Used by both the
* M3DImporter and the M3DExporter, so you have to define these relations
* only once. D.R.Y. and K.I.S.S.
*/
typedef struct {
const char *pKey;
unsigned int type;
unsigned int index;
} aiMatProp;
/* --- Scalar Properties --- !!!!! must match m3d_propertytypes !!!!! */
static const aiMatProp aiProps[] = {
{ AI_MATKEY_COLOR_DIFFUSE }, /* m3dp_Kd */
{ AI_MATKEY_COLOR_AMBIENT }, /* m3dp_Ka */
{ AI_MATKEY_COLOR_SPECULAR }, /* m3dp_Ks */
{ AI_MATKEY_SHININESS }, /* m3dp_Ns */
{ AI_MATKEY_COLOR_EMISSIVE }, /* m3dp_Ke */
{ AI_MATKEY_COLOR_REFLECTIVE }, /* m3dp_Tf */
{ AI_MATKEY_BUMPSCALING }, /* m3dp_Km */
{ AI_MATKEY_OPACITY }, /* m3dp_d */
{ AI_MATKEY_SHADING_MODEL }, /* m3dp_il */
{ NULL, 0, 0 }, /* m3dp_Pr */
{ AI_MATKEY_REFLECTIVITY }, /* m3dp_Pm */
{ NULL, 0, 0 }, /* m3dp_Ps */
{ AI_MATKEY_REFRACTI }, /* m3dp_Ni */
{ NULL, 0, 0 }, /* m3dp_Nt */
{ NULL, 0, 0 },
{ NULL, 0, 0 },
{ NULL, 0, 0 }
};
/* --- Texture Map Properties --- !!!!! must match m3d_propertytypes !!!!! */
static const aiMatProp aiTxProps[] = {
{ AI_MATKEY_TEXTURE_DIFFUSE(0) }, /* m3dp_map_Kd */
{ AI_MATKEY_TEXTURE_AMBIENT(0) }, /* m3dp_map_Ka */
{ AI_MATKEY_TEXTURE_SPECULAR(0) }, /* m3dp_map_Ks */
{ AI_MATKEY_TEXTURE_SHININESS(0) }, /* m3dp_map_Ns */
{ AI_MATKEY_TEXTURE_EMISSIVE(0) }, /* m3dp_map_Ke */
{ NULL, 0, 0 }, /* m3dp_map_Tf */
{ AI_MATKEY_TEXTURE_HEIGHT(0) }, /* m3dp_bump */
{ AI_MATKEY_TEXTURE_OPACITY(0) }, /* m3dp_map_d */
{ AI_MATKEY_TEXTURE_REFLECTION(0) }, /* m3dp_refl */
{ AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE_ROUGHNESS,0) },/* m3dp_map_Pr */
{ AI_MATKEY_TEXTURE(aiTextureType_METALNESS,0) }, /* m3dp_map_Pm */
{ NULL, 0, 0 }, /* m3dp_map_Ps */
{ AI_MATKEY_TEXTURE(aiTextureType_AMBIENT_OCCLUSION,0) },/* m3dp_map_Ni */
{ NULL, 0, 0 }, /* m3dp_map_Nt */
{ NULL, 0, 0 },
{ NULL, 0, 0 },
{ NULL, 0, 0 }
};
#endif // AI_M3DMATERIALS_H_INC

5568
code/M3D/m3d.h 100644

File diff suppressed because it is too large Load Diff

View File

@ -344,7 +344,7 @@ void MD2Importer::InternReadFile( const std::string& pFile,
if (pcSkins->name[0]) if (pcSkins->name[0])
{ {
aiString szString; aiString szString;
const size_t iLen = ::strlen(pcSkins->name); const ai_uint32 iLen = (ai_uint32) ::strlen(pcSkins->name);
::memcpy(szString.data,pcSkins->name,iLen); ::memcpy(szString.data,pcSkins->name,iLen);
szString.data[iLen] = '\0'; szString.data[iLen] = '\0';
szString.length = iLen; szString.length = iLen;

View File

@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "MD5Loader.h" #include "MD5Loader.h"
#include <assimp/StringComparison.h> #include <assimp/StringComparison.h>
#include <assimp/fast_atof.h> #include <assimp/fast_atof.h>
#include <assimp/MathFunctions.h>
#include <assimp/SkeletonMeshBuilder.h> #include <assimp/SkeletonMeshBuilder.h>
#include <assimp/Importer.hpp> #include <assimp/Importer.hpp>
#include <assimp/scene.h> #include <assimp/scene.h>
@ -64,7 +65,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace Assimp; using namespace Assimp;
// Minimum weight value. Weights inside [-n ... n] are ignored // Minimum weight value. Weights inside [-n ... n] are ignored
#define AI_MD5_WEIGHT_EPSILON 1e-5f #define AI_MD5_WEIGHT_EPSILON Math::getEpsilon<float>()
static const aiImporterDesc desc = { static const aiImporterDesc desc = {

View File

@ -235,7 +235,7 @@ bool MD5Parser::ParseSection(Section& out)
const char* szStart = ++sz; \ const char* szStart = ++sz; \
while('\"'!=*sz)++sz; \ while('\"'!=*sz)++sz; \
const char* szEnd = (sz++); \ const char* szEnd = (sz++); \
out.length = (size_t)(szEnd - szStart); \ out.length = (ai_uint32) (szEnd - szStart); \
::memcpy(out.data,szStart,out.length); \ ::memcpy(out.data,szStart,out.length); \
out.data[out.length] = '\0'; out.data[out.length] = '\0';
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------

View File

@ -5,8 +5,6 @@ Open Asset Import Library (assimp)
Copyright (c) 2006-2019, assimp team Copyright (c) 2006-2019, assimp team
All rights reserved. All rights reserved.
Redistribution and use of this software in source and binary forms, Redistribution and use of this software in source and binary forms,
@ -54,7 +52,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "MDL/MDLDefaultColorMap.h" #include "MDL/MDLDefaultColorMap.h"
#include "MD2/MD2FileData.h" #include "MD2/MD2FileData.h"
#include <assimp/Macros.h>
#include <assimp/qnan.h> #include <assimp/qnan.h>
#include <assimp/StringUtils.h> #include <assimp/StringUtils.h>
#include <assimp/Importer.hpp> #include <assimp/Importer.hpp>
@ -94,23 +91,24 @@ static const aiImporterDesc desc = {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Constructor to be privately used by Importer // Constructor to be privately used by Importer
MDLImporter::MDLImporter() MDLImporter::MDLImporter()
: configFrameID(), : configFrameID()
mBuffer(), , mBuffer()
iGSFileVersion(), , iGSFileVersion()
pIOHandler(), , pIOHandler()
pScene(), , pScene()
iFileSize() , iFileSize() {
{} // empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor, private as well // Destructor, private as well
MDLImporter::~MDLImporter() MDLImporter::~MDLImporter() {
{} // empty
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns whether the class can handle the format of the given file. // Returns whether the class can handle the format of the given file.
bool MDLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const bool MDLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
{
const std::string extension = GetExtension(pFile); const std::string extension = GetExtension(pFile);
// if check for extension is not enough, check for the magic tokens // if check for extension is not enough, check for the magic tokens
@ -404,23 +402,15 @@ void MDLImporter::InternReadFile_Quake1() {
// now get a pointer to the first frame in the file // now get a pointer to the first frame in the file
BE_NCONST MDL::Frame* pcFrames = (BE_NCONST MDL::Frame*)szCurrent; BE_NCONST MDL::Frame* pcFrames = (BE_NCONST MDL::Frame*)szCurrent;
BE_NCONST MDL::SimpleFrame* pcFirstFrame; MDL::SimpleFrame* pcFirstFrame;
if (0 == pcFrames->type) { if (0 == pcFrames->type) {
// get address of single frame // get address of single frame
pcFirstFrame = &pcFrames->frame; pcFirstFrame =( MDL::SimpleFrame*) &pcFrames->frame;
} else { } else {
// get the first frame in the group // get the first frame in the group
BE_NCONST MDL::GroupFrame* pcFrames2 = (BE_NCONST MDL::GroupFrame*) pcFrames;
#if 1 pcFirstFrame = &(pcFrames2->frames[0]);
// FIXME: the cast is wrong and cause a warning on clang 5.0
// disable this code for now, fix it later
ai_assert(false && "Bad pointer cast");
pcFirstFrame = nullptr; // Workaround: msvc++ C4703 error
#else
BE_NCONST MDL::GroupFrame* pcFrames2 = (BE_NCONST MDL::GroupFrame*)pcFrames;
pcFirstFrame = (BE_NCONST MDL::SimpleFrame*)(&pcFrames2->time + pcFrames->type);
#endif
} }
BE_NCONST MDL::Vertex* pcVertices = (BE_NCONST MDL::Vertex*) ((pcFirstFrame->name) + sizeof(pcFirstFrame->name)); BE_NCONST MDL::Vertex* pcVertices = (BE_NCONST MDL::Vertex*) ((pcFirstFrame->name) + sizeof(pcFirstFrame->name));
VALIDATE_FILE_SIZE((const unsigned char*)(pcVertices + pcHeader->num_verts)); VALIDATE_FILE_SIZE((const unsigned char*)(pcVertices + pcHeader->num_verts));

View File

@ -89,16 +89,12 @@ public:
MDLImporter(); MDLImporter();
~MDLImporter(); ~MDLImporter();
public:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Returns whether the class can handle the format of the given file. /** Returns whether the class can handle the format of the given file.
* See BaseImporter::CanRead() for details. */ * See BaseImporter::CanRead() for details. */
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
bool checkSig) const; bool checkSig) const;
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Called prior to ReadFile(). /** Called prior to ReadFile().
* The function is a request to the importer to update its configuration * The function is a request to the importer to update its configuration
@ -107,8 +103,6 @@ public:
void SetupProperties(const Importer* pImp); void SetupProperties(const Importer* pImp);
protected: protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Return importer meta information. /** Return importer meta information.
* See #BaseImporter::GetInfo for the details * See #BaseImporter::GetInfo for the details
@ -122,8 +116,6 @@ protected:
void InternReadFile( const std::string& pFile, aiScene* pScene, void InternReadFile( const std::string& pFile, aiScene* pScene,
IOSystem* pIOHandler); IOSystem* pIOHandler);
protected:
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Import a quake 1 MDL file (IDPO) /** Import a quake 1 MDL file (IDPO)
*/ */
@ -154,7 +146,6 @@ protected:
void SizeCheck(const void* szPos); void SizeCheck(const void* szPos);
void SizeCheck(const void* szPos, const char* szFile, unsigned int iLine); void SizeCheck(const void* szPos, const char* szFile, unsigned int iLine);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Validate the header data structure of a game studio MDL7 file /** Validate the header data structure of a game studio MDL7 file
* \param pcHeader Input header to be validated * \param pcHeader Input header to be validated
@ -167,7 +158,6 @@ protected:
*/ */
void ValidateHeader_Quake1(const MDL::Header* pcHeader); void ValidateHeader_Quake1(const MDL::Header* pcHeader);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Try to load a palette from the current directory (colormap.lmp) /** Try to load a palette from the current directory (colormap.lmp)
* If it is not found the default palette of Quake1 is returned * If it is not found the default palette of Quake1 is returned
@ -179,9 +169,8 @@ protected:
*/ */
void FreePalette(const unsigned char* pszColorMap); void FreePalette(const unsigned char* pszColorMap);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Load a paletized texture from the file and convert it to 32bpp /** Load a palletized texture from the file and convert it to 32bpp
*/ */
void CreateTextureARGB8_3DGS_MDL3(const unsigned char* szData); void CreateTextureARGB8_3DGS_MDL3(const unsigned char* szData);
@ -195,7 +184,6 @@ protected:
unsigned int iType, unsigned int iType,
unsigned int* piSkip); unsigned int* piSkip);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Used to load textures from MDL5 /** Used to load textures from MDL5
* \param szData Input data * \param szData Input data
@ -206,7 +194,6 @@ protected:
unsigned int iType, unsigned int iType,
unsigned int* piSkip); unsigned int* piSkip);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Checks whether a texture can be replaced with a single color /** Checks whether a texture can be replaced with a single color
* This is useful for all file formats before MDL7 (all those * This is useful for all file formats before MDL7 (all those
@ -218,14 +205,12 @@ protected:
*/ */
aiColor4D ReplaceTextureWithColor(const aiTexture* pcTexture); aiColor4D ReplaceTextureWithColor(const aiTexture* pcTexture);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Converts the absolute texture coordinates in MDL5 files to /** Converts the absolute texture coordinates in MDL5 files to
* relative in a range between 0 and 1 * relative in a range between 0 and 1
*/ */
void CalculateUVCoordinates_MDL5(); void CalculateUVCoordinates_MDL5();
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Read an UV coordinate from the file. If the file format is not /** Read an UV coordinate from the file. If the file format is not
* MDL5, the function calculates relative texture coordinates * MDL5, the function calculates relative texture coordinates
@ -245,7 +230,6 @@ protected:
*/ */
void SetupMaterialProperties_3DGS_MDL5_Quake1( ); void SetupMaterialProperties_3DGS_MDL5_Quake1( );
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Parse a skin lump in a MDL7/HMP7 file with all of its features /** Parse a skin lump in a MDL7/HMP7 file with all of its features
* variant 1: Current cursor position is the beginning of the skin header * variant 1: Current cursor position is the beginning of the skin header

View File

@ -51,7 +51,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/types.h> #include <assimp/types.h>
#include <assimp/material.h> #include <assimp/material.h>
#include <assimp/DefaultLogger.hpp> #include <assimp/DefaultLogger.hpp>
#include <assimp/Macros.h>
using namespace Assimp; using namespace Assimp;
@ -472,12 +471,12 @@ aiReturn aiMaterial::AddBinaryProperty (const void* pInput,
aiPropertyTypeInfo pType aiPropertyTypeInfo pType
) )
{ {
ai_assert( pInput != NULL ); ai_assert( pInput != nullptr );
ai_assert( pKey != NULL ); ai_assert(pKey != nullptr );
ai_assert( 0 != pSizeInBytes ); ai_assert( 0 != pSizeInBytes );
if ( 0 == pSizeInBytes ) { if ( 0 == pSizeInBytes ) {
return AI_FAILURE;
} }
// first search the list whether there is already an entry with this key // first search the list whether there is already an entry with this key
@ -545,23 +544,7 @@ aiReturn aiMaterial::AddProperty (const aiString* pInput,
unsigned int type, unsigned int type,
unsigned int index) unsigned int index)
{ {
// We don't want to add the whole buffer .. write a 32 bit length ai_assert(sizeof(ai_uint32)==4);
// prefix followed by the zero-terminated UTF8 string.
// (HACK) I don't want to break the ABI now, but we definitely
// ought to change aiString::mLength to uint32_t one day.
if (sizeof(size_t) == 8) {
aiString copy = *pInput;
uint32_t* s = reinterpret_cast<uint32_t*>(&copy.length);
s[1] = static_cast<uint32_t>(pInput->length);
return AddBinaryProperty(s+1,
static_cast<unsigned int>(pInput->length+1+4),
pKey,
type,
index,
aiPTI_String);
}
ai_assert(sizeof(size_t)==4);
return AddBinaryProperty(pInput, return AddBinaryProperty(pInput,
static_cast<unsigned int>(pInput->length+1+4), static_cast<unsigned int>(pInput->length+1+4),
pKey, pKey,

View File

@ -79,10 +79,7 @@ using namespace std;
ObjFileImporter::ObjFileImporter() ObjFileImporter::ObjFileImporter()
: m_Buffer() : m_Buffer()
, m_pRootObject( nullptr ) , m_pRootObject( nullptr )
, m_strAbsPath( "" ) { , m_strAbsPath( std::string(1, DefaultIOSystem().getOsSeparator()) ) {}
DefaultIOSystem io;
m_strAbsPath = io.getOsSeparator();
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Destructor. // Destructor.

View File

@ -118,7 +118,7 @@ void ObjFileParser::parseFile( IOStreamBuffer<char> &streamBuffer ) {
size_t lastFilePos( 0 ); size_t lastFilePos( 0 );
std::vector<char> buffer; std::vector<char> buffer;
while ( streamBuffer.getNextDataLine( buffer, '\0' ) ) { while ( streamBuffer.getNextDataLine( buffer, '\\' ) ) {
m_DataIt = buffer.begin(); m_DataIt = buffer.begin();
m_DataItEnd = buffer.end(); m_DataItEnd = buffer.end();
@ -244,8 +244,8 @@ void ObjFileParser::copyNextWord(char *pBuffer, size_t length) {
size_t index = 0; size_t index = 0;
m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd); m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
if ( *m_DataIt == '\\' ) { if ( *m_DataIt == '\\' ) {
m_DataIt++; ++m_DataIt;
m_DataIt++; ++m_DataIt;
m_DataIt = getNextWord<DataArrayIt>( m_DataIt, m_DataItEnd ); m_DataIt = getNextWord<DataArrayIt>( m_DataIt, m_DataItEnd );
} }
while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) { while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) {

View File

@ -49,7 +49,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// internal headers // internal headers
#include "PlyLoader.h" #include "PlyLoader.h"
#include <assimp/IOStreamBuffer.h> #include <assimp/IOStreamBuffer.h>
#include <assimp/Macros.h>
#include <memory> #include <memory>
#include <assimp/IOSystem.hpp> #include <assimp/IOSystem.hpp>
#include <assimp/scene.h> #include <assimp/scene.h>

View File

@ -0,0 +1,268 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the
following conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
----------------------------------------------------------------------
*/
#include "ArmaturePopulate.h"
#include <assimp/BaseImporter.h>
#include <assimp/DefaultLogger.hpp>
#include <assimp/postprocess.h>
#include <assimp/scene.h>
#include <iostream>
namespace Assimp {
/// The default class constructor.
ArmaturePopulate::ArmaturePopulate() : BaseProcess()
{}
/// The class destructor.
ArmaturePopulate::~ArmaturePopulate()
{}
bool ArmaturePopulate::IsActive(unsigned int pFlags) const {
return (pFlags & aiProcess_PopulateArmatureData) != 0;
}
void ArmaturePopulate::SetupProperties(const Importer *pImp) {
// do nothing
}
void ArmaturePopulate::Execute(aiScene *out) {
// Now convert all bone positions to the correct mOffsetMatrix
std::vector<aiBone *> bones;
std::vector<aiNode *> nodes;
std::map<aiBone *, aiNode *> bone_stack;
BuildBoneList(out->mRootNode, out->mRootNode, out, bones);
BuildNodeList(out->mRootNode, nodes);
BuildBoneStack(out->mRootNode, out->mRootNode, out, bones, bone_stack, nodes);
ASSIMP_LOG_DEBUG_F("Bone stack size: ", bone_stack.size());
for (std::pair<aiBone *, aiNode *> kvp : bone_stack) {
aiBone *bone = kvp.first;
aiNode *bone_node = kvp.second;
ASSIMP_LOG_DEBUG_F("active node lookup: ", bone->mName.C_Str());
// lcl transform grab - done in generate_nodes :)
// bone->mOffsetMatrix = bone_node->mTransformation;
aiNode *armature = GetArmatureRoot(bone_node, bones);
ai_assert(armature);
// set up bone armature id
bone->mArmature = armature;
// set this bone node to be referenced properly
ai_assert(bone_node);
bone->mNode = bone_node;
}
}
/* Reprocess all nodes to calculate bone transforms properly based on the REAL
* mOffsetMatrix not the local. */
/* Before this would use mesh transforms which is wrong for bone transforms */
/* Before this would work for simple character skeletons but not complex meshes
* with multiple origins */
/* Source: sketch fab log cutter fbx */
void ArmaturePopulate::BuildBoneList(aiNode *current_node,
const aiNode *root_node,
const aiScene *scene,
std::vector<aiBone *> &bones) {
ai_assert(scene);
for (unsigned int nodeId = 0; nodeId < current_node->mNumChildren; ++nodeId) {
aiNode *child = current_node->mChildren[nodeId];
ai_assert(child);
// check for bones
for (unsigned int meshId = 0; meshId < child->mNumMeshes; ++meshId) {
ai_assert(child->mMeshes);
unsigned int mesh_index = child->mMeshes[meshId];
aiMesh *mesh = scene->mMeshes[mesh_index];
ai_assert(mesh);
for (unsigned int boneId = 0; boneId < mesh->mNumBones; ++boneId) {
aiBone *bone = mesh->mBones[boneId];
ai_assert(bone);
// duplicate meshes exist with the same bones sometimes :)
// so this must be detected
if (std::find(bones.begin(), bones.end(), bone) == bones.end()) {
// add the element once
bones.push_back(bone);
}
}
// find mesh and get bones
// then do recursive lookup for bones in root node hierarchy
}
BuildBoneList(child, root_node, scene, bones);
}
}
/* Prepare flat node list which can be used for non recursive lookups later */
void ArmaturePopulate::BuildNodeList(const aiNode *current_node,
std::vector<aiNode *> &nodes) {
ai_assert(current_node);
for (unsigned int nodeId = 0; nodeId < current_node->mNumChildren; ++nodeId) {
aiNode *child = current_node->mChildren[nodeId];
ai_assert(child);
nodes.push_back(child);
BuildNodeList(child, nodes);
}
}
/* A bone stack allows us to have multiple armatures, with the same bone names
* A bone stack allows us also to retrieve bones true transform even with
* duplicate names :)
*/
void ArmaturePopulate::BuildBoneStack(aiNode *current_node,
const aiNode *root_node,
const aiScene *scene,
const std::vector<aiBone *> &bones,
std::map<aiBone *, aiNode *> &bone_stack,
std::vector<aiNode *> &node_stack) {
ai_assert(scene);
ai_assert(root_node);
ai_assert(!node_stack.empty());
for (aiBone *bone : bones) {
ai_assert(bone);
aiNode *node = GetNodeFromStack(bone->mName, node_stack);
if (node == nullptr) {
node_stack.clear();
BuildNodeList(root_node, node_stack);
ASSIMP_LOG_DEBUG_F("Resetting bone stack: nullptr element ", bone->mName.C_Str());
node = GetNodeFromStack(bone->mName, node_stack);
if (!node) {
ASSIMP_LOG_ERROR("serious import issue node for bone was not detected");
continue;
}
}
ASSIMP_LOG_DEBUG_F("Successfully added bone[", bone->mName.C_Str(), "] to stack and bone node is: ", node->mName.C_Str());
bone_stack.insert(std::pair<aiBone *, aiNode *>(bone, node));
}
}
/* Returns the armature root node */
/* This is required to be detected for a bone initially, it will recurse up
* until it cannot find another bone and return the node No known failure
* points. (yet)
*/
aiNode *ArmaturePopulate::GetArmatureRoot(aiNode *bone_node,
std::vector<aiBone *> &bone_list) {
while (bone_node) {
if (!IsBoneNode(bone_node->mName, bone_list)) {
ASSIMP_LOG_DEBUG_F("GetArmatureRoot() Found valid armature: ", bone_node->mName.C_Str());
return bone_node;
}
bone_node = bone_node->mParent;
}
ASSIMP_LOG_ERROR("GetArmatureRoot() can't find armature!");
return nullptr;
}
/* Simple IsBoneNode check if this could be a bone */
bool ArmaturePopulate::IsBoneNode(const aiString &bone_name,
std::vector<aiBone *> &bones) {
for (aiBone *bone : bones) {
if (bone->mName == bone_name) {
return true;
}
}
return false;
}
/* Pop this node by name from the stack if found */
/* Used in multiple armature situations with duplicate node / bone names */
/* Known flaw: cannot have nodes with bone names, will be fixed in later release
*/
/* (serious to be fixed) Known flaw: nodes which have more than one bone could
* be prematurely dropped from stack */
aiNode *ArmaturePopulate::GetNodeFromStack(const aiString &node_name,
std::vector<aiNode *> &nodes) {
std::vector<aiNode *>::iterator iter;
aiNode *found = nullptr;
for (iter = nodes.begin(); iter < nodes.end(); ++iter) {
aiNode *element = *iter;
ai_assert(element);
// node valid and node name matches
if (element->mName == node_name) {
found = element;
break;
}
}
if (found != nullptr) {
ASSIMP_LOG_INFO_F("Removed node from stack: ", found->mName.C_Str());
// now pop the element from the node list
nodes.erase(iter);
return found;
}
// unique names can cause this problem
ASSIMP_LOG_ERROR("[Serious] GetNodeFromStack() can't find node from stack!");
return nullptr;
}
} // Namespace Assimp

View File

@ -0,0 +1,112 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, 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 ARMATURE_POPULATE_H_
#define ARMATURE_POPULATE_H_
#include "Common/BaseProcess.h"
#include <assimp/BaseImporter.h>
#include <vector>
#include <map>
struct aiNode;
struct aiBone;
namespace Assimp {
// ---------------------------------------------------------------------------
/** Armature Populate: This is a post process designed
* To save you time when importing models into your game engines
* This was originally designed only for fbx but will work with other formats
* it is intended to auto populate aiBone data with armature and the aiNode
* This is very useful when dealing with skinned meshes
* or when dealing with many different skeletons
* It's off by default but recommend that you try it and use it
* It should reduce down any glue code you have in your
* importers
* You can contact RevoluPowered <gordon@gordonite.tech>
* For more info about this
*/
class ASSIMP_API ArmaturePopulate : public BaseProcess {
public:
/// The default class constructor.
ArmaturePopulate();
/// The class destructor.
virtual ~ArmaturePopulate();
/// Overwritten, @see BaseProcess
virtual bool IsActive( unsigned int pFlags ) const;
/// Overwritten, @see BaseProcess
virtual void SetupProperties( const Importer* pImp );
/// Overwritten, @see BaseProcess
virtual void Execute( aiScene* pScene );
static aiNode *GetArmatureRoot(aiNode *bone_node,
std::vector<aiBone *> &bone_list);
static bool IsBoneNode(const aiString &bone_name,
std::vector<aiBone *> &bones);
static aiNode *GetNodeFromStack(const aiString &node_name,
std::vector<aiNode *> &nodes);
static void BuildNodeList(const aiNode *current_node,
std::vector<aiNode *> &nodes);
static void BuildBoneList(aiNode *current_node, const aiNode *root_node,
const aiScene *scene,
std::vector<aiBone *> &bones);
static void BuildBoneStack(aiNode *current_node, const aiNode *root_node,
const aiScene *scene,
const std::vector<aiBone *> &bones,
std::map<aiBone *, aiNode *> &bone_stack,
std::vector<aiNode *> &node_stack);
};
} // Namespace Assimp
#endif // SCALE_PROCESS_H_

View File

@ -212,7 +212,7 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
// project tangent and bitangent into the plane formed by the vertex' normal // project tangent and bitangent into the plane formed by the vertex' normal
aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]); aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]); aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
localTangent.Normalize(); localBitangent.Normalize(); localTangent.NormalizeSafe(); localBitangent.NormalizeSafe();
// reconstruct tangent/bitangent according to normal and bitangent/tangent when it's infinite or NaN. // reconstruct tangent/bitangent according to normal and bitangent/tangent when it's infinite or NaN.
bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z); bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z);
@ -220,10 +220,10 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
if (invalid_tangent != invalid_bitangent) { if (invalid_tangent != invalid_bitangent) {
if (invalid_tangent) { if (invalid_tangent) {
localTangent = meshNorm[p] ^ localBitangent; localTangent = meshNorm[p] ^ localBitangent;
localTangent.Normalize(); localTangent.NormalizeSafe();
} else { } else {
localBitangent = localTangent ^ meshNorm[p]; localBitangent = localTangent ^ meshNorm[p];
localBitangent.Normalize(); localBitangent.NormalizeSafe();
} }
} }

View File

@ -354,12 +354,12 @@ void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D&
} }
else if (axis * base_axis_z >= angle_epsilon) { else if (axis * base_axis_z >= angle_epsilon) {
FindMeshCenter(mesh, center, min, max); FindMeshCenter(mesh, center, min, max);
diffu = max.y - min.y; diffu = max.x - min.x;
diffv = max.z - min.z; diffv = max.y - min.y;
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
const aiVector3D& pos = mesh->mVertices[pnt]; const aiVector3D& pos = mesh->mVertices[pnt];
out[pnt].Set((pos.y - min.y) / diffu,(pos.x - min.x) / diffv,0.0); out[pnt].Set((pos.x - min.x) / diffu,(pos.y - min.y) / diffv,0.0);
} }
} }
// slower code path in case the mapping axis is not one of the coordinate system axes // slower code path in case the mapping axis is not one of the coordinate system axes

View File

@ -52,7 +52,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "FindInvalidDataProcess.h" #include "FindInvalidDataProcess.h"
#include "ProcessHelper.h" #include "ProcessHelper.h"
#include <assimp/Macros.h>
#include <assimp/Exceptional.h> #include <assimp/Exceptional.h>
#include <assimp/qnan.h> #include <assimp/qnan.h>

View File

@ -431,31 +431,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
bone->mWeights = new aiVertexWeight[bone->mNumWeights]; bone->mWeights = new aiVertexWeight[bone->mNumWeights];
memcpy( bone->mWeights, &newWeights[0], bone->mNumWeights * sizeof( aiVertexWeight)); memcpy( bone->mWeights, &newWeights[0], bone->mNumWeights * sizeof( aiVertexWeight));
} }
else {
/* NOTE:
*
* In the algorithm above we're assuming that there are no vertices
* with a different bone weight setup at the same position. That wouldn't
* make sense, but it is not absolutely impossible. SkeletonMeshBuilder
* for example generates such input data if two skeleton points
* share the same position. Again this doesn't make sense but is
* reality for some model formats (MD5 for example uses these special
* nodes as attachment tags for its weapons).
*
* Then it is possible that a bone has no weights anymore .... as a quick
* workaround, we're just removing these bones. If they're animated,
* model geometry might be modified but at least there's no risk of a crash.
*/
delete bone;
--pMesh->mNumBones;
for (unsigned int n = a; n < pMesh->mNumBones; ++n) {
pMesh->mBones[n] = pMesh->mBones[n+1];
}
--a;
ASSIMP_LOG_WARN("Removing bone -> no weights remaining");
}
} }
return pMesh->mNumVertices; return pMesh->mNumVertices;
} }

View File

@ -224,3 +224,32 @@ bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh* pcMesh)
} }
return (pcMesh->mNumVertices != iOldNumVertices); return (pcMesh->mNumVertices != iOldNumVertices);
} }
// ------------------------------------------------------------------------------------------------
bool IsMeshInVerboseFormat(const aiMesh* mesh) {
// avoid slow vector<bool> specialization
std::vector<unsigned int> seen(mesh->mNumVertices,0);
for(unsigned int i = 0; i < mesh->mNumFaces; ++i) {
const aiFace& f = mesh->mFaces[i];
for(unsigned int j = 0; j < f.mNumIndices; ++j) {
if(++seen[f.mIndices[j]] == 2) {
// found a duplicate index
return false;
}
}
}
return true;
}
// ------------------------------------------------------------------------------------------------
bool MakeVerboseFormatProcess::IsVerboseFormat(const aiScene* pScene) {
for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
if(!IsMeshInVerboseFormat(pScene->mMeshes[i])) {
return false;
}
}
return true;
}

View File

@ -94,6 +94,13 @@ public:
* @param pScene The imported data to work at. */ * @param pScene The imported data to work at. */
void Execute( aiScene* pScene); void Execute( aiScene* pScene);
public:
// -------------------------------------------------------------------
/** Checks whether the scene is already in verbose format.
* @param pScene The data to check.
* @return true if the scene is already in verbose format. */
static bool IsVerboseFormat(const aiScene* pScene);
private: private:

View File

@ -39,19 +39,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
#ifndef ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS
#include "ScaleProcess.h" #include "ScaleProcess.h"
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/postprocess.h> #include <assimp/postprocess.h>
#include <assimp/BaseImporter.h>
namespace Assimp { namespace Assimp {
ScaleProcess::ScaleProcess() ScaleProcess::ScaleProcess()
: BaseProcess() : BaseProcess()
, mScale( AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT ) { , mScale( AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT ) {
// empty
} }
ScaleProcess::~ScaleProcess() { ScaleProcess::~ScaleProcess() {
@ -71,10 +69,26 @@ bool ScaleProcess::IsActive( unsigned int pFlags ) const {
} }
void ScaleProcess::SetupProperties( const Importer* pImp ) { void ScaleProcess::SetupProperties( const Importer* pImp ) {
mScale = pImp->GetPropertyFloat( AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY, 0 ); // User scaling
mScale = pImp->GetPropertyFloat( AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY, 1.0f );
// File scaling * Application Scaling
float importerScale = pImp->GetPropertyFloat( AI_CONFIG_APP_SCALE_KEY, 1.0f );
// apply scale to the scale
// helps prevent bugs with backward compatibility for anyone using normal scaling.
mScale *= importerScale;
} }
void ScaleProcess::Execute( aiScene* pScene ) { void ScaleProcess::Execute( aiScene* pScene ) {
if(mScale == 1.0f) {
return; // nothing to scale
}
ai_assert( mScale != 0 );
ai_assert( nullptr != pScene );
ai_assert( nullptr != pScene->mRootNode );
if ( nullptr == pScene ) { if ( nullptr == pScene ) {
return; return;
} }
@ -83,21 +97,112 @@ void ScaleProcess::Execute( aiScene* pScene ) {
return; return;
} }
// Process animations and update position transform to new unit system
for( unsigned int animationID = 0; animationID < pScene->mNumAnimations; animationID++ )
{
aiAnimation* animation = pScene->mAnimations[animationID];
for( unsigned int animationChannel = 0; animationChannel < animation->mNumChannels; animationChannel++)
{
aiNodeAnim* anim = animation->mChannels[animationChannel];
for( unsigned int posKey = 0; posKey < anim->mNumPositionKeys; posKey++)
{
aiVectorKey& vectorKey = anim->mPositionKeys[posKey];
vectorKey.mValue *= mScale;
}
}
}
for( unsigned int meshID = 0; meshID < pScene->mNumMeshes; meshID++)
{
aiMesh *mesh = pScene->mMeshes[meshID];
// Reconstruct mesh vertexes to the new unit system
for( unsigned int vertexID = 0; vertexID < mesh->mNumVertices; vertexID++)
{
aiVector3D& vertex = mesh->mVertices[vertexID];
vertex *= mScale;
}
// bone placement / scaling
for( unsigned int boneID = 0; boneID < mesh->mNumBones; boneID++)
{
// Reconstruct matrix by transform rather than by scale
// This prevent scale values being changed which can
// be meaningful in some cases
// like when you want the modeller to see 1:1 compatibility.
aiBone* bone = mesh->mBones[boneID];
aiVector3D pos, scale;
aiQuaternion rotation;
bone->mOffsetMatrix.Decompose( scale, rotation, pos);
aiMatrix4x4 translation;
aiMatrix4x4::Translation( pos * mScale, translation );
aiMatrix4x4 scaling;
aiMatrix4x4::Scaling( aiVector3D(scale), scaling );
aiMatrix4x4 RotMatrix = aiMatrix4x4 (rotation.GetMatrix());
bone->mOffsetMatrix = translation * RotMatrix * scaling;
}
// animation mesh processing
// convert by position rather than scale.
for( unsigned int animMeshID = 0; animMeshID < mesh->mNumAnimMeshes; animMeshID++)
{
aiAnimMesh * animMesh = mesh->mAnimMeshes[animMeshID];
for( unsigned int vertexID = 0; vertexID < animMesh->mNumVertices; vertexID++)
{
aiVector3D& vertex = animMesh->mVertices[vertexID];
vertex *= mScale;
}
}
}
traverseNodes( pScene->mRootNode ); traverseNodes( pScene->mRootNode );
} }
void ScaleProcess::traverseNodes( aiNode *node ) { void ScaleProcess::traverseNodes( aiNode *node, unsigned int nested_node_id ) {
applyScaling( node ); applyScaling( node );
for( size_t i = 0; i < node->mNumChildren; i++)
{
// recurse into the tree until we are done!
traverseNodes( node->mChildren[i], nested_node_id+1 );
}
} }
void ScaleProcess::applyScaling( aiNode *currentNode ) { void ScaleProcess::applyScaling( aiNode *currentNode ) {
if ( nullptr != currentNode ) { if ( nullptr != currentNode ) {
currentNode->mTransformation.a1 = currentNode->mTransformation.a1 * mScale; // Reconstruct matrix by transform rather than by scale
currentNode->mTransformation.b2 = currentNode->mTransformation.b2 * mScale; // This prevent scale values being changed which can
currentNode->mTransformation.c3 = currentNode->mTransformation.c3 * mScale; // be meaningful in some cases
// like when you want the modeller to
// see 1:1 compatibility.
aiVector3D pos, scale;
aiQuaternion rotation;
currentNode->mTransformation.Decompose( scale, rotation, pos);
aiMatrix4x4 translation;
aiMatrix4x4::Translation( pos * mScale, translation );
aiMatrix4x4 scaling;
// note: we do not use mScale here, this is on purpose.
aiMatrix4x4::Scaling( scale, scaling );
aiMatrix4x4 RotMatrix = aiMatrix4x4 (rotation.GetMatrix());
currentNode->mTransformation = translation * RotMatrix * scaling;
} }
} }
} // Namespace Assimp } // Namespace Assimp
#endif // !! ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS

View File

@ -39,7 +39,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------- ----------------------------------------------------------------------
*/ */
#pragma once #ifndef SCALE_PROCESS_H_
#define SCALE_PROCESS_H_
#include "Common/BaseProcess.h" #include "Common/BaseProcess.h"
@ -53,6 +54,11 @@ namespace Assimp {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/** ScaleProcess: Class to rescale the whole model. /** ScaleProcess: Class to rescale the whole model.
* Now rescales animations, bones, and blend shapes properly.
* Please note this will not write to 'scale' transform it will rewrite mesh
* and matrixes so that your scale values
* from your model package are preserved, so this is completely intentional
* bugs should be reported as soon as they are found.
*/ */
class ASSIMP_API ScaleProcess : public BaseProcess { class ASSIMP_API ScaleProcess : public BaseProcess {
public: public:
@ -78,7 +84,7 @@ public:
virtual void Execute( aiScene* pScene ); virtual void Execute( aiScene* pScene );
private: private:
void traverseNodes( aiNode *currentNode ); void traverseNodes( aiNode *currentNode, unsigned int nested_node_id = 0 );
void applyScaling( aiNode *currentNode ); void applyScaling( aiNode *currentNode );
private: private:
@ -86,3 +92,6 @@ private:
}; };
} // Namespace Assimp } // Namespace Assimp
#endif // SCALE_PROCESS_H_

View File

@ -538,13 +538,17 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation)
{ {
Validate(&pAnimation->mName); Validate(&pAnimation->mName);
// validate all materials // validate all animations
if (pAnimation->mNumChannels) if (pAnimation->mNumChannels || pAnimation->mNumMorphMeshChannels)
{ {
if (!pAnimation->mChannels) { if (!pAnimation->mChannels && pAnimation->mNumChannels) {
ReportError("aiAnimation::mChannels is NULL (aiAnimation::mNumChannels is %i)", ReportError("aiAnimation::mChannels is NULL (aiAnimation::mNumChannels is %i)",
pAnimation->mNumChannels); pAnimation->mNumChannels);
} }
if (!pAnimation->mMorphMeshChannels && pAnimation->mNumMorphMeshChannels) {
ReportError("aiAnimation::mMorphMeshChannels is NULL (aiAnimation::mNumMorphMeshChannels is %i)",
pAnimation->mNumMorphMeshChannels);
}
for (unsigned int i = 0; i < pAnimation->mNumChannels;++i) for (unsigned int i = 0; i < pAnimation->mNumChannels;++i)
{ {
if (!pAnimation->mChannels[i]) if (!pAnimation->mChannels[i])
@ -554,6 +558,15 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation)
} }
Validate(pAnimation, pAnimation->mChannels[i]); Validate(pAnimation, pAnimation->mChannels[i]);
} }
for (unsigned int i = 0; i < pAnimation->mNumMorphMeshChannels;++i)
{
if (!pAnimation->mMorphMeshChannels[i])
{
ReportError("aiAnimation::mMorphMeshChannels[%i] is NULL (aiAnimation::mNumMorphMeshChannels is %i)",
i, pAnimation->mNumMorphMeshChannels);
}
Validate(pAnimation, pAnimation->mMorphMeshChannels[i]);
}
} }
else { else {
ReportError("aiAnimation::mNumChannels is 0. At least one node animation channel must be there."); ReportError("aiAnimation::mNumChannels is 0. At least one node animation channel must be there.");
@ -590,15 +603,18 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
ReportError("%s #%i is set, but there are only %i %s textures", ReportError("%s #%i is set, but there are only %i %s textures",
szType,iIndex,iNumIndices,szType); szType,iIndex,iNumIndices,szType);
} }
if (!iNumIndices)return; if (!iNumIndices) {
return;
}
std::vector<aiTextureMapping> mappings(iNumIndices); std::vector<aiTextureMapping> mappings(iNumIndices);
// Now check whether all UV indices are valid ... // Now check whether all UV indices are valid ...
bool bNoSpecified = true; bool bNoSpecified = true;
for (unsigned int i = 0; i < pMaterial->mNumProperties;++i) for (unsigned int i = 0; i < pMaterial->mNumProperties;++i) {
{
aiMaterialProperty* prop = pMaterial->mProperties[i]; aiMaterialProperty* prop = pMaterial->mProperties[i];
if (prop->mSemantic != type)continue; if (prop->mSemantic != type) {
continue;
}
if ((int)prop->mIndex >= iNumIndices) if ((int)prop->mIndex >= iNumIndices)
{ {
@ -621,7 +637,7 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial,
ReportError("Material property %s%i is expected to be 5 floats large (size is %i)", ReportError("Material property %s%i is expected to be 5 floats large (size is %i)",
prop->mKey.data,prop->mIndex, prop->mDataLength); prop->mKey.data,prop->mIndex, prop->mDataLength);
} }
mappings[prop->mIndex] = *((aiTextureMapping*)prop->mData); //mappings[prop->mIndex] = ((aiUVTransform*)prop->mData);
} }
else if (!::strcmp(prop->mKey.data,"$tex.uvwsrc")) { else if (!::strcmp(prop->mKey.data,"$tex.uvwsrc")) {
if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength) if (aiPTI_Integer != prop->mType || sizeof(int) > prop->mDataLength)
@ -903,6 +919,48 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation,
} }
} }
void ValidateDSProcess::Validate( const aiAnimation* pAnimation,
const aiMeshMorphAnim* pMeshMorphAnim)
{
Validate(&pMeshMorphAnim->mName);
if (!pMeshMorphAnim->mNumKeys) {
ReportError("Empty mesh morph animation channel");
}
// otherwise check whether one of the keys exceeds the total duration of the animation
if (pMeshMorphAnim->mNumKeys)
{
if (!pMeshMorphAnim->mKeys)
{
ReportError("aiMeshMorphAnim::mKeys is NULL (aiMeshMorphAnim::mNumKeys is %i)",
pMeshMorphAnim->mNumKeys);
}
double dLast = -10e10;
for (unsigned int i = 0; i < pMeshMorphAnim->mNumKeys;++i)
{
// ScenePreprocessor will compute the duration if still the default value
// (Aramis) Add small epsilon, comparison tended to fail if max_time == duration,
// seems to be due the compilers register usage/width.
if (pAnimation->mDuration > 0. && pMeshMorphAnim->mKeys[i].mTime > pAnimation->mDuration+0.001)
{
ReportError("aiMeshMorphAnim::mKeys[%i].mTime (%.5f) is larger "
"than aiAnimation::mDuration (which is %.5f)",i,
(float)pMeshMorphAnim->mKeys[i].mTime,
(float)pAnimation->mDuration);
}
if (i && pMeshMorphAnim->mKeys[i].mTime <= dLast)
{
ReportWarning("aiMeshMorphAnim::mKeys[%i].mTime (%.5f) is smaller "
"than aiMeshMorphAnim::mKeys[%i] (which is %.5f)",i,
(float)pMeshMorphAnim->mKeys[i].mTime,
i-1, (float)dLast);
}
dLast = pMeshMorphAnim->mKeys[i].mTime;
}
}
}
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
void ValidateDSProcess::Validate( const aiNode* pNode) void ValidateDSProcess::Validate( const aiNode* pNode)
{ {
@ -958,7 +1016,7 @@ void ValidateDSProcess::Validate( const aiString* pString)
{ {
if (pString->length > MAXLEN) if (pString->length > MAXLEN)
{ {
ReportError("aiString::length is too large (%lu, maximum is %lu)", ReportError("aiString::length is too large (%u, maximum is %lu)",
pString->length,MAXLEN); pString->length,MAXLEN);
} }
const char* sz = pString->data; const char* sz = pString->data;

View File

@ -55,6 +55,7 @@ struct aiBone;
struct aiMesh; struct aiMesh;
struct aiAnimation; struct aiAnimation;
struct aiNodeAnim; struct aiNodeAnim;
struct aiMeshMorphAnim;
struct aiTexture; struct aiTexture;
struct aiMaterial; struct aiMaterial;
struct aiNode; struct aiNode;
@ -150,6 +151,13 @@ protected:
void Validate( const aiAnimation* pAnimation, void Validate( const aiAnimation* pAnimation,
const aiNodeAnim* pBoneAnim); const aiNodeAnim* pBoneAnim);
/** Validates a mesh morph animation channel.
* @param pAnimation Input animation.
* @param pMeshMorphAnim Mesh morph animation channel.
* */
void Validate( const aiAnimation* pAnimation,
const aiMeshMorphAnim* pMeshMorphAnim);
// ------------------------------------------------------------------- // -------------------------------------------------------------------
/** Validates a node and all of its subnodes /** Validates a node and all of its subnodes
* @param Node Input node*/ * @param Node Input node*/

View File

@ -43,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER #ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER
#include "Q3BSPFileImporter.h" #include "Q3BSPFileImporter.h"
#include "Q3BSPZipArchive.h"
#include "Q3BSPFileParser.h" #include "Q3BSPFileParser.h"
#include "Q3BSPFileData.h" #include "Q3BSPFileData.h"
@ -60,6 +59,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <assimp/scene.h> #include <assimp/scene.h>
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
#include <assimp/DefaultIOSystem.h> #include <assimp/DefaultIOSystem.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <assimp/importerdesc.h> #include <assimp/importerdesc.h>
#include <vector> #include <vector>
#include <sstream> #include <sstream>
@ -181,7 +181,7 @@ const aiImporterDesc* Q3BSPFileImporter::GetInfo () const {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Import method. // Import method.
void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene* scene, IOSystem* ioHandler) { void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene* scene, IOSystem* ioHandler) {
Q3BSPZipArchive Archive( ioHandler, rFile ); ZipArchiveIOSystem Archive( ioHandler, rFile );
if ( !Archive.isOpen() ) { if ( !Archive.isOpen() ) {
throw DeadlyImportError( "Failed to open file " + rFile + "." ); throw DeadlyImportError( "Failed to open file " + rFile + "." );
} }
@ -223,10 +223,10 @@ void Q3BSPFileImporter::separateMapName( const std::string &importName, std::str
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Returns the first map in the map archive. // Returns the first map in the map archive.
bool Q3BSPFileImporter::findFirstMapInArchive( Q3BSPZipArchive &bspArchive, std::string &mapName ) { bool Q3BSPFileImporter::findFirstMapInArchive(ZipArchiveIOSystem &bspArchive, std::string &mapName ) {
mapName = ""; mapName = "";
std::vector<std::string> fileList; std::vector<std::string> fileList;
bspArchive.getFileList( fileList ); bspArchive.getFileListExtension( fileList, "bsp" );
if (fileList.empty()) { if (fileList.empty()) {
return false; return false;
} }
@ -249,7 +249,7 @@ bool Q3BSPFileImporter::findFirstMapInArchive( Q3BSPZipArchive &bspArchive, std:
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Creates the assimp specific data. // Creates the assimp specific data.
void Q3BSPFileImporter::CreateDataFromImport( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, void Q3BSPFileImporter::CreateDataFromImport( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene,
Q3BSPZipArchive *pArchive ) { ZipArchiveIOSystem *pArchive ) {
if (nullptr == pModel || nullptr == pScene) { if (nullptr == pModel || nullptr == pScene) {
return; return;
} }
@ -418,7 +418,7 @@ void Q3BSPFileImporter::createTriangleTopology( const Q3BSP::Q3BSPModel *pModel,
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Creates all referenced materials. // Creates all referenced materials.
void Q3BSPFileImporter::createMaterials( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, void Q3BSPFileImporter::createMaterials( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene,
Q3BSPZipArchive *pArchive ) { ZipArchiveIOSystem *pArchive ) {
if ( m_MaterialLookupMap.empty() ) { if ( m_MaterialLookupMap.empty() ) {
return; return;
} }
@ -564,7 +564,7 @@ aiFace *Q3BSPFileImporter::getNextFace( aiMesh *mesh, unsigned int &faceIdx ) {
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Imports a texture file. // Imports a texture file.
bool Q3BSPFileImporter::importTextureFromArchive( const Q3BSP::Q3BSPModel *model, bool Q3BSPFileImporter::importTextureFromArchive( const Q3BSP::Q3BSPModel *model,
Q3BSP::Q3BSPZipArchive *archive, aiScene*, ZipArchiveIOSystem *archive, aiScene*,
aiMaterial *pMatHelper, int textureId ) { aiMaterial *pMatHelper, int textureId ) {
if (nullptr == archive || nullptr == pMatHelper ) { if (nullptr == archive || nullptr == pMatHelper ) {
return false; return false;
@ -669,7 +669,7 @@ bool Q3BSPFileImporter::importLightmap( const Q3BSP::Q3BSPModel *pModel, aiScene
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
// Will search for a supported extension. // Will search for a supported extension.
bool Q3BSPFileImporter::expandFile( Q3BSP::Q3BSPZipArchive *pArchive, const std::string &rFilename, bool Q3BSPFileImporter::expandFile(ZipArchiveIOSystem *pArchive, const std::string &rFilename,
const std::vector<std::string> &rExtList, std::string &rFile, const std::vector<std::string> &rExtList, std::string &rFile,
std::string &rExt ) std::string &rExt )
{ {

View File

@ -54,9 +54,9 @@ struct aiMaterial;
struct aiTexture; struct aiTexture;
namespace Assimp { namespace Assimp {
class ZipArchiveIOSystem;
namespace Q3BSP { namespace Q3BSP {
class Q3BSPZipArchive;
struct Q3BSPModel; struct Q3BSPModel;
struct sQ3BSPFace; struct sQ3BSPFace;
} }
@ -85,24 +85,24 @@ protected:
const aiImporterDesc* GetInfo () const; const aiImporterDesc* GetInfo () const;
void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
void separateMapName( const std::string &rImportName, std::string &rArchiveName, std::string &rMapName ); void separateMapName( const std::string &rImportName, std::string &rArchiveName, std::string &rMapName );
bool findFirstMapInArchive( Q3BSP::Q3BSPZipArchive &rArchive, std::string &rMapName ); bool findFirstMapInArchive(ZipArchiveIOSystem &rArchive, std::string &rMapName );
void CreateDataFromImport( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, Q3BSP::Q3BSPZipArchive *pArchive ); void CreateDataFromImport( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, ZipArchiveIOSystem *pArchive );
void CreateNodes( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, aiNode *pParent ); void CreateNodes( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, aiNode *pParent );
aiNode *CreateTopology( const Q3BSP::Q3BSPModel *pModel, unsigned int materialIdx, aiNode *CreateTopology( const Q3BSP::Q3BSPModel *pModel, unsigned int materialIdx,
std::vector<Q3BSP::sQ3BSPFace*> &rArray, aiMesh **pMesh ); std::vector<Q3BSP::sQ3BSPFace*> &rArray, aiMesh **pMesh );
void createTriangleTopology( const Q3BSP::Q3BSPModel *pModel, Q3BSP::sQ3BSPFace *pQ3BSPFace, aiMesh* pMesh, unsigned int &rFaceIdx, void createTriangleTopology( const Q3BSP::Q3BSPModel *pModel, Q3BSP::sQ3BSPFace *pQ3BSPFace, aiMesh* pMesh, unsigned int &rFaceIdx,
unsigned int &rVertIdx ); unsigned int &rVertIdx );
void createMaterials( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, Q3BSP::Q3BSPZipArchive *pArchive ); void createMaterials( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, ZipArchiveIOSystem *pArchive );
size_t countData( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const; size_t countData( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const;
size_t countFaces( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const; size_t countFaces( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const;
size_t countTriangles( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const; size_t countTriangles( const std::vector<Q3BSP::sQ3BSPFace*> &rArray ) const;
void createMaterialMap( const Q3BSP::Q3BSPModel *pModel); void createMaterialMap( const Q3BSP::Q3BSPModel *pModel);
aiFace *getNextFace( aiMesh *pMesh, unsigned int &rFaceIdx ); aiFace *getNextFace( aiMesh *pMesh, unsigned int &rFaceIdx );
bool importTextureFromArchive( const Q3BSP::Q3BSPModel *pModel, Q3BSP::Q3BSPZipArchive *pArchive, aiScene* pScene, bool importTextureFromArchive( const Q3BSP::Q3BSPModel *pModel, ZipArchiveIOSystem *pArchive, aiScene* pScene,
aiMaterial *pMatHelper, int textureId ); aiMaterial *pMatHelper, int textureId );
bool importLightmap( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, aiMaterial *pMatHelper, int lightmapId ); bool importLightmap( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, aiMaterial *pMatHelper, int lightmapId );
bool importEntities( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene ); bool importEntities( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene );
bool expandFile( Q3BSP::Q3BSPZipArchive *pArchive, const std::string &rFilename, const std::vector<std::string> &rExtList, bool expandFile(ZipArchiveIOSystem *pArchive, const std::string &rFilename, const std::vector<std::string> &rExtList,
std::string &rFile, std::string &rExt ); std::string &rFile, std::string &rExt );
private: private:

View File

@ -45,9 +45,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "Q3BSPFileParser.h" #include "Q3BSPFileParser.h"
#include "Q3BSPFileData.h" #include "Q3BSPFileData.h"
#include "Q3BSPZipArchive.h"
#include <vector> #include <vector>
#include <assimp/DefaultIOSystem.h> #include <assimp/DefaultIOSystem.h>
#include <assimp/ZipArchiveIOSystem.h>
#include <assimp/ai_assert.h> #include <assimp/ai_assert.h>
namespace Assimp { namespace Assimp {
@ -55,7 +55,7 @@ namespace Assimp {
using namespace Q3BSP; using namespace Q3BSP;
// ------------------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------------------
Q3BSPFileParser::Q3BSPFileParser( const std::string &mapName, Q3BSPZipArchive *pZipArchive ) : Q3BSPFileParser::Q3BSPFileParser( const std::string &mapName, ZipArchiveIOSystem *pZipArchive ) :
m_sOffset( 0 ), m_sOffset( 0 ),
m_Data(), m_Data(),
m_pModel(nullptr), m_pModel(nullptr),
@ -101,6 +101,7 @@ bool Q3BSPFileParser::readData( const std::string &rMapName ) {
const size_t readSize = pMapFile->Read( &m_Data[0], sizeof( char ), size ); const size_t readSize = pMapFile->Read( &m_Data[0], sizeof( char ), size );
if ( readSize != size ) { if ( readSize != size ) {
m_Data.clear(); m_Data.clear();
m_pZipArchive->Close(pMapFile);
return false; return false;
} }
m_pZipArchive->Close( pMapFile ); m_pZipArchive->Close( pMapFile );

View File

@ -48,13 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
namespace Assimp namespace Assimp
{ {
class ZipArchiveIOSystem;
namespace Q3BSP namespace Q3BSP
{ {
struct Q3BSPModel;
class Q3BSPZipArchive; class ZipFile;
struct Q3BSPModel;
class ZipFile;
} }
// ------------------------------------------------------------------- // -------------------------------------------------------------------
@ -62,7 +61,7 @@ class ZipFile;
class Q3BSPFileParser class Q3BSPFileParser
{ {
public: public:
Q3BSPFileParser( const std::string &rMapName, Q3BSP::Q3BSPZipArchive *pZipArchive ); Q3BSPFileParser( const std::string &rMapName, ZipArchiveIOSystem *pZipArchive );
~Q3BSPFileParser(); ~Q3BSPFileParser();
Q3BSP::Q3BSPModel *getModel() const; Q3BSP::Q3BSPModel *getModel() const;
@ -83,7 +82,7 @@ private:
size_t m_sOffset; size_t m_sOffset;
std::vector<char> m_Data; std::vector<char> m_Data;
Q3BSP::Q3BSPModel *m_pModel; Q3BSP::Q3BSPModel *m_pModel;
Q3BSP::Q3BSPZipArchive *m_pZipArchive; ZipArchiveIOSystem *m_pZipArchive;
}; };
} // Namespace Assimp } // Namespace Assimp

View File

@ -1,325 +0,0 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, 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_Q3BSP_IMPORTER
#include "Q3BSPZipArchive.h"
#include <cassert>
#include <cstdlib>
#include <assimp/ai_assert.h>
namespace Assimp {
namespace Q3BSP {
voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) {
IOSystem* io_system = (IOSystem*) opaque;
const char* mode_fopen = NULL;
if((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) {
mode_fopen = "rb";
} else {
if(mode & ZLIB_FILEFUNC_MODE_EXISTING) {
mode_fopen = "r+b";
} else {
if(mode & ZLIB_FILEFUNC_MODE_CREATE) {
mode_fopen = "wb";
}
}
}
return (voidpf) io_system->Open(filename, mode_fopen);
}
uLong IOSystem2Unzip::read(voidpf /*opaque*/, voidpf stream, void* buf, uLong size) {
IOStream* io_stream = (IOStream*) stream;
return static_cast<uLong>(io_stream->Read(buf, 1, size));
}
uLong IOSystem2Unzip::write(voidpf /*opaque*/, voidpf stream, const void* buf, uLong size) {
IOStream* io_stream = (IOStream*) stream;
return static_cast<uLong>(io_stream->Write(buf, 1, size));
}
long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) {
IOStream* io_stream = (IOStream*) stream;
return static_cast<long>(io_stream->Tell());
}
long IOSystem2Unzip::seek(voidpf /*opaque*/, voidpf stream, uLong offset, int origin) {
IOStream* io_stream = (IOStream*) stream;
aiOrigin assimp_origin;
switch (origin) {
default:
case ZLIB_FILEFUNC_SEEK_CUR:
assimp_origin = aiOrigin_CUR;
break;
case ZLIB_FILEFUNC_SEEK_END:
assimp_origin = aiOrigin_END;
break;
case ZLIB_FILEFUNC_SEEK_SET:
assimp_origin = aiOrigin_SET;
break;
}
return (io_stream->Seek(offset, assimp_origin) == aiReturn_SUCCESS ? 0 : -1);
}
int IOSystem2Unzip::close(voidpf opaque, voidpf stream) {
IOSystem* io_system = (IOSystem*) opaque;
IOStream* io_stream = (IOStream*) stream;
io_system->Close(io_stream);
return 0;
}
int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) {
return 0;
}
zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) {
zlib_filefunc_def mapping;
#ifdef ASSIMP_USE_HUNTER
mapping.zopen_file = (open_file_func)open;
mapping.zread_file = (read_file_func)read;
mapping.zwrite_file = (write_file_func)write;
mapping.ztell_file = (tell_file_func)tell;
mapping.zseek_file = (seek_file_func)seek;
mapping.zclose_file = (close_file_func)close;
mapping.zerror_file = (error_file_func)testerror;
#else
mapping.zopen_file = open;
mapping.zread_file = read;
mapping.zwrite_file = write;
mapping.ztell_file = tell;
mapping.zseek_file = seek;
mapping.zclose_file = close;
mapping.zerror_file = testerror;
#endif
mapping.opaque = (voidpf) pIOHandler;
return mapping;
}
ZipFile::ZipFile(size_t size) : m_Size(size) {
ai_assert(m_Size != 0);
m_Buffer = malloc(m_Size);
}
ZipFile::~ZipFile() {
free(m_Buffer);
m_Buffer = NULL;
}
size_t ZipFile::Read(void* pvBuffer, size_t pSize, size_t pCount) {
const size_t size = pSize * pCount;
assert(size <= m_Size);
std::memcpy(pvBuffer, m_Buffer, size);
return size;
}
size_t ZipFile::Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) {
return 0;
}
size_t ZipFile::FileSize() const {
return m_Size;
}
aiReturn ZipFile::Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) {
return aiReturn_FAILURE;
}
size_t ZipFile::Tell() const {
return 0;
}
void ZipFile::Flush() {
// empty
}
// ------------------------------------------------------------------------------------------------
// Constructor.
Q3BSPZipArchive::Q3BSPZipArchive(IOSystem* pIOHandler, const std::string& rFile) : m_ZipFileHandle(NULL), m_ArchiveMap() {
if (! rFile.empty()) {
zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);
m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping);
if(m_ZipFileHandle != nullptr) {
mapArchive();
}
}
}
// ------------------------------------------------------------------------------------------------
// Destructor.
Q3BSPZipArchive::~Q3BSPZipArchive() {
for(auto &file : m_ArchiveMap) {
delete file.second;
}
m_ArchiveMap.clear();
if(m_ZipFileHandle != nullptr) {
unzClose(m_ZipFileHandle);
m_ZipFileHandle = nullptr;
}
}
// ------------------------------------------------------------------------------------------------
// Returns true, if the archive is already open.
bool Q3BSPZipArchive::isOpen() const {
return (m_ZipFileHandle != nullptr);
}
// ------------------------------------------------------------------------------------------------
// Returns true, if the filename is part of the archive.
bool Q3BSPZipArchive::Exists(const char* pFile) const {
bool exist = false;
if (pFile != nullptr) {
std::string rFile(pFile);
std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(rFile);
if(it != m_ArchiveMap.end()) {
exist = true;
}
}
return exist;
}
// ------------------------------------------------------------------------------------------------
// Returns the separator delimiter.
char Q3BSPZipArchive::getOsSeparator() const {
#ifndef _WIN32
return '/';
#else
return '\\';
#endif
}
// ------------------------------------------------------------------------------------------------
// Opens a file, which is part of the archive.
IOStream *Q3BSPZipArchive::Open(const char* pFile, const char* /*pMode*/) {
ai_assert(pFile != nullptr);
IOStream* result = nullptr;
std::map<std::string, ZipFile*>::iterator it = m_ArchiveMap.find(pFile);
if(it != m_ArchiveMap.end()) {
result = (IOStream*) it->second;
}
return result;
}
// ------------------------------------------------------------------------------------------------
// Close a filestream.
void Q3BSPZipArchive::Close(IOStream *pFile) {
(void)(pFile);
ai_assert(pFile != nullptr);
// We don't do anything in case the file would be opened again in the future
}
// ------------------------------------------------------------------------------------------------
// Returns the file-list of the archive.
void Q3BSPZipArchive::getFileList(std::vector<std::string> &rFileList) {
rFileList.clear();
for(auto &file : m_ArchiveMap) {
rFileList.push_back(file.first);
}
}
// ------------------------------------------------------------------------------------------------
// Maps the archive content.
bool Q3BSPZipArchive::mapArchive() {
bool success = false;
if(m_ZipFileHandle != nullptr) {
if(m_ArchiveMap.empty()) {
// At first ensure file is already open
if(unzGoToFirstFile(m_ZipFileHandle) == UNZ_OK) {
// Loop over all files
do {
char filename[FileNameSize];
unz_file_info fileInfo;
if(unzGetCurrentFileInfo(m_ZipFileHandle, &fileInfo, filename, FileNameSize, NULL, 0, NULL, 0) == UNZ_OK) {
// The file has EXACTLY the size of uncompressed_size. In C
// you need to mark the last character with '\0', so add
// another character
if(fileInfo.uncompressed_size != 0 && unzOpenCurrentFile(m_ZipFileHandle) == UNZ_OK) {
std::pair<std::map<std::string, ZipFile*>::iterator, bool> result = m_ArchiveMap.insert(std::make_pair(filename, new ZipFile(fileInfo.uncompressed_size)));
if(unzReadCurrentFile(m_ZipFileHandle, result.first->second->m_Buffer, fileInfo.uncompressed_size) == (long int) fileInfo.uncompressed_size) {
if(unzCloseCurrentFile(m_ZipFileHandle) == UNZ_OK) {
// Nothing to do anymore...
}
}
}
}
} while(unzGoToNextFile(m_ZipFileHandle) != UNZ_END_OF_LIST_OF_FILE);
}
}
success = true;
}
return success;
}
// ------------------------------------------------------------------------------------------------
} // Namespace Q3BSP
} // Namespace Assimp
#endif // ASSIMP_BUILD_NO_Q3BSP_IMPORTER

View File

@ -1,135 +0,0 @@
/*
Open Asset Import Library (assimp)
----------------------------------------------------------------------
Copyright (c) 2006-2019, 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 AI_Q3BSP_ZIPARCHIVE_H_INC
#define AI_Q3BSP_ZIPARCHIVE_H_INC
#ifdef ASSIMP_USE_HUNTER
# include <minizip/unzip.h>
#else
# include <unzip.h>
#endif
#include <assimp/IOStream.hpp>
#include <assimp/IOSystem.hpp>
#include <vector>
#include <map>
#include <cassert>
namespace Assimp {
namespace Q3BSP {
// ------------------------------------------------------------------------------------------------
/// \class IOSystem2Unzip
/// \ingroup Assimp::Q3BSP
///
/// \brief
// ------------------------------------------------------------------------------------------------
class IOSystem2Unzip {
public:
static voidpf open(voidpf opaque, const char* filename, int mode);
static uLong read(voidpf opaque, voidpf stream, void* buf, uLong size);
static uLong write(voidpf opaque, voidpf stream, const void* buf, uLong size);
static long tell(voidpf opaque, voidpf stream);
static long seek(voidpf opaque, voidpf stream, uLong offset, int origin);
static int close(voidpf opaque, voidpf stream);
static int testerror(voidpf opaque, voidpf stream);
static zlib_filefunc_def get(IOSystem* pIOHandler);
};
// ------------------------------------------------------------------------------------------------
/// \class ZipFile
/// \ingroup Assimp::Q3BSP
///
/// \brief
// ------------------------------------------------------------------------------------------------
class ZipFile : public IOStream {
friend class Q3BSPZipArchive;
public:
explicit ZipFile(size_t size);
~ZipFile();
size_t Read(void* pvBuffer, size_t pSize, size_t pCount );
size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/);
size_t FileSize() const;
aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/);
size_t Tell() const;
void Flush();
private:
void* m_Buffer;
size_t m_Size;
};
// ------------------------------------------------------------------------------------------------
/// \class Q3BSPZipArchive
/// \ingroup Assimp::Q3BSP
///
/// \brief IMplements a zip archive like the WinZip archives. Will be also used to import data
/// from a P3K archive ( Quake level format ).
// ------------------------------------------------------------------------------------------------
class Q3BSPZipArchive : public Assimp::IOSystem {
public:
static const unsigned int FileNameSize = 256;
public:
Q3BSPZipArchive(IOSystem* pIOHandler, const std::string & rFile);
~Q3BSPZipArchive();
bool Exists(const char* pFile) const;
char getOsSeparator() const;
IOStream* Open(const char* pFile, const char* pMode = "rb");
void Close(IOStream* pFile);
bool isOpen() const;
void getFileList(std::vector<std::string> &rFileList);
private:
bool mapArchive();
private:
unzFile m_ZipFileHandle;
std::map<std::string, ZipFile*> m_ArchiveMap;
};
// ------------------------------------------------------------------------------------------------
} // Namespace Q3BSP
} // Namespace Assimp
#endif // AI_Q3BSP_ZIPARCHIVE_H_INC

View File

@ -225,7 +225,7 @@ void STLImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
} }
pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_DIFFUSE); pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_DIFFUSE);
pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_SPECULAR); pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_SPECULAR);
clrDiffuse = aiColor4D( ai_real(1.0), ai_real(1.0), ai_real(1.0), ai_real(1.0)); clrDiffuse = aiColor4D( ai_real(0.05), ai_real(0.05), ai_real(0.05), ai_real(1.0));
pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_AMBIENT); pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_AMBIENT);
pScene->mNumMaterials = 1; pScene->mNumMaterials = 1;

View File

@ -127,7 +127,8 @@ inline void CompressVertex(const aiVector3D& v, uint32_t& out)
n.X = (int32_t)v.x; n.X = (int32_t)v.x;
n.Y = (int32_t)v.y; n.Y = (int32_t)v.y;
n.Z = (int32_t)v.z; n.Z = (int32_t)v.z;
out = t; ::memcpy( &out, &t, sizeof(int32_t));
//out = t;
} }
// UNREAL vertex decompression // UNREAL vertex decompression

View File

@ -596,11 +596,11 @@ void XFileParser::ParseDataObjectMeshNormals( Mesh* pMesh)
// do not crah when no face definitions are there // do not crah when no face definitions are there
if (numFaces > 0) { if (numFaces > 0) {
// normal face creation // normal face creation
pMesh->mNormFaces.resize( pMesh->mNormFaces.size() + numFaces ); pMesh->mNormFaces.resize( numFaces );
for( unsigned int a = 0; a < numFaces; ++a ) { for( unsigned int a = 0; a < numFaces; ++a ) {
unsigned int numIndices = ReadInt(); unsigned int numIndices = ReadInt();
pMesh->mNormFaces.push_back( Face() ); pMesh->mNormFaces[a] = Face();
Face& face = pMesh->mNormFaces.back(); Face& face = pMesh->mNormFaces[a];
for( unsigned int b = 0; b < numIndices; ++b ) { for( unsigned int b = 0; b < numIndices; ++b ) {
face.mIndices.push_back( ReadInt()); face.mIndices.push_back( ReadInt());
} }

View File

@ -68,7 +68,7 @@ aiMatrix4x4 out_matr;
} }
// multiplicate all matrices in reverse order // multiplicate all matrices in reverse order
for(std::list<aiMatrix4x4>::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); rit++) out_matr = out_matr * (*rit); for(std::list<aiMatrix4x4>::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); ++rit) out_matr = out_matr * (*rit);
return out_matr; return out_matr;
} }

View File

@ -80,7 +80,13 @@ const aiImporterDesc X3DImporter::Description = {
//const std::regex X3DImporter::pattern_nws(R"([^, \t\r\n]+)"); //const std::regex X3DImporter::pattern_nws(R"([^, \t\r\n]+)");
//const std::regex X3DImporter::pattern_true(R"(^\s*(?:true|1)\s*$)", std::regex::icase); //const std::regex X3DImporter::pattern_true(R"(^\s*(?:true|1)\s*$)", std::regex::icase);
struct WordIterator: public std::iterator<std::input_iterator_tag, const char*> { struct WordIterator {
using iterator_category = std::input_iterator_tag;
using value_type = const char*;
using difference_type = ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
static const char *whitespace; static const char *whitespace;
const char *start_, *end_; const char *start_, *end_;
WordIterator(const char *start, const char *end): start_(start), end_(end) { WordIterator(const char *start, const char *end): start_(start), end_(end) {
@ -130,8 +136,8 @@ X3DImporter::~X3DImporter() {
void X3DImporter::Clear() { void X3DImporter::Clear() {
NodeElement_Cur = nullptr; NodeElement_Cur = nullptr;
// Delete all elements // Delete all elements
if(NodeElement_List.size()) { if(!NodeElement_List.empty()) {
for ( std::list<CX3DImporter_NodeElement*>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); it++ ) { for ( std::list<CX3DImporter_NodeElement*>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); ++it ) {
delete *it; delete *it;
} }
NodeElement_List.clear(); NodeElement_List.clear();
@ -145,7 +151,7 @@ void X3DImporter::Clear() {
bool X3DImporter::FindNodeElement_FromRoot(const std::string& pID, const CX3DImporter_NodeElement::EType pType, CX3DImporter_NodeElement** pElement) bool X3DImporter::FindNodeElement_FromRoot(const std::string& pID, const CX3DImporter_NodeElement::EType pType, CX3DImporter_NodeElement** pElement)
{ {
for(std::list<CX3DImporter_NodeElement*>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); it++) for(std::list<CX3DImporter_NodeElement*>::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); ++it)
{ {
if(((*it)->Type == pType) && ((*it)->ID == pID)) if(((*it)->Type == pType) && ((*it)->ID == pID))
{ {
@ -176,7 +182,7 @@ bool X3DImporter::FindNodeElement_FromNode(CX3DImporter_NodeElement* pStartNode,
}// if((pStartNode->Type() == pType) && (pStartNode->ID() == pID)) }// if((pStartNode->Type() == pType) && (pStartNode->ID() == pID))
// Check childs of pStartNode. // Check childs of pStartNode.
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = pStartNode->Child.begin(); ch_it != pStartNode->Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = pStartNode->Child.begin(); ch_it != pStartNode->Child.end(); ++ch_it)
{ {
found = FindNodeElement_FromNode(*ch_it, pID, pType, pElement); found = FindNodeElement_FromNode(*ch_it, pID, pType, pElement);
if ( found ) if ( found )
@ -608,10 +614,10 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrCol3f(const int pAttrIdx, std::ve
XML_ReadNode_GetAttrVal_AsListCol3f(pAttrIdx, tlist);// read as list XML_ReadNode_GetAttrVal_AsListCol3f(pAttrIdx, tlist);// read as list
// and copy to array // and copy to array
if(tlist.size() > 0) if(!tlist.empty())
{ {
pValue.reserve(tlist.size()); pValue.reserve(tlist.size());
for(std::list<aiColor3D>::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it); for(std::list<aiColor3D>::iterator it = tlist.begin(); it != tlist.end(); ++it) pValue.push_back(*it);
} }
} }
@ -641,10 +647,10 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrCol4f(const int pAttrIdx, std::ve
XML_ReadNode_GetAttrVal_AsListCol4f(pAttrIdx, tlist);// read as list XML_ReadNode_GetAttrVal_AsListCol4f(pAttrIdx, tlist);// read as list
// and copy to array // and copy to array
if(tlist.size() > 0) if(!tlist.empty())
{ {
pValue.reserve(tlist.size()); pValue.reserve(tlist.size());
for ( std::list<aiColor4D>::iterator it = tlist.begin(); it != tlist.end(); it++ ) for ( std::list<aiColor4D>::iterator it = tlist.begin(); it != tlist.end(); ++it )
{ {
pValue.push_back( *it ); pValue.push_back( *it );
} }
@ -678,10 +684,10 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrVec2f(const int pAttrIdx, std::ve
XML_ReadNode_GetAttrVal_AsListVec2f(pAttrIdx, tlist);// read as list XML_ReadNode_GetAttrVal_AsListVec2f(pAttrIdx, tlist);// read as list
// and copy to array // and copy to array
if(tlist.size() > 0) if(!tlist.empty())
{ {
pValue.reserve(tlist.size()); pValue.reserve(tlist.size());
for ( std::list<aiVector2D>::iterator it = tlist.begin(); it != tlist.end(); it++ ) for ( std::list<aiVector2D>::iterator it = tlist.begin(); it != tlist.end(); ++it )
{ {
pValue.push_back( *it ); pValue.push_back( *it );
} }
@ -716,10 +722,10 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrVec3f(const int pAttrIdx, std::ve
XML_ReadNode_GetAttrVal_AsListVec3f(pAttrIdx, tlist);// read as list XML_ReadNode_GetAttrVal_AsListVec3f(pAttrIdx, tlist);// read as list
// and copy to array // and copy to array
if(tlist.size() > 0) if(!tlist.empty())
{ {
pValue.reserve(tlist.size()); pValue.reserve(tlist.size());
for ( std::list<aiVector3D>::iterator it = tlist.begin(); it != tlist.end(); it++ ) for ( std::list<aiVector3D>::iterator it = tlist.begin(); it != tlist.end(); ++it )
{ {
pValue.push_back( *it ); pValue.push_back( *it );
} }
@ -817,7 +823,7 @@ void X3DImporter::GeometryHelper_Extend_PointToLine(const std::list<aiVector3D>&
std::list<aiVector3D>::const_iterator pit = pPoint.begin(); std::list<aiVector3D>::const_iterator pit = pPoint.begin();
std::list<aiVector3D>::const_iterator pit_last = pPoint.end(); std::list<aiVector3D>::const_iterator pit_last = pPoint.end();
pit_last--; --pit_last;
if ( pPoint.size() < 2 ) if ( pPoint.size() < 2 )
{ {
@ -831,7 +837,7 @@ void X3DImporter::GeometryHelper_Extend_PointToLine(const std::list<aiVector3D>&
{ {
pLine.push_back(*pit);// second point of previous line pLine.push_back(*pit);// second point of previous line
pLine.push_back(*pit);// first point of next line pLine.push_back(*pit);// first point of next line
pit++; ++pit;
} }
// add last point of last line // add last point of last line
pLine.push_back(*pit); pLine.push_back(*pit);
@ -849,7 +855,7 @@ void X3DImporter::GeometryHelper_Extend_PolylineIdxToLineIdx(const std::list<int
{ {
std::list<int32_t>::const_iterator plit_next; std::list<int32_t>::const_iterator plit_next;
plit_next = plit, plit_next++; plit_next = plit, ++plit_next;
pLineCoordIdx.push_back(*plit);// second point of previous line. pLineCoordIdx.push_back(*plit);// second point of previous line.
pLineCoordIdx.push_back(-1);// delimiter pLineCoordIdx.push_back(-1);// delimiter
if((*plit_next == (-1)) || (plit_next == pPolylineCoordIdx.end())) break;// current polyline is finished if((*plit_next == (-1)) || (plit_next == pPolylineCoordIdx.end())) break;// current polyline is finished
@ -904,7 +910,7 @@ void X3DImporter::GeometryHelper_CoordIdxStr2FacesArr(const std::vector<int32_t>
pFaces.reserve(f_data.size() / 3); pFaces.reserve(f_data.size() / 3);
inds.reserve(4); inds.reserve(4);
//PrintVectorSet("build. ci", pCoordIdx); //PrintVectorSet("build. ci", pCoordIdx);
for(std::vector<int32_t>::iterator it = f_data.begin(); it != f_data.end(); it++) for(std::vector<int32_t>::iterator it = f_data.begin(); it != f_data.end(); ++it)
{ {
// when face is got count how many indices in it. // when face is got count how many indices in it.
if(*it == (-1)) if(*it == (-1))
@ -951,7 +957,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list<aiColor3D
std::list<aiColor4D> tcol; std::list<aiColor4D> tcol;
// create RGBA array from RGB. // create RGBA array from RGB.
for(std::list<aiColor3D>::const_iterator it = pColors.begin(); it != pColors.end(); it++) tcol.push_back(aiColor4D((*it).r, (*it).g, (*it).b, 1)); for(std::list<aiColor3D>::const_iterator it = pColors.begin(); it != pColors.end(); ++it) tcol.push_back(aiColor4D((*it).r, (*it).g, (*it).b, 1));
// call existing function for adding RGBA colors // call existing function for adding RGBA colors
MeshGeometry_AddColor(pMesh, tcol, pColorPerVertex); MeshGeometry_AddColor(pMesh, tcol, pColorPerVertex);
@ -991,7 +997,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list<aiColor4D
pMesh.mColors[ 0 ][ pMesh.mFaces[ fi ].mIndices[ vi ] ] = *col_it; pMesh.mColors[ 0 ][ pMesh.mFaces[ fi ].mIndices[ vi ] ] = *col_it;
} }
col_it++; ++col_it;
} }
}// if(pColorPerVertex) else }// if(pColorPerVertex) else
} }
@ -1002,7 +1008,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::vector<int32_t
std::list<aiColor4D> tcol; std::list<aiColor4D> tcol;
// create RGBA array from RGB. // create RGBA array from RGB.
for ( std::list<aiColor3D>::const_iterator it = pColors.begin(); it != pColors.end(); it++ ) for ( std::list<aiColor3D>::const_iterator it = pColors.begin(); it != pColors.end(); ++it )
{ {
tcol.push_back( aiColor4D( ( *it ).r, ( *it ).g, ( *it ).b, 1 ) ); tcol.push_back( aiColor4D( ( *it ).r, ( *it ).g, ( *it ).b, 1 ) );
} }
@ -1025,7 +1031,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::vector<int32_t
// copy list to array because we are need indexed access to colors. // copy list to array because we are need indexed access to colors.
col_arr_copy.reserve(pColors.size()); col_arr_copy.reserve(pColors.size());
for ( std::list<aiColor4D>::const_iterator it = pColors.begin(); it != pColors.end(); it++ ) for ( std::list<aiColor4D>::const_iterator it = pColors.begin(); it != pColors.end(); ++it )
{ {
col_arr_copy.push_back( *it ); col_arr_copy.push_back( *it );
} }
@ -1042,7 +1048,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::vector<int32_t
} }
// create list with colors for every vertex. // create list with colors for every vertex.
col_tgt_arr.resize(pMesh.mNumVertices); col_tgt_arr.resize(pMesh.mNumVertices);
for(std::vector<int32_t>::const_iterator colidx_it = pColorIdx.begin(), coordidx_it = pCoordIdx.begin(); colidx_it != pColorIdx.end(); colidx_it++, coordidx_it++) for(std::vector<int32_t>::const_iterator colidx_it = pColorIdx.begin(), coordidx_it = pCoordIdx.begin(); colidx_it != pColorIdx.end(); ++colidx_it, ++coordidx_it)
{ {
if ( *colidx_it == ( -1 ) ) if ( *colidx_it == ( -1 ) )
{ {
@ -1115,7 +1121,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::vector<int32_t
}// if(pColorPerVertex) else }// if(pColorPerVertex) else
// copy array to list for calling function that add colors. // copy array to list for calling function that add colors.
for(std::vector<aiColor4D>::const_iterator it = col_tgt_arr.begin(); it != col_tgt_arr.end(); it++) col_tgt_list.push_back(*it); for(std::vector<aiColor4D>::const_iterator it = col_tgt_arr.begin(); it != col_tgt_arr.end(); ++it) col_tgt_list.push_back(*it);
// add prepared colors list to mesh. // add prepared colors list to mesh.
MeshGeometry_AddColor(pMesh, col_tgt_list, pColorPerVertex); MeshGeometry_AddColor(pMesh, col_tgt_list, pColorPerVertex);
} }
@ -1128,7 +1134,7 @@ void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::vector<int32_
// copy list to array because we are need indexed access to normals. // copy list to array because we are need indexed access to normals.
norm_arr_copy.reserve(pNormals.size()); norm_arr_copy.reserve(pNormals.size());
for ( std::list<aiVector3D>::const_iterator it = pNormals.begin(); it != pNormals.end(); it++ ) for ( std::list<aiVector3D>::const_iterator it = pNormals.begin(); it != pNormals.end(); ++it )
{ {
norm_arr_copy.push_back( *it ); norm_arr_copy.push_back( *it );
} }
@ -1141,7 +1147,7 @@ void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::vector<int32_
if(pNormalIdx.size() != pCoordIdx.size()) throw DeadlyImportError("Normals and Coords inidces count must be equal."); if(pNormalIdx.size() != pCoordIdx.size()) throw DeadlyImportError("Normals and Coords inidces count must be equal.");
tind.reserve(pNormalIdx.size()); tind.reserve(pNormalIdx.size());
for(std::vector<int32_t>::const_iterator it = pNormalIdx.begin(); it != pNormalIdx.end(); it++) for(std::vector<int32_t>::const_iterator it = pNormalIdx.begin(); it != pNormalIdx.end(); ++it)
{ {
if(*it != (-1)) tind.push_back(*it); if(*it != (-1)) tind.push_back(*it);
} }
@ -1221,7 +1227,7 @@ void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::list<aiVector
// apply color to all vertices of face // apply color to all vertices of face
for(size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++) pMesh.mNormals[pMesh.mFaces[fi].mIndices[vi]] = *norm_it; for(size_t vi = 0, vi_e = pMesh.mFaces[fi].mNumIndices; vi < vi_e; vi++) pMesh.mNormals[pMesh.mFaces[fi].mIndices[vi]] = *norm_it;
norm_it++; ++norm_it;
} }
}// if(pNormalPerVertex) else }// if(pNormalPerVertex) else
} }
@ -1235,7 +1241,7 @@ void X3DImporter::MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::vector<int3
// copy list to array because we are need indexed access to normals. // copy list to array because we are need indexed access to normals.
texcoord_arr_copy.reserve(pTexCoords.size()); texcoord_arr_copy.reserve(pTexCoords.size());
for(std::list<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); it++) for(std::list<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it)
{ {
texcoord_arr_copy.push_back(aiVector3D((*it).x, (*it).y, 0)); texcoord_arr_copy.push_back(aiVector3D((*it).x, (*it).y, 0));
} }
@ -1285,7 +1291,7 @@ void X3DImporter::MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list<aiVect
// copy list to array because we are need convert aiVector2D to aiVector3D and also get indexed access as a bonus. // copy list to array because we are need convert aiVector2D to aiVector3D and also get indexed access as a bonus.
tc_arr_copy.reserve(pTexCoords.size()); tc_arr_copy.reserve(pTexCoords.size());
for ( std::list<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); it++ ) for ( std::list<aiVector2D>::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it )
{ {
tc_arr_copy.push_back( aiVector3D( ( *it ).x, ( *it ).y, 0 ) ); tc_arr_copy.push_back( aiVector3D( ( *it ).x, ( *it ).y, 0 ) );
} }
@ -1693,7 +1699,7 @@ void X3DImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
// create nodes tree // create nodes tree
Postprocess_BuildNode(*NodeElement_Cur, *pScene->mRootNode, mesh_list, mat_list, light_list); Postprocess_BuildNode(*NodeElement_Cur, *pScene->mRootNode, mesh_list, mat_list, light_list);
// copy needed data to scene // copy needed data to scene
if(mesh_list.size() > 0) if(!mesh_list.empty())
{ {
std::list<aiMesh*>::const_iterator it = mesh_list.begin(); std::list<aiMesh*>::const_iterator it = mesh_list.begin();
@ -1702,7 +1708,7 @@ void X3DImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
for(size_t i = 0; i < pScene->mNumMeshes; i++) pScene->mMeshes[i] = *it++; for(size_t i = 0; i < pScene->mNumMeshes; i++) pScene->mMeshes[i] = *it++;
} }
if(mat_list.size() > 0) if(!mat_list.empty())
{ {
std::list<aiMaterial*>::const_iterator it = mat_list.begin(); std::list<aiMaterial*>::const_iterator it = mat_list.begin();
@ -1711,7 +1717,7 @@ void X3DImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy
for(size_t i = 0; i < pScene->mNumMaterials; i++) pScene->mMaterials[i] = *it++; for(size_t i = 0; i < pScene->mNumMaterials; i++) pScene->mMaterials[i] = *it++;
} }
if(light_list.size() > 0) if(!light_list.empty())
{ {
std::list<aiLight*>::const_iterator it = light_list.begin(); std::list<aiLight*>::const_iterator it = light_list.begin();

View File

@ -356,7 +356,7 @@ void X3DImporter::ParseNode_Geometry2D_Polyline2D()
std::list<aiVector3D> tlist; std::list<aiVector3D> tlist;
// convert vec2 to vec3 // convert vec2 to vec3
for(std::list<aiVector2D>::iterator it2 = lineSegments.begin(); it2 != lineSegments.end(); it2++) tlist.push_back(aiVector3D(it2->x, it2->y, 0)); for(std::list<aiVector2D>::iterator it2 = lineSegments.begin(); it2 != lineSegments.end(); ++it2) tlist.push_back(aiVector3D(it2->x, it2->y, 0));
// convert point set to line set // convert point set to line set
GeometryHelper_Extend_PointToLine(tlist, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices); GeometryHelper_Extend_PointToLine(tlist, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices);
@ -399,7 +399,7 @@ void X3DImporter::ParseNode_Geometry2D_Polypoint2D()
if(!def.empty()) ne->ID = def; if(!def.empty()) ne->ID = def;
// convert vec2 to vec3 // convert vec2 to vec3
for(std::list<aiVector2D>::iterator it2 = point.begin(); it2 != point.end(); it2++) for(std::list<aiVector2D>::iterator it2 = point.begin(); it2 != point.end(); ++it2)
{ {
((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0)); ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0));
} }
@ -500,7 +500,7 @@ void X3DImporter::ParseNode_Geometry2D_TriangleSet2D()
if(!def.empty()) ne->ID = def; if(!def.empty()) ne->ID = def;
// convert vec2 to vec3 // convert vec2 to vec3
for(std::list<aiVector2D>::iterator it2 = vertices.begin(); it2 != vertices.end(); it2++) for(std::list<aiVector2D>::iterator it2 = vertices.begin(); it2 != vertices.end(); ++it2)
{ {
((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0)); ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0));
} }

View File

@ -153,11 +153,11 @@ void X3DImporter::ParseNode_Geometry3D_Cone()
{ {
StandardShapes::MakeCircle(bottomRadius, tess, tvec); StandardShapes::MakeCircle(bottomRadius, tess, tvec);
height = -(height / 2); height = -(height / 2);
for(std::vector<aiVector3D>::iterator it = tvec.begin(); it != tvec.end(); it++) it->y = height;// y - because circle made in oXZ. for(std::vector<aiVector3D>::iterator it = tvec.begin(); it != tvec.end(); ++it) it->y = height;// y - because circle made in oXZ.
} }
// copy data from temp array // copy data from temp array
for(std::vector<aiVector3D>::iterator it = tvec.begin(); it != tvec.end(); it++) ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices.push_back(*it); for(std::vector<aiVector3D>::iterator it = tvec.begin(); it != tvec.end(); ++it) ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices.push_back(*it);
((CX3DImporter_NodeElement_Geometry3D*)ne)->Solid = solid; ((CX3DImporter_NodeElement_Geometry3D*)ne)->Solid = solid;
((CX3DImporter_NodeElement_Geometry3D*)ne)->NumIndices = 3; ((CX3DImporter_NodeElement_Geometry3D*)ne)->NumIndices = 3;
@ -226,11 +226,11 @@ void X3DImporter::ParseNode_Geometry3D_Cylinder()
// copy data from temp arrays // copy data from temp arrays
std::list<aiVector3D>& vlist = ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices;// just short alias. std::list<aiVector3D>& vlist = ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices;// just short alias.
for(std::vector<aiVector3D>::iterator it = tside.begin(); it != tside.end(); it++) vlist.push_back(*it); for(std::vector<aiVector3D>::iterator it = tside.begin(); it != tside.end(); ++it) vlist.push_back(*it);
if(top) if(top)
{ {
for(std::vector<aiVector3D>::iterator it = tcir.begin(); it != tcir.end(); it++) for(std::vector<aiVector3D>::iterator it = tcir.begin(); it != tcir.end(); ++it)
{ {
(*it).y = height;// y - because circle made in oXZ. (*it).y = height;// y - because circle made in oXZ.
vlist.push_back(*it); vlist.push_back(*it);
@ -239,7 +239,7 @@ void X3DImporter::ParseNode_Geometry3D_Cylinder()
if(bottom) if(bottom)
{ {
for(std::vector<aiVector3D>::iterator it = tcir.begin(); it != tcir.end(); it++) for(std::vector<aiVector3D>::iterator it = tcir.begin(); it != tcir.end(); ++it)
{ {
(*it).y = -height;// y - because circle made in oXZ. (*it).y = -height;// y - because circle made in oXZ.
vlist.push_back(*it); vlist.push_back(*it);
@ -336,7 +336,7 @@ void X3DImporter::ParseNode_Geometry3D_ElevationGrid()
aiVector3D tvec(xSpacing * xi, *he_it, zSpacing * zi); aiVector3D tvec(xSpacing * xi, *he_it, zSpacing * zi);
grid_alias.Vertices.push_back(tvec); grid_alias.Vertices.push_back(tvec);
he_it++; ++he_it;
} }
} }
}// END: create grid vertices list }// END: create grid vertices list
@ -977,7 +977,7 @@ void X3DImporter::ParseNode_Geometry3D_Sphere()
StandardShapes::MakeSphere(tess, tlist); StandardShapes::MakeSphere(tess, tlist);
// copy data from temp array and apply scale // copy data from temp array and apply scale
for(std::vector<aiVector3D>::iterator it = tlist.begin(); it != tlist.end(); it++) for(std::vector<aiVector3D>::iterator it = tlist.begin(); it != tlist.end(); ++it)
{ {
((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices.push_back(*it * radius); ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices.push_back(*it * radius);
} }

View File

@ -93,7 +93,7 @@ void X3DImporter::ParseNode_Networking_Inline()
// at this place new group mode created and made current, so we can name it. // at this place new group mode created and made current, so we can name it.
if(!def.empty()) NodeElement_Cur->ID = def; if(!def.empty()) NodeElement_Cur->ID = def;
if(load && (url.size() > 0)) if(load && !url.empty())
{ {
std::string full_path = mpIOHandler->CurrentDirectory() + url.front(); std::string full_path = mpIOHandler->CurrentDirectory() + url.front();

View File

@ -81,7 +81,7 @@ aiMatrix4x4 X3DImporter::PostprocessHelper_Matrix_GlobalToCurrent() const
} }
// multiplicate all matrices in reverse order // multiplicate all matrices in reverse order
for(std::list<aiMatrix4x4>::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); rit++) out_matr = out_matr * (*rit); for(std::list<aiMatrix4x4>::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); ++rit) out_matr = out_matr * (*rit);
return out_matr; return out_matr;
} }
@ -89,7 +89,7 @@ aiMatrix4x4 X3DImporter::PostprocessHelper_Matrix_GlobalToCurrent() const
void X3DImporter::PostprocessHelper_CollectMetadata(const CX3DImporter_NodeElement& pNodeElement, std::list<CX3DImporter_NodeElement*>& pList) const void X3DImporter::PostprocessHelper_CollectMetadata(const CX3DImporter_NodeElement& pNodeElement, std::list<CX3DImporter_NodeElement*>& pList) const
{ {
// walk through childs and find for metadata. // walk through childs and find for metadata.
for(std::list<CX3DImporter_NodeElement*>::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); el_it++) for(std::list<CX3DImporter_NodeElement*>::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); ++el_it)
{ {
if(((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaBoolean) || ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaDouble) || if(((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaBoolean) || ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaDouble) ||
((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaFloat) || ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaInteger) || ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaFloat) || ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaInteger) ||
@ -194,7 +194,7 @@ void X3DImporter::Postprocess_BuildMaterial(const CX3DImporter_NodeElement& pNod
aiMaterial& taimat = **pMaterial;// creating alias for convenience. aiMaterial& taimat = **pMaterial;// creating alias for convenience.
// at this point pNodeElement point to <Appearance> node. Walk through childs and add all stored data. // at this point pNodeElement point to <Appearance> node. Walk through childs and add all stored data.
for(std::list<CX3DImporter_NodeElement*>::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); el_it++) for(std::list<CX3DImporter_NodeElement*>::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); ++el_it)
{ {
if((*el_it)->Type == CX3DImporter_NodeElement::ENET_Material) if((*el_it)->Type == CX3DImporter_NodeElement::ENET_Material)
{ {
@ -255,7 +255,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
std::vector<aiVector3D> tarr; std::vector<aiVector3D> tarr;
tarr.reserve(tnemesh.Vertices.size()); tarr.reserve(tnemesh.Vertices.size());
for(std::list<aiVector3D>::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); it++) tarr.push_back(*it); for(std::list<aiVector3D>::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); ++it) tarr.push_back(*it);
*pMesh = StandardShapes::MakeMesh(tarr, static_cast<unsigned int>(tnemesh.NumIndices));// create mesh from vertices using Assimp help. *pMesh = StandardShapes::MakeMesh(tarr, static_cast<unsigned int>(tnemesh.NumIndices));// create mesh from vertices using Assimp help.
return;// mesh is build, nothing to do anymore. return;// mesh is build, nothing to do anymore.
@ -273,7 +273,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
std::vector<aiVector3D> tarr; std::vector<aiVector3D> tarr;
tarr.reserve(tnemesh.Vertices.size()); tarr.reserve(tnemesh.Vertices.size());
for(std::list<aiVector3D>::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); it++) tarr.push_back(*it); for(std::list<aiVector3D>::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); ++it) tarr.push_back(*it);
*pMesh = StandardShapes::MakeMesh(tarr, static_cast<unsigned int>(tnemesh.NumIndices));// create mesh from vertices using Assimp help. *pMesh = StandardShapes::MakeMesh(tarr, static_cast<unsigned int>(tnemesh.NumIndices));// create mesh from vertices using Assimp help.
@ -289,7 +289,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
// at first create mesh from existing vertices. // at first create mesh from existing vertices.
*pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIdx, tnemesh.Vertices); *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIdx, tnemesh.Vertices);
// copy additional information from children // copy additional information from children
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex); MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex);
@ -301,7 +301,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
MeshGeometry_AddTexCoord(**pMesh, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); MeshGeometry_AddTexCoord(**pMesh, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value);
else else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of ElevationGrid: " + to_string((*ch_it)->Type) + "."); throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of ElevationGrid: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore. return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_ElevationGrid) }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_ElevationGrid)
@ -313,7 +313,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience
// at first search for <Coordinate> node and create mesh. // at first search for <Coordinate> node and create mesh.
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
{ {
@ -322,7 +322,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
} }
// copy additional information from children // copy additional information from children
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex); MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex);
@ -338,7 +338,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value);
else else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedFaceSet: " + to_string((*ch_it)->Type) + "."); throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedFaceSet: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore. return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedFaceSet) }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedFaceSet)
@ -348,7 +348,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience
// at first search for <Coordinate> node and create mesh. // at first search for <Coordinate> node and create mesh.
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
{ {
@ -357,7 +357,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
} }
// copy additional information from children // copy additional information from children
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
ai_assert(*pMesh); ai_assert(*pMesh);
if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
@ -369,7 +369,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
{} // skip because already read when mesh created. {} // skip because already read when mesh created.
else else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedLineSet: " + to_string((*ch_it)->Type) + "."); throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedLineSet: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore. return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedLineSet) }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedLineSet)
@ -381,7 +381,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience
// at first search for <Coordinate> node and create mesh. // at first search for <Coordinate> node and create mesh.
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
{ {
@ -390,7 +390,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
} }
// copy additional information from children // copy additional information from children
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
ai_assert(*pMesh); ai_assert(*pMesh);
if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
@ -408,7 +408,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
else else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedTriangleSet or IndexedTriangleFanSet, or \ throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedTriangleSet or IndexedTriangleFanSet, or \
IndexedTriangleStripSet: " + to_string((*ch_it)->Type) + "."); IndexedTriangleStripSet: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore. return;// mesh is build, nothing to do anymore.
}// if((pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleFanSet) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleStripSet)) }// if((pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleFanSet) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleStripSet))
@ -430,7 +430,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience
// at first search for <Coordinate> node and create mesh. // at first search for <Coordinate> node and create mesh.
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
{ {
@ -438,7 +438,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
vec_copy.reserve(((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.size()); vec_copy.reserve(((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.size());
for(std::list<aiVector3D>::const_iterator it = ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.begin(); for(std::list<aiVector3D>::const_iterator it = ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.begin();
it != ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.end(); it++) it != ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.end(); ++it)
{ {
vec_copy.push_back(*it); vec_copy.push_back(*it);
} }
@ -448,7 +448,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
} }
// copy additional information from children // copy additional information from children
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
ai_assert(*pMesh); ai_assert(*pMesh);
if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
@ -459,7 +459,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
{} // skip because already read when mesh created. {} // skip because already read when mesh created.
else else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of PointSet: " + to_string((*ch_it)->Type) + "."); throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of PointSet: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore. return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_PointSet) }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_PointSet)
@ -469,7 +469,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience
// at first search for <Coordinate> node and create mesh. // at first search for <Coordinate> node and create mesh.
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
{ {
@ -478,7 +478,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
} }
// copy additional information from children // copy additional information from children
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
ai_assert(*pMesh); ai_assert(*pMesh);
if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
@ -489,7 +489,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
{} // skip because already read when mesh created. {} // skip because already read when mesh created.
else else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of LineSet: " + to_string((*ch_it)->Type) + "."); throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of LineSet: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore. return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_LineSet) }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_LineSet)
@ -499,7 +499,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience
// at first search for <Coordinate> node and create mesh. // at first search for <Coordinate> node and create mesh.
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
{ {
@ -508,7 +508,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
} }
// copy additional information from children // copy additional information from children
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
if ( nullptr == *pMesh ) { if ( nullptr == *pMesh ) {
break; break;
@ -526,7 +526,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value);
else else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeFanSet: " + to_string((*ch_it)->Type) + "."); throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeFanSet: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore. return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleFanSet) }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleFanSet)
@ -536,7 +536,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience
// at first search for <Coordinate> node and create mesh. // at first search for <Coordinate> node and create mesh.
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
{ {
@ -544,7 +544,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
vec_copy.reserve(((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.size()); vec_copy.reserve(((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.size());
for(std::list<aiVector3D>::const_iterator it = ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.begin(); for(std::list<aiVector3D>::const_iterator it = ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.begin();
it != ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.end(); it++) it != ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.end(); ++it)
{ {
vec_copy.push_back(*it); vec_copy.push_back(*it);
} }
@ -554,7 +554,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
} }
// copy additional information from children // copy additional information from children
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
ai_assert(*pMesh); ai_assert(*pMesh);
if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
@ -570,7 +570,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value);
else else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeSet: " + to_string((*ch_it)->Type) + "."); throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeSet: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore. return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleSet) }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleSet)
@ -580,7 +580,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience
// at first search for <Coordinate> node and create mesh. // at first search for <Coordinate> node and create mesh.
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate)
{ {
@ -589,7 +589,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
} }
// copy additional information from children // copy additional information from children
for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
{ {
ai_assert(*pMesh); ai_assert(*pMesh);
if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color)
@ -605,7 +605,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle
MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value);
else else
throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TriangleStripSet: " + to_string((*ch_it)->Type) + "."); throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TriangleStripSet: " + to_string((*ch_it)->Type) + ".");
}// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) }// for(std::list<CX3DImporter_NodeElement*>::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it)
return;// mesh is build, nothing to do anymore. return;// mesh is build, nothing to do anymore.
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleStripSet) }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleStripSet)
@ -639,16 +639,16 @@ void X3DImporter::Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeEle
} }
else else
{ {
for(size_t i = 0; i < (size_t)tne_group.Choice; i++) chit_begin++;// forward iterator to chosen node. for(size_t i = 0; i < (size_t)tne_group.Choice; i++) ++chit_begin;// forward iterator to chosen node.
chit_end = chit_begin; chit_end = chit_begin;
chit_end++;// point end iterator to next element after chosen node. ++chit_end;// point end iterator to next element after chosen node.
} }
}// if(tne_group.UseChoice) }// if(tne_group.UseChoice)
}// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_Group) }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_Group)
// Reserve memory for fast access and check children. // Reserve memory for fast access and check children.
for(std::list<CX3DImporter_NodeElement*>::const_iterator it = chit_begin; it != chit_end; it++) for(std::list<CX3DImporter_NodeElement*>::const_iterator it = chit_begin; it != chit_end; ++it)
{// in this loop we do not read metadata because it's already read at begin. {// in this loop we do not read metadata because it's already read at begin.
if((*it)->Type == CX3DImporter_NodeElement::ENET_Group) if((*it)->Type == CX3DImporter_NodeElement::ENET_Group)
{ {
@ -677,7 +677,7 @@ void X3DImporter::Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeEle
}// for(std::list<CX3DImporter_NodeElement*>::const_iterator it = chit_begin; it != chit_end; it++) }// for(std::list<CX3DImporter_NodeElement*>::const_iterator it = chit_begin; it != chit_end; it++)
// copy data about children and meshes to aiNode. // copy data about children and meshes to aiNode.
if(SceneNode_Child.size() > 0) if(!SceneNode_Child.empty())
{ {
std::list<aiNode*>::const_iterator it = SceneNode_Child.begin(); std::list<aiNode*>::const_iterator it = SceneNode_Child.begin();
@ -686,7 +686,7 @@ void X3DImporter::Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeEle
for(size_t i = 0; i < pSceneNode.mNumChildren; i++) pSceneNode.mChildren[i] = *it++; for(size_t i = 0; i < pSceneNode.mNumChildren; i++) pSceneNode.mChildren[i] = *it++;
} }
if(SceneNode_Mesh.size() > 0) if(!SceneNode_Mesh.empty())
{ {
std::list<unsigned int>::const_iterator it = SceneNode_Mesh.begin(); std::list<unsigned int>::const_iterator it = SceneNode_Mesh.begin();
@ -706,7 +706,7 @@ void X3DImporter::Postprocess_BuildShape(const CX3DImporter_NodeElement_Shape& p
CX3DImporter_NodeElement::EType mesh_type = CX3DImporter_NodeElement::ENET_Invalid; CX3DImporter_NodeElement::EType mesh_type = CX3DImporter_NodeElement::ENET_Invalid;
unsigned int mat_ind = 0; unsigned int mat_ind = 0;
for(std::list<CX3DImporter_NodeElement*>::const_iterator it = pShapeNodeElement.Child.begin(); it != pShapeNodeElement.Child.end(); it++) for(std::list<CX3DImporter_NodeElement*>::const_iterator it = pShapeNodeElement.Child.begin(); it != pShapeNodeElement.Child.end(); ++it)
{ {
if(PostprocessHelper_ElementIsMesh((*it)->Type)) if(PostprocessHelper_ElementIsMesh((*it)->Type))
{ {
@ -779,7 +779,7 @@ void X3DImporter::Postprocess_CollectMetadata(const CX3DImporter_NodeElement& pN
// copy collected metadata to output node. // copy collected metadata to output node.
pSceneNode.mMetaData = aiMetadata::Alloc( static_cast<unsigned int>(meta_list.size()) ); pSceneNode.mMetaData = aiMetadata::Alloc( static_cast<unsigned int>(meta_list.size()) );
meta_idx = 0; meta_idx = 0;
for(std::list<CX3DImporter_NodeElement*>::const_iterator it = meta_list.begin(); it != meta_list.end(); it++, meta_idx++) for(std::list<CX3DImporter_NodeElement*>::const_iterator it = meta_list.begin(); it != meta_list.end(); ++it, ++meta_idx)
{ {
CX3DImporter_NodeElement_Meta* cur_meta = (CX3DImporter_NodeElement_Meta*)*it; CX3DImporter_NodeElement_Meta* cur_meta = (CX3DImporter_NodeElement_Meta*)*it;

View File

@ -295,7 +295,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleFanSet()
ne_alias.CoordIndex.clear(); ne_alias.CoordIndex.clear();
int counter = 0; int counter = 0;
int32_t idx[3]; int32_t idx[3];
for(std::vector<int32_t>::const_iterator idx_it = index.begin(); idx_it != index.end(); idx_it++) for(std::vector<int32_t>::const_iterator idx_it = index.begin(); idx_it != index.end(); ++idx_it)
{ {
idx[2] = *idx_it; idx[2] = *idx_it;
if (idx[2] < 0) if (idx[2] < 0)
@ -413,7 +413,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleSet()
ne_alias.CoordIndex.clear(); ne_alias.CoordIndex.clear();
int counter = 0; int counter = 0;
int32_t idx[3]; int32_t idx[3];
for(std::vector<int32_t>::const_iterator idx_it = index.begin(); idx_it != index.end(); idx_it++) for(std::vector<int32_t>::const_iterator idx_it = index.begin(); idx_it != index.end(); ++idx_it)
{ {
idx[counter++] = *idx_it; idx[counter++] = *idx_it;
if (counter > 2) if (counter > 2)
@ -519,7 +519,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleStripSet()
ne_alias.CoordIndex.clear(); ne_alias.CoordIndex.clear();
int counter = 0; int counter = 0;
int32_t idx[3]; int32_t idx[3];
for(std::vector<int32_t>::const_iterator idx_it = index.begin(); idx_it != index.end(); idx_it++) for(std::vector<int32_t>::const_iterator idx_it = index.begin(); idx_it != index.end(); ++idx_it)
{ {
idx[2] = *idx_it; idx[2] = *idx_it;
if (idx[2] < 0) if (idx[2] < 0)
@ -617,7 +617,7 @@ void X3DImporter::ParseNode_Rendering_LineSet()
size_t coord_num = 0; size_t coord_num = 0;
ne_alias.CoordIndex.clear(); ne_alias.CoordIndex.clear();
for(std::vector<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++) for(std::vector<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); ++vc_it)
{ {
if(*vc_it < 2) throw DeadlyImportError("LineSet. vertexCount shall be greater than or equal to two."); if(*vc_it < 2) throw DeadlyImportError("LineSet. vertexCount shall be greater than or equal to two.");
@ -765,7 +765,7 @@ void X3DImporter::ParseNode_Rendering_TriangleFanSet()
// assign indices for first triangle // assign indices for first triangle
coord_num_first = 0; coord_num_first = 0;
coord_num_prev = 1; coord_num_prev = 1;
for(std::vector<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++) for(std::vector<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); ++vc_it)
{ {
if(*vc_it < 3) throw DeadlyImportError("TriangleFanSet. fanCount shall be greater than or equal to three."); if(*vc_it < 3) throw DeadlyImportError("TriangleFanSet. fanCount shall be greater than or equal to three.");
@ -956,7 +956,7 @@ void X3DImporter::ParseNode_Rendering_TriangleStripSet()
ne_alias.CoordIndex.clear(); ne_alias.CoordIndex.clear();
coord_num_sb = 0; coord_num_sb = 0;
for(std::vector<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++) for(std::vector<int32_t>::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); ++vc_it)
{ {
if(*vc_it < 3) throw DeadlyImportError("TriangleStripSet. stripCount shall be greater than or equal to three."); if(*vc_it < 3) throw DeadlyImportError("TriangleStripSet. stripCount shall be greater than or equal to three.");

View File

@ -89,7 +89,7 @@ void X3DImporter::ParseNode_Texturing_ImageTexture()
((CX3DImporter_NodeElement_ImageTexture*)ne)->RepeatS = repeatS; ((CX3DImporter_NodeElement_ImageTexture*)ne)->RepeatS = repeatS;
((CX3DImporter_NodeElement_ImageTexture*)ne)->RepeatT = repeatT; ((CX3DImporter_NodeElement_ImageTexture*)ne)->RepeatT = repeatT;
// Attribute "url" can contain list of strings. But we need only one - first. // Attribute "url" can contain list of strings. But we need only one - first.
if(url.size() > 0) if(!url.empty())
((CX3DImporter_NodeElement_ImageTexture*)ne)->URL = url.front(); ((CX3DImporter_NodeElement_ImageTexture*)ne)->URL = url.front();
else else
((CX3DImporter_NodeElement_ImageTexture*)ne)->URL = ""; ((CX3DImporter_NodeElement_ImageTexture*)ne)->URL = "";

View File

@ -92,38 +92,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# endif # endif
#endif #endif
#include "glTF/glTFCommon.h"
namespace glTF namespace glTF
{ {
#ifdef ASSIMP_API using glTFCommon::shared_ptr;
using Assimp::IOStream; using glTFCommon::IOSystem;
using Assimp::IOSystem; using glTFCommon::IOStream;
using std::shared_ptr;
#else
using std::shared_ptr;
typedef std::runtime_error DeadlyImportError;
typedef std::runtime_error DeadlyExportError;
enum aiOrigin { aiOrigin_SET = 0, aiOrigin_CUR = 1, aiOrigin_END = 2 };
class IOSystem;
class IOStream
{
FILE* f;
public:
IOStream(FILE* file) : f(file) {}
~IOStream() { fclose(f); f = 0; }
size_t Read(void* b, size_t sz, size_t n) { return fread(b, sz, n, f); }
size_t Write(const void* b, size_t sz, size_t n) { return fwrite(b, sz, n, f); }
int Seek(size_t off, aiOrigin orig) { return fseek(f, off, int(orig)); }
size_t Tell() const { return ftell(f); }
size_t FileSize() {
long p = Tell(), len = (Seek(0, aiOrigin_END), Tell());
return size_t((Seek(p, aiOrigin_SET), len));
}
};
#endif
using rapidjson::Value; using rapidjson::Value;
using rapidjson::Document; using rapidjson::Document;
@ -136,37 +111,9 @@ namespace glTF
struct Light; struct Light;
struct Skin; struct Skin;
using glTFCommon::vec3;
// Vec/matrix types, as raw float arrays using glTFCommon::vec4;
typedef float (vec3)[3]; using glTFCommon::mat4;
typedef float (vec4)[4];
typedef float (mat4)[16];
namespace Util
{
void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out);
size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out);
inline size_t DecodeBase64(const char* in, uint8_t*& out)
{
return DecodeBase64(in, strlen(in), out);
}
struct DataURI
{
const char* mediaType;
const char* charset;
bool base64;
const char* data;
size_t dataLength;
};
//! Check if a uri is a data URI
inline bool ParseDataURI(const char* uri, size_t uriLen, DataURI& out);
}
//! Magic number for GLB files //! Magic number for GLB files
#define AI_GLB_MAGIC_NUMBER "glTF" #define AI_GLB_MAGIC_NUMBER "glTF"

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