Merge branch 'master' into fix_gltf_accessor_overflow
commit
36ca37f9ac
|
@ -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,6 +2,11 @@
|
||||||
build
|
build
|
||||||
.project
|
.project
|
||||||
*.kdev4*
|
*.kdev4*
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
# build artefacts
|
||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
|
||||||
# Visual Studio
|
# Visual Studio
|
||||||
*.sln
|
*.sln
|
||||||
|
|
28
Build.md
28
Build.md
|
@ -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
|
||||||
|
|
|
@ -253,7 +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 /DEBUG:FULL /Zi")
|
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}")
|
||||||
|
@ -391,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)
|
||||||
|
|
10
Readme.md
10
Readme.md
|
@ -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)
|
||||||
|
|
10
appveyor.yml
10
appveyor.yml
|
@ -14,8 +14,10 @@ matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
|
|
||||||
image:
|
image:
|
||||||
|
- Visual Studio 2013
|
||||||
- Visual Studio 2015
|
- Visual Studio 2015
|
||||||
- Visual Studio 2017
|
- Visual Studio 2017
|
||||||
|
- Visual Studio 2019
|
||||||
- MinGW
|
- MinGW
|
||||||
|
|
||||||
platform:
|
platform:
|
||||||
|
@ -28,11 +30,13 @@ 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 [%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 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
|
# 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"
|
- 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
|
||||||
|
|
|
@ -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)
|
||||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
|
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@")
|
||||||
|
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}"
|
||||||
|
|
|
@ -34,6 +34,8 @@ if(MSVC)
|
||||||
endif()
|
endif()
|
||||||
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@")
|
||||||
|
@ -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)
|
||||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
|
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@")
|
||||||
|
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 )
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -78,4 +82,4 @@ else(WIN32)
|
||||||
endif (assimp_FIND_REQUIRED)
|
endif (assimp_FIND_REQUIRED)
|
||||||
endif (assimp_FOUND)
|
endif (assimp_FOUND)
|
||||||
|
|
||||||
endif(WIN32)
|
endif(WIN32)
|
||||||
|
|
|
@ -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 ) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -137,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
|
||||||
)
|
)
|
||||||
|
@ -408,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
|
||||||
|
@ -671,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
|
||||||
)
|
)
|
||||||
|
@ -1059,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}
|
||||||
|
|
|
@ -92,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)
|
||||||
|
@ -146,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();
|
||||||
|
@ -356,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();
|
||||||
|
@ -412,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();
|
||||||
|
@ -586,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>";
|
||||||
|
|
||||||
|
@ -619,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;
|
||||||
|
@ -633,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();
|
||||||
|
@ -699,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";
|
||||||
|
@ -768,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();
|
||||||
|
@ -819,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;
|
||||||
}
|
}
|
||||||
|
@ -850,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;
|
||||||
|
@ -886,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;
|
||||||
|
|
||||||
|
@ -1021,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;
|
||||||
|
@ -1059,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;
|
||||||
|
|
||||||
|
@ -1079,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>";
|
||||||
|
@ -1113,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>";
|
||||||
|
@ -1173,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 )
|
||||||
|
@ -1265,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
|
||||||
|
@ -1300,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();
|
||||||
|
@ -1372,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] << " ";
|
||||||
}
|
}
|
||||||
|
@ -1387,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;
|
||||||
|
@ -1409,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;
|
||||||
|
@ -1426,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1437,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();
|
||||||
|
@ -1546,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();
|
||||||
|
@ -1594,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1615,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();
|
||||||
|
|
||||||
|
@ -1631,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;
|
||||||
}
|
}
|
||||||
|
@ -1639,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 )
|
||||||
{
|
{
|
||||||
|
|
|
@ -583,7 +583,7 @@ struct Image
|
||||||
/** Embedded image data */
|
/** Embedded image data */
|
||||||
std::vector<uint8_t> mImageData;
|
std::vector<uint8_t> mImageData;
|
||||||
|
|
||||||
/** File format hint ofembedded image data */
|
/** File format hint of embedded image data */
|
||||||
std::string mEmbeddedFormat;
|
std::string mEmbeddedFormat;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1735,6 +1735,7 @@ void ColladaLoader::BuildMaterials(ColladaParser& pParser, aiScene* /*pScene*/)
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Resolves the texture name for the given effect texture entry
|
// Resolves the texture name for the given effect texture entry
|
||||||
|
// and loads the texture data
|
||||||
aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParser,
|
aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParser,
|
||||||
const Collada::Effect& pEffect, const std::string& pName)
|
const Collada::Effect& pEffect, const std::string& pName)
|
||||||
{
|
{
|
||||||
|
@ -1762,7 +1763,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse
|
||||||
|
|
||||||
//set default texture file name
|
//set default texture file name
|
||||||
result.Set(name + ".jpg");
|
result.Set(name + ".jpg");
|
||||||
ConvertPath(result);
|
ColladaParser::UriDecodePath(result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1781,7 +1782,7 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse
|
||||||
|
|
||||||
|
|
||||||
// setup format hint
|
// setup format hint
|
||||||
if (imIt->second.mEmbeddedFormat.length() > 3) {
|
if (imIt->second.mEmbeddedFormat.length() >= HINTMAXTEXTURELEN) {
|
||||||
ASSIMP_LOG_WARN("Collada: texture format hint is too long, truncating to 3 characters");
|
ASSIMP_LOG_WARN("Collada: texture format hint is too long, truncating to 3 characters");
|
||||||
}
|
}
|
||||||
strncpy(tex->achFormatHint, imIt->second.mEmbeddedFormat.c_str(), 3);
|
strncpy(tex->achFormatHint, imIt->second.mEmbeddedFormat.c_str(), 3);
|
||||||
|
@ -1802,61 +1803,10 @@ aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParse
|
||||||
}
|
}
|
||||||
|
|
||||||
result.Set(imIt->second.mFileName);
|
result.Set(imIt->second.mFileName);
|
||||||
ConvertPath(result);
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
|
||||||
// Convert a path read from a collada file to the usual representation
|
|
||||||
void ColladaLoader::ConvertPath(aiString& ss)
|
|
||||||
{
|
|
||||||
// TODO: collada spec, p 22. Handle URI correctly.
|
|
||||||
// For the moment we're just stripping the file:// away to make it work.
|
|
||||||
// Windows doesn't seem to be able to find stuff like
|
|
||||||
// 'file://..\LWO\LWO2\MappingModes\earthSpherical.jpg'
|
|
||||||
if (0 == strncmp(ss.data, "file://", 7))
|
|
||||||
{
|
|
||||||
ss.length -= 7;
|
|
||||||
memmove(ss.data, ss.data + 7, ss.length);
|
|
||||||
ss.data[ss.length] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes...
|
|
||||||
// I need to filter it without destroying linux paths starting with "/somewhere"
|
|
||||||
#if defined( _MSC_VER )
|
|
||||||
if (ss.data[0] == '/' && isalpha((unsigned char)ss.data[1]) && ss.data[2] == ':') {
|
|
||||||
#else
|
|
||||||
if (ss.data[0] == '/' && isalpha(ss.data[1]) && ss.data[2] == ':') {
|
|
||||||
#endif
|
|
||||||
--ss.length;
|
|
||||||
::memmove(ss.data, ss.data + 1, ss.length);
|
|
||||||
ss.data[ss.length] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find and convert all %xy special chars
|
|
||||||
char* out = ss.data;
|
|
||||||
for (const char* it = ss.data; it != ss.data + ss.length; /**/)
|
|
||||||
{
|
|
||||||
if (*it == '%' && (it + 3) < ss.data + ss.length)
|
|
||||||
{
|
|
||||||
// separate the number to avoid dragging in chars from behind into the parsing
|
|
||||||
char mychar[3] = { it[1], it[2], 0 };
|
|
||||||
size_t nbr = strtoul16(mychar);
|
|
||||||
it += 3;
|
|
||||||
*out++ = (char)(nbr & 0xFF);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*out++ = *it++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// adjust length and terminator of the shortened string
|
|
||||||
*out = 0;
|
|
||||||
ss.length = (ptrdiff_t)(out - ss.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Reads a float value from an accessor and its data array.
|
// Reads a float value from an accessor and its data array.
|
||||||
ai_real ColladaLoader::ReadFloat(const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex, size_t pOffset) const
|
ai_real ColladaLoader::ReadFloat(const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex, size_t pOffset) const
|
||||||
|
|
|
@ -94,7 +94,7 @@ 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 override;
|
bool CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Return importer meta information.
|
/** Return importer meta information.
|
||||||
|
@ -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
|
||||||
|
|
|
@ -183,13 +183,67 @@ std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) {
|
||||||
if (filepath == nullptr)
|
if (filepath == nullptr)
|
||||||
return std::string();
|
return std::string();
|
||||||
|
|
||||||
return std::string(filepath);
|
aiString ai_str(filepath);
|
||||||
|
UriDecodePath(ai_str);
|
||||||
|
|
||||||
|
return std::string(ai_str.C_Str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return std::string();
|
return std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
// Convert a path read from a collada file to the usual representation
|
||||||
|
void ColladaParser::UriDecodePath(aiString& ss)
|
||||||
|
{
|
||||||
|
// TODO: collada spec, p 22. Handle URI correctly.
|
||||||
|
// For the moment we're just stripping the file:// away to make it work.
|
||||||
|
// Windows doesn't seem to be able to find stuff like
|
||||||
|
// 'file://..\LWO\LWO2\MappingModes\earthSpherical.jpg'
|
||||||
|
if (0 == strncmp(ss.data, "file://", 7))
|
||||||
|
{
|
||||||
|
ss.length -= 7;
|
||||||
|
memmove(ss.data, ss.data + 7, ss.length);
|
||||||
|
ss.data[ss.length] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes...
|
||||||
|
// I need to filter it without destroying linux paths starting with "/somewhere"
|
||||||
|
#if defined( _MSC_VER )
|
||||||
|
if (ss.data[0] == '/' && isalpha((unsigned char)ss.data[1]) && ss.data[2] == ':') {
|
||||||
|
#else
|
||||||
|
if (ss.data[0] == '/' && isalpha(ss.data[1]) && ss.data[2] == ':') {
|
||||||
|
#endif
|
||||||
|
--ss.length;
|
||||||
|
::memmove(ss.data, ss.data + 1, ss.length);
|
||||||
|
ss.data[ss.length] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find and convert all %xy special chars
|
||||||
|
char* out = ss.data;
|
||||||
|
for (const char* it = ss.data; it != ss.data + ss.length; /**/)
|
||||||
|
{
|
||||||
|
if (*it == '%' && (it + 3) < ss.data + ss.length)
|
||||||
|
{
|
||||||
|
// separate the number to avoid dragging in chars from behind into the parsing
|
||||||
|
char mychar[3] = { it[1], it[2], 0 };
|
||||||
|
size_t nbr = strtoul16(mychar);
|
||||||
|
it += 3;
|
||||||
|
*out++ = (char)(nbr & 0xFF);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*out++ = *it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// adjust length and terminator of the shortened string
|
||||||
|
*out = 0;
|
||||||
|
ai_assert(out > ss.data);
|
||||||
|
ss.length = static_cast<ai_uint32>(out - ss.data);
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// Read bool from text contents of current element
|
// Read bool from text contents of current element
|
||||||
bool ColladaParser::ReadBoolFromTextContent()
|
bool ColladaParser::ReadBoolFromTextContent()
|
||||||
|
@ -1120,7 +1174,12 @@ void ColladaParser::ReadImage(Collada::Image& pImage)
|
||||||
if (!mReader->isEmptyElement()) {
|
if (!mReader->isEmptyElement()) {
|
||||||
// element content is filename - hopefully
|
// element content is filename - hopefully
|
||||||
const char* sz = TestTextContent();
|
const char* sz = TestTextContent();
|
||||||
if (sz)pImage.mFileName = sz;
|
if (sz)
|
||||||
|
{
|
||||||
|
aiString filepath(sz);
|
||||||
|
UriDecodePath(filepath);
|
||||||
|
pImage.mFileName = filepath.C_Str();
|
||||||
|
}
|
||||||
TestClosing("init_from");
|
TestClosing("init_from");
|
||||||
}
|
}
|
||||||
if (!pImage.mFileName.length()) {
|
if (!pImage.mFileName.length()) {
|
||||||
|
@ -1153,7 +1212,12 @@ void ColladaParser::ReadImage(Collada::Image& pImage)
|
||||||
{
|
{
|
||||||
// element content is filename - hopefully
|
// element content is filename - hopefully
|
||||||
const char* sz = TestTextContent();
|
const char* sz = TestTextContent();
|
||||||
if (sz)pImage.mFileName = sz;
|
if (sz)
|
||||||
|
{
|
||||||
|
aiString filepath(sz);
|
||||||
|
UriDecodePath(filepath);
|
||||||
|
pImage.mFileName = filepath.C_Str();
|
||||||
|
}
|
||||||
TestClosing("ref");
|
TestClosing("ref");
|
||||||
}
|
}
|
||||||
else if (IsElement("hex") && !pImage.mFileName.length())
|
else if (IsElement("hex") && !pImage.mFileName.length())
|
||||||
|
@ -3056,7 +3120,7 @@ void ColladaParser::ReadMaterialVertexInputBinding(Collada::SemanticMappingTable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Assimp::ColladaParser::ReadEmbeddedTextures(ZipArchiveIOSystem& zip_archive)
|
void ColladaParser::ReadEmbeddedTextures(ZipArchiveIOSystem& zip_archive)
|
||||||
{
|
{
|
||||||
// Attempt to load any undefined Collada::Image in ImageLibrary
|
// Attempt to load any undefined Collada::Image in ImageLibrary
|
||||||
for (ImageLibrary::iterator it = mImageLibrary.begin(); it != mImageLibrary.end(); ++it) {
|
for (ImageLibrary::iterator it = mImageLibrary.begin(); it != mImageLibrary.end(); ++it) {
|
||||||
|
|
|
@ -66,12 +66,15 @@ 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();
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
|
|
|
@ -107,7 +107,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams,
|
||||||
return nullptr;
|
return nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Platform-independent default streams
|
// Platform-independent default streams
|
||||||
case aiDefaultLogStream_STDERR:
|
case aiDefaultLogStream_STDERR:
|
||||||
return new StdOStreamLogStream(std::cerr);
|
return new StdOStreamLogStream(std::cerr);
|
||||||
case aiDefaultLogStream_STDOUT:
|
case aiDefaultLogStream_STDOUT:
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
|
|
|
@ -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 File", "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", "Assimp XML 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( "assjson", "Assimp JSON Document", "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,24 +247,28 @@ Exporter :: Exporter()
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
Exporter::~Exporter() {
|
Exporter::~Exporter() {
|
||||||
FreeBlob();
|
ai_assert(nullptr != pimpl);
|
||||||
|
FreeBlob();
|
||||||
delete pimpl;
|
delete pimpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
void Exporter::SetIOHandler( IOSystem* pIOHandler) {
|
void Exporter::SetIOHandler( IOSystem* pIOHandler) {
|
||||||
pimpl->mIsDefaultIOHandler = !pIOHandler;
|
ai_assert(nullptr != pimpl);
|
||||||
|
pimpl->mIsDefaultIOHandler = !pIOHandler;
|
||||||
pimpl->mIOSystem.reset(pIOHandler);
|
pimpl->mIOSystem.reset(pIOHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
IOSystem* Exporter::GetIOHandler() const {
|
IOSystem* Exporter::GetIOHandler() const {
|
||||||
return pimpl->mIOSystem.get();
|
ai_assert(nullptr != pimpl);
|
||||||
|
return pimpl->mIOSystem.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
bool Exporter::IsDefaultIOHandler() const {
|
bool Exporter::IsDefaultIOHandler() const {
|
||||||
return pimpl->mIsDefaultIOHandler;
|
ai_assert(nullptr != pimpl);
|
||||||
|
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;
|
||||||
|
@ -319,7 +319,7 @@ const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const cha
|
||||||
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
|
||||||
|
@ -466,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;
|
||||||
|
|
||||||
|
@ -479,30 +481,34 @@ void Exporter::FreeBlob() {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
const aiExportDataBlob* Exporter::GetBlob() const {
|
const aiExportDataBlob* Exporter::GetBlob() const {
|
||||||
return pimpl->blob;
|
ai_assert(nullptr != pimpl);
|
||||||
|
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 {
|
||||||
if (index >= GetExportFormatCount()) {
|
ai_assert(nullptr != pimpl);
|
||||||
|
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;
|
||||||
|
@ -510,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;
|
||||||
}
|
}
|
||||||
|
@ -522,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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -1196,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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -1215,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 ) {
|
||||||
|
|
|
@ -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"
|
||||||
;
|
;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
@ -70,13 +69,13 @@ ASSIMP_API const char* aiGetLegalString () {
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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 +103,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;
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <iostream>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
namespace FBX {
|
namespace FBX {
|
||||||
|
@ -77,7 +78,7 @@ 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 )
|
FBXConverter::FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones )
|
||||||
: defaultMaterialIndex()
|
: defaultMaterialIndex()
|
||||||
|
@ -96,6 +97,14 @@ namespace Assimp {
|
||||||
// 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) {
|
||||||
|
@ -145,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)
|
||||||
|
@ -179,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;
|
||||||
|
@ -191,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
|
||||||
|
@ -258,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;
|
||||||
|
@ -280,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());
|
||||||
|
@ -297,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;
|
||||||
|
@ -803,7 +828,7 @@ 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) == ((chainBits & chainMaskComplex) != 0));
|
//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
|
||||||
|
@ -905,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();
|
||||||
|
|
||||||
|
@ -917,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 {
|
||||||
|
@ -930,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;
|
||||||
|
|
||||||
|
@ -962,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;
|
||||||
|
|
||||||
|
@ -984,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
|
||||||
|
@ -1019,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);
|
||||||
|
@ -1036,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();
|
||||||
|
@ -1113,7 +1142,7 @@ namespace Assimp {
|
||||||
binormals = &tempBinormals;
|
binormals = &tempBinormals;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
binormals = NULL;
|
binormals = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1163,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;
|
||||||
|
@ -1209,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());
|
||||||
|
@ -1221,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1229,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;
|
||||||
|
@ -1300,7 +1332,7 @@ namespace Assimp {
|
||||||
binormals = &tempBinormals;
|
binormals = &tempBinormals;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
binormals = NULL;
|
binormals = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1399,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;
|
||||||
|
@ -1449,10 +1481,10 @@ namespace Assimp {
|
||||||
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());
|
||||||
|
|
||||||
|
@ -1463,13 +1495,12 @@ 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);
|
||||||
|
|
||||||
|
@ -1483,15 +1514,16 @@ namespace Assimp {
|
||||||
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);
|
||||||
|
@ -1520,68 +1552,107 @@ 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.
|
||||||
ConvertCluster(bones, model, *cluster, out_indices, index_out_indices,
|
ConvertCluster(bones, cluster, out_indices, index_out_indices,
|
||||||
count_out_indices, node_global_transform);
|
count_out_indices, absolute_transform, parent, root_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bone_map.clear();
|
||||||
}
|
}
|
||||||
catch (std::exception&) {
|
catch (std::exception&e) {
|
||||||
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->mNumBones = static_cast<unsigned int>(bones.size());
|
||||||
|
|
||||||
|
std::swap_ranges(bones.begin(), bones.end(), out->mBones);
|
||||||
}
|
}
|
||||||
|
|
||||||
out->mBones = new aiBone*[bones.size()]();
|
|
||||||
out->mNumBones = static_cast<unsigned int>(bones.size());
|
|
||||||
|
|
||||||
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)) {
|
||||||
bone->mOffsetMatrix.Inverse();
|
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;
|
||||||
|
|
||||||
bone->mOffsetMatrix = bone->mOffsetMatrix * node_global_transform;
|
// store local transform link for post processing
|
||||||
|
bone->mOffsetMatrix = cl->TransformLink();
|
||||||
|
bone->mOffsetMatrix.Inverse();
|
||||||
|
|
||||||
bone->mNumWeights = static_cast<unsigned int>(out_indices.size());
|
aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform;
|
||||||
aiVertexWeight* cursor = bone->mWeights = new aiVertexWeight[out_indices.size()];
|
|
||||||
|
|
||||||
const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
|
bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset
|
||||||
const WeightArray& weights = cl.GetWeights();
|
|
||||||
|
|
||||||
const size_t c = index_out_indices.size();
|
|
||||||
for (size_t i = 0; i < c; ++i) {
|
|
||||||
const size_t index_index = index_out_indices[i];
|
|
||||||
|
|
||||||
if (index_index == no_index_sentinel) {
|
//
|
||||||
continue;
|
// Now calculate the aiVertexWeights
|
||||||
|
//
|
||||||
|
|
||||||
|
aiVertexWeight *cursor = nullptr;
|
||||||
|
|
||||||
|
bone->mNumWeights = static_cast<unsigned int>(out_indices.size());
|
||||||
|
cursor = bone->mWeights = new aiVertexWeight[out_indices.size()];
|
||||||
|
|
||||||
|
const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
|
||||||
|
const WeightArray& weights = cl->GetWeights();
|
||||||
|
|
||||||
|
const size_t c = index_out_indices.size();
|
||||||
|
for (size_t i = 0; i < c; ++i) {
|
||||||
|
const size_t index_index = index_out_indices[i];
|
||||||
|
|
||||||
|
if (index_index == no_index_sentinel) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t cc = count_out_indices[i];
|
||||||
|
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++;
|
||||||
|
|
||||||
|
out_weight.mVertexId = static_cast<unsigned int>(out_indices[index_index + j]);
|
||||||
|
out_weight.mWeight = weights[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t cc = count_out_indices[i];
|
bone_map.insert(std::pair<const std::string, aiBone *>(deformer_name, bone));
|
||||||
for (size_t j = 0; j < cc; ++j) {
|
|
||||||
aiVertexWeight& out_weight = *cursor++;
|
|
||||||
|
|
||||||
out_weight.mVertexId = static_cast<unsigned int>(out_indices[index_index + j]);
|
|
||||||
out_weight.mWeight = weights[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
@ -1711,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;
|
||||||
|
@ -1719,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2243,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)
|
||||||
|
@ -2677,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();
|
||||||
|
@ -2708,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);
|
||||||
|
|
||||||
|
@ -3556,7 +3627,7 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
||||||
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.
|
||||||
|
|
||||||
|
@ -3603,6 +3674,47 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FBXConverter::ConvertOrphantEmbeddedTextures()
|
||||||
|
{
|
||||||
|
// 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)
|
void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones)
|
||||||
{
|
{
|
||||||
|
|
|
@ -123,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 );
|
||||||
|
@ -179,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() */
|
||||||
|
@ -217,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,
|
||||||
|
@ -424,6 +427,10 @@ private:
|
||||||
// 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;
|
||||||
|
@ -435,27 +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;
|
||||||
|
|
||||||
|
static void BuildBoneList(aiNode *current_node, const aiNode *root_node, const aiScene *scene,
|
||||||
|
std::vector<aiBone*>& bones);
|
||||||
|
|
||||||
|
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);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,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.
|
||||||
|
@ -1289,7 +1289,7 @@ void FBXExporter::WriteObjects ()
|
||||||
|
|
||||||
for(unsigned int lr = 1; lr < m->GetNumUVChannels(); ++ lr)
|
for(unsigned int lr = 1; lr < m->GetNumUVChannels(); ++ lr)
|
||||||
{
|
{
|
||||||
FBX::Node layerExtra("Layer", int32_t(1));
|
FBX::Node layerExtra("Layer", int32_t(lr));
|
||||||
layerExtra.AddChild("Version", int32_t(100));
|
layerExtra.AddChild("Version", int32_t(100));
|
||||||
FBX::Node leExtra("LayerElement");
|
FBX::Node leExtra("LayerElement");
|
||||||
leExtra.AddChild("Type", "LayerElementUV");
|
leExtra.AddChild("Type", "LayerElementUV");
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -76,131 +76,123 @@ using namespace Assimp::FBX;
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
static const aiImporterDesc desc = {
|
static const aiImporterDesc desc = {
|
||||||
"Autodesk FBX Importer",
|
"Autodesk FBX Importer",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
"",
|
"",
|
||||||
aiImporterFlags_SupportTextFlavour,
|
aiImporterFlags_SupportTextFlavour,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
"fbx"
|
"fbx"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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);
|
settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
|
||||||
settings.readTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_TEXTURES, true);
|
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
||||||
settings.readCameras = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_CAMERAS, true);
|
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
||||||
settings.readLights = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_LIGHTS, true);
|
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
||||||
settings.readAnimations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ANIMATIONS, true);
|
settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
|
||||||
settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false);
|
settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
|
||||||
settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true);
|
settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
|
||||||
settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true);
|
settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
|
||||||
settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false);
|
settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
|
||||||
settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true);
|
settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
|
||||||
settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------------------
|
||||||
// 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");
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// read entire file into memory - no streaming for this, fbx
|
// read entire file into memory - no streaming for this, fbx
|
||||||
// files can grow large, but the assimp output data structure
|
// files can grow large, but the assimp output data structure
|
||||||
// then becomes very large, too. Assimp doesn't support
|
// then becomes very large, too. Assimp doesn't support
|
||||||
// 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)
|
||||||
TokenList tokens;
|
TokenList tokens;
|
||||||
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
|
||||||
// parse-tree representing the FBX scope structure
|
// parse-tree representing the FBX scope structure
|
||||||
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);
|
||||||
|
|
||||||
// convert the FBX DOM to aiScene
|
// convert the FBX DOM to aiScene
|
||||||
ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones);
|
ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones);
|
||||||
|
|
||||||
// size relative to cm
|
// size relative to cm
|
||||||
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
|
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
|
||||||
|
|
||||||
// Set FBX file scale is relative to CM must be converted to M for
|
// Set FBX file scale is relative to CM must be converted to M for
|
||||||
// assimp universal format (M)
|
// assimp universal format (M)
|
||||||
SetFileScale( size_relative_to_cm * 0.01f);
|
SetFileScale(size_relative_to_cm * 0.01f);
|
||||||
|
|
||||||
std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
|
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
|
||||||
}
|
} catch (std::exception &) {
|
||||||
catch(std::exception&) {
|
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
|
||||||
std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
|
throw;
|
||||||
throw;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // !ASSIMP_BUILD_NO_FBX_IMPORTER
|
#endif // !ASSIMP_BUILD_NO_FBX_IMPORTER
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -52,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>
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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
|
|
@ -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_
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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*/
|
||||||
|
|
|
@ -1427,9 +1427,6 @@ inline void Asset::ReadExtensionsUsed(Document& doc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_EXT(EXT) \
|
|
||||||
if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
|
|
||||||
|
|
||||||
CHECK_EXT(KHR_binary_glTF);
|
CHECK_EXT(KHR_binary_glTF);
|
||||||
CHECK_EXT(KHR_materials_common);
|
CHECK_EXT(KHR_materials_common);
|
||||||
|
|
||||||
|
|
|
@ -188,7 +188,7 @@ namespace glTFCommon {
|
||||||
size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out);
|
size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out);
|
||||||
|
|
||||||
inline
|
inline
|
||||||
size_t DecodeBase64(const char* in, uint8_t*& out) {
|
size_t DecodeBase64(const char* in, uint8_t*& out) {
|
||||||
return DecodeBase64(in, strlen(in), out);
|
return DecodeBase64(in, strlen(in), out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,25 +221,22 @@ namespace glTFCommon {
|
||||||
};
|
};
|
||||||
|
|
||||||
inline
|
inline
|
||||||
char EncodeCharBase64(uint8_t b) {
|
char EncodeCharBase64(uint8_t b) {
|
||||||
return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="[size_t(b)];
|
return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="[size_t(b)];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
uint8_t DecodeCharBase64(char c) {
|
uint8_t DecodeCharBase64(char c) {
|
||||||
return DATA<true>::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs?
|
return DATA<true>::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs?
|
||||||
/*if (c >= 'A' && c <= 'Z') return c - 'A';
|
|
||||||
if (c >= 'a' && c <= 'z') return c - 'a' + 26;
|
|
||||||
if (c >= '0' && c <= '9') return c - '0' + 52;
|
|
||||||
if (c == '+') return 62;
|
|
||||||
if (c == '/') return 63;
|
|
||||||
return 64; // '-' */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out);
|
size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out);
|
||||||
|
|
||||||
void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out);
|
void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out);
|
||||||
}
|
} // namespace Util
|
||||||
|
|
||||||
|
#define CHECK_EXT(EXT) \
|
||||||
|
if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -170,6 +170,8 @@ void glTFImporter::ImportMaterials(glTF::Asset& r) {
|
||||||
|
|
||||||
if (mScene->mNumMaterials == 0) {
|
if (mScene->mNumMaterials == 0) {
|
||||||
mScene->mNumMaterials = 1;
|
mScene->mNumMaterials = 1;
|
||||||
|
// Delete the array of length zero created above.
|
||||||
|
delete[] mScene->mMaterials;
|
||||||
mScene->mMaterials = new aiMaterial*[1];
|
mScene->mMaterials = new aiMaterial*[1];
|
||||||
mScene->mMaterials[0] = new aiMaterial();
|
mScene->mMaterials[0] = new aiMaterial();
|
||||||
}
|
}
|
||||||
|
@ -330,6 +332,10 @@ void glTFImporter::ImportMeshes(glTF::Asset& r)
|
||||||
|
|
||||||
case PrimitiveMode_LINES: {
|
case PrimitiveMode_LINES: {
|
||||||
nFaces = count / 2;
|
nFaces = count / 2;
|
||||||
|
if (nFaces * 2 != count) {
|
||||||
|
ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
|
||||||
|
count = nFaces * 2;
|
||||||
|
}
|
||||||
faces = new aiFace[nFaces];
|
faces = new aiFace[nFaces];
|
||||||
for (unsigned int i = 0; i < count; i += 2) {
|
for (unsigned int i = 0; i < count; i += 2) {
|
||||||
SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1));
|
SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1));
|
||||||
|
@ -353,6 +359,10 @@ void glTFImporter::ImportMeshes(glTF::Asset& r)
|
||||||
|
|
||||||
case PrimitiveMode_TRIANGLES: {
|
case PrimitiveMode_TRIANGLES: {
|
||||||
nFaces = count / 3;
|
nFaces = count / 3;
|
||||||
|
if (nFaces * 3 != count) {
|
||||||
|
ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
|
||||||
|
count = nFaces * 3;
|
||||||
|
}
|
||||||
faces = new aiFace[nFaces];
|
faces = new aiFace[nFaces];
|
||||||
for (unsigned int i = 0; i < count; i += 3) {
|
for (unsigned int i = 0; i < count; i += 3) {
|
||||||
SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
|
SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2));
|
||||||
|
@ -395,6 +405,10 @@ void glTFImporter::ImportMeshes(glTF::Asset& r)
|
||||||
|
|
||||||
case PrimitiveMode_LINES: {
|
case PrimitiveMode_LINES: {
|
||||||
nFaces = count / 2;
|
nFaces = count / 2;
|
||||||
|
if (nFaces * 2 != count) {
|
||||||
|
ASSIMP_LOG_WARN("The number of vertices was not compatible with the LINES mode. Some vertices were dropped.");
|
||||||
|
count = nFaces * 2;
|
||||||
|
}
|
||||||
faces = new aiFace[nFaces];
|
faces = new aiFace[nFaces];
|
||||||
for (unsigned int i = 0; i < count; i += 2) {
|
for (unsigned int i = 0; i < count; i += 2) {
|
||||||
SetFace(faces[i / 2], i, i + 1);
|
SetFace(faces[i / 2], i, i + 1);
|
||||||
|
@ -418,6 +432,10 @@ void glTFImporter::ImportMeshes(glTF::Asset& r)
|
||||||
|
|
||||||
case PrimitiveMode_TRIANGLES: {
|
case PrimitiveMode_TRIANGLES: {
|
||||||
nFaces = count / 3;
|
nFaces = count / 3;
|
||||||
|
if (nFaces * 3 != count) {
|
||||||
|
ASSIMP_LOG_WARN("The number of vertices was not compatible with the TRIANGLES mode. Some vertices were dropped.");
|
||||||
|
count = nFaces * 3;
|
||||||
|
}
|
||||||
faces = new aiFace[nFaces];
|
faces = new aiFace[nFaces];
|
||||||
for (unsigned int i = 0; i < count; i += 3) {
|
for (unsigned int i = 0; i < count; i += 3) {
|
||||||
SetFace(faces[i / 3], i, i + 1, i + 2);
|
SetFace(faces[i / 3], i, i + 1, i + 2);
|
||||||
|
|
|
@ -685,6 +685,13 @@ namespace glTF2
|
||||||
Ref<Texture> texture;
|
Ref<Texture> texture;
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
unsigned int texCoord = 0;
|
unsigned int texCoord = 0;
|
||||||
|
|
||||||
|
bool textureTransformSupported = false;
|
||||||
|
struct TextureTransformExt {
|
||||||
|
float offset[2];
|
||||||
|
float rotation;
|
||||||
|
float scale[2];
|
||||||
|
} TextureTransformExt_t;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NormalTextureInfo : TextureInfo
|
struct NormalTextureInfo : TextureInfo
|
||||||
|
@ -1024,7 +1031,7 @@ namespace glTF2
|
||||||
bool KHR_materials_pbrSpecularGlossiness;
|
bool KHR_materials_pbrSpecularGlossiness;
|
||||||
bool KHR_materials_unlit;
|
bool KHR_materials_unlit;
|
||||||
bool KHR_lights_punctual;
|
bool KHR_lights_punctual;
|
||||||
|
bool KHR_texture_transform;
|
||||||
} extensionsUsed;
|
} extensionsUsed;
|
||||||
|
|
||||||
AssetMetadata asset;
|
AssetMetadata asset;
|
||||||
|
|
|
@ -800,8 +800,34 @@ inline void Texture::Read(Value& obj, Asset& r)
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
inline void SetTextureProperties(Asset& r, Value* prop, TextureInfo& out)
|
inline void SetTextureProperties(Asset& r, Value* prop, TextureInfo& out) {
|
||||||
{
|
if (r.extensionsUsed.KHR_texture_transform) {
|
||||||
|
if (Value *extensions = FindObject(*prop, "extensions")) {
|
||||||
|
out.textureTransformSupported = true;
|
||||||
|
if (Value *pKHR_texture_transform = FindObject(*extensions, "KHR_texture_transform")) {
|
||||||
|
if (Value *array = FindArray(*pKHR_texture_transform, "offset")) {
|
||||||
|
out.TextureTransformExt_t.offset[0] = (*array)[0].GetFloat();
|
||||||
|
out.TextureTransformExt_t.offset[1] = (*array)[1].GetFloat();
|
||||||
|
} else {
|
||||||
|
out.TextureTransformExt_t.offset[0] = 0;
|
||||||
|
out.TextureTransformExt_t.offset[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ReadMember(*pKHR_texture_transform, "rotation", out.TextureTransformExt_t.rotation)) {
|
||||||
|
out.TextureTransformExt_t.rotation = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Value *array = FindArray(*pKHR_texture_transform, "scale")) {
|
||||||
|
out.TextureTransformExt_t.scale[0] = (*array)[0].GetFloat();
|
||||||
|
out.TextureTransformExt_t.scale[1] = (*array)[1].GetFloat();
|
||||||
|
} else {
|
||||||
|
out.TextureTransformExt_t.scale[0] = 1;
|
||||||
|
out.TextureTransformExt_t.scale[1] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Value* index = FindUInt(*prop, "index")) {
|
if (Value* index = FindUInt(*prop, "index")) {
|
||||||
out.texture = r.textures.Retrieve(index->GetUint());
|
out.texture = r.textures.Retrieve(index->GetUint());
|
||||||
}
|
}
|
||||||
|
@ -877,6 +903,9 @@ inline void Material::Read(Value& material, Asset& r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (r.extensionsUsed.KHR_texture_transform) {
|
||||||
|
}
|
||||||
|
|
||||||
unlit = nullptr != FindObject(*extensions, "KHR_materials_unlit");
|
unlit = nullptr != FindObject(*extensions, "KHR_materials_unlit");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1463,12 +1492,10 @@ inline void Asset::ReadExtensionsUsed(Document& doc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CHECK_EXT(EXT) \
|
|
||||||
if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true;
|
|
||||||
|
|
||||||
CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
|
CHECK_EXT(KHR_materials_pbrSpecularGlossiness);
|
||||||
CHECK_EXT(KHR_materials_unlit);
|
CHECK_EXT(KHR_materials_unlit);
|
||||||
CHECK_EXT(KHR_lights_punctual);
|
CHECK_EXT(KHR_lights_punctual);
|
||||||
|
CHECK_EXT(KHR_texture_transform);
|
||||||
|
|
||||||
#undef CHECK_EXT
|
#undef CHECK_EXT
|
||||||
}
|
}
|
||||||
|
|
|
@ -375,7 +375,7 @@ namespace glTF2 {
|
||||||
WriteVec(pbrSpecularGlossiness, pbrSG.specularFactor, "specularFactor", defaultSpecularFactor, w.mAl);
|
WriteVec(pbrSpecularGlossiness, pbrSG.specularFactor, "specularFactor", defaultSpecularFactor, w.mAl);
|
||||||
|
|
||||||
if (pbrSG.glossinessFactor != 1) {
|
if (pbrSG.glossinessFactor != 1) {
|
||||||
WriteFloat(obj, pbrSG.glossinessFactor, "glossinessFactor", w.mAl);
|
WriteFloat(pbrSpecularGlossiness, pbrSG.glossinessFactor, "glossinessFactor", w.mAl);
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteTex(pbrSpecularGlossiness, pbrSG.diffuseTexture, "diffuseTexture", w.mAl);
|
WriteTex(pbrSpecularGlossiness, pbrSG.diffuseTexture, "diffuseTexture", w.mAl);
|
||||||
|
|
|
@ -350,7 +350,9 @@ void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref<Texture>& texture, aiTe
|
||||||
if (path[0] == '*') { // embedded
|
if (path[0] == '*') { // embedded
|
||||||
aiTexture* tex = mScene->mTextures[atoi(&path[1])];
|
aiTexture* tex = mScene->mTextures[atoi(&path[1])];
|
||||||
|
|
||||||
uint8_t* data = reinterpret_cast<uint8_t*>(tex->pcData);
|
// copy data since lifetime control is handed over to the asset
|
||||||
|
uint8_t* data = new uint8_t[tex->mWidth];
|
||||||
|
memcpy(data, tex->pcData, tex->mWidth);
|
||||||
texture->source->SetData(data, tex->mWidth, *mAsset);
|
texture->source->SetData(data, tex->mWidth, *mAsset);
|
||||||
|
|
||||||
if (tex->achFormatHint[0]) {
|
if (tex->achFormatHint[0]) {
|
||||||
|
|
|
@ -74,6 +74,7 @@ namespace glTF2
|
||||||
struct Texture;
|
struct Texture;
|
||||||
|
|
||||||
// Vec/matrix types, as raw float arrays
|
// Vec/matrix types, as raw float arrays
|
||||||
|
typedef float (vec2)[2];
|
||||||
typedef float (vec3)[3];
|
typedef float (vec3)[3];
|
||||||
typedef float (vec4)[4];
|
typedef float (vec4)[4];
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,6 +15,9 @@
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
//using namespace Assimp;
|
//using namespace Assimp;
|
||||||
|
|
||||||
|
// For locale independent number conversion
|
||||||
|
#include <sstream>
|
||||||
|
#include <locale>
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
#define IRR_DEBUGPRINT(x) printf((x));
|
#define IRR_DEBUGPRINT(x) printf((x));
|
||||||
|
@ -178,8 +181,11 @@ public:
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
core::stringc c = attrvalue;
|
core::stringc c = attrvalue;
|
||||||
return static_cast<float>(atof(c.c_str()));
|
std::istringstream sstr(c.c_str());
|
||||||
//return fast_atof(c.c_str());
|
sstr.imbue(std::locale("C")); // Locale free number convert
|
||||||
|
float fNum;
|
||||||
|
sstr >> fNum;
|
||||||
|
return fNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
/build/
|
/build/
|
||||||
/test/build/
|
/test/build/
|
||||||
/xcodeproj/
|
/xcodeproj/
|
||||||
|
.vscode/
|
||||||
|
|
||||||
# Object files
|
# Object files
|
||||||
*.o
|
*.o
|
||||||
|
@ -54,3 +55,4 @@ zip.dir/
|
||||||
test/test.exe.vcxproj.filters
|
test/test.exe.vcxproj.filters
|
||||||
test/test.exe.vcxproj
|
test/test.exe.vcxproj
|
||||||
test/test.exe.dir/
|
test/test.exe.dir/
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
cmake_minimum_required(VERSION 2.8)
|
cmake_minimum_required(VERSION 3.0)
|
||||||
project(zip)
|
|
||||||
enable_language(C)
|
project(zip
|
||||||
|
LANGUAGES C
|
||||||
|
VERSION "0.1.15")
|
||||||
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
||||||
|
|
||||||
|
option(CMAKE_DISABLE_TESTING "Disable test creation" OFF)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
# Use secure functions by defaualt and suppress warnings about "deprecated" functions
|
# Use secure functions by default and suppress warnings about "deprecated" functions
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1")
|
||||||
|
@ -12,28 +16,80 @@ elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR
|
||||||
"${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
|
"${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR
|
||||||
"${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
|
"${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Werror -pedantic")
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Werror -pedantic")
|
||||||
|
if(ENABLE_COVERAGE)
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
|
||||||
|
endif()
|
||||||
endif (MSVC)
|
endif (MSVC)
|
||||||
|
|
||||||
# zip
|
# zip
|
||||||
set(SRC src/miniz.h src/zip.h src/zip.c)
|
set(SRC src/miniz.h src/zip.h src/zip.c)
|
||||||
add_library(${PROJECT_NAME} ${SRC})
|
add_library(${PROJECT_NAME} ${SRC})
|
||||||
target_include_directories(${PROJECT_NAME} INTERFACE src)
|
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||||
|
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>
|
||||||
|
$<INSTALL_INTERFACE:include>
|
||||||
|
)
|
||||||
|
|
||||||
# test
|
# test
|
||||||
if (NOT CMAKE_DISABLE_TESTING)
|
if (NOT CMAKE_DISABLE_TESTING)
|
||||||
enable_testing()
|
enable_testing()
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
find_package(Sanitizers)
|
find_package(Sanitizers)
|
||||||
add_sanitizers(${PROJECT_NAME} test.exe)
|
add_sanitizers(${PROJECT_NAME} ${test_out} ${test_miniz_out})
|
||||||
add_sanitizers(${PROJECT_NAME} test_miniz.exe)
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
####
|
||||||
|
# Installation (https://github.com/forexample/package-example) {
|
||||||
|
|
||||||
|
set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}")
|
||||||
|
set(INCLUDE_INSTALL_DIR "include")
|
||||||
|
|
||||||
|
set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated")
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
|
||||||
|
set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake")
|
||||||
|
set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
|
||||||
|
set(NAMESPACE "${PROJECT_NAME}::")
|
||||||
|
|
||||||
|
# Include module with fuction 'write_basic_package_version_file'
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
|
||||||
|
# Note: PROJECT_VERSION is used as a VERSION
|
||||||
|
write_basic_package_version_file(
|
||||||
|
"${VERSION_CONFIG}" COMPATIBILITY SameMajorVersion
|
||||||
|
)
|
||||||
|
|
||||||
|
# Use variables:
|
||||||
|
# * TARGETS_EXPORT_NAME
|
||||||
|
# * PROJECT_NAME
|
||||||
|
configure_package_config_file(
|
||||||
|
"cmake/Config.cmake.in"
|
||||||
|
"${PROJECT_CONFIG}"
|
||||||
|
INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}"
|
||||||
|
DESTINATION "${CONFIG_INSTALL_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
EXPORT "${TARGETS_EXPORT_NAME}"
|
||||||
|
NAMESPACE "${NAMESPACE}"
|
||||||
|
DESTINATION "${CONFIG_INSTALL_DIR}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# }
|
||||||
|
|
||||||
install(TARGETS ${PROJECT_NAME}
|
install(TARGETS ${PROJECT_NAME}
|
||||||
|
EXPORT ${TARGETS_EXPORT_NAME}
|
||||||
RUNTIME DESTINATION bin
|
RUNTIME DESTINATION bin
|
||||||
ARCHIVE DESTINATION lib
|
ARCHIVE DESTINATION lib
|
||||||
LIBRARY DESTINATION lib
|
LIBRARY DESTINATION lib
|
||||||
COMPONENT library)
|
INCLUDES DESTINATION ${INCLUDE_INSTALL_DIR}
|
||||||
install(FILES ${PROJECT_SOURCE_DIR}/src/zip.h DESTINATION include)
|
)
|
||||||
|
install(FILES ${PROJECT_SOURCE_DIR}/src/zip.h DESTINATION ${INCLUDE_INSTALL_DIR}/zip)
|
||||||
|
|
||||||
# uninstall target (https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake)
|
# uninstall target (https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake)
|
||||||
if(NOT TARGET uninstall)
|
if(NOT TARGET uninstall)
|
||||||
|
@ -45,3 +101,12 @@ if(NOT TARGET uninstall)
|
||||||
add_custom_target(uninstall
|
add_custom_target(uninstall
|
||||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake)
|
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
find_package(Doxygen)
|
||||||
|
if(DOXYGEN_FOUND)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile @ONLY)
|
||||||
|
add_custom_target(doc
|
||||||
|
${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
COMMENT "Generating API documentation with Doxygen" VERBATIM)
|
||||||
|
endif()
|
||||||
|
|
|
@ -71,7 +71,7 @@ int arg = 2;
|
||||||
zip_extract("foo.zip", "/tmp", on_extract_entry, &arg);
|
zip_extract("foo.zip", "/tmp", on_extract_entry, &arg);
|
||||||
```
|
```
|
||||||
|
|
||||||
* Extract a zip entry into memory.
|
* Extract a zip entry into memory.
|
||||||
```c
|
```c
|
||||||
void *buf = NULL;
|
void *buf = NULL;
|
||||||
size_t bufsize;
|
size_t bufsize;
|
||||||
|
@ -89,7 +89,7 @@ zip_close(zip);
|
||||||
free(buf);
|
free(buf);
|
||||||
```
|
```
|
||||||
|
|
||||||
* Extract a zip entry into memory (no internal allocation).
|
* Extract a zip entry into memory (no internal allocation).
|
||||||
```c
|
```c
|
||||||
unsigned char *buf;
|
unsigned char *buf;
|
||||||
size_t bufsize;
|
size_t bufsize;
|
||||||
|
@ -110,7 +110,7 @@ zip_close(zip);
|
||||||
free(buf);
|
free(buf);
|
||||||
```
|
```
|
||||||
|
|
||||||
* Extract a zip entry into memory using callback.
|
* Extract a zip entry into memory using callback.
|
||||||
```c
|
```c
|
||||||
struct buffer_t {
|
struct buffer_t {
|
||||||
char *data;
|
char *data;
|
||||||
|
@ -144,7 +144,7 @@ free(buf.data);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
* Extract a zip entry into a file.
|
* Extract a zip entry into a file.
|
||||||
```c
|
```c
|
||||||
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
||||||
{
|
{
|
||||||
|
@ -157,7 +157,7 @@ struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
||||||
zip_close(zip);
|
zip_close(zip);
|
||||||
```
|
```
|
||||||
|
|
||||||
* List of all zip entries
|
* List of all zip entries
|
||||||
```c
|
```c
|
||||||
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
struct zip_t *zip = zip_open("foo.zip", 0, 'r');
|
||||||
int i, n = zip_total_entries(zip);
|
int i, n = zip_total_entries(zip);
|
||||||
|
@ -174,7 +174,7 @@ for (i = 0; i < n; ++i) {
|
||||||
zip_close(zip);
|
zip_close(zip);
|
||||||
```
|
```
|
||||||
|
|
||||||
## Bindings
|
# Bindings
|
||||||
Compile zip library as a dynamic library.
|
Compile zip library as a dynamic library.
|
||||||
```shell
|
```shell
|
||||||
$ mkdir build
|
$ mkdir build
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
version: zip-0.1.9.{build}
|
version: zip-0.1.15.{build}
|
||||||
build_script:
|
build_script:
|
||||||
- cmd: >-
|
- cmd: >-
|
||||||
cd c:\projects\zip
|
cd c:\projects\zip
|
||||||
|
|
|
@ -221,6 +221,7 @@
|
||||||
#ifndef MINIZ_HEADER_INCLUDED
|
#ifndef MINIZ_HEADER_INCLUDED
|
||||||
#define MINIZ_HEADER_INCLUDED
|
#define MINIZ_HEADER_INCLUDED
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
// Defines to completely disable specific portions of miniz.c:
|
// Defines to completely disable specific portions of miniz.c:
|
||||||
|
@ -284,7 +285,8 @@
|
||||||
/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */
|
/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */
|
||||||
#if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES)
|
#if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES)
|
||||||
#if MINIZ_X86_OR_X64_CPU
|
#if MINIZ_X86_OR_X64_CPU
|
||||||
/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */
|
/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient
|
||||||
|
* integer loads and stores from unaligned addresses. */
|
||||||
#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
|
#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
|
||||||
#define MINIZ_UNALIGNED_USE_MEMCPY
|
#define MINIZ_UNALIGNED_USE_MEMCPY
|
||||||
#else
|
#else
|
||||||
|
@ -354,6 +356,44 @@ enum {
|
||||||
MZ_FIXED = 4
|
MZ_FIXED = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or
|
||||||
|
* modify this enum. */
|
||||||
|
typedef enum {
|
||||||
|
MZ_ZIP_NO_ERROR = 0,
|
||||||
|
MZ_ZIP_UNDEFINED_ERROR,
|
||||||
|
MZ_ZIP_TOO_MANY_FILES,
|
||||||
|
MZ_ZIP_FILE_TOO_LARGE,
|
||||||
|
MZ_ZIP_UNSUPPORTED_METHOD,
|
||||||
|
MZ_ZIP_UNSUPPORTED_ENCRYPTION,
|
||||||
|
MZ_ZIP_UNSUPPORTED_FEATURE,
|
||||||
|
MZ_ZIP_FAILED_FINDING_CENTRAL_DIR,
|
||||||
|
MZ_ZIP_NOT_AN_ARCHIVE,
|
||||||
|
MZ_ZIP_INVALID_HEADER_OR_CORRUPTED,
|
||||||
|
MZ_ZIP_UNSUPPORTED_MULTIDISK,
|
||||||
|
MZ_ZIP_DECOMPRESSION_FAILED,
|
||||||
|
MZ_ZIP_COMPRESSION_FAILED,
|
||||||
|
MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE,
|
||||||
|
MZ_ZIP_CRC_CHECK_FAILED,
|
||||||
|
MZ_ZIP_UNSUPPORTED_CDIR_SIZE,
|
||||||
|
MZ_ZIP_ALLOC_FAILED,
|
||||||
|
MZ_ZIP_FILE_OPEN_FAILED,
|
||||||
|
MZ_ZIP_FILE_CREATE_FAILED,
|
||||||
|
MZ_ZIP_FILE_WRITE_FAILED,
|
||||||
|
MZ_ZIP_FILE_READ_FAILED,
|
||||||
|
MZ_ZIP_FILE_CLOSE_FAILED,
|
||||||
|
MZ_ZIP_FILE_SEEK_FAILED,
|
||||||
|
MZ_ZIP_FILE_STAT_FAILED,
|
||||||
|
MZ_ZIP_INVALID_PARAMETER,
|
||||||
|
MZ_ZIP_INVALID_FILENAME,
|
||||||
|
MZ_ZIP_BUF_TOO_SMALL,
|
||||||
|
MZ_ZIP_INTERNAL_ERROR,
|
||||||
|
MZ_ZIP_FILE_NOT_FOUND,
|
||||||
|
MZ_ZIP_ARCHIVE_TOO_LARGE,
|
||||||
|
MZ_ZIP_VALIDATION_FAILED,
|
||||||
|
MZ_ZIP_WRITE_CALLBACK_FAILED,
|
||||||
|
MZ_ZIP_TOTAL_ERRORS
|
||||||
|
} mz_zip_error;
|
||||||
|
|
||||||
// Method
|
// Method
|
||||||
#define MZ_DEFLATED 8
|
#define MZ_DEFLATED 8
|
||||||
|
|
||||||
|
@ -696,6 +736,7 @@ typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs,
|
||||||
void *pBuf, size_t n);
|
void *pBuf, size_t n);
|
||||||
typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs,
|
typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs,
|
||||||
const void *pBuf, size_t n);
|
const void *pBuf, size_t n);
|
||||||
|
typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque);
|
||||||
|
|
||||||
struct mz_zip_internal_state_tag;
|
struct mz_zip_internal_state_tag;
|
||||||
typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
|
typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
|
||||||
|
@ -707,13 +748,27 @@ typedef enum {
|
||||||
MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
|
MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
|
||||||
} mz_zip_mode;
|
} mz_zip_mode;
|
||||||
|
|
||||||
typedef struct mz_zip_archive_tag {
|
typedef enum {
|
||||||
|
MZ_ZIP_TYPE_INVALID = 0,
|
||||||
|
MZ_ZIP_TYPE_USER,
|
||||||
|
MZ_ZIP_TYPE_MEMORY,
|
||||||
|
MZ_ZIP_TYPE_HEAP,
|
||||||
|
MZ_ZIP_TYPE_FILE,
|
||||||
|
MZ_ZIP_TYPE_CFILE,
|
||||||
|
MZ_ZIP_TOTAL_TYPES
|
||||||
|
} mz_zip_type;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
mz_uint64 m_archive_size;
|
mz_uint64 m_archive_size;
|
||||||
mz_uint64 m_central_directory_file_ofs;
|
mz_uint64 m_central_directory_file_ofs;
|
||||||
mz_uint m_total_files;
|
|
||||||
mz_zip_mode m_zip_mode;
|
|
||||||
|
|
||||||
mz_uint m_file_offset_alignment;
|
/* We only support up to UINT32_MAX files in zip64 mode. */
|
||||||
|
mz_uint32 m_total_files;
|
||||||
|
mz_zip_mode m_zip_mode;
|
||||||
|
mz_zip_type m_zip_type;
|
||||||
|
mz_zip_error m_last_error;
|
||||||
|
|
||||||
|
mz_uint64 m_file_offset_alignment;
|
||||||
|
|
||||||
mz_alloc_func m_pAlloc;
|
mz_alloc_func m_pAlloc;
|
||||||
mz_free_func m_pFree;
|
mz_free_func m_pFree;
|
||||||
|
@ -722,6 +777,7 @@ typedef struct mz_zip_archive_tag {
|
||||||
|
|
||||||
mz_file_read_func m_pRead;
|
mz_file_read_func m_pRead;
|
||||||
mz_file_write_func m_pWrite;
|
mz_file_write_func m_pWrite;
|
||||||
|
mz_file_needs_keepalive m_pNeeds_keepalive;
|
||||||
void *m_pIO_opaque;
|
void *m_pIO_opaque;
|
||||||
|
|
||||||
mz_zip_internal_state *m_pState;
|
mz_zip_internal_state *m_pState;
|
||||||
|
@ -1263,6 +1319,9 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
|
||||||
int strategy);
|
int strategy);
|
||||||
#endif // #ifndef MINIZ_NO_ZLIB_APIS
|
#endif // #ifndef MINIZ_NO_ZLIB_APIS
|
||||||
|
|
||||||
|
#define MZ_UINT16_MAX (0xFFFFU)
|
||||||
|
#define MZ_UINT32_MAX (0xFFFFFFFFU)
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -1311,6 +1370,11 @@ typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
|
||||||
((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
|
((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define MZ_READ_LE64(p) \
|
||||||
|
(((mz_uint64)MZ_READ_LE32(p)) | \
|
||||||
|
(((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) \
|
||||||
|
<< 32U))
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#define MZ_FORCEINLINE __forceinline
|
#define MZ_FORCEINLINE __forceinline
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
|
@ -4160,6 +4224,17 @@ enum {
|
||||||
MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,
|
MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,
|
||||||
MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,
|
MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,
|
||||||
MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
|
MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
|
||||||
|
|
||||||
|
/* ZIP64 archive identifier and record sizes */
|
||||||
|
MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50,
|
||||||
|
MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50,
|
||||||
|
MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56,
|
||||||
|
MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20,
|
||||||
|
MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001,
|
||||||
|
MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50,
|
||||||
|
MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24,
|
||||||
|
MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16,
|
||||||
|
|
||||||
// Central directory header record offsets
|
// Central directory header record offsets
|
||||||
MZ_ZIP_CDH_SIG_OFS = 0,
|
MZ_ZIP_CDH_SIG_OFS = 0,
|
||||||
MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,
|
MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,
|
||||||
|
@ -4199,6 +4274,31 @@ enum {
|
||||||
MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,
|
MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,
|
||||||
MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,
|
MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,
|
||||||
MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
|
MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
|
||||||
|
|
||||||
|
/* ZIP64 End of central directory locator offsets */
|
||||||
|
MZ_ZIP64_ECDL_SIG_OFS = 0, /* 4 bytes */
|
||||||
|
MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4, /* 4 bytes */
|
||||||
|
MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8, /* 8 bytes */
|
||||||
|
MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */
|
||||||
|
|
||||||
|
/* ZIP64 End of central directory header offsets */
|
||||||
|
MZ_ZIP64_ECDH_SIG_OFS = 0, /* 4 bytes */
|
||||||
|
MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4, /* 8 bytes */
|
||||||
|
MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12, /* 2 bytes */
|
||||||
|
MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14, /* 2 bytes */
|
||||||
|
MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16, /* 4 bytes */
|
||||||
|
MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20, /* 4 bytes */
|
||||||
|
MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */
|
||||||
|
MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32, /* 8 bytes */
|
||||||
|
MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40, /* 8 bytes */
|
||||||
|
MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48, /* 8 bytes */
|
||||||
|
MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0,
|
||||||
|
MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10,
|
||||||
|
MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1,
|
||||||
|
MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32,
|
||||||
|
MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64,
|
||||||
|
MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192,
|
||||||
|
MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -4211,7 +4311,24 @@ struct mz_zip_internal_state_tag {
|
||||||
mz_zip_array m_central_dir;
|
mz_zip_array m_central_dir;
|
||||||
mz_zip_array m_central_dir_offsets;
|
mz_zip_array m_central_dir_offsets;
|
||||||
mz_zip_array m_sorted_central_dir_offsets;
|
mz_zip_array m_sorted_central_dir_offsets;
|
||||||
|
|
||||||
|
/* The flags passed in when the archive is initially opened. */
|
||||||
|
uint32_t m_init_flags;
|
||||||
|
|
||||||
|
/* MZ_TRUE if the archive has a zip64 end of central directory headers, etc.
|
||||||
|
*/
|
||||||
|
mz_bool m_zip64;
|
||||||
|
|
||||||
|
/* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64
|
||||||
|
* will also be slammed to true too, even if we didn't find a zip64 end of
|
||||||
|
* central dir header, etc.) */
|
||||||
|
mz_bool m_zip64_has_extended_info_fields;
|
||||||
|
|
||||||
|
/* These fields are used by the file, FILE, memory, and memory/heap read/write
|
||||||
|
* helpers. */
|
||||||
MZ_FILE *m_pFile;
|
MZ_FILE *m_pFile;
|
||||||
|
mz_uint64 m_file_archive_start_ofs;
|
||||||
|
|
||||||
void *m_pMem;
|
void *m_pMem;
|
||||||
size_t m_mem_size;
|
size_t m_mem_size;
|
||||||
size_t m_mem_capacity;
|
size_t m_mem_capacity;
|
||||||
|
@ -4363,6 +4480,13 @@ static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time,
|
||||||
#endif /* #ifndef MINIZ_NO_STDIO */
|
#endif /* #ifndef MINIZ_NO_STDIO */
|
||||||
#endif /* #ifndef MINIZ_NO_TIME */
|
#endif /* #ifndef MINIZ_NO_TIME */
|
||||||
|
|
||||||
|
static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip,
|
||||||
|
mz_zip_error err_num) {
|
||||||
|
if (pZip)
|
||||||
|
pZip->m_last_error = err_num;
|
||||||
|
return MZ_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip,
|
static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip,
|
||||||
mz_uint32 flags) {
|
mz_uint32 flags) {
|
||||||
(void)flags;
|
(void)flags;
|
||||||
|
@ -4480,127 +4604,346 @@ mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
|
static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip,
|
||||||
mz_uint32 flags) {
|
mz_uint32 record_sig,
|
||||||
mz_uint cdir_size, num_this_disk, cdir_disk_index;
|
mz_uint32 record_size,
|
||||||
mz_uint64 cdir_ofs;
|
mz_int64 *pOfs) {
|
||||||
mz_int64 cur_file_ofs;
|
mz_int64 cur_file_ofs;
|
||||||
const mz_uint8 *p;
|
|
||||||
mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
|
mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
|
||||||
mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
|
mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
|
||||||
mz_bool sort_central_dir =
|
|
||||||
((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
|
/* Basic sanity checks - reject files which are too small */
|
||||||
// Basic sanity checks - reject files which are too small, and check the first
|
if (pZip->m_archive_size < record_size)
|
||||||
// 4 bytes of the file to make sure a local header is there.
|
|
||||||
if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
|
|
||||||
return MZ_FALSE;
|
return MZ_FALSE;
|
||||||
// Find the end of central directory record by scanning the file from the end
|
|
||||||
// towards the beginning.
|
/* Find the record by scanning the file from the end towards the beginning. */
|
||||||
cur_file_ofs =
|
cur_file_ofs =
|
||||||
MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
|
MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int i,
|
int i,
|
||||||
n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
|
n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
|
||||||
|
|
||||||
if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
|
if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
|
||||||
return MZ_FALSE;
|
return MZ_FALSE;
|
||||||
for (i = n - 4; i >= 0; --i)
|
|
||||||
if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
|
for (i = n - 4; i >= 0; --i) {
|
||||||
break;
|
mz_uint s = MZ_READ_LE32(pBuf + i);
|
||||||
|
if (s == record_sig) {
|
||||||
|
if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (i >= 0) {
|
if (i >= 0) {
|
||||||
cur_file_ofs += i;
|
cur_file_ofs += i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Give up if we've searched the entire file, or we've gone back "too far"
|
||||||
|
* (~64kb) */
|
||||||
if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >=
|
if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >=
|
||||||
(0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
|
(MZ_UINT16_MAX + record_size)))
|
||||||
return MZ_FALSE;
|
return MZ_FALSE;
|
||||||
|
|
||||||
cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
|
cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
|
||||||
}
|
}
|
||||||
// Read and verify the end of central directory record.
|
|
||||||
|
*pOfs = cur_file_ofs;
|
||||||
|
return MZ_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip,
|
||||||
|
mz_uint flags) {
|
||||||
|
mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0,
|
||||||
|
cdir_disk_index = 0;
|
||||||
|
mz_uint64 cdir_ofs = 0;
|
||||||
|
mz_int64 cur_file_ofs = 0;
|
||||||
|
const mz_uint8 *p;
|
||||||
|
|
||||||
|
mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
|
||||||
|
mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
|
||||||
|
mz_bool sort_central_dir =
|
||||||
|
((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
|
||||||
|
mz_uint32 zip64_end_of_central_dir_locator_u32
|
||||||
|
[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) /
|
||||||
|
sizeof(mz_uint32)];
|
||||||
|
mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32;
|
||||||
|
|
||||||
|
mz_uint32 zip64_end_of_central_dir_header_u32
|
||||||
|
[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) /
|
||||||
|
sizeof(mz_uint32)];
|
||||||
|
mz_uint8 *pZip64_end_of_central_dir =
|
||||||
|
(mz_uint8 *)zip64_end_of_central_dir_header_u32;
|
||||||
|
|
||||||
|
mz_uint64 zip64_end_of_central_dir_ofs = 0;
|
||||||
|
|
||||||
|
/* Basic sanity checks - reject files which are too small, and check the first
|
||||||
|
* 4 bytes of the file to make sure a local header is there. */
|
||||||
|
if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
|
||||||
|
|
||||||
|
if (!mz_zip_reader_locate_header_sig(
|
||||||
|
pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG,
|
||||||
|
MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs))
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR);
|
||||||
|
|
||||||
|
/* Read and verify the end of central directory record. */
|
||||||
if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
|
if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf,
|
||||||
MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
|
MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) !=
|
||||||
MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
|
MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
|
||||||
return MZ_FALSE;
|
return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
|
||||||
if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
|
|
||||||
MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ||
|
|
||||||
((pZip->m_total_files =
|
|
||||||
MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) !=
|
|
||||||
MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS)))
|
|
||||||
return MZ_FALSE;
|
|
||||||
|
|
||||||
|
if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) !=
|
||||||
|
MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
|
||||||
|
|
||||||
|
if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE +
|
||||||
|
MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)) {
|
||||||
|
if (pZip->m_pRead(pZip->m_pIO_opaque,
|
||||||
|
cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE,
|
||||||
|
pZip64_locator,
|
||||||
|
MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) ==
|
||||||
|
MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) {
|
||||||
|
if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) ==
|
||||||
|
MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG) {
|
||||||
|
zip64_end_of_central_dir_ofs = MZ_READ_LE64(
|
||||||
|
pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS);
|
||||||
|
if (zip64_end_of_central_dir_ofs >
|
||||||
|
(pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
|
||||||
|
|
||||||
|
if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs,
|
||||||
|
pZip64_end_of_central_dir,
|
||||||
|
MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) ==
|
||||||
|
MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) {
|
||||||
|
if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) ==
|
||||||
|
MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG) {
|
||||||
|
pZip->m_pState->m_zip64 = MZ_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS);
|
||||||
|
cdir_entries_on_this_disk =
|
||||||
|
MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
|
||||||
num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
|
num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
|
||||||
cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
|
cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
|
||||||
|
cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS);
|
||||||
|
cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
|
||||||
|
|
||||||
|
if (pZip->m_pState->m_zip64) {
|
||||||
|
mz_uint32 zip64_total_num_of_disks =
|
||||||
|
MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS);
|
||||||
|
mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(
|
||||||
|
pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS);
|
||||||
|
mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(
|
||||||
|
pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
|
||||||
|
mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(
|
||||||
|
pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS);
|
||||||
|
mz_uint64 zip64_size_of_central_directory =
|
||||||
|
MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS);
|
||||||
|
|
||||||
|
if (zip64_size_of_end_of_central_dir_record <
|
||||||
|
(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12))
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
|
||||||
|
|
||||||
|
if (zip64_total_num_of_disks != 1U)
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
|
||||||
|
|
||||||
|
/* Check for miniz's practical limits */
|
||||||
|
if (zip64_cdir_total_entries > MZ_UINT32_MAX)
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
|
||||||
|
|
||||||
|
pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries;
|
||||||
|
|
||||||
|
if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX)
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
|
||||||
|
|
||||||
|
cdir_entries_on_this_disk =
|
||||||
|
(mz_uint32)zip64_cdir_total_entries_on_this_disk;
|
||||||
|
|
||||||
|
/* Check for miniz's current practical limits (sorry, this should be enough
|
||||||
|
* for millions of files) */
|
||||||
|
if (zip64_size_of_central_directory > MZ_UINT32_MAX)
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
|
||||||
|
|
||||||
|
cdir_size = (mz_uint32)zip64_size_of_central_directory;
|
||||||
|
|
||||||
|
num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir +
|
||||||
|
MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS);
|
||||||
|
|
||||||
|
cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir +
|
||||||
|
MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS);
|
||||||
|
|
||||||
|
cdir_ofs =
|
||||||
|
MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pZip->m_total_files != cdir_entries_on_this_disk)
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
|
||||||
|
|
||||||
if (((num_this_disk | cdir_disk_index) != 0) &&
|
if (((num_this_disk | cdir_disk_index) != 0) &&
|
||||||
((num_this_disk != 1) || (cdir_disk_index != 1)))
|
((num_this_disk != 1) || (cdir_disk_index != 1)))
|
||||||
return MZ_FALSE;
|
return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
|
||||||
|
|
||||||
if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) <
|
if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
|
||||||
pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
|
return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
|
||||||
return MZ_FALSE;
|
|
||||||
|
|
||||||
cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
|
|
||||||
if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)
|
if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)
|
||||||
return MZ_FALSE;
|
return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
|
||||||
|
|
||||||
pZip->m_central_directory_file_ofs = cdir_ofs;
|
pZip->m_central_directory_file_ofs = cdir_ofs;
|
||||||
|
|
||||||
if (pZip->m_total_files) {
|
if (pZip->m_total_files) {
|
||||||
mz_uint i, n;
|
mz_uint i, n;
|
||||||
|
/* Read the entire central directory into a heap block, and allocate another
|
||||||
// Read the entire central directory into a heap block, and allocate another
|
* heap block to hold the unsorted central dir file record offsets, and
|
||||||
// heap block to hold the unsorted central dir file record offsets, and
|
* possibly another to hold the sorted indices. */
|
||||||
// another to hold the sorted indices.
|
|
||||||
if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size,
|
if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size,
|
||||||
MZ_FALSE)) ||
|
MZ_FALSE)) ||
|
||||||
(!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets,
|
(!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets,
|
||||||
pZip->m_total_files, MZ_FALSE)))
|
pZip->m_total_files, MZ_FALSE)))
|
||||||
return MZ_FALSE;
|
return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
|
||||||
|
|
||||||
if (sort_central_dir) {
|
if (sort_central_dir) {
|
||||||
if (!mz_zip_array_resize(pZip,
|
if (!mz_zip_array_resize(pZip,
|
||||||
&pZip->m_pState->m_sorted_central_dir_offsets,
|
&pZip->m_pState->m_sorted_central_dir_offsets,
|
||||||
pZip->m_total_files, MZ_FALSE))
|
pZip->m_total_files, MZ_FALSE))
|
||||||
return MZ_FALSE;
|
return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs,
|
if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs,
|
||||||
pZip->m_pState->m_central_dir.m_p,
|
pZip->m_pState->m_central_dir.m_p,
|
||||||
cdir_size) != cdir_size)
|
cdir_size) != cdir_size)
|
||||||
return MZ_FALSE;
|
return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
|
||||||
|
|
||||||
// Now create an index into the central directory file records, do some
|
/* Now create an index into the central directory file records, do some
|
||||||
// basic sanity checking on each record, and check for zip64 entries (which
|
* basic sanity checking on each record */
|
||||||
// are not yet supported).
|
|
||||||
p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
|
p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
|
||||||
for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) {
|
for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) {
|
||||||
mz_uint total_header_size, comp_size, decomp_size, disk_index;
|
mz_uint total_header_size, disk_index, bit_flags, filename_size,
|
||||||
|
ext_data_size;
|
||||||
|
mz_uint64 comp_size, decomp_size, local_header_ofs;
|
||||||
|
|
||||||
if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) ||
|
if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) ||
|
||||||
(MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
|
(MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
|
||||||
return MZ_FALSE;
|
return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
|
||||||
|
|
||||||
MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
|
MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32,
|
||||||
i) =
|
i) =
|
||||||
(mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
|
(mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
|
||||||
|
|
||||||
if (sort_central_dir)
|
if (sort_central_dir)
|
||||||
MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets,
|
MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets,
|
||||||
mz_uint32, i) = i;
|
mz_uint32, i) = i;
|
||||||
|
|
||||||
comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
|
comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
|
||||||
decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
|
decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
|
||||||
if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
|
local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
|
||||||
(decomp_size != comp_size)) ||
|
filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
|
||||||
(decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) ||
|
ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);
|
||||||
(comp_size == 0xFFFFFFFF))
|
|
||||||
return MZ_FALSE;
|
if ((!pZip->m_pState->m_zip64_has_extended_info_fields) &&
|
||||||
|
(ext_data_size) &&
|
||||||
|
(MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) ==
|
||||||
|
MZ_UINT32_MAX)) {
|
||||||
|
/* Attempt to find zip64 extended information field in the entry's extra
|
||||||
|
* data */
|
||||||
|
mz_uint32 extra_size_remaining = ext_data_size;
|
||||||
|
|
||||||
|
if (extra_size_remaining) {
|
||||||
|
const mz_uint8 *pExtra_data;
|
||||||
|
void *buf = NULL;
|
||||||
|
|
||||||
|
if (MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + ext_data_size >
|
||||||
|
n) {
|
||||||
|
buf = MZ_MALLOC(ext_data_size);
|
||||||
|
if (buf == NULL)
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
|
||||||
|
|
||||||
|
if (pZip->m_pRead(pZip->m_pIO_opaque,
|
||||||
|
cdir_ofs + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
|
||||||
|
filename_size,
|
||||||
|
buf, ext_data_size) != ext_data_size) {
|
||||||
|
MZ_FREE(buf);
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
|
pExtra_data = (mz_uint8 *)buf;
|
||||||
|
} else {
|
||||||
|
pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
mz_uint32 field_id;
|
||||||
|
mz_uint32 field_data_size;
|
||||||
|
|
||||||
|
if (extra_size_remaining < (sizeof(mz_uint16) * 2)) {
|
||||||
|
MZ_FREE(buf);
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
field_id = MZ_READ_LE16(pExtra_data);
|
||||||
|
field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
|
||||||
|
|
||||||
|
if ((field_data_size + sizeof(mz_uint16) * 2) >
|
||||||
|
extra_size_remaining) {
|
||||||
|
MZ_FREE(buf);
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID) {
|
||||||
|
/* Ok, the archive didn't have any zip64 headers but it uses a
|
||||||
|
* zip64 extended information field so mark it as zip64 anyway
|
||||||
|
* (this can occur with infozip's zip util when it reads
|
||||||
|
* compresses files from stdin). */
|
||||||
|
pZip->m_pState->m_zip64 = MZ_TRUE;
|
||||||
|
pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;
|
||||||
|
extra_size_remaining =
|
||||||
|
extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
|
||||||
|
} while (extra_size_remaining);
|
||||||
|
|
||||||
|
MZ_FREE(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* I've seen archives that aren't marked as zip64 that uses zip64 ext
|
||||||
|
* data, argh */
|
||||||
|
if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX)) {
|
||||||
|
if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) &&
|
||||||
|
(decomp_size != comp_size)) ||
|
||||||
|
(decomp_size && !comp_size))
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
|
||||||
|
}
|
||||||
|
|
||||||
disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
|
disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
|
||||||
if ((disk_index != num_this_disk) && (disk_index != 1))
|
if ((disk_index == MZ_UINT16_MAX) ||
|
||||||
return MZ_FALSE;
|
((disk_index != num_this_disk) && (disk_index != 1)))
|
||||||
if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
|
return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
|
||||||
MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
|
|
||||||
return MZ_FALSE;
|
if (comp_size != MZ_UINT32_MAX) {
|
||||||
|
if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) +
|
||||||
|
MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
|
||||||
|
if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED)
|
||||||
|
return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
|
||||||
|
|
||||||
if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
|
if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
|
||||||
MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
|
MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
|
||||||
MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
|
MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) +
|
||||||
MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) >
|
MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) >
|
||||||
n)
|
n)
|
||||||
return MZ_FALSE;
|
return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
|
||||||
|
|
||||||
n -= total_header_size;
|
n -= total_header_size;
|
||||||
p += total_header_size;
|
p += total_header_size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) && \
|
((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) && \
|
||||||
(P)[1] == ':')
|
(P)[1] == ':')
|
||||||
#define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE(P) ? 2 : 0)
|
#define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE(P) ? 2 : 0)
|
||||||
#define ISSLASH(C) ((C) == '/' || (C) == '\\')
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
|
@ -48,7 +47,7 @@ int symlink(const char *target, const char *linkpath); // needed on Linux
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef ISSLASH
|
#ifndef ISSLASH
|
||||||
#define ISSLASH(C) ((C) == '/')
|
#define ISSLASH(C) ((C) == '/' || (C) == '\\')
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define CLEANUP(ptr) \
|
#define CLEANUP(ptr) \
|
||||||
|
@ -78,26 +77,34 @@ static const char *base_name(const char *name) {
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mkpath(const char *path) {
|
static int mkpath(char *path) {
|
||||||
char const *p;
|
char *p;
|
||||||
char npath[MAX_PATH + 1];
|
char npath[MAX_PATH + 1];
|
||||||
int len = 0;
|
int len = 0;
|
||||||
int has_device = HAS_DEVICE(path);
|
int has_device = HAS_DEVICE(path);
|
||||||
|
|
||||||
memset(npath, 0, MAX_PATH + 1);
|
memset(npath, 0, MAX_PATH + 1);
|
||||||
|
if (has_device) {
|
||||||
#ifdef _WIN32
|
// only on windows
|
||||||
// only on windows fix the path
|
npath[0] = path[0];
|
||||||
npath[0] = path[0];
|
npath[1] = path[1];
|
||||||
npath[1] = path[1];
|
len = 2;
|
||||||
len = 2;
|
}
|
||||||
#endif // _WIN32
|
|
||||||
|
|
||||||
for (p = path + len; *p && len < MAX_PATH; p++) {
|
for (p = path + len; *p && len < MAX_PATH; p++) {
|
||||||
if (ISSLASH(*p) && ((!has_device && len > 0) || (has_device && len > 2))) {
|
if (ISSLASH(*p) && ((!has_device && len > 0) || (has_device && len > 2))) {
|
||||||
if (MKDIR(npath) == -1)
|
#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \
|
||||||
if (errno != EEXIST)
|
defined(__MINGW32__)
|
||||||
|
#else
|
||||||
|
if ('\\' == *p) {
|
||||||
|
*p = '/';
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (MKDIR(npath) == -1) {
|
||||||
|
if (errno != EEXIST) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
npath[len++] = *p;
|
npath[len++] = *p;
|
||||||
}
|
}
|
||||||
|
@ -279,7 +286,14 @@ int zip_entry_open(struct zip_t *zip, const char *entryname) {
|
||||||
zip->entry.header_offset = zip->archive.m_archive_size;
|
zip->entry.header_offset = zip->archive.m_archive_size;
|
||||||
memset(zip->entry.header, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8));
|
memset(zip->entry.header, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8));
|
||||||
zip->entry.method = 0;
|
zip->entry.method = 0;
|
||||||
|
|
||||||
|
// UNIX or APPLE
|
||||||
|
#if MZ_PLATFORM == 3 || MZ_PLATFORM == 19
|
||||||
|
// regular file with rw-r--r-- persmissions
|
||||||
|
zip->entry.external_attr = (mz_uint32)(0100644) << 16;
|
||||||
|
#else
|
||||||
zip->entry.external_attr = 0;
|
zip->entry.external_attr = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
num_alignment_padding_bytes =
|
num_alignment_padding_bytes =
|
||||||
mz_zip_writer_compute_padding_needed_for_file_alignment(pzip);
|
mz_zip_writer_compute_padding_needed_for_file_alignment(pzip);
|
||||||
|
@ -660,7 +674,7 @@ ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mz_zip_reader_extract_to_mem_no_alloc(pzip, (mz_uint)zip->entry.index,
|
if (!mz_zip_reader_extract_to_mem_no_alloc(pzip, (mz_uint)zip->entry.index,
|
||||||
buf, bufsize, 0, NULL, 0)) {
|
buf, bufsize, 0, NULL, 0)) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -670,10 +684,7 @@ ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) {
|
||||||
int zip_entry_fread(struct zip_t *zip, const char *filename) {
|
int zip_entry_fread(struct zip_t *zip, const char *filename) {
|
||||||
mz_zip_archive *pzip = NULL;
|
mz_zip_archive *pzip = NULL;
|
||||||
mz_uint idx;
|
mz_uint idx;
|
||||||
#if defined(_MSC_VER)
|
|
||||||
#else
|
|
||||||
mz_uint32 xattr = 0;
|
mz_uint32 xattr = 0;
|
||||||
#endif
|
|
||||||
mz_zip_archive_file_stat info;
|
mz_zip_archive_file_stat info;
|
||||||
|
|
||||||
if (!zip) {
|
if (!zip) {
|
||||||
|
@ -875,12 +886,19 @@ int zip_extract(const char *zipname, const char *dir,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((((info.m_version_made_by >> 8) == 3) || ((info.m_version_made_by >> 8) == 19)) // if zip is produced on Unix or macOS (3 and 19 from section 4.4.2.2 of zip standard)
|
if ((((info.m_version_made_by >> 8) == 3) ||
|
||||||
&& info.m_external_attr & (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40 is directory)
|
((info.m_version_made_by >> 8) ==
|
||||||
|
19)) // if zip is produced on Unix or macOS (3 and 19 from
|
||||||
|
// section 4.4.2.2 of zip standard)
|
||||||
|
&& info.m_external_attr &
|
||||||
|
(0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40
|
||||||
|
// is directory)
|
||||||
#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \
|
#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \
|
||||||
defined(__MINGW32__)
|
defined(__MINGW32__)
|
||||||
#else
|
#else
|
||||||
if (info.m_uncomp_size > MAX_PATH || !mz_zip_reader_extract_to_mem_no_alloc(&zip_archive, i, symlink_to, MAX_PATH, 0, NULL, 0)) {
|
if (info.m_uncomp_size > MAX_PATH ||
|
||||||
|
!mz_zip_reader_extract_to_mem_no_alloc(&zip_archive, i, symlink_to,
|
||||||
|
MAX_PATH, 0, NULL, 0)) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
symlink_to[info.m_uncomp_size] = '\0';
|
symlink_to[info.m_uncomp_size] = '\0';
|
||||||
|
|
|
@ -20,241 +20,240 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(_SSIZE_T_DEFINED) && !defined(_SSIZE_T_DEFINED_) && \
|
#if !defined(_SSIZE_T_DEFINED) && !defined(_SSIZE_T_DEFINED_) && \
|
||||||
!defined(_SSIZE_T) && !defined(_SSIZE_T_) && !defined(__ssize_t_defined)
|
!defined(__DEFINED_ssize_t) && !defined(__ssize_t_defined) && \
|
||||||
#define _SSIZE_T
|
!defined(_SSIZE_T) && !defined(_SSIZE_T_)
|
||||||
|
|
||||||
// 64-bit Windows is the only mainstream platform
|
// 64-bit Windows is the only mainstream platform
|
||||||
// where sizeof(long) != sizeof(void*)
|
// where sizeof(long) != sizeof(void*)
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
typedef long long ssize_t; /* byte count or error */
|
typedef long long ssize_t; /* byte count or error */
|
||||||
#else
|
#else
|
||||||
typedef long ssize_t; /* byte count or error */
|
typedef long ssize_t; /* byte count or error */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define _SSIZE_T_DEFINED
|
||||||
|
#define _SSIZE_T_DEFINED_
|
||||||
|
#define __DEFINED_ssize_t
|
||||||
|
#define __ssize_t_defined
|
||||||
|
#define _SSIZE_T
|
||||||
|
#define _SSIZE_T_
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef MAX_PATH
|
#ifndef MAX_PATH
|
||||||
#define MAX_PATH 32767 /* # chars in a path name including NULL */
|
#define MAX_PATH 32767 /* # chars in a path name including NULL */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @mainpage
|
||||||
|
*
|
||||||
|
* Documenation for @ref zip.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @addtogroup zip
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default zip compression level.
|
||||||
|
*/
|
||||||
|
|
||||||
#define ZIP_DEFAULT_COMPRESSION_LEVEL 6
|
#define ZIP_DEFAULT_COMPRESSION_LEVEL 6
|
||||||
|
|
||||||
/*
|
/**
|
||||||
This data structure is used throughout the library to represent zip archive
|
* @struct zip_t
|
||||||
- forward declaration.
|
*
|
||||||
*/
|
* This data structure is used throughout the library to represent zip archive -
|
||||||
|
* forward declaration.
|
||||||
|
*/
|
||||||
struct zip_t;
|
struct zip_t;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Opens zip archive with compression level using the given mode.
|
* Opens zip archive with compression level using the given mode.
|
||||||
|
*
|
||||||
Args:
|
* @param zipname zip archive file name.
|
||||||
zipname: zip archive file name.
|
* @param level compression level (0-9 are the standard zlib-style levels).
|
||||||
level: compression level (0-9 are the standard zlib-style levels).
|
* @param mode file access mode.
|
||||||
mode: file access mode.
|
* - 'r': opens a file for reading/extracting (the file must exists).
|
||||||
'r': opens a file for reading/extracting (the file must exists).
|
* - 'w': creates an empty file for writing.
|
||||||
'w': creates an empty file for writing.
|
* - 'a': appends to an existing archive.
|
||||||
'a': appends to an existing archive.
|
*
|
||||||
|
* @return the zip archive handler or NULL on error
|
||||||
Returns:
|
*/
|
||||||
The zip archive handler or NULL on error
|
|
||||||
*/
|
|
||||||
extern struct zip_t *zip_open(const char *zipname, int level, char mode);
|
extern struct zip_t *zip_open(const char *zipname, int level, char mode);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Closes the zip archive, releases resources - always finalize.
|
* Closes the zip archive, releases resources - always finalize.
|
||||||
|
*
|
||||||
Args:
|
* @param zip zip archive handler.
|
||||||
zip: zip archive handler.
|
*/
|
||||||
*/
|
|
||||||
extern void zip_close(struct zip_t *zip);
|
extern void zip_close(struct zip_t *zip);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Opens an entry by name in the zip archive.
|
* Opens an entry by name in the zip archive.
|
||||||
For zip archive opened in 'w' or 'a' mode the function will append
|
*
|
||||||
a new entry. In readonly mode the function tries to locate the entry
|
* For zip archive opened in 'w' or 'a' mode the function will append
|
||||||
in global dictionary.
|
* a new entry. In readonly mode the function tries to locate the entry
|
||||||
|
* in global dictionary.
|
||||||
Args:
|
*
|
||||||
zip: zip archive handler.
|
* @param zip zip archive handler.
|
||||||
entryname: an entry name in local dictionary.
|
* @param entryname an entry name in local dictionary.
|
||||||
|
*
|
||||||
Returns:
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
The return code - 0 on success, negative number (< 0) on error.
|
*/
|
||||||
*/
|
|
||||||
extern int zip_entry_open(struct zip_t *zip, const char *entryname);
|
extern int zip_entry_open(struct zip_t *zip, const char *entryname);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Opens a new entry by index in the zip archive.
|
* Opens a new entry by index in the zip archive.
|
||||||
This function is only valid if zip archive was opened in 'r' (readonly) mode.
|
*
|
||||||
|
* This function is only valid if zip archive was opened in 'r' (readonly) mode.
|
||||||
Args:
|
*
|
||||||
zip: zip archive handler.
|
* @param zip zip archive handler.
|
||||||
index: index in local dictionary.
|
* @param index index in local dictionary.
|
||||||
|
*
|
||||||
Returns:
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
The return code - 0 on success, negative number (< 0) on error.
|
*/
|
||||||
*/
|
|
||||||
extern int zip_entry_openbyindex(struct zip_t *zip, int index);
|
extern int zip_entry_openbyindex(struct zip_t *zip, int index);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Closes a zip entry, flushes buffer and releases resources.
|
* Closes a zip entry, flushes buffer and releases resources.
|
||||||
|
*
|
||||||
Args:
|
* @param zip zip archive handler.
|
||||||
zip: zip archive handler.
|
*
|
||||||
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
Returns:
|
*/
|
||||||
The return code - 0 on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_entry_close(struct zip_t *zip);
|
extern int zip_entry_close(struct zip_t *zip);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Returns a local name of the current zip entry.
|
* Returns a local name of the current zip entry.
|
||||||
The main difference between user's entry name and local entry name
|
*
|
||||||
is optional relative path.
|
* The main difference between user's entry name and local entry name
|
||||||
Following .ZIP File Format Specification - the path stored MUST not contain
|
* is optional relative path.
|
||||||
a drive or device letter, or a leading slash.
|
* Following .ZIP File Format Specification - the path stored MUST not contain
|
||||||
All slashes MUST be forward slashes '/' as opposed to backwards slashes '\'
|
* a drive or device letter, or a leading slash.
|
||||||
for compatibility with Amiga and UNIX file systems etc.
|
* All slashes MUST be forward slashes '/' as opposed to backwards slashes '\'
|
||||||
|
* for compatibility with Amiga and UNIX file systems etc.
|
||||||
Args:
|
*
|
||||||
zip: zip archive handler.
|
* @param zip: zip archive handler.
|
||||||
|
*
|
||||||
Returns:
|
* @return the pointer to the current zip entry name, or NULL on error.
|
||||||
The pointer to the current zip entry name, or NULL on error.
|
*/
|
||||||
*/
|
|
||||||
extern const char *zip_entry_name(struct zip_t *zip);
|
extern const char *zip_entry_name(struct zip_t *zip);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Returns an index of the current zip entry.
|
* Returns an index of the current zip entry.
|
||||||
|
*
|
||||||
Args:
|
* @param zip zip archive handler.
|
||||||
zip: zip archive handler.
|
*
|
||||||
|
* @return the index on success, negative number (< 0) on error.
|
||||||
Returns:
|
*/
|
||||||
The index on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_entry_index(struct zip_t *zip);
|
extern int zip_entry_index(struct zip_t *zip);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Determines if the current zip entry is a directory entry.
|
* Determines if the current zip entry is a directory entry.
|
||||||
|
*
|
||||||
Args:
|
* @param zip zip archive handler.
|
||||||
zip: zip archive handler.
|
*
|
||||||
|
* @return the return code - 1 (true), 0 (false), negative number (< 0) on
|
||||||
Returns:
|
* error.
|
||||||
The return code - 1 (true), 0 (false), negative number (< 0) on error.
|
*/
|
||||||
*/
|
|
||||||
extern int zip_entry_isdir(struct zip_t *zip);
|
extern int zip_entry_isdir(struct zip_t *zip);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Returns an uncompressed size of the current zip entry.
|
* Returns an uncompressed size of the current zip entry.
|
||||||
|
*
|
||||||
Args:
|
* @param zip zip archive handler.
|
||||||
zip: zip archive handler.
|
*
|
||||||
|
* @return the uncompressed size in bytes.
|
||||||
Returns:
|
*/
|
||||||
The uncompressed size in bytes.
|
|
||||||
*/
|
|
||||||
extern unsigned long long zip_entry_size(struct zip_t *zip);
|
extern unsigned long long zip_entry_size(struct zip_t *zip);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Returns CRC-32 checksum of the current zip entry.
|
* Returns CRC-32 checksum of the current zip entry.
|
||||||
|
*
|
||||||
Args:
|
* @param zip zip archive handler.
|
||||||
zip: zip archive handler.
|
*
|
||||||
|
* @return the CRC-32 checksum.
|
||||||
Returns:
|
*/
|
||||||
The CRC-32 checksum.
|
|
||||||
*/
|
|
||||||
extern unsigned int zip_entry_crc32(struct zip_t *zip);
|
extern unsigned int zip_entry_crc32(struct zip_t *zip);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Compresses an input buffer for the current zip entry.
|
* Compresses an input buffer for the current zip entry.
|
||||||
|
*
|
||||||
Args:
|
* @param zip zip archive handler.
|
||||||
zip: zip archive handler.
|
* @param buf input buffer.
|
||||||
buf: input buffer.
|
* @param bufsize input buffer size (in bytes).
|
||||||
bufsize: input buffer size (in bytes).
|
*
|
||||||
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
Returns:
|
*/
|
||||||
The return code - 0 on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
|
extern int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Compresses a file for the current zip entry.
|
* Compresses a file for the current zip entry.
|
||||||
|
*
|
||||||
Args:
|
* @param zip zip archive handler.
|
||||||
zip: zip archive handler.
|
* @param filename input file.
|
||||||
filename: input file.
|
*
|
||||||
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
Returns:
|
*/
|
||||||
The return code - 0 on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_entry_fwrite(struct zip_t *zip, const char *filename);
|
extern int zip_entry_fwrite(struct zip_t *zip, const char *filename);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Extracts the current zip entry into output buffer.
|
* Extracts the current zip entry into output buffer.
|
||||||
The function allocates sufficient memory for a output buffer.
|
*
|
||||||
|
* The function allocates sufficient memory for a output buffer.
|
||||||
Args:
|
*
|
||||||
zip: zip archive handler.
|
* @param zip zip archive handler.
|
||||||
buf: output buffer.
|
* @param buf output buffer.
|
||||||
bufsize: output buffer size (in bytes).
|
* @param bufsize output buffer size (in bytes).
|
||||||
|
*
|
||||||
Note:
|
* @note remember to release memory allocated for a output buffer.
|
||||||
- remember to release memory allocated for a output buffer.
|
* for large entries, please take a look at zip_entry_extract function.
|
||||||
- for large entries, please take a look at zip_entry_extract function.
|
*
|
||||||
|
* @return the return code - the number of bytes actually read on success.
|
||||||
Returns:
|
* Otherwise a -1 on error.
|
||||||
The return code - the number of bytes actually read on success.
|
*/
|
||||||
Otherwise a -1 on error.
|
|
||||||
*/
|
|
||||||
extern ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize);
|
extern ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Extracts the current zip entry into a memory buffer using no memory
|
* Extracts the current zip entry into a memory buffer using no memory
|
||||||
allocation.
|
* allocation.
|
||||||
|
*
|
||||||
|
* @param zip zip archive handler.
|
||||||
|
* @param buf preallocated output buffer.
|
||||||
|
* @param bufsize output buffer size (in bytes).
|
||||||
|
*
|
||||||
|
* @note ensure supplied output buffer is large enough.
|
||||||
|
* zip_entry_size function (returns uncompressed size for the current
|
||||||
|
* entry) can be handy to estimate how big buffer is needed. for large
|
||||||
|
* entries, please take a look at zip_entry_extract function.
|
||||||
|
*
|
||||||
|
* @return the return code - the number of bytes actually read on success.
|
||||||
|
* Otherwise a -1 on error (e.g. bufsize is not large enough).
|
||||||
|
*/
|
||||||
|
extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf,
|
||||||
|
size_t bufsize);
|
||||||
|
|
||||||
Args:
|
/**
|
||||||
zip: zip archive handler.
|
* Extracts the current zip entry into output file.
|
||||||
buf: preallocated output buffer.
|
*
|
||||||
bufsize: output buffer size (in bytes).
|
* @param zip zip archive handler.
|
||||||
|
* @param filename output file.
|
||||||
Note:
|
*
|
||||||
- ensure supplied output buffer is large enough.
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
- zip_entry_size function (returns uncompressed size for the current entry)
|
*/
|
||||||
can be handy to estimate how big buffer is needed.
|
|
||||||
- for large entries, please take a look at zip_entry_extract function.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The return code - the number of bytes actually read on success.
|
|
||||||
Otherwise a -1 on error (e.g. bufsize is not large enough).
|
|
||||||
*/
|
|
||||||
extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize);
|
|
||||||
|
|
||||||
/*
|
|
||||||
Extracts the current zip entry into output file.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
zip: zip archive handler.
|
|
||||||
filename: output file.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
The return code - 0 on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_entry_fread(struct zip_t *zip, const char *filename);
|
extern int zip_entry_fread(struct zip_t *zip, const char *filename);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Extracts the current zip entry using a callback function (on_extract).
|
* Extracts the current zip entry using a callback function (on_extract).
|
||||||
|
*
|
||||||
Args:
|
* @param zip zip archive handler.
|
||||||
zip: zip archive handler.
|
* @param on_extract callback function.
|
||||||
on_extract: callback function.
|
* @param arg opaque pointer (optional argument, which you can pass to the
|
||||||
arg: opaque pointer (optional argument,
|
* on_extract callback)
|
||||||
which you can pass to the on_extract callback)
|
*
|
||||||
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
Returns:
|
|
||||||
The return code - 0 on success, negative number (< 0) on error.
|
|
||||||
*/
|
*/
|
||||||
extern int
|
extern int
|
||||||
zip_entry_extract(struct zip_t *zip,
|
zip_entry_extract(struct zip_t *zip,
|
||||||
|
@ -262,53 +261,49 @@ zip_entry_extract(struct zip_t *zip,
|
||||||
const void *data, size_t size),
|
const void *data, size_t size),
|
||||||
void *arg);
|
void *arg);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Returns the number of all entries (files and directories) in the zip archive.
|
* Returns the number of all entries (files and directories) in the zip archive.
|
||||||
|
*
|
||||||
Args:
|
* @param zip zip archive handler.
|
||||||
zip: zip archive handler.
|
*
|
||||||
|
* @return the return code - the number of entries on success, negative number
|
||||||
Returns:
|
* (< 0) on error.
|
||||||
The return code - the number of entries on success,
|
*/
|
||||||
negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_total_entries(struct zip_t *zip);
|
extern int zip_total_entries(struct zip_t *zip);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Creates a new archive and puts files into a single zip archive.
|
* Creates a new archive and puts files into a single zip archive.
|
||||||
|
*
|
||||||
Args:
|
* @param zipname zip archive file.
|
||||||
zipname: zip archive file.
|
* @param filenames input files.
|
||||||
filenames: input files.
|
* @param len: number of input files.
|
||||||
len: number of input files.
|
*
|
||||||
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
Returns:
|
*/
|
||||||
The return code - 0 on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_create(const char *zipname, const char *filenames[], size_t len);
|
extern int zip_create(const char *zipname, const char *filenames[], size_t len);
|
||||||
|
|
||||||
/*
|
/**
|
||||||
Extracts a zip archive file into directory.
|
* Extracts a zip archive file into directory.
|
||||||
|
*
|
||||||
If on_extract_entry is not NULL, the callback will be called after
|
* If on_extract_entry is not NULL, the callback will be called after
|
||||||
successfully extracted each zip entry.
|
* successfully extracted each zip entry.
|
||||||
Returning a negative value from the callback will cause abort and return an
|
* Returning a negative value from the callback will cause abort and return an
|
||||||
error. The last argument (void *arg) is optional, which you can use to pass
|
* error. The last argument (void *arg) is optional, which you can use to pass
|
||||||
data to the on_extract_entry callback.
|
* data to the on_extract_entry callback.
|
||||||
|
*
|
||||||
Args:
|
* @param zipname zip archive file.
|
||||||
zipname: zip archive file.
|
* @param dir output directory.
|
||||||
dir: output directory.
|
* @param on_extract_entry on extract callback.
|
||||||
on_extract_entry: on extract callback.
|
* @param arg opaque pointer.
|
||||||
arg: opaque pointer.
|
*
|
||||||
|
* @return the return code - 0 on success, negative number (< 0) on error.
|
||||||
Returns:
|
*/
|
||||||
The return code - 0 on success, negative number (< 0) on error.
|
|
||||||
*/
|
|
||||||
extern int zip_extract(const char *zipname, const char *dir,
|
extern int zip_extract(const char *zipname, const char *dir,
|
||||||
int (*on_extract_entry)(const char *filename, void *arg),
|
int (*on_extract_entry)(const char *filename, void *arg),
|
||||||
void *arg);
|
void *arg);
|
||||||
|
|
||||||
|
/** @} */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
cmake_minimum_required(VERSION 2.8)
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
|
||||||
if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang")
|
|
||||||
if(ENABLE_COVERAGE)
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g ")
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs")
|
|
||||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftest-coverage")
|
|
||||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
|
|
||||||
endif()
|
|
||||||
endif ()
|
|
||||||
|
|
||||||
# test
|
# test
|
||||||
include_directories(../src)
|
set(test_out test.out)
|
||||||
add_executable(test.exe test.c ../src/zip.c)
|
set(test_miniz_out test_miniz.out)
|
||||||
add_executable(test_miniz.exe test_miniz.c)
|
|
||||||
|
|
||||||
add_test(NAME test COMMAND test.exe)
|
add_executable(${test_out} test.c)
|
||||||
add_test(NAME test_miniz COMMAND test_miniz.exe)
|
target_link_libraries(${test_out} zip)
|
||||||
|
add_executable(${test_miniz_out} test_miniz.c)
|
||||||
|
target_link_libraries(${test_miniz_out} zip)
|
||||||
|
|
||||||
|
add_test(NAME ${test_out} COMMAND ${test_out})
|
||||||
|
add_test(NAME ${test_miniz_out} COMMAND ${test_miniz_out})
|
||||||
|
|
||||||
|
set(test_out ${test_out} PARENT_SCOPE)
|
||||||
|
set(test_miniz_out ${test_miniz_out} PARENT_SCOPE)
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
#define XFILE "7.txt\0"
|
#define XFILE "7.txt\0"
|
||||||
#define XMODE 0100777
|
#define XMODE 0100777
|
||||||
|
|
||||||
|
#define UNIXMODE 0100644
|
||||||
|
|
||||||
#define UNUSED(x) (void)x
|
#define UNUSED(x) (void)x
|
||||||
|
|
||||||
static int total_entries = 0;
|
static int total_entries = 0;
|
||||||
|
@ -102,7 +104,8 @@ static void test_read(void) {
|
||||||
assert(0 == zip_entry_close(zip));
|
assert(0 == zip_entry_close(zip));
|
||||||
free(buf);
|
free(buf);
|
||||||
buf = NULL;
|
buf = NULL;
|
||||||
|
bufsize = 0;
|
||||||
|
|
||||||
assert(0 == zip_entry_open(zip, "test/test-2.txt"));
|
assert(0 == zip_entry_open(zip, "test/test-2.txt"));
|
||||||
assert(strlen(TESTDATA2) == zip_entry_size(zip));
|
assert(strlen(TESTDATA2) == zip_entry_size(zip));
|
||||||
assert(CRC32DATA2 == zip_entry_crc32(zip));
|
assert(CRC32DATA2 == zip_entry_crc32(zip));
|
||||||
|
@ -131,7 +134,8 @@ static void test_read(void) {
|
||||||
assert(0 == zip_entry_close(zip));
|
assert(0 == zip_entry_close(zip));
|
||||||
free(buf);
|
free(buf);
|
||||||
buf = NULL;
|
buf = NULL;
|
||||||
|
bufsize = 0;
|
||||||
|
|
||||||
buftmp = strlen(TESTDATA1);
|
buftmp = strlen(TESTDATA1);
|
||||||
buf = calloc(buftmp, sizeof(char));
|
buf = calloc(buftmp, sizeof(char));
|
||||||
assert(0 == zip_entry_open(zip, "test/test-1.txt"));
|
assert(0 == zip_entry_open(zip, "test/test-1.txt"));
|
||||||
|
@ -433,6 +437,35 @@ static void test_mtime(void) {
|
||||||
remove(ZIPNAME);
|
remove(ZIPNAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_unix_permissions(void) {
|
||||||
|
#if defined(_WIN64) || defined(_WIN32) || defined(__WIN32__)
|
||||||
|
#else
|
||||||
|
// UNIX or APPLE
|
||||||
|
struct MZ_FILE_STAT_STRUCT file_stats;
|
||||||
|
|
||||||
|
remove(ZIPNAME);
|
||||||
|
|
||||||
|
struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w');
|
||||||
|
assert(zip != NULL);
|
||||||
|
|
||||||
|
assert(0 == zip_entry_open(zip, RFILE));
|
||||||
|
assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1)));
|
||||||
|
assert(0 == zip_entry_close(zip));
|
||||||
|
|
||||||
|
zip_close(zip);
|
||||||
|
|
||||||
|
remove(RFILE);
|
||||||
|
|
||||||
|
assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL));
|
||||||
|
|
||||||
|
assert(0 == MZ_FILE_STAT(RFILE, &file_stats));
|
||||||
|
assert(UNIXMODE == file_stats.st_mode);
|
||||||
|
|
||||||
|
remove(RFILE);
|
||||||
|
remove(ZIPNAME);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
UNUSED(argc);
|
UNUSED(argc);
|
||||||
UNUSED(argv);
|
UNUSED(argv);
|
||||||
|
@ -453,6 +486,7 @@ int main(int argc, char *argv[]) {
|
||||||
test_write_permissions();
|
test_write_permissions();
|
||||||
test_exe_permissions();
|
test_exe_permissions();
|
||||||
test_mtime();
|
test_mtime();
|
||||||
|
test_unix_permissions();
|
||||||
|
|
||||||
remove(ZIPNAME);
|
remove(ZIPNAME);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -23,16 +23,39 @@ int main(int argc, char *argv[]) {
|
||||||
uint step = 0;
|
uint step = 0;
|
||||||
int cmp_status;
|
int cmp_status;
|
||||||
uLong src_len = (uLong)strlen(s_pStr);
|
uLong src_len = (uLong)strlen(s_pStr);
|
||||||
uLong cmp_len = compressBound(src_len);
|
|
||||||
uLong uncomp_len = src_len;
|
uLong uncomp_len = src_len;
|
||||||
|
uLong cmp_len;
|
||||||
uint8 *pCmp, *pUncomp;
|
uint8 *pCmp, *pUncomp;
|
||||||
|
size_t sz;
|
||||||
uint total_succeeded = 0;
|
uint total_succeeded = 0;
|
||||||
(void)argc, (void)argv;
|
(void)argc, (void)argv;
|
||||||
|
|
||||||
printf("miniz.c version: %s\n", MZ_VERSION);
|
printf("miniz.c version: %s\n", MZ_VERSION);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
pCmp = (uint8 *)tdefl_compress_mem_to_heap(s_pStr, src_len, &cmp_len, 0);
|
||||||
|
if (!pCmp) {
|
||||||
|
printf("tdefl_compress_mem_to_heap failed\n");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
if (src_len <= cmp_len) {
|
||||||
|
printf("tdefl_compress_mem_to_heap failed: from %u to %u bytes\n",
|
||||||
|
(mz_uint32)uncomp_len, (mz_uint32)cmp_len);
|
||||||
|
free(pCmp);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
sz = tdefl_compress_mem_to_mem(pCmp, cmp_len, s_pStr, src_len, 0);
|
||||||
|
if (sz != cmp_len) {
|
||||||
|
printf("tdefl_compress_mem_to_mem failed: expected %u, got %u\n",
|
||||||
|
(mz_uint32)cmp_len, (mz_uint32)sz);
|
||||||
|
free(pCmp);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
// Allocate buffers to hold compressed and uncompressed data.
|
// Allocate buffers to hold compressed and uncompressed data.
|
||||||
|
free(pCmp);
|
||||||
|
cmp_len = compressBound(src_len);
|
||||||
pCmp = (mz_uint8 *)malloc((size_t)cmp_len);
|
pCmp = (mz_uint8 *)malloc((size_t)cmp_len);
|
||||||
pUncomp = (mz_uint8 *)malloc((size_t)src_len);
|
pUncomp = (mz_uint8 *)malloc((size_t)src_len);
|
||||||
if ((!pCmp) || (!pUncomp)) {
|
if ((!pCmp) || (!pUncomp)) {
|
||||||
|
|
|
@ -41,9 +41,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file Definition of the base class for all importer worker classes. */
|
/** @file Definition of the base class for all importer worker classes. */
|
||||||
|
#pragma once
|
||||||
#ifndef INCLUDED_AI_BASEIMPORTER_H
|
#ifndef INCLUDED_AI_BASEIMPORTER_H
|
||||||
#define INCLUDED_AI_BASEIMPORTER_H
|
#define INCLUDED_AI_BASEIMPORTER_H
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Exceptional.h"
|
#include "Exceptional.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -191,16 +196,13 @@ public:
|
||||||
/**
|
/**
|
||||||
* Assimp Importer
|
* Assimp Importer
|
||||||
* unit conversions available
|
* unit conversions available
|
||||||
* if you need another measurment unit add it below.
|
* NOTE: Valid options are initialised in the
|
||||||
* it's currently defined in assimp that we prefer meters.
|
* constructor in the implementation file to
|
||||||
|
* work around a VS2013 compiler bug if support
|
||||||
|
* for that compiler is dropped in the future
|
||||||
|
* initialisation can be moved back here
|
||||||
* */
|
* */
|
||||||
std::map<ImporterUnits, double> importerUnits = {
|
std::map<ImporterUnits, double> importerUnits;
|
||||||
{ImporterUnits::M, 1},
|
|
||||||
{ImporterUnits::CM, 0.01},
|
|
||||||
{ImporterUnits::MM, 0.001},
|
|
||||||
{ImporterUnits::INCHES, 0.0254},
|
|
||||||
{ImporterUnits::FEET, 0.3048}
|
|
||||||
};
|
|
||||||
|
|
||||||
virtual void SetApplicationUnits( const ImporterUnits& unit )
|
virtual void SetApplicationUnits( const ImporterUnits& unit )
|
||||||
{
|
{
|
||||||
|
|
|
@ -46,10 +46,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* Used for file formats which embed their textures into the model file.
|
* Used for file formats which embed their textures into the model file.
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
#ifndef AI_BITMAP_H_INC
|
#ifndef AI_BITMAP_H_INC
|
||||||
#define AI_BITMAP_H_INC
|
#define AI_BITMAP_H_INC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
|
@ -42,9 +42,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
/** @file Helper class tp perform various byte oder swappings
|
/** @file Helper class tp perform various byte oder swappings
|
||||||
(e.g. little to big endian) */
|
(e.g. little to big endian) */
|
||||||
|
#pragma once
|
||||||
#ifndef AI_BYTESWAPPER_H_INC
|
#ifndef AI_BYTESWAPPER_H_INC
|
||||||
#define AI_BYTESWAPPER_H_INC
|
#define AI_BYTESWAPPER_H_INC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <assimp/ai_assert.h>
|
#include <assimp/ai_assert.h>
|
||||||
#include <assimp/types.h>
|
#include <assimp/types.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
|
@ -43,16 +43,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
/** @file CreateAnimMesh.h
|
/** @file CreateAnimMesh.h
|
||||||
* Create AnimMesh from Mesh
|
* Create AnimMesh from Mesh
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
#ifndef INCLUDED_AI_CREATE_ANIM_MESH_H
|
#ifndef INCLUDED_AI_CREATE_ANIM_MESH_H
|
||||||
#define INCLUDED_AI_CREATE_ANIM_MESH_H
|
#define INCLUDED_AI_CREATE_ANIM_MESH_H
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <assimp/mesh.h>
|
#include <assimp/mesh.h>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
/** Create aiAnimMesh from aiMesh. */
|
/**
|
||||||
|
* Create aiAnimMesh from aiMesh.
|
||||||
|
* @param mesh The input mesh to create an animated mesh from.
|
||||||
|
* @return The new created animated mesh.
|
||||||
|
*/
|
||||||
ASSIMP_API aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh);
|
ASSIMP_API aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh);
|
||||||
|
|
||||||
} // end of namespace Assimp
|
} // end of namespace Assimp
|
||||||
|
|
||||||
#endif // INCLUDED_AI_CREATE_ANIM_MESH_H
|
#endif // INCLUDED_AI_CREATE_ANIM_MESH_H
|
||||||
|
|
||||||
|
|
|
@ -41,15 +41,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file Default file I/O using fXXX()-family of functions */
|
/** @file Default file I/O using fXXX()-family of functions */
|
||||||
|
#pragma once
|
||||||
#ifndef AI_DEFAULTIOSTREAM_H_INC
|
#ifndef AI_DEFAULTIOSTREAM_H_INC
|
||||||
#define AI_DEFAULTIOSTREAM_H_INC
|
#define AI_DEFAULTIOSTREAM_H_INC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <assimp/IOStream.hpp>
|
#include <assimp/IOStream.hpp>
|
||||||
#include <assimp/importerdesc.h>
|
#include <assimp/importerdesc.h>
|
||||||
#include <assimp/Defines.h>
|
#include <assimp/Defines.h>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
//! @class DefaultIOStream
|
//! @class DefaultIOStream
|
||||||
|
@ -57,8 +62,7 @@ namespace Assimp {
|
||||||
//! @note An instance of this class can exist without a valid file handle
|
//! @note An instance of this class can exist without a valid file handle
|
||||||
//! attached to it. All calls fail, but the instance can nevertheless be
|
//! attached to it. All calls fail, but the instance can nevertheless be
|
||||||
//! used with no restrictions.
|
//! used with no restrictions.
|
||||||
class ASSIMP_API DefaultIOStream : public IOStream
|
class ASSIMP_API DefaultIOStream : public IOStream {
|
||||||
{
|
|
||||||
friend class DefaultIOSystem;
|
friend class DefaultIOSystem;
|
||||||
#if __ANDROID__
|
#if __ANDROID__
|
||||||
# if __ANDROID_API__ > 9
|
# if __ANDROID_API__ > 9
|
||||||
|
@ -82,7 +86,6 @@ public:
|
||||||
size_t pSize,
|
size_t pSize,
|
||||||
size_t pCount);
|
size_t pCount);
|
||||||
|
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
/// Write to stream
|
/// Write to stream
|
||||||
size_t Write(const void* pvBuffer,
|
size_t Write(const void* pvBuffer,
|
||||||
|
@ -107,16 +110,13 @@ public:
|
||||||
void Flush();
|
void Flush();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// File data-structure, using clib
|
|
||||||
FILE* mFile;
|
FILE* mFile;
|
||||||
// Filename
|
|
||||||
std::string mFilename;
|
std::string mFilename;
|
||||||
// Cached file size
|
|
||||||
mutable size_t mCachedSize;
|
mutable size_t mCachedSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
DefaultIOStream::DefaultIOStream() AI_NO_EXCEPT
|
DefaultIOStream::DefaultIOStream() AI_NO_EXCEPT
|
||||||
: mFile(nullptr)
|
: mFile(nullptr)
|
||||||
, mFilename("")
|
, mFilename("")
|
||||||
|
@ -125,7 +125,7 @@ DefaultIOStream::DefaultIOStream() AI_NO_EXCEPT
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
DefaultIOStream::DefaultIOStream (FILE* pFile, const std::string &strFilename)
|
DefaultIOStream::DefaultIOStream (FILE* pFile, const std::string &strFilename)
|
||||||
: mFile(pFile)
|
: mFile(pFile)
|
||||||
, mFilename(strFilename)
|
, mFilename(strFilename)
|
||||||
|
@ -137,4 +137,3 @@ DefaultIOStream::DefaultIOStream (FILE* pFile, const std::string &strFilename)
|
||||||
} // ns assimp
|
} // ns assimp
|
||||||
|
|
||||||
#endif //!!AI_DEFAULTIOSTREAM_H_INC
|
#endif //!!AI_DEFAULTIOSTREAM_H_INC
|
||||||
|
|
||||||
|
|
|
@ -41,9 +41,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @file Default implementation of IOSystem using the standard C file functions */
|
/** @file Default implementation of IOSystem using the standard C file functions */
|
||||||
|
#pragma once
|
||||||
#ifndef AI_DEFAULTIOSYSTEM_H_INC
|
#ifndef AI_DEFAULTIOSYSTEM_H_INC
|
||||||
#define AI_DEFAULTIOSYSTEM_H_INC
|
#define AI_DEFAULTIOSYSTEM_H_INC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <assimp/IOSystem.hpp>
|
#include <assimp/IOSystem.hpp>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
|
@ -38,6 +38,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef AI_DEFINES_H_INC
|
||||||
|
#define AI_DEFINES_H_INC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
// We need those constants, workaround for any platforms where nobody defined them yet
|
// We need those constants, workaround for any platforms where nobody defined them yet
|
||||||
#if (!defined SIZE_MAX)
|
#if (!defined SIZE_MAX)
|
||||||
# define SIZE_MAX (~((size_t)0))
|
# define SIZE_MAX (~((size_t)0))
|
||||||
|
@ -47,3 +55,4 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
# define UINT_MAX (~((unsigned int)0))
|
# define UINT_MAX (~((unsigned int)0))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif // AI_DEINES_H_INC
|
||||||
|
|
|
@ -38,11 +38,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef INCLUDED_EXCEPTIONAL_H
|
#pragma once
|
||||||
#define INCLUDED_EXCEPTIONAL_H
|
#ifndef AI_INCLUDED_EXCEPTIONAL_H
|
||||||
|
#define AI_INCLUDED_EXCEPTIONAL_H
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <assimp/DefaultIOStream.h>
|
#include <assimp/DefaultIOStream.h>
|
||||||
|
|
||||||
using std::runtime_error;
|
using std::runtime_error;
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
|
@ -53,17 +59,14 @@ using std::runtime_error;
|
||||||
/** FOR IMPORTER PLUGINS ONLY: Simple exception class to be thrown if an
|
/** FOR IMPORTER PLUGINS ONLY: Simple exception class to be thrown if an
|
||||||
* unrecoverable error occurs while importing. Loading APIs return
|
* unrecoverable error occurs while importing. Loading APIs return
|
||||||
* NULL instead of a valid aiScene then. */
|
* NULL instead of a valid aiScene then. */
|
||||||
class DeadlyImportError
|
class DeadlyImportError : public runtime_error {
|
||||||
: public runtime_error
|
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
/** Constructor with arguments */
|
/** Constructor with arguments */
|
||||||
explicit DeadlyImportError( const std::string& errorText)
|
explicit DeadlyImportError( const std::string& errorText)
|
||||||
: runtime_error(errorText)
|
: runtime_error(errorText) {
|
||||||
{
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef DeadlyImportError DeadlyExportError;
|
typedef DeadlyImportError DeadlyExportError;
|
||||||
|
@ -84,7 +87,7 @@ struct ExceptionSwallower {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct ExceptionSwallower<T*> {
|
struct ExceptionSwallower<T*> {
|
||||||
T* operator ()() const {
|
T* operator ()() const {
|
||||||
return NULL;
|
return nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -122,4 +125,4 @@ struct ExceptionSwallower<void> {
|
||||||
}\
|
}\
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // INCLUDED_EXCEPTIONAL_H
|
#endif // AI_INCLUDED_EXCEPTIONAL_H
|
||||||
|
|
|
@ -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,
|
||||||
|
@ -48,6 +46,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef AI_EXPORT_HPP_INC
|
#ifndef AI_EXPORT_HPP_INC
|
||||||
#define AI_EXPORT_HPP_INC
|
#define AI_EXPORT_HPP_INC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef ASSIMP_BUILD_NO_EXPORT
|
#ifndef ASSIMP_BUILD_NO_EXPORT
|
||||||
|
|
||||||
#include "cexport.h"
|
#include "cexport.h"
|
||||||
|
|
|
@ -40,12 +40,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
#ifndef AI_GENERIC_PROPERTY_H_INCLUDED
|
#ifndef AI_GENERIC_PROPERTY_H_INCLUDED
|
||||||
#define AI_GENERIC_PROPERTY_H_INCLUDED
|
#define AI_GENERIC_PROPERTY_H_INCLUDED
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <assimp/Importer.hpp>
|
#include <assimp/Importer.hpp>
|
||||||
#include <assimp/ai_assert.h>
|
#include <assimp/ai_assert.h>
|
||||||
#include "Hash.h"
|
#include <assimp/Hash.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
|
|
@ -39,10 +39,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
#ifndef AI_HASH_H_INCLUDED
|
#ifndef AI_HASH_H_INCLUDED
|
||||||
#define AI_HASH_H_INCLUDED
|
#define AI_HASH_H_INCLUDED
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
|
@ -48,14 +48,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef AI_IOSTREAM_H_INC
|
#ifndef AI_IOSTREAM_H_INC
|
||||||
#define AI_IOSTREAM_H_INC
|
#define AI_IOSTREAM_H_INC
|
||||||
|
|
||||||
#include "types.h"
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <assimp/types.h>
|
||||||
|
|
||||||
#ifndef __cplusplus
|
#ifndef __cplusplus
|
||||||
# error This header requires C++ to be used. aiFileIO.h is the \
|
# error This header requires C++ to be used. aiFileIO.h is the \
|
||||||
corresponding C interface.
|
corresponding C interface.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
/** @brief CPP-API: Class to handle file I/O for C++
|
/** @brief CPP-API: Class to handle file I/O for C++
|
||||||
|
@ -125,13 +129,13 @@ public:
|
||||||
}; //! class IOStream
|
}; //! class IOStream
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
IOStream::IOStream() AI_NO_EXCEPT {
|
IOStream::IOStream() AI_NO_EXCEPT {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
IOStream::~IOStream() {
|
IOStream::~IOStream() {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Open Asset Import Library (assimp)
|
Open Asset Import Library (assimp)
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
|
@ -42,10 +40,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
----------------------------------------------------------------------
|
----------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#ifndef AI_IOSTREAMBUFFER_H_INC
|
||||||
|
#define AI_IOSTREAMBUFFER_H_INC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <assimp/types.h>
|
#include <assimp/types.h>
|
||||||
#include <assimp/IOStream.hpp>
|
#include <assimp/IOStream.hpp>
|
||||||
|
#include <assimp/ParsingUtils.h>
|
||||||
#include "ParsingUtils.h"
|
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
@ -124,7 +129,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
IOStreamBuffer<T>::IOStreamBuffer( size_t cache )
|
IOStreamBuffer<T>::IOStreamBuffer( size_t cache )
|
||||||
: m_stream( nullptr )
|
: m_stream( nullptr )
|
||||||
, m_filesize( 0 )
|
, m_filesize( 0 )
|
||||||
|
@ -138,13 +143,13 @@ IOStreamBuffer<T>::IOStreamBuffer( size_t cache )
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
IOStreamBuffer<T>::~IOStreamBuffer() {
|
IOStreamBuffer<T>::~IOStreamBuffer() {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
bool IOStreamBuffer<T>::open( IOStream *stream ) {
|
bool IOStreamBuffer<T>::open( IOStream *stream ) {
|
||||||
// file still opened!
|
// file still opened!
|
||||||
if ( nullptr != m_stream ) {
|
if ( nullptr != m_stream ) {
|
||||||
|
@ -174,7 +179,7 @@ bool IOStreamBuffer<T>::open( IOStream *stream ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
bool IOStreamBuffer<T>::close() {
|
bool IOStreamBuffer<T>::close() {
|
||||||
if ( nullptr == m_stream ) {
|
if ( nullptr == m_stream ) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -192,19 +197,19 @@ bool IOStreamBuffer<T>::close() {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
size_t IOStreamBuffer<T>::size() const {
|
size_t IOStreamBuffer<T>::size() const {
|
||||||
return m_filesize;
|
return m_filesize;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
size_t IOStreamBuffer<T>::cacheSize() const {
|
size_t IOStreamBuffer<T>::cacheSize() const {
|
||||||
return m_cacheSize;
|
return m_cacheSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
bool IOStreamBuffer<T>::readNextBlock() {
|
bool IOStreamBuffer<T>::readNextBlock() {
|
||||||
m_stream->Seek( m_filePos, aiOrigin_SET );
|
m_stream->Seek( m_filePos, aiOrigin_SET );
|
||||||
size_t readLen = m_stream->Read( &m_cache[ 0 ], sizeof( T ), m_cacheSize );
|
size_t readLen = m_stream->Read( &m_cache[ 0 ], sizeof( T ), m_cacheSize );
|
||||||
|
@ -222,25 +227,25 @@ bool IOStreamBuffer<T>::readNextBlock() {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
size_t IOStreamBuffer<T>::getNumBlocks() const {
|
size_t IOStreamBuffer<T>::getNumBlocks() const {
|
||||||
return m_numBlocks;
|
return m_numBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
size_t IOStreamBuffer<T>::getCurrentBlockIndex() const {
|
size_t IOStreamBuffer<T>::getCurrentBlockIndex() const {
|
||||||
return m_blockIdx;
|
return m_blockIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
size_t IOStreamBuffer<T>::getFilePos() const {
|
size_t IOStreamBuffer<T>::getFilePos() const {
|
||||||
return m_filePos;
|
return m_filePos;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
bool IOStreamBuffer<T>::getNextDataLine( std::vector<T> &buffer, T continuationToken ) {
|
bool IOStreamBuffer<T>::getNextDataLine( std::vector<T> &buffer, T continuationToken ) {
|
||||||
buffer.resize( m_cacheSize );
|
buffer.resize( m_cacheSize );
|
||||||
if ( m_cachePos >= m_cacheSize || 0 == m_filePos ) {
|
if ( m_cachePos >= m_cacheSize || 0 == m_filePos ) {
|
||||||
|
@ -289,13 +294,13 @@ bool IOStreamBuffer<T>::getNextDataLine( std::vector<T> &buffer, T continuationT
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline
|
static AI_FORCE_INLINE
|
||||||
bool isEndOfCache( size_t pos, size_t cacheSize ) {
|
bool isEndOfCache( size_t pos, size_t cacheSize ) {
|
||||||
return ( pos == cacheSize );
|
return ( pos == cacheSize );
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
bool IOStreamBuffer<T>::getNextLine(std::vector<T> &buffer) {
|
bool IOStreamBuffer<T>::getNextLine(std::vector<T> &buffer) {
|
||||||
buffer.resize(m_cacheSize);
|
buffer.resize(m_cacheSize);
|
||||||
if ( isEndOfCache( m_cachePos, m_cacheSize ) || 0 == m_filePos) {
|
if ( isEndOfCache( m_cachePos, m_cacheSize ) || 0 == m_filePos) {
|
||||||
|
@ -335,7 +340,7 @@ bool IOStreamBuffer<T>::getNextLine(std::vector<T> &buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
bool IOStreamBuffer<T>::getNextBlock( std::vector<T> &buffer) {
|
bool IOStreamBuffer<T>::getNextBlock( std::vector<T> &buffer) {
|
||||||
// Return the last block-value if getNextLine was used before
|
// Return the last block-value if getNextLine was used before
|
||||||
if ( 0 != m_cachePos ) {
|
if ( 0 != m_cachePos ) {
|
||||||
|
@ -353,3 +358,5 @@ bool IOStreamBuffer<T>::getNextBlock( std::vector<T> &buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
} // !ns Assimp
|
} // !ns Assimp
|
||||||
|
|
||||||
|
#endif // AI_IOSTREAMBUFFER_H_INC
|
||||||
|
|
|
@ -50,6 +50,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef AI_IOSYSTEM_H_INC
|
#ifndef AI_IOSYSTEM_H_INC
|
||||||
#define AI_IOSYSTEM_H_INC
|
#define AI_IOSYSTEM_H_INC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef __cplusplus
|
#ifndef __cplusplus
|
||||||
# error This header requires C++ to be used. aiFileIO.h is the \
|
# error This header requires C++ to be used. aiFileIO.h is the \
|
||||||
corresponding C interface.
|
corresponding C interface.
|
||||||
|
|
|
@ -48,6 +48,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef AI_ASSIMP_HPP_INC
|
#ifndef AI_ASSIMP_HPP_INC
|
||||||
#define AI_ASSIMP_HPP_INC
|
#define AI_ASSIMP_HPP_INC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef __cplusplus
|
#ifndef __cplusplus
|
||||||
# error This header requires C++ to be used. Use assimp.h for plain C.
|
# error This header requires C++ to be used. Use assimp.h for plain C.
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
|
@ -48,9 +48,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef INCLUDED_LINE_SPLITTER_H
|
#ifndef INCLUDED_LINE_SPLITTER_H
|
||||||
#define INCLUDED_LINE_SPLITTER_H
|
#define INCLUDED_LINE_SPLITTER_H
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include "StreamReader.h"
|
#include <assimp/StreamReader.h>
|
||||||
#include "ParsingUtils.h"
|
#include <assimp/ParsingUtils.h>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
|
@ -140,7 +144,7 @@ private:
|
||||||
bool mSwallow, mSkip_empty_lines, mTrim;
|
bool mSwallow, mSkip_empty_lines, mTrim;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_empty_lines, bool trim )
|
LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_empty_lines, bool trim )
|
||||||
: mIdx(0)
|
: mIdx(0)
|
||||||
, mCur()
|
, mCur()
|
||||||
|
@ -153,12 +157,12 @@ LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_empty_lines, bool t
|
||||||
mIdx = 0;
|
mIdx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
LineSplitter::~LineSplitter() {
|
LineSplitter::~LineSplitter() {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
LineSplitter& LineSplitter::operator++() {
|
LineSplitter& LineSplitter::operator++() {
|
||||||
if (mSwallow) {
|
if (mSwallow) {
|
||||||
mSwallow = false;
|
mSwallow = false;
|
||||||
|
@ -199,12 +203,12 @@ LineSplitter& LineSplitter::operator++() {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
LineSplitter &LineSplitter::operator++(int) {
|
LineSplitter &LineSplitter::operator++(int) {
|
||||||
return ++(*this);
|
return ++(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
const char *LineSplitter::operator[] (size_t idx) const {
|
const char *LineSplitter::operator[] (size_t idx) const {
|
||||||
const char* s = operator->()->c_str();
|
const char* s = operator->()->c_str();
|
||||||
|
|
||||||
|
@ -222,7 +226,7 @@ const char *LineSplitter::operator[] (size_t idx) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
void LineSplitter::get_tokens(const char* (&tokens)[N]) const {
|
void LineSplitter::get_tokens(const char* (&tokens)[N]) const {
|
||||||
const char* s = operator->()->c_str();
|
const char* s = operator->()->c_str();
|
||||||
|
|
||||||
|
@ -238,44 +242,44 @@ void LineSplitter::get_tokens(const char* (&tokens)[N]) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
const std::string* LineSplitter::operator -> () const {
|
const std::string* LineSplitter::operator -> () const {
|
||||||
return &mCur;
|
return &mCur;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
std::string LineSplitter::operator* () const {
|
std::string LineSplitter::operator* () const {
|
||||||
return mCur;
|
return mCur;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
LineSplitter::operator bool() const {
|
LineSplitter::operator bool() const {
|
||||||
return mStream.GetRemainingSize() > 0;
|
return mStream.GetRemainingSize() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
LineSplitter::operator line_idx() const {
|
LineSplitter::operator line_idx() const {
|
||||||
return mIdx;
|
return mIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
LineSplitter::line_idx LineSplitter::get_index() const {
|
LineSplitter::line_idx LineSplitter::get_index() const {
|
||||||
return mIdx;
|
return mIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
StreamReaderLE &LineSplitter::get_stream() {
|
StreamReaderLE &LineSplitter::get_stream() {
|
||||||
return mStream;
|
return mStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
bool LineSplitter::match_start(const char* check) {
|
bool LineSplitter::match_start(const char* check) {
|
||||||
const size_t len = ::strlen(check);
|
const size_t len = ::strlen(check);
|
||||||
|
|
||||||
return len <= mCur.length() && std::equal(check, check + len, mCur.begin());
|
return len <= mCur.length() && std::equal(check, check + len, mCur.begin());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
AI_FORCE_INLINE
|
||||||
void LineSplitter::swallow_next_increment() {
|
void LineSplitter::swallow_next_increment() {
|
||||||
mSwallow = true;
|
mSwallow = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,9 +43,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
/** @file LogAux.h
|
/** @file LogAux.h
|
||||||
* @brief Common logging usage patterns for importer implementations
|
* @brief Common logging usage patterns for importer implementations
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
#ifndef INCLUDED_AI_LOGAUX_H
|
#ifndef INCLUDED_AI_LOGAUX_H
|
||||||
#define INCLUDED_AI_LOGAUX_H
|
#define INCLUDED_AI_LOGAUX_H
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <assimp/TinyFormatter.h>
|
#include <assimp/TinyFormatter.h>
|
||||||
#include <assimp/Exceptional.h>
|
#include <assimp/Exceptional.h>
|
||||||
#include <assimp/DefaultLogger.hpp>
|
#include <assimp/DefaultLogger.hpp>
|
||||||
|
|
|
@ -41,6 +41,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
/** @file MathFunctions.h
|
/** @file MathFunctions.h
|
||||||
* @brief Implementation of math utility functions.
|
* @brief Implementation of math utility functions.
|
||||||
*
|
*
|
||||||
|
|
|
@ -42,12 +42,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
/** @file MemoryIOWrapper.h
|
/** @file MemoryIOWrapper.h
|
||||||
* Handy IOStream/IOSystem implemetation to read directly from a memory buffer */
|
* Handy IOStream/IOSystem implemetation to read directly from a memory buffer */
|
||||||
|
#pragma once
|
||||||
#ifndef AI_MEMORYIOSTREAM_H_INC
|
#ifndef AI_MEMORYIOSTREAM_H_INC
|
||||||
#define AI_MEMORYIOSTREAM_H_INC
|
#define AI_MEMORYIOSTREAM_H_INC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <assimp/IOStream.hpp>
|
#include <assimp/IOStream.hpp>
|
||||||
#include <assimp/IOSystem.hpp>
|
#include <assimp/IOSystem.hpp>
|
||||||
#include <assimp/ai_assert.h>
|
#include <assimp/ai_assert.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
|
@ -44,11 +44,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
/** @file ParsingUtils.h
|
/** @file ParsingUtils.h
|
||||||
* @brief Defines helper functions for text parsing
|
* @brief Defines helper functions for text parsing
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
#ifndef AI_PARSING_UTILS_H_INC
|
#ifndef AI_PARSING_UTILS_H_INC
|
||||||
#define AI_PARSING_UTILS_H_INC
|
#define AI_PARSING_UTILS_H_INC
|
||||||
|
|
||||||
#include "StringComparison.h"
|
#ifdef __GNUC__
|
||||||
#include "StringUtils.h"
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <assimp/StringComparison.h>
|
||||||
|
#include <assimp/StringUtils.h>
|
||||||
#include <assimp/defs.h>
|
#include <assimp/defs.h>
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
|
@ -43,12 +43,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
/** @file Profiler.h
|
/** @file Profiler.h
|
||||||
* @brief Utility to measure the respective runtime of each import step
|
* @brief Utility to measure the respective runtime of each import step
|
||||||
*/
|
*/
|
||||||
#ifndef INCLUDED_PROFILER_H
|
#pragma once
|
||||||
#define INCLUDED_PROFILER_H
|
#ifndef AI_INCLUDED_PROFILER_H
|
||||||
|
#define AI_INCLUDED_PROFILER_H
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <assimp/DefaultLogger.hpp>
|
#include <assimp/DefaultLogger.hpp>
|
||||||
#include "TinyFormatter.h"
|
#include <assimp/TinyFormatter.h>
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
@ -67,7 +72,6 @@ public:
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/** Start a named timer */
|
/** Start a named timer */
|
||||||
void BeginRegion(const std::string& region) {
|
void BeginRegion(const std::string& region) {
|
||||||
|
@ -95,5 +99,5 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif // AI_INCLUDED_PROFILER_H
|
||||||
|
|
||||||
|
|
|
@ -47,9 +47,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
#ifndef AI_PROGRESSHANDLER_H_INC
|
#ifndef AI_PROGRESSHANDLER_H_INC
|
||||||
#define AI_PROGRESSHANDLER_H_INC
|
#define AI_PROGRESSHANDLER_H_INC
|
||||||
|
|
||||||
#include "types.h"
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace Assimp {
|
#include <assimp/types.h>
|
||||||
|
|
||||||
|
namespace Assimp {
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------------
|
// ------------------------------------------------------------------------------------
|
||||||
/** @brief CPP-API: Abstract interface for custom progress report receivers.
|
/** @brief CPP-API: Abstract interface for custom progress report receivers.
|
||||||
|
|
|
@ -4,7 +4,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,
|
||||||
|
@ -43,9 +42,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
/** @file Declares a helper class, "CommentRemover", which can be
|
/** @file Declares a helper class, "CommentRemover", which can be
|
||||||
* used to remove comments (single and multi line) from a text file.
|
* used to remove comments (single and multi line) from a text file.
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
#ifndef AI_REMOVE_COMMENTS_H_INC
|
#ifndef AI_REMOVE_COMMENTS_H_INC
|
||||||
#define AI_REMOVE_COMMENTS_H_INC
|
#define AI_REMOVE_COMMENTS_H_INC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <assimp/defs.h>
|
#include <assimp/defs.h>
|
||||||
|
|
||||||
|
@ -58,8 +61,7 @@ namespace Assimp {
|
||||||
* to those in C or C++ so this code has been moved to a separate
|
* to those in C or C++ so this code has been moved to a separate
|
||||||
* module.
|
* module.
|
||||||
*/
|
*/
|
||||||
class ASSIMP_API CommentRemover
|
class ASSIMP_API CommentRemover {
|
||||||
{
|
|
||||||
// class cannot be instanced
|
// class cannot be instanced
|
||||||
CommentRemover() {}
|
CommentRemover() {}
|
||||||
|
|
||||||
|
|
|
@ -42,9 +42,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
/** Small helper classes to optimize finding vertices close to a given location
|
/** Small helper classes to optimize finding vertices close to a given location
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
#ifndef AI_D3DSSPATIALSORT_H_INC
|
#ifndef AI_D3DSSPATIALSORT_H_INC
|
||||||
#define AI_D3DSSPATIALSORT_H_INC
|
#define AI_D3DSSPATIALSORT_H_INC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <assimp/types.h>
|
#include <assimp/types.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
|
@ -43,17 +43,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
/** @file Declares a helper class, "SceneCombiner" providing various
|
/** @file Declares a helper class, "SceneCombiner" providing various
|
||||||
* utilities to merge scenes.
|
* utilities to merge scenes.
|
||||||
*/
|
*/
|
||||||
|
#pragma once
|
||||||
#ifndef AI_SCENE_COMBINER_H_INC
|
#ifndef AI_SCENE_COMBINER_H_INC
|
||||||
#define AI_SCENE_COMBINER_H_INC
|
#define AI_SCENE_COMBINER_H_INC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <assimp/ai_assert.h>
|
#include <assimp/ai_assert.h>
|
||||||
#include <assimp/types.h>
|
#include <assimp/types.h>
|
||||||
#include <assimp/Defines.h>
|
#include <assimp/Defines.h>
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
struct aiScene;
|
struct aiScene;
|
||||||
|
@ -68,6 +73,7 @@ struct aiMesh;
|
||||||
struct aiAnimMesh;
|
struct aiAnimMesh;
|
||||||
struct aiAnimation;
|
struct aiAnimation;
|
||||||
struct aiNodeAnim;
|
struct aiNodeAnim;
|
||||||
|
struct aiMeshMorphAnim;
|
||||||
|
|
||||||
namespace Assimp {
|
namespace Assimp {
|
||||||
|
|
||||||
|
@ -372,6 +378,7 @@ public:
|
||||||
static void Copy (aiBone** dest, const aiBone* src);
|
static void Copy (aiBone** dest, const aiBone* src);
|
||||||
static void Copy (aiLight** dest, const aiLight* src);
|
static void Copy (aiLight** dest, const aiLight* src);
|
||||||
static void Copy (aiNodeAnim** dest, const aiNodeAnim* src);
|
static void Copy (aiNodeAnim** dest, const aiNodeAnim* src);
|
||||||
|
static void Copy (aiMeshMorphAnim** dest, const aiMeshMorphAnim* src);
|
||||||
static void Copy (aiMetadata** dest, const aiMetadata* src);
|
static void Copy (aiMetadata** dest, const aiMetadata* src);
|
||||||
|
|
||||||
// recursive, of course
|
// recursive, of course
|
||||||
|
|
|
@ -47,9 +47,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
* for animation skeletons.
|
* for animation skeletons.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
#ifndef AI_SKELETONMESHBUILDER_H_INC
|
#ifndef AI_SKELETONMESHBUILDER_H_INC
|
||||||
#define AI_SKELETONMESHBUILDER_H_INC
|
#define AI_SKELETONMESHBUILDER_H_INC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <assimp/mesh.h>
|
#include <assimp/mesh.h>
|
||||||
|
|
||||||
|
|
|
@ -43,10 +43,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
/** @file Defines the helper data structures for importing 3DS files.
|
/** @file Defines the helper data structures for importing 3DS files.
|
||||||
http://www.jalix.org/ressources/graphics/3DS/_unofficials/3ds-unofficial.txt */
|
http://www.jalix.org/ressources/graphics/3DS/_unofficials/3ds-unofficial.txt */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
#ifndef AI_SMOOTHINGGROUPS_H_INC
|
#ifndef AI_SMOOTHINGGROUPS_H_INC
|
||||||
#define AI_SMOOTHINGGROUPS_H_INC
|
#define AI_SMOOTHINGGROUPS_H_INC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <assimp/vector3.h>
|
#include <assimp/vector3.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|
|
@ -41,13 +41,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
/** @file Generation of normal vectors basing on smoothing groups */
|
/** @file Generation of normal vectors basing on smoothing groups */
|
||||||
|
|
||||||
|
#pragma once
|
||||||
#ifndef AI_SMOOTHINGGROUPS_INL_INCLUDED
|
#ifndef AI_SMOOTHINGGROUPS_INL_INCLUDED
|
||||||
#define AI_SMOOTHINGGROUPS_INL_INCLUDED
|
#define AI_SMOOTHINGGROUPS_INL_INCLUDED
|
||||||
|
|
||||||
// internal headers
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <assimp/SGSpatialSort.h>
|
#include <assimp/SGSpatialSort.h>
|
||||||
|
|
||||||
// CRT header
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace Assimp;
|
using namespace Assimp;
|
||||||
|
|
|
@ -41,9 +41,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Small helper classes to optimise finding vertizes close to a given location */
|
/** Small helper classes to optimise finding vertizes close to a given location */
|
||||||
|
#pragma once
|
||||||
#ifndef AI_SPATIALSORT_H_INC
|
#ifndef AI_SPATIALSORT_H_INC
|
||||||
#define AI_SPATIALSORT_H_INC
|
#define AI_SPATIALSORT_H_INC
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# pragma GCC system_header
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <assimp/types.h>
|
#include <assimp/types.h>
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue