Merge branch 'master' into pugi_xml
commit
d48b93cf34
|
@ -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
|
||||
...
|
|
@ -0,0 +1,2 @@
|
|||
patreon: assimp
|
||||
ko_fi: kimkulling
|
|
@ -2,6 +2,11 @@
|
|||
build
|
||||
.project
|
||||
*.kdev4*
|
||||
.DS_Store
|
||||
|
||||
# build artefacts
|
||||
*.o
|
||||
*.a
|
||||
|
||||
# Visual Studio
|
||||
*.sln
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#
|
||||
function generate() {
|
||||
OPTIONS="-DASSIMP_WERROR=ON"
|
||||
OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=NO"
|
||||
|
||||
if [ "$DISABLE_EXPORTERS" = "YES" ] ; then
|
||||
OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=YES"
|
||||
|
|
|
@ -30,6 +30,9 @@ env:
|
|||
- secure: "lZ7pHQvl5dpZWzBQAaIMf0wqrvtcZ4wiZKeIZjf83TEsflW8+z0uTpIuN30ZV6Glth/Sq1OhLnTP5+N57fZU/1ebA5twHdvP4bS5CIUUg71/CXQZNl36xeaqvxsG/xRrdpKOsPdjAOsQ9KPTQulsX43XDLS7CasMiLvYOpqKcPc="
|
||||
- PV=r8e PLATF=linux-x86_64 NDK_HOME=${TRAVIS_BUILD_DIR}/android-ndk-${PV} PATH=${PATH}:${NDK_HOME}
|
||||
|
||||
git:
|
||||
depth: 1
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
:: This is an example file to generate binaries using Windows Operating System
|
||||
:: This script is configured to be executed from the source directory
|
||||
|
||||
:: Compiled binaries will be placed in BINARIES_DIR\code\CONFIG
|
||||
|
||||
:: NOTE
|
||||
:: The build process will generate a config.h file that is placed in BINARIES_DIR\include
|
||||
:: This file must be merged with SOURCE_DIR\include
|
||||
:: You should write yourself a script that copies the files where you want them.
|
||||
:: Also see: https://github.com/assimp/assimp/pull/2646
|
||||
|
||||
SET SOURCE_DIR=.
|
||||
|
||||
:: For generators see "cmake --help"
|
||||
SET GENERATOR=Visual Studio 15 2017
|
||||
|
||||
SET BINARIES_DIR="./BINARIES/Win32"
|
||||
cmake CMakeLists.txt -G "%GENERATOR%" -S %SOURCE_DIR% -B %BINARIES_DIR%
|
||||
cmake --build %BINARIES_DIR% --config release
|
||||
|
||||
SET BINARIES_DIR="./BINARIES/x64"
|
||||
cmake CMakeLists.txt -G "%GENERATOR% Win64" -S %SOURCE_DIR% -B %BINARIES_DIR%
|
||||
cmake --build %BINARIES_DIR% --config debug
|
||||
cmake --build %BINARIES_DIR% --config release
|
||||
|
||||
PAUSE
|
29
Build.md
29
Build.md
|
@ -1,17 +1,31 @@
|
|||
# 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
|
||||
```bash
|
||||
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:
|
||||
```bash
|
||||
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/
|
||||
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.
|
||||
|
||||
## 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>
|
||||
|
||||
## 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:
|
||||
|
||||
```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.
|
||||
|
||||
## 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
|
||||
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.
|
||||
|
@ -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.
|
||||
|
||||
## CMake build options
|
||||
### CMake build options
|
||||
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_FRAMEWORK ( default OFF, MacOnly)**: Build package as Mac OS X Framework bundle
|
||||
|
@ -63,6 +77,7 @@ The cmake-build-environment provides options to configure the build. The followi
|
|||
- **ASSIMP_BUILD_SAMPLES ( default OFF )**: If the official samples are built as well (needs Glut).
|
||||
- **ASSIMP_BUILD_TESTS ( default ON )**: If the test suite for Assimp is built in addition to the library.
|
||||
- **ASSIMP_COVERALLS ( default OFF )**: Enable this to measure test coverage.
|
||||
- **ASSIMP_ERROR_MAX( default OFF)**: Enable all warnings.
|
||||
- **ASSIMP_WERROR( default OFF )**: Treat warnings as errors.
|
||||
- **ASSIMP_ASAN ( default OFF )**: Enable AddressSanitizer.
|
||||
- **ASSIMP_UBSAN ( default OFF )**: Enable Undefined Behavior sanitizer.
|
||||
|
|
|
@ -100,6 +100,10 @@ OPTION ( ASSIMP_COVERALLS
|
|||
"Enable this to measure test coverage."
|
||||
OFF
|
||||
)
|
||||
OPTION ( ASSIMP_ERROR_MAX
|
||||
"Enable all warnings."
|
||||
OFF
|
||||
)
|
||||
OPTION ( ASSIMP_WERROR
|
||||
"Treat warnings as errors."
|
||||
OFF
|
||||
|
@ -173,7 +177,6 @@ SET (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VER
|
|||
SET (ASSIMP_SOVERSION 5)
|
||||
|
||||
SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" )
|
||||
|
||||
if(NOT HUNTER_ENABLED)
|
||||
# Enable C++11 support globally
|
||||
set_property( GLOBAL PROPERTY CXX_STANDARD 11 )
|
||||
|
@ -255,6 +258,7 @@ ELSEIF(MSVC)
|
|||
IF(MSVC12)
|
||||
ADD_COMPILE_OPTIONS(/wd4351)
|
||||
ENDIF()
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /Zi /Od")
|
||||
ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" )
|
||||
IF(NOT HUNTER_ENABLED)
|
||||
SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}")
|
||||
|
@ -272,22 +276,20 @@ ELSEIF( CMAKE_COMPILER_IS_MINGW )
|
|||
SET(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
|
||||
SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}")
|
||||
ENDIF()
|
||||
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -Wa,-mbig-obj ${CMAKE_CXX_FLAGS}")
|
||||
SET(CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -Wa,-mbig-obj -O3 ${CMAKE_CXX_FLAGS}")
|
||||
SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}")
|
||||
ADD_DEFINITIONS( -U__STRICT_ANSI__ )
|
||||
ENDIF()
|
||||
|
||||
IF ( IOS AND NOT HUNTER_ENABLED)
|
||||
|
||||
IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
IF (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -Og")
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -Og")
|
||||
ELSE()
|
||||
ELSE()
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3")
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3")
|
||||
# Experimental for pdb generation
|
||||
ENDIF()
|
||||
|
||||
ENDIF()
|
||||
ENDIF( IOS AND NOT HUNTER_ENABLED)
|
||||
|
||||
IF (ASSIMP_COVERALLS)
|
||||
|
@ -297,6 +299,16 @@ IF (ASSIMP_COVERALLS)
|
|||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage")
|
||||
ENDIF()
|
||||
|
||||
IF (ASSIMP_ERROR_MAX)
|
||||
MESSAGE(STATUS "Turning on all warnings")
|
||||
IF (MSVC)
|
||||
ADD_COMPILE_OPTIONS(/W4) # NB: there is a /Wall option, pedantic mode
|
||||
ELSE()
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
|
||||
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF (ASSIMP_WERROR)
|
||||
MESSAGE(STATUS "Treating warnings as errors")
|
||||
IF (MSVC)
|
||||
|
@ -342,7 +354,7 @@ SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING
|
|||
|
||||
get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG)
|
||||
|
||||
IF (is_multi_config OR (CMAKE_BUILD_TYPE STREQUAL "Debug"))
|
||||
IF (INJECT_DEBUG_POSTFIX AND (is_multi_config OR CMAKE_BUILD_TYPE STREQUAL "Debug"))
|
||||
SET(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfix for lib, samples and tools")
|
||||
ELSE()
|
||||
SET(CMAKE_DEBUG_POSTFIX "" CACHE STRING "Debug Postfix for lib, samples and tools")
|
||||
|
@ -394,6 +406,11 @@ IF(HUNTER_ENABLED)
|
|||
)
|
||||
ELSE(HUNTER_ENABLED)
|
||||
# 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}/assimpTargets.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE)
|
||||
IF (is_multi_config)
|
||||
|
@ -560,17 +577,15 @@ ENDIF(NOT HUNTER_ENABLED)
|
|||
|
||||
ADD_SUBDIRECTORY( code/ )
|
||||
IF ( ASSIMP_BUILD_ASSIMP_TOOLS )
|
||||
# The viewer for windows only
|
||||
IF ( WIN32 AND DirectX_D3DX9_LIBRARY )
|
||||
OPTION ( ASSIMP_BUILD_ASSIMP_VIEW "If the Assimp view tool is built. (requires DirectX)" ${DirectX_FOUND} )
|
||||
IF ( ASSIMP_BUILD_ASSIMP_VIEW )
|
||||
ADD_SUBDIRECTORY( tools/assimp_view/ )
|
||||
ENDIF ( ASSIMP_BUILD_ASSIMP_VIEW )
|
||||
ENDIF ( WIN32 AND DirectX_D3DX9_LIBRARY )
|
||||
|
||||
# Te command line tool
|
||||
ADD_SUBDIRECTORY( tools/assimp_cmd/ )
|
||||
IF (NOT IOS)
|
||||
ADD_SUBDIRECTORY( tools/assimp_qt_viewer/ )
|
||||
ENDIF (NOT IOS)
|
||||
ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS )
|
||||
|
||||
IF ( ASSIMP_BUILD_SAMPLES)
|
||||
|
|
12
Readme.md
12
Readme.md
|
@ -60,13 +60,19 @@ __Importers__:
|
|||
- ENFF
|
||||
- [FBX](https://en.wikipedia.org/wiki/FBX)
|
||||
- [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
|
||||
- IFC-STEP
|
||||
- IRR / IRRMESH
|
||||
- [LWO](https://en.wikipedia.org/wiki/LightWave_3D)
|
||||
- LWS
|
||||
- LXO
|
||||
- [M3D](https://bztsrc.gitlab.io/model3d)
|
||||
- MD2
|
||||
- MD3
|
||||
- MD5
|
||||
|
@ -120,12 +126,12 @@ __Exporters__:
|
|||
- FBX ( experimental )
|
||||
|
||||
### 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 ###
|
||||
* [Android](port/AndroidJNI/README.md)
|
||||
* [Python](port/PyAssimp/README.md)
|
||||
* [.NET](https://github.com/kebby/assimp-net)
|
||||
* [.NET](https://github.com/assimp/assimp-net)
|
||||
* [Pascal](port/AssimpPascal/Readme.md)
|
||||
* [Javascript (Alpha)](https://github.com/makc/assimp2json)
|
||||
* [Unity 3d Plugin](https://www.assetstore.unity3d.com/en/#!/content/91777)
|
||||
|
|
18
appveyor.yml
18
appveyor.yml
|
@ -4,6 +4,8 @@
|
|||
# clone directory
|
||||
clone_folder: c:\projects\assimp
|
||||
|
||||
clone_depth: 1
|
||||
|
||||
# branches to build
|
||||
branches:
|
||||
# whitelist
|
||||
|
@ -17,6 +19,8 @@ image:
|
|||
- Visual Studio 2013
|
||||
- Visual Studio 2015
|
||||
- Visual Studio 2017
|
||||
- Visual Studio 2019
|
||||
- MinGW
|
||||
|
||||
platform:
|
||||
- Win32
|
||||
|
@ -27,11 +31,15 @@ configuration: Release
|
|||
install:
|
||||
- set PATH=C:\Ruby24-x64\bin;%PATH%
|
||||
- set CMAKE_DEFINES -DASSIMP_WERROR=ON
|
||||
- if [%COMPILER%]==[MinGW] set PATH=C:\MinGW\bin;%PATH%
|
||||
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2013" set CMAKE_GENERATOR_NAME=Visual Studio 12 2013
|
||||
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 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 "%platform%"=="x64" set CMAKE_GENERATOR_NAME=%CMAKE_GENERATOR_NAME% Win64
|
||||
- cmake %CMAKE_DEFINES% -G "%CMAKE_GENERATOR_NAME%" .
|
||||
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2019" set CMAKE_GENERATOR_NAME=Visual Studio 16 2019
|
||||
- cmake %CMAKE_DEFINES% -G "%CMAKE_GENERATOR_NAME%" -A %platform% .
|
||||
# Rename sh.exe as sh.exe in PATH interferes with MinGW - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2015" set CMAKE_GENERATOR_NAME=Visual Studio 14 2015
|
||||
|
||||
- rename "C:\Program Files\Git\usr\bin\sh.exe" "sh2.exe"
|
||||
- set PATH=%PATH%;"C:\\Program Files (x86)\\Inno Setup 5"
|
||||
- ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/5/7/b/57b2947c-7221-4f33-b35e-2fc78cb10df4/vc_redist.x64.exe -OutFile .\packaging\windows-innosetup\vc_redist.x64.exe
|
||||
- ps: Invoke-WebRequest -Uri https://download.microsoft.com/download/1/d/8/1d8137db-b5bb-4925-8c5d-927424a2e4de/vc_redist.x86.exe -OutFile .\packaging\windows-innosetup\vc_redist.x86.exe
|
||||
|
@ -46,11 +54,11 @@ cache:
|
|||
- bin\.mtime_cache
|
||||
|
||||
before_build:
|
||||
- echo NUMBER_OF_PROCESSORS=%NUMBER_OF_PROCESSORS%
|
||||
- ruby scripts\AppVeyor\mtime_cache -g scripts\AppVeyor\cacheglobs.txt -c bin\.mtime_cache\cache.json
|
||||
|
||||
build:
|
||||
parallel: true
|
||||
project: Assimp.sln
|
||||
build_script:
|
||||
cmake --build . --config Release -- /maxcpucount:2
|
||||
|
||||
after_build:
|
||||
- if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" (
|
||||
|
|
|
@ -35,6 +35,8 @@ if(MSVC)
|
|||
endif()
|
||||
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)
|
||||
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@")
|
||||
|
@ -63,7 +65,14 @@ if(MSVC)
|
|||
else()
|
||||
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" )
|
||||
if(ASSIMP_BUILD_SHARED_LIBS)
|
||||
if(WIN32)
|
||||
# Handle MinGW compiler.
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
|
||||
elseif(APPLE)
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@")
|
||||
else()
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
|
||||
endif()
|
||||
set_target_properties(assimp::assimp PROPERTIES
|
||||
IMPORTED_SONAME_DEBUG "${sharedLibraryName}"
|
||||
IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${sharedLibraryName}"
|
||||
|
|
|
@ -35,6 +35,8 @@ if(MSVC)
|
|||
endif()
|
||||
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)
|
||||
set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@")
|
||||
set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_IMPORT_LIBRARY_SUFFIX@")
|
||||
|
@ -63,9 +65,17 @@ if(MSVC)
|
|||
else()
|
||||
set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" )
|
||||
if(ASSIMP_BUILD_SHARED_LIBS)
|
||||
if(WIN32)
|
||||
# Handle MinGW compiler.
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@")
|
||||
elseif(APPLE)
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@")
|
||||
else()
|
||||
set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@")
|
||||
endif()
|
||||
set_target_properties(assimp::assimp PROPERTIES
|
||||
IMPORTED_SONAME_RELEASE "${sharedLibraryName}"
|
||||
|
||||
IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${sharedLibraryName}"
|
||||
)
|
||||
list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp )
|
||||
|
|
|
@ -5,6 +5,9 @@ if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5)
|
|||
endif()
|
||||
cmake_policy(PUSH)
|
||||
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.
|
||||
#----------------------------------------------------------------
|
||||
|
@ -51,11 +54,7 @@ if(_IMPORT_PREFIX STREQUAL "/")
|
|||
endif()
|
||||
|
||||
# Create imported target assimp::assimp
|
||||
if(@BUILD_SHARED_LIBS@)
|
||||
add_library(assimp::assimp SHARED IMPORTED)
|
||||
else()
|
||||
add_library(assimp::assimp STATIC IMPORTED)
|
||||
endif()
|
||||
add_library(assimp::assimp @BUILD_LIB_TYPE@ IMPORTED)
|
||||
|
||||
set_target_properties(assimp::assimp PROPERTIES
|
||||
COMPATIBLE_INTERFACE_STRING "assimp_MAJOR_VERSION"
|
||||
|
|
|
@ -54,14 +54,18 @@ else(WIN32)
|
|||
|
||||
find_path(
|
||||
assimp_INCLUDE_DIRS
|
||||
NAMES postprocess.h scene.h version.h config.h cimport.h
|
||||
PATHS /usr/local/include/
|
||||
NAMES assimp/postprocess.h assimp/scene.h assimp/version.h assimp/config.h assimp/cimport.h
|
||||
PATHS /usr/local/include
|
||||
PATHS /usr/include/
|
||||
|
||||
)
|
||||
|
||||
find_library(
|
||||
assimp_LIBRARIES
|
||||
NAMES assimp
|
||||
PATHS /usr/local/lib/
|
||||
PATHS /usr/lib64/
|
||||
PATHS /usr/lib/
|
||||
)
|
||||
|
||||
if (assimp_INCLUDE_DIRS AND assimp_LIBRARIES)
|
||||
|
|
|
@ -72,7 +72,7 @@ void Discreet3DSImporter::ReplaceDefaultMaterial()
|
|||
unsigned int idx( NotSet );
|
||||
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 ) {
|
||||
*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
|
||||
|
||||
// internal headers
|
||||
#include "3DSLoader.h"
|
||||
#include <assimp/Macros.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
|
|
|
@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/StringUtils.h>
|
||||
#include <assimp/ZipArchiveIOSystem.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
@ -58,11 +59,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <memory>
|
||||
|
||||
#include "D3MFOpcPackage.h"
|
||||
#ifdef ASSIMP_USE_HUNTER
|
||||
# include <minizip/unzip.h>
|
||||
#else
|
||||
# include <unzip.h>
|
||||
#endif
|
||||
#include <assimp/irrXMLWrapper.h>
|
||||
#include "3MFXmlTags.h"
|
||||
#include <assimp/fast_atof.h>
|
||||
|
@ -453,7 +449,7 @@ bool D3MFImporter::CanRead(const std::string &filename, IOSystem *pIOHandler, bo
|
|||
if ( nullptr == pIOHandler ) {
|
||||
return false;
|
||||
}
|
||||
if ( !D3MF::D3MFOpcPackage::isZipArchive( pIOHandler, filename ) ) {
|
||||
if ( !ZipArchiveIOSystem::isZipArchive( pIOHandler, filename ) ) {
|
||||
return false;
|
||||
}
|
||||
D3MF::D3MFOpcPackage opcPackage( pIOHandler, filename );
|
||||
|
|
|
@ -49,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/ZipArchiveIOSystem.h>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
|
@ -56,344 +57,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#ifdef ASSIMP_USE_HUNTER
|
||||
# include <minizip/unzip.h>
|
||||
#else
|
||||
# include <unzip.h>
|
||||
#endif
|
||||
#include "3MFXmlTags.h"
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
namespace D3MF {
|
||||
|
||||
class IOSystem2Unzip {
|
||||
public:
|
||||
static voidpf open(voidpf opaque, const char* filename, int mode);
|
||||
static uLong read(voidpf opaque, voidpf stream, void* buf, uLong size);
|
||||
static uLong write(voidpf opaque, voidpf stream, const void* buf, uLong size);
|
||||
static long tell(voidpf opaque, voidpf stream);
|
||||
static long seek(voidpf opaque, voidpf stream, uLong offset, int origin);
|
||||
static int close(voidpf opaque, voidpf stream);
|
||||
static int testerror(voidpf opaque, voidpf stream);
|
||||
static zlib_filefunc_def get(IOSystem* pIOHandler);
|
||||
};
|
||||
|
||||
voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) {
|
||||
IOSystem* io_system = reinterpret_cast<IOSystem*>(opaque);
|
||||
|
||||
const char* mode_fopen = NULL;
|
||||
if((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) {
|
||||
mode_fopen = "rb";
|
||||
} else {
|
||||
if(mode & ZLIB_FILEFUNC_MODE_EXISTING) {
|
||||
mode_fopen = "r+b";
|
||||
} else {
|
||||
if(mode & ZLIB_FILEFUNC_MODE_CREATE) {
|
||||
mode_fopen = "wb";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (voidpf) io_system->Open(filename, mode_fopen);
|
||||
}
|
||||
|
||||
uLong IOSystem2Unzip::read(voidpf /*opaque*/, voidpf stream, void* buf, uLong size) {
|
||||
IOStream* io_stream = (IOStream*) stream;
|
||||
|
||||
return static_cast<uLong>(io_stream->Read(buf, 1, size));
|
||||
}
|
||||
|
||||
uLong IOSystem2Unzip::write(voidpf /*opaque*/, voidpf stream, const void* buf, uLong size) {
|
||||
IOStream* io_stream = (IOStream*) stream;
|
||||
|
||||
return static_cast<uLong>(io_stream->Write(buf, 1, size));
|
||||
}
|
||||
|
||||
long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) {
|
||||
IOStream* io_stream = (IOStream*) stream;
|
||||
|
||||
return static_cast<long>(io_stream->Tell());
|
||||
}
|
||||
|
||||
long IOSystem2Unzip::seek(voidpf /*opaque*/, voidpf stream, uLong offset, int origin) {
|
||||
IOStream* io_stream = (IOStream*) stream;
|
||||
|
||||
aiOrigin assimp_origin;
|
||||
switch (origin) {
|
||||
default:
|
||||
case ZLIB_FILEFUNC_SEEK_CUR:
|
||||
assimp_origin = aiOrigin_CUR;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_END:
|
||||
assimp_origin = aiOrigin_END;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_SET:
|
||||
assimp_origin = aiOrigin_SET;
|
||||
break;
|
||||
}
|
||||
|
||||
return (io_stream->Seek(offset, assimp_origin) == aiReturn_SUCCESS ? 0 : -1);
|
||||
}
|
||||
|
||||
int IOSystem2Unzip::close(voidpf opaque, voidpf stream) {
|
||||
IOSystem* io_system = (IOSystem*) opaque;
|
||||
IOStream* io_stream = (IOStream*) stream;
|
||||
|
||||
io_system->Close(io_stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) {
|
||||
zlib_filefunc_def mapping;
|
||||
|
||||
#ifdef ASSIMP_USE_HUNTER
|
||||
mapping.zopen_file = (open_file_func)open;
|
||||
mapping.zread_file = (read_file_func)read;
|
||||
mapping.zwrite_file = (write_file_func)write;
|
||||
mapping.ztell_file = (tell_file_func)tell;
|
||||
mapping.zseek_file = (seek_file_func)seek;
|
||||
mapping.zclose_file = (close_file_func)close;
|
||||
mapping.zerror_file = (error_file_func)testerror;
|
||||
#else
|
||||
mapping.zopen_file = open;
|
||||
mapping.zread_file = read;
|
||||
mapping.zwrite_file = write;
|
||||
mapping.ztell_file = tell;
|
||||
mapping.zseek_file = seek;
|
||||
mapping.zclose_file = close;
|
||||
mapping.zerror_file = testerror;
|
||||
#endif
|
||||
mapping.opaque = reinterpret_cast<voidpf>(pIOHandler);
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
class ZipFile : public IOStream {
|
||||
friend class D3MFZipArchive;
|
||||
|
||||
public:
|
||||
explicit ZipFile(size_t size);
|
||||
virtual ~ZipFile();
|
||||
size_t Read(void* pvBuffer, size_t pSize, size_t pCount );
|
||||
size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/);
|
||||
size_t FileSize() const;
|
||||
aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/);
|
||||
size_t Tell() const;
|
||||
void Flush();
|
||||
|
||||
private:
|
||||
void *m_Buffer;
|
||||
size_t m_Size;
|
||||
};
|
||||
|
||||
ZipFile::ZipFile(size_t size)
|
||||
: m_Buffer( nullptr )
|
||||
, m_Size(size) {
|
||||
ai_assert(m_Size != 0);
|
||||
m_Buffer = ::malloc(m_Size);
|
||||
}
|
||||
|
||||
ZipFile::~ZipFile() {
|
||||
::free(m_Buffer);
|
||||
m_Buffer = NULL;
|
||||
}
|
||||
|
||||
size_t ZipFile::Read(void* pvBuffer, size_t pSize, size_t pCount) {
|
||||
const size_t size = pSize * pCount;
|
||||
ai_assert(size <= m_Size);
|
||||
|
||||
std::memcpy(pvBuffer, m_Buffer, size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t ZipFile::Write(const void* pvBuffer, size_t size, size_t pCount ) {
|
||||
const size_t size_to_write( size * pCount );
|
||||
if ( 0 == size_to_write ) {
|
||||
return 0U;
|
||||
}
|
||||
return 0U;
|
||||
}
|
||||
|
||||
size_t ZipFile::FileSize() const {
|
||||
return m_Size;
|
||||
}
|
||||
|
||||
aiReturn ZipFile::Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) {
|
||||
return aiReturn_FAILURE;
|
||||
}
|
||||
|
||||
size_t ZipFile::Tell() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ZipFile::Flush() {
|
||||
// empty
|
||||
}
|
||||
|
||||
class D3MFZipArchive : public IOSystem {
|
||||
public:
|
||||
static const unsigned int FileNameSize = 256;
|
||||
|
||||
D3MFZipArchive(IOSystem* pIOHandler, const std::string & rFile);
|
||||
~D3MFZipArchive();
|
||||
bool Exists(const char* pFile) const;
|
||||
char getOsSeparator() const;
|
||||
IOStream* Open(const char* pFile, const char* pMode = "rb");
|
||||
void Close(IOStream* pFile);
|
||||
bool isOpen() const;
|
||||
void getFileList(std::vector<std::string> &rFileList);
|
||||
|
||||
private:
|
||||
bool mapArchive();
|
||||
|
||||
private:
|
||||
unzFile m_ZipFileHandle;
|
||||
std::map<std::string, ZipFile*> m_ArchiveMap;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor.
|
||||
D3MFZipArchive::D3MFZipArchive(IOSystem* pIOHandler, const std::string& rFile)
|
||||
: m_ZipFileHandle( nullptr )
|
||||
, m_ArchiveMap() {
|
||||
if (! rFile.empty()) {
|
||||
zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);
|
||||
|
||||
m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping);
|
||||
if(m_ZipFileHandle != nullptr ) {
|
||||
mapArchive();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor.
|
||||
D3MFZipArchive::~D3MFZipArchive() {
|
||||
for(auto &file : m_ArchiveMap) {
|
||||
delete file.second;
|
||||
}
|
||||
m_ArchiveMap.clear();
|
||||
|
||||
if(m_ZipFileHandle != nullptr) {
|
||||
unzClose(m_ZipFileHandle);
|
||||
m_ZipFileHandle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns true, if the archive is already open.
|
||||
bool D3MFZipArchive::isOpen() const {
|
||||
return (m_ZipFileHandle != nullptr );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns true, if the filename is part of the archive.
|
||||
bool D3MFZipArchive::Exists(const char* pFile) const {
|
||||
ai_assert(pFile != nullptr );
|
||||
|
||||
if ( pFile == nullptr ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string filename(pFile);
|
||||
std::map<std::string, ZipFile*>::const_iterator it = m_ArchiveMap.find(filename);
|
||||
bool exist( false );
|
||||
if(it != m_ArchiveMap.end()) {
|
||||
exist = true;
|
||||
}
|
||||
|
||||
return exist;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns the separator delimiter.
|
||||
char D3MFZipArchive::getOsSeparator() const {
|
||||
#ifndef _WIN32
|
||||
return '/';
|
||||
#else
|
||||
return '\\';
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Opens a file, which is part of the archive.
|
||||
IOStream *D3MFZipArchive::Open(const char* pFile, const char* /*pMode*/) {
|
||||
ai_assert(pFile != NULL);
|
||||
|
||||
IOStream* result = NULL;
|
||||
|
||||
std::map<std::string, ZipFile*>::iterator it = m_ArchiveMap.find(pFile);
|
||||
|
||||
if(it != m_ArchiveMap.end()) {
|
||||
result = static_cast<IOStream*>(it->second);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Close a filestream.
|
||||
void D3MFZipArchive::Close(IOStream *pFile) {
|
||||
(void)(pFile);
|
||||
ai_assert(pFile != NULL);
|
||||
|
||||
// We don't do anything in case the file would be opened again in the future
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns the file-list of the archive.
|
||||
void D3MFZipArchive::getFileList(std::vector<std::string> &rFileList) {
|
||||
rFileList.clear();
|
||||
|
||||
for(const auto &file : m_ArchiveMap) {
|
||||
rFileList.push_back(file.first);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Maps the archive content.
|
||||
bool D3MFZipArchive::mapArchive() {
|
||||
bool success = false;
|
||||
|
||||
if(m_ZipFileHandle != NULL) {
|
||||
if(m_ArchiveMap.empty()) {
|
||||
// At first ensure file is already open
|
||||
if(unzGoToFirstFile(m_ZipFileHandle) == UNZ_OK) {
|
||||
// Loop over all files
|
||||
do {
|
||||
char filename[FileNameSize];
|
||||
unz_file_info fileInfo;
|
||||
|
||||
if(unzGetCurrentFileInfo(m_ZipFileHandle, &fileInfo, filename, FileNameSize, NULL, 0, NULL, 0) == UNZ_OK) {
|
||||
// The file has EXACTLY the size of uncompressed_size. In C
|
||||
// you need to mark the last character with '\0', so add
|
||||
// another character
|
||||
if(fileInfo.uncompressed_size != 0 && unzOpenCurrentFile(m_ZipFileHandle) == UNZ_OK) {
|
||||
std::pair<std::map<std::string, ZipFile*>::iterator, bool> result = m_ArchiveMap.insert(std::make_pair(filename, new ZipFile(fileInfo.uncompressed_size)));
|
||||
|
||||
if(unzReadCurrentFile(m_ZipFileHandle, result.first->second->m_Buffer, fileInfo.uncompressed_size) == (long int) fileInfo.uncompressed_size) {
|
||||
if(unzCloseCurrentFile(m_ZipFileHandle) == UNZ_OK) {
|
||||
// Nothing to do anymore...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while(unzGoToNextFile(m_ZipFileHandle) != UNZ_END_OF_LIST_OF_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
typedef std::shared_ptr<OpcPackageRelationship> OpcPackageRelationshipPtr;
|
||||
|
@ -453,7 +121,7 @@ public:
|
|||
D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
|
||||
: mRootStream(nullptr)
|
||||
, mZipArchive() {
|
||||
mZipArchive.reset( new D3MF::D3MFZipArchive( pIOHandler, rFile ) );
|
||||
mZipArchive.reset( new ZipArchiveIOSystem( pIOHandler, rFile ) );
|
||||
if(!mZipArchive->isOpen()) {
|
||||
throw DeadlyImportError("Failed to open file " + rFile+ ".");
|
||||
}
|
||||
|
@ -481,14 +149,14 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
|
|||
|
||||
ASSIMP_LOG_DEBUG(rootFile);
|
||||
|
||||
mZipArchive->Close(fileStream);
|
||||
|
||||
mRootStream = mZipArchive->Open(rootFile.c_str());
|
||||
ai_assert( mRootStream != nullptr );
|
||||
if ( nullptr == mRootStream ) {
|
||||
throw DeadlyExportError( "Cannot open root-file in archive : " + rootFile );
|
||||
}
|
||||
|
||||
mZipArchive->Close( fileStream );
|
||||
|
||||
} else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) {
|
||||
ASSIMP_LOG_WARN_F("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES",file);
|
||||
} else {
|
||||
|
@ -499,7 +167,7 @@ D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile)
|
|||
}
|
||||
|
||||
D3MFOpcPackage::~D3MFOpcPackage() {
|
||||
// empty
|
||||
mZipArchive->Close(mRootStream);
|
||||
}
|
||||
|
||||
IOStream* D3MFOpcPackage::RootStream() const {
|
||||
|
@ -516,15 +184,6 @@ bool D3MFOpcPackage::validate() {
|
|||
return mZipArchive->Exists( ModelRef.c_str() );
|
||||
}
|
||||
|
||||
bool D3MFOpcPackage::isZipArchive( IOSystem* pIOHandler, const std::string& rFile ) {
|
||||
D3MF::D3MFZipArchive ar( pIOHandler, rFile );
|
||||
if ( !ar.isOpen() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) {
|
||||
std::unique_ptr<CIrrXML_IOStreamReader> xmlStream(new CIrrXML_IOStreamReader(stream));
|
||||
std::unique_ptr<XmlReader> xml(irr::io::createIrrXMLReader(xmlStream.get()));
|
||||
|
|
|
@ -49,6 +49,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/irrXMLWrapper.h>
|
||||
|
||||
namespace Assimp {
|
||||
class ZipArchiveIOSystem;
|
||||
|
||||
namespace D3MF {
|
||||
|
||||
using XmlReader = irr::io::IrrXMLReader ;
|
||||
|
@ -60,22 +62,19 @@ struct OpcPackageRelationship {
|
|||
std::string target;
|
||||
};
|
||||
|
||||
class D3MFZipArchive;
|
||||
|
||||
class D3MFOpcPackage {
|
||||
public:
|
||||
D3MFOpcPackage( IOSystem* pIOHandler, const std::string& rFile );
|
||||
~D3MFOpcPackage();
|
||||
IOStream* RootStream() const;
|
||||
bool validate();
|
||||
static bool isZipArchive( IOSystem* pIOHandler, const std::string& rFile );
|
||||
|
||||
protected:
|
||||
std::string ReadPackageRootRelationship(IOStream* stream);
|
||||
|
||||
private:
|
||||
IOStream* mRootStream;
|
||||
std::unique_ptr<D3MFZipArchive> mZipArchive;
|
||||
std::unique_ptr<ZipArchiveIOSystem> mZipArchive;
|
||||
};
|
||||
|
||||
} // Namespace D3MF
|
||||
|
|
|
@ -83,7 +83,7 @@ void AMFImporter::Clear()
|
|||
mMaterial_Converted.clear();
|
||||
mTexture_Converted.clear();
|
||||
// Delete all elements
|
||||
if(mNodeElement_List.size())
|
||||
if(!mNodeElement_List.empty())
|
||||
{
|
||||
for(CAMFImporter_NodeElement* ne: mNodeElement_List) { delete ne; }
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ aiColor4D AMFImporter::SPP_Material::GetColor(const float /*pX*/, const float /*
|
|||
aiColor4D tcol;
|
||||
|
||||
// Check if stored data are supported.
|
||||
if(Composition.size() != 0)
|
||||
if(!Composition.empty())
|
||||
{
|
||||
throw DeadlyImportError("IME. GetColor for composition");
|
||||
}
|
||||
|
@ -321,7 +321,7 @@ void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace
|
|||
};
|
||||
|
||||
pOutputList_Separated.clear();
|
||||
if(pInputList.size() == 0) return;
|
||||
if(pInputList.empty()) return;
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -334,19 +334,19 @@ void AMFImporter::PostprocessHelper_SplitFacesByTextureID(std::list<SComplexFace
|
|||
{
|
||||
auto it_old = it;
|
||||
|
||||
it++;
|
||||
++it;
|
||||
face_list_cur.push_back(*it_old);
|
||||
pInputList.erase(it_old);
|
||||
}
|
||||
else
|
||||
{
|
||||
it++;
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
if(face_list_cur.size() > 0) pOutputList_Separated.push_back(face_list_cur);
|
||||
if(!face_list_cur.empty()) pOutputList_Separated.push_back(face_list_cur);
|
||||
|
||||
} while(pInputList.size() > 0);
|
||||
} while(!pInputList.empty());
|
||||
}
|
||||
|
||||
void AMFImporter::Postprocess_AddMetadata(const std::list<CAMFImporter_NodeElement_Metadata*>& metadataList, aiNode& sceneNode) const
|
||||
|
@ -712,7 +712,7 @@ std::list<unsigned int> mesh_idx;
|
|||
}// for(const CAMFImporter_NodeElement* ne_child: pNodeElement.Child)
|
||||
|
||||
// if meshes was created then assign new indices with current aiNode
|
||||
if(mesh_idx.size() > 0)
|
||||
if(!mesh_idx.empty())
|
||||
{
|
||||
std::list<unsigned int>::const_iterator mit = mesh_idx.begin();
|
||||
|
||||
|
@ -787,7 +787,7 @@ std::list<aiNode*> ch_node;
|
|||
}// for(const CAMFImporter_NodeElement* ne: pConstellation.Child)
|
||||
|
||||
// copy found aiNode's as children
|
||||
if(ch_node.size() == 0) throw DeadlyImportError("<constellation> must have at least one <instance>.");
|
||||
if(ch_node.empty()) throw DeadlyImportError("<constellation> must have at least one <instance>.");
|
||||
|
||||
size_t ch_idx = 0;
|
||||
|
||||
|
@ -883,13 +883,13 @@ nl_clean_loop:
|
|||
if(node_list.size() > 1)
|
||||
{
|
||||
// walk through all nodes
|
||||
for(std::list<aiNode*>::iterator nl_it = node_list.begin(); nl_it != node_list.end(); nl_it++)
|
||||
for(std::list<aiNode*>::iterator nl_it = node_list.begin(); nl_it != node_list.end(); ++nl_it)
|
||||
{
|
||||
// and try to find them in another top nodes.
|
||||
std::list<aiNode*>::const_iterator next_it = nl_it;
|
||||
|
||||
next_it++;
|
||||
for(; next_it != node_list.end(); next_it++)
|
||||
++next_it;
|
||||
for(; next_it != node_list.end(); ++next_it)
|
||||
{
|
||||
if((*next_it)->FindNode((*nl_it)->mName) != nullptr)
|
||||
{
|
||||
|
@ -907,7 +907,7 @@ nl_clean_loop:
|
|||
//
|
||||
//
|
||||
// Nodes
|
||||
if(node_list.size() > 0)
|
||||
if(!node_list.empty())
|
||||
{
|
||||
std::list<aiNode*>::const_iterator nl_it = node_list.begin();
|
||||
|
||||
|
@ -924,7 +924,7 @@ nl_clean_loop:
|
|||
|
||||
//
|
||||
// Meshes
|
||||
if(mesh_list.size() > 0)
|
||||
if(!mesh_list.empty())
|
||||
{
|
||||
std::list<aiMesh*>::const_iterator ml_it = mesh_list.begin();
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
|
|||
{
|
||||
state_in->result = result;
|
||||
state_in->step = step_A;
|
||||
return codechar - code_out;
|
||||
return (int)(codechar - code_out);
|
||||
}
|
||||
fragment = *plainchar++;
|
||||
result = (fragment & 0x0fc) >> 2;
|
||||
|
@ -53,7 +53,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
|
|||
{
|
||||
state_in->result = result;
|
||||
state_in->step = step_B;
|
||||
return codechar - code_out;
|
||||
return (int)(codechar - code_out);
|
||||
}
|
||||
fragment = *plainchar++;
|
||||
result |= (fragment & 0x0f0) >> 4;
|
||||
|
@ -64,7 +64,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
|
|||
{
|
||||
state_in->result = result;
|
||||
state_in->step = step_C;
|
||||
return codechar - code_out;
|
||||
return (int)(codechar - code_out);
|
||||
}
|
||||
fragment = *plainchar++;
|
||||
result |= (fragment & 0x0c0) >> 6;
|
||||
|
@ -81,7 +81,7 @@ int base64_encode_block(const char* plaintext_in, int length_in, char* code_out,
|
|||
}
|
||||
}
|
||||
/* control should not reach here */
|
||||
return codechar - code_out;
|
||||
return (int)(codechar - code_out);
|
||||
}
|
||||
|
||||
int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
|
||||
|
@ -104,6 +104,6 @@ int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
|
|||
}
|
||||
*codechar++ = '\n';
|
||||
|
||||
return codechar - code_out;
|
||||
return (int)(codechar - code_out);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,15 +34,6 @@ namespace Assimp {
|
|||
|
||||
void ExportAssimp2Json(const char*, Assimp::IOSystem*, const aiScene*, const Assimp::ExportProperties*);
|
||||
|
||||
Exporter::ExportFormatEntry Assimp2Json_desc = Assimp::Exporter::ExportFormatEntry(
|
||||
"json",
|
||||
"Plain JSON representation of the Assimp scene data structure",
|
||||
"json",
|
||||
&ExportAssimp2Json,
|
||||
0u
|
||||
);
|
||||
|
||||
|
||||
// small utility class to simplify serializing the aiScene to Json
|
||||
class JSONWriter {
|
||||
public:
|
||||
|
|
|
@ -5,8 +5,6 @@ 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,
|
||||
|
@ -78,7 +76,6 @@ static const aiImporterDesc desc = {
|
|||
"b3d"
|
||||
};
|
||||
|
||||
// (fixme, Aramis) quick workaround to get rid of all those signed to unsigned warnings
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning (disable: 4018)
|
||||
#endif
|
||||
|
@ -86,10 +83,8 @@ static const aiImporterDesc desc = {
|
|||
//#define DEBUG_B3D
|
||||
|
||||
template<typename T>
|
||||
void DeleteAllBarePointers(std::vector<T>& x)
|
||||
{
|
||||
for(auto p : x)
|
||||
{
|
||||
void DeleteAllBarePointers(std::vector<T>& x) {
|
||||
for(auto p : x) {
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
@ -102,10 +97,14 @@ B3DImporter::~B3DImporter()
|
|||
bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{
|
||||
|
||||
size_t pos=pFile.find_last_of( '.' );
|
||||
if( pos==string::npos ) return false;
|
||||
if( pos==string::npos ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
string ext=pFile.substr( pos+1 );
|
||||
if( ext.size()!=3 ) return false;
|
||||
if( ext.size()!=3 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D');
|
||||
}
|
||||
|
@ -117,30 +116,21 @@ const aiImporterDesc* B3DImporter::GetInfo () const
|
|||
return &desc;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_B3D
|
||||
extern "C"{ void _stdcall AllocConsole(); }
|
||||
#endif
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler){
|
||||
|
||||
#ifdef DEBUG_B3D
|
||||
AllocConsole();
|
||||
freopen( "conin$","r",stdin );
|
||||
freopen( "conout$","w",stdout );
|
||||
freopen( "conout$","w",stderr );
|
||||
cout<<"Hello world from the B3DImporter!"<<endl;
|
||||
#endif
|
||||
|
||||
std::unique_ptr<IOStream> file( pIOHandler->Open( pFile));
|
||||
|
||||
// Check whether we can read from the file
|
||||
if( file.get() == NULL)
|
||||
if( file.get() == nullptr) {
|
||||
throw DeadlyImportError( "Failed to open B3D file " + pFile + ".");
|
||||
}
|
||||
|
||||
// check whether the .b3d file is large enough to contain
|
||||
// at least one chunk.
|
||||
size_t fileSize = file->FileSize();
|
||||
if( fileSize<8 ) throw DeadlyImportError( "B3D File is too small.");
|
||||
if( fileSize<8 ) {
|
||||
throw DeadlyImportError( "B3D File is too small.");
|
||||
}
|
||||
|
||||
_pos=0;
|
||||
_buf.resize( fileSize );
|
||||
|
@ -158,14 +148,17 @@ AI_WONT_RETURN void B3DImporter::Oops(){
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
AI_WONT_RETURN void B3DImporter::Fail( string str ){
|
||||
#ifdef DEBUG_B3D
|
||||
cout<<"Error in B3D file data: "<<str<<endl;
|
||||
ASSIMP_LOG_ERROR_F("Error in B3D file data: ", str);
|
||||
#endif
|
||||
throw DeadlyImportError( "B3D Importer - error in B3D file data: "+str );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
int B3DImporter::ReadByte(){
|
||||
if( _pos<_buf.size() ) return _buf[_pos++];
|
||||
if( _pos<_buf.size() ) {
|
||||
return _buf[_pos++];
|
||||
}
|
||||
|
||||
Fail( "EOF" );
|
||||
return 0;
|
||||
}
|
||||
|
@ -224,7 +217,9 @@ string B3DImporter::ReadString(){
|
|||
string str;
|
||||
while( _pos<_buf.size() ){
|
||||
char c=(char)ReadByte();
|
||||
if( !c ) return str;
|
||||
if( !c ) {
|
||||
return str;
|
||||
}
|
||||
str+=c;
|
||||
}
|
||||
Fail( "EOF" );
|
||||
|
@ -238,7 +233,7 @@ string B3DImporter::ReadChunk(){
|
|||
tag+=char( ReadByte() );
|
||||
}
|
||||
#ifdef DEBUG_B3D
|
||||
// cout<<"ReadChunk:"<<tag<<endl;
|
||||
ASSIMP_LOG_DEBUG_F("ReadChunk: ", tag);
|
||||
#endif
|
||||
unsigned sz=(unsigned)ReadInt();
|
||||
_stack.push_back( _pos+sz );
|
||||
|
@ -269,7 +264,6 @@ T *B3DImporter::to_array( const vector<T> &v ){
|
|||
return p;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template<class T>
|
||||
T **unique_to_array( vector<std::unique_ptr<T> > &v ){
|
||||
|
@ -283,7 +277,6 @@ T **unique_to_array( vector<std::unique_ptr<T> > &v ){
|
|||
return p;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void B3DImporter::ReadTEXS(){
|
||||
while( ChunkSize() ){
|
||||
|
@ -376,9 +369,13 @@ void B3DImporter::ReadVRTS(){
|
|||
|
||||
v.vertex=ReadVec3();
|
||||
|
||||
if( _vflags & 1 ) v.normal=ReadVec3();
|
||||
if( _vflags & 1 ) {
|
||||
v.normal=ReadVec3();
|
||||
}
|
||||
|
||||
if( _vflags & 2 ) ReadQuat(); //skip v 4bytes...
|
||||
if( _vflags & 2 ) {
|
||||
ReadQuat(); //skip v 4bytes...
|
||||
}
|
||||
|
||||
for( int i=0;i<_tcsets;++i ){
|
||||
float t[4]={0,0,0,0};
|
||||
|
@ -386,53 +383,55 @@ void B3DImporter::ReadVRTS(){
|
|||
t[j]=ReadFloat();
|
||||
}
|
||||
t[1]=1-t[1];
|
||||
if( !i ) v.texcoords=aiVector3D( t[0],t[1],t[2] );
|
||||
if( !i ) {
|
||||
v.texcoords=aiVector3D( t[0],t[1],t[2] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void B3DImporter::ReadTRIS( int v0 ){
|
||||
int matid=ReadInt();
|
||||
if( matid==-1 ){
|
||||
matid=0;
|
||||
}else if( matid<0 || matid>=(int)_materials.size() ){
|
||||
void B3DImporter::ReadTRIS(int v0) {
|
||||
int matid = ReadInt();
|
||||
if (matid == -1) {
|
||||
matid = 0;
|
||||
} else if (matid < 0 || matid >= (int)_materials.size()) {
|
||||
#ifdef DEBUG_B3D
|
||||
cout<<"material id="<<matid<<endl;
|
||||
ASSIMP_LOG_ERROR_F("material id=", matid);
|
||||
#endif
|
||||
Fail( "Bad material id" );
|
||||
Fail("Bad material id");
|
||||
}
|
||||
|
||||
std::unique_ptr<aiMesh> mesh(new aiMesh);
|
||||
|
||||
mesh->mMaterialIndex=matid;
|
||||
mesh->mNumFaces=0;
|
||||
mesh->mPrimitiveTypes=aiPrimitiveType_TRIANGLE;
|
||||
mesh->mMaterialIndex = matid;
|
||||
mesh->mNumFaces = 0;
|
||||
mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE;
|
||||
|
||||
int n_tris=ChunkSize()/12;
|
||||
aiFace *face=mesh->mFaces=new aiFace[n_tris];
|
||||
int n_tris = ChunkSize() / 12;
|
||||
aiFace *face = mesh->mFaces = new aiFace[n_tris];
|
||||
|
||||
for( int i=0;i<n_tris;++i ){
|
||||
int i0=ReadInt()+v0;
|
||||
int i1=ReadInt()+v0;
|
||||
int i2=ReadInt()+v0;
|
||||
if( i0<0 || i0>=(int)_vertices.size() || i1<0 || i1>=(int)_vertices.size() || i2<0 || i2>=(int)_vertices.size() ){
|
||||
for (int i = 0; i < n_tris; ++i) {
|
||||
int i0 = ReadInt() + v0;
|
||||
int i1 = ReadInt() + v0;
|
||||
int i2 = ReadInt() + v0;
|
||||
if (i0 < 0 || i0 >= (int)_vertices.size() || i1 < 0 || i1 >= (int)_vertices.size() || i2 < 0 || i2 >= (int)_vertices.size()) {
|
||||
#ifdef DEBUG_B3D
|
||||
cout<<"Bad triangle index: i0="<<i0<<", i1="<<i1<<", i2="<<i2<<endl;
|
||||
ASSIMP_LOG_ERROR_F("Bad triangle index: i0=", i0, ", i1=", i1, ", i2=", i2);
|
||||
#endif
|
||||
Fail( "Bad triangle index" );
|
||||
Fail("Bad triangle index");
|
||||
continue;
|
||||
}
|
||||
face->mNumIndices=3;
|
||||
face->mIndices=new unsigned[3];
|
||||
face->mIndices[0]=i0;
|
||||
face->mIndices[1]=i1;
|
||||
face->mIndices[2]=i2;
|
||||
face->mNumIndices = 3;
|
||||
face->mIndices = new unsigned[3];
|
||||
face->mIndices[0] = i0;
|
||||
face->mIndices[1] = i1;
|
||||
face->mIndices[2] = i2;
|
||||
++mesh->mNumFaces;
|
||||
++face;
|
||||
}
|
||||
|
||||
_meshes.emplace_back( std::move(mesh) );
|
||||
_meshes.emplace_back(std::move(mesh));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -453,28 +452,22 @@ void B3DImporter::ReadMESH(){
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void B3DImporter::ReadBONE( int id ){
|
||||
while( ChunkSize() ){
|
||||
int vertex=ReadInt();
|
||||
float weight=ReadFloat();
|
||||
if( vertex<0 || vertex>=(int)_vertices.size() ){
|
||||
Fail( "Bad vertex index" );
|
||||
void B3DImporter::ReadBONE(int id) {
|
||||
while (ChunkSize()) {
|
||||
int vertex = ReadInt();
|
||||
float weight = ReadFloat();
|
||||
if (vertex < 0 || vertex >= (int)_vertices.size()) {
|
||||
Fail("Bad vertex index");
|
||||
}
|
||||
|
||||
Vertex &v=_vertices[vertex];
|
||||
int i;
|
||||
for( i=0;i<4;++i ){
|
||||
if( !v.weights[i] ){
|
||||
v.bones[i]=id;
|
||||
v.weights[i]=weight;
|
||||
Vertex &v = _vertices[vertex];
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
if (!v.weights[i]) {
|
||||
v.bones[i] = id;
|
||||
v.weights[i] = weight;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef DEBUG_B3D
|
||||
if( i==4 ){
|
||||
cout<<"Too many bone weights"<<endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -633,11 +626,15 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
|
|||
}
|
||||
ExitChunk();
|
||||
|
||||
if( !_nodes.size() ) Fail( "No nodes" );
|
||||
if( !_nodes.size() ) {
|
||||
Fail( "No nodes" );
|
||||
}
|
||||
|
||||
if( !_meshes.size() ) Fail( "No meshes" );
|
||||
if( !_meshes.size() ) {
|
||||
Fail( "No meshes" );
|
||||
}
|
||||
|
||||
//Fix nodes/meshes/bones
|
||||
// Fix nodes/meshes/bones
|
||||
for(size_t i=0;i<_nodes.size();++i ){
|
||||
aiNode *node=_nodes[i];
|
||||
|
||||
|
@ -648,8 +645,12 @@ void B3DImporter::ReadBB3D( aiScene *scene ){
|
|||
int n_verts=mesh->mNumVertices=n_tris * 3;
|
||||
|
||||
aiVector3D *mv=mesh->mVertices=new aiVector3D[ n_verts ],*mn=0,*mc=0;
|
||||
if( _vflags & 1 ) mn=mesh->mNormals=new aiVector3D[ n_verts ];
|
||||
if( _tcsets ) mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ];
|
||||
if( _vflags & 1 ) {
|
||||
mn=mesh->mNormals=new aiVector3D[ n_verts ];
|
||||
}
|
||||
if( _tcsets ) {
|
||||
mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ];
|
||||
}
|
||||
|
||||
aiFace *face=mesh->mFaces;
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ SET( PUBLIC_HEADERS
|
|||
${HEADER_PATH}/color4.h
|
||||
${HEADER_PATH}/color4.inl
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../include/assimp/config.h
|
||||
${HEADER_PATH}/commonMetaData.h
|
||||
${HEADER_PATH}/defs.h
|
||||
${HEADER_PATH}/Defines.h
|
||||
${HEADER_PATH}/cfileio.h
|
||||
|
@ -104,6 +105,7 @@ SET( PUBLIC_HEADERS
|
|||
${HEADER_PATH}/Exporter.hpp
|
||||
${HEADER_PATH}/DefaultIOStream.h
|
||||
${HEADER_PATH}/DefaultIOSystem.h
|
||||
${HEADER_PATH}/ZipArchiveIOSystem.h
|
||||
${HEADER_PATH}/SceneCombiner.h
|
||||
${HEADER_PATH}/fast_atof.h
|
||||
${HEADER_PATH}/qnan.h
|
||||
|
@ -136,7 +138,6 @@ SET( PUBLIC_HEADERS
|
|||
${HEADER_PATH}/irrXMLWrapper.h
|
||||
${HEADER_PATH}/BlobIOSystem.h
|
||||
${HEADER_PATH}/MathFunctions.h
|
||||
${HEADER_PATH}/Macros.h
|
||||
${HEADER_PATH}/Exceptional.h
|
||||
${HEADER_PATH}/ByteSwapper.h
|
||||
)
|
||||
|
@ -172,6 +173,7 @@ SET( Common_SRCS
|
|||
Common/DefaultProgressHandler.h
|
||||
Common/DefaultIOStream.cpp
|
||||
Common/DefaultIOSystem.cpp
|
||||
Common/ZipArchiveIOSystem.cpp
|
||||
Common/PolyTools.h
|
||||
Common/Importer.cpp
|
||||
Common/IFF.h
|
||||
|
@ -347,6 +349,7 @@ ADD_ASSIMP_IMPORTER( BVH
|
|||
)
|
||||
|
||||
ADD_ASSIMP_IMPORTER( COLLADA
|
||||
Collada/ColladaHelper.cpp
|
||||
Collada/ColladaHelper.h
|
||||
Collada/ColladaLoader.cpp
|
||||
Collada/ColladaLoader.h
|
||||
|
@ -406,6 +409,20 @@ ADD_ASSIMP_IMPORTER( LWS
|
|||
LWS/LWSLoader.h
|
||||
)
|
||||
|
||||
ADD_ASSIMP_IMPORTER( M3D
|
||||
M3D/M3DMaterials.h
|
||||
M3D/M3DImporter.h
|
||||
M3D/M3DImporter.cpp
|
||||
M3D/M3DWrapper.h
|
||||
M3D/M3DWrapper.cpp
|
||||
M3D/m3d.h
|
||||
)
|
||||
|
||||
ADD_ASSIMP_EXPORTER( M3D
|
||||
M3D/M3DExporter.h
|
||||
M3D/M3DExporter.cpp
|
||||
)
|
||||
|
||||
ADD_ASSIMP_IMPORTER( MD2
|
||||
MD2/MD2FileData.h
|
||||
MD2/MD2Loader.cpp
|
||||
|
@ -439,6 +456,16 @@ ADD_ASSIMP_IMPORTER( MDL
|
|||
MDL/MDLLoader.cpp
|
||||
MDL/MDLLoader.h
|
||||
MDL/MDLMaterialLoader.cpp
|
||||
MDL/HalfLife/HalfLifeMDLBaseHeader.h
|
||||
MDL/HalfLife/HL1FileData.h
|
||||
MDL/HalfLife/HL1MDLLoader.cpp
|
||||
MDL/HalfLife/HL1MDLLoader.h
|
||||
MDL/HalfLife/HL1ImportDefinitions.h
|
||||
MDL/HalfLife/HL1ImportSettings.h
|
||||
MDL/HalfLife/HL1MeshTrivert.h
|
||||
MDL/HalfLife/LogFunctions.h
|
||||
MDL/HalfLife/UniqueNameGenerator.cpp
|
||||
MDL/HalfLife/UniqueNameGenerator.h
|
||||
)
|
||||
|
||||
SET( MaterialSystem_SRCS
|
||||
|
@ -669,6 +696,8 @@ SET( PostProcessing_SRCS
|
|||
PostProcessing/MakeVerboseFormat.h
|
||||
PostProcessing/ScaleProcess.cpp
|
||||
PostProcessing/ScaleProcess.h
|
||||
PostProcessing/ArmaturePopulate.cpp
|
||||
PostProcessing/ArmaturePopulate.h
|
||||
PostProcessing/GenBoundingBoxesProcess.cpp
|
||||
PostProcessing/GenBoundingBoxesProcess.h
|
||||
)
|
||||
|
@ -688,8 +717,6 @@ ADD_ASSIMP_IMPORTER( Q3BSP
|
|||
Q3BSP/Q3BSPFileParser.cpp
|
||||
Q3BSP/Q3BSPFileImporter.h
|
||||
Q3BSP/Q3BSPFileImporter.cpp
|
||||
Q3BSP/Q3BSPZipArchive.h
|
||||
Q3BSP/Q3BSPZipArchive.cpp
|
||||
)
|
||||
|
||||
ADD_ASSIMP_IMPORTER( RAW
|
||||
|
@ -766,6 +793,8 @@ ADD_ASSIMP_EXPORTER( X3D
|
|||
)
|
||||
|
||||
ADD_ASSIMP_IMPORTER( GLTF
|
||||
glTF/glTFCommon.h
|
||||
glTF/glTFCommon.cpp
|
||||
glTF/glTFAsset.h
|
||||
glTF/glTFAsset.inl
|
||||
glTF/glTFAssetWriter.h
|
||||
|
@ -810,7 +839,7 @@ ADD_ASSIMP_IMPORTER( MMD
|
|||
MMD/MMDVmdParser.h
|
||||
)
|
||||
|
||||
ADD_ASSIMP_EXPORTER( Assjson
|
||||
ADD_ASSIMP_EXPORTER( ASSJSON
|
||||
Assjson/cencode.c
|
||||
Assjson/cencode.h
|
||||
Assjson/json_exporter.cpp
|
||||
|
@ -1057,6 +1086,8 @@ MESSAGE(STATUS "Disabled importer formats:${ASSIMP_IMPORTERS_DISABLED}")
|
|||
MESSAGE(STATUS "Enabled exporter formats:${ASSIMP_EXPORTERS_ENABLED}")
|
||||
MESSAGE(STATUS "Disabled exporter formats:${ASSIMP_EXPORTERS_DISABLED}")
|
||||
|
||||
SOURCE_GROUP( include\\assimp FILES ${PUBLIC_HEADERS} )
|
||||
|
||||
SET( assimp_src
|
||||
# Assimp Files
|
||||
${Core_SRCS}
|
||||
|
|
|
@ -178,7 +178,7 @@ void CSMImporter::InternReadFile( const std::string& pFile,
|
|||
*ot++ = *buffer++;
|
||||
|
||||
*ot = '\0';
|
||||
nda->mNodeName.length = (size_t)(ot-nda->mNodeName.data);
|
||||
nda->mNodeName.length = (ai_uint32)(ot-nda->mNodeName.data);
|
||||
}
|
||||
|
||||
anim->mNumChannels = static_cast<unsigned int>(anims_temp.size());
|
||||
|
|
|
@ -45,6 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "ColladaExporter.h"
|
||||
#include <assimp/Bitmap.h>
|
||||
#include <assimp/commonMetaData.h>
|
||||
#include <assimp/MathFunctions.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/SceneCombiner.h>
|
||||
#include <assimp/StringUtils.h>
|
||||
|
@ -91,6 +93,36 @@ void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* p
|
|||
|
||||
} // 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
|
||||
ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file)
|
||||
|
@ -145,7 +177,7 @@ void ColladaExporter::WriteFile() {
|
|||
// useless Collada fu at the end, just in case we haven't had enough indirections, yet.
|
||||
mOutput << startstr << "<scene>" << endstr;
|
||||
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();
|
||||
mOutput << startstr << "</scene>" << endstr;
|
||||
PopTag();
|
||||
|
@ -155,7 +187,7 @@ void ColladaExporter::WriteFile() {
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Writes the asset header
|
||||
void ColladaExporter::WriteHeader() {
|
||||
static const ai_real epsilon = ai_real( 0.00001 );
|
||||
static const ai_real epsilon = Math::getEpsilon<ai_real>();
|
||||
static const aiQuaternion x_rot(aiMatrix3x3(
|
||||
0, -1, 0,
|
||||
1, 0, 0,
|
||||
|
@ -246,7 +278,7 @@ void ColladaExporter::WriteHeader() {
|
|||
mOutput << startstr << "<author>" << XMLEscape(value.C_Str()) << "</author>" << endstr;
|
||||
}
|
||||
|
||||
if (nullptr == meta || !meta->Get("AuthoringTool", value)) {
|
||||
if (nullptr == meta || !meta->Get(AI_METADATA_SOURCE_GENERATOR, value)) {
|
||||
mOutput << startstr << "<authoring_tool>" << "Assimp Exporter" << "</authoring_tool>" << endstr;
|
||||
} else {
|
||||
mOutput << startstr << "<authoring_tool>" << XMLEscape(value.C_Str()) << "</authoring_tool>" << endstr;
|
||||
|
@ -256,7 +288,7 @@ void ColladaExporter::WriteHeader() {
|
|||
if (meta->Get("Comments", value)) {
|
||||
mOutput << startstr << "<comments>" << XMLEscape(value.C_Str()) << "</comments>" << endstr;
|
||||
}
|
||||
if (meta->Get("Copyright", value)) {
|
||||
if (meta->Get(AI_METADATA_SOURCE_COPYRIGHT, value)) {
|
||||
mOutput << startstr << "<copyright>" << XMLEscape(value.C_Str()) << "</copyright>" << endstr;
|
||||
}
|
||||
if (meta->Get("SourceData", value)) {
|
||||
|
@ -317,7 +349,7 @@ void ColladaExporter::WriteTextures() {
|
|||
|
||||
std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char*) texture->achFormatHint);
|
||||
|
||||
std::unique_ptr<IOStream> outfile(mIOSystem->Open(mPath + name, "wb"));
|
||||
std::unique_ptr<IOStream> outfile(mIOSystem->Open(mPath + mIOSystem->getOsSeparator() + name, "wb"));
|
||||
if(outfile == NULL) {
|
||||
throw DeadlyExportError("could not open output texture file: " + mPath + name);
|
||||
}
|
||||
|
@ -355,9 +387,10 @@ void ColladaExporter::WriteCamerasLibrary() {
|
|||
void ColladaExporter::WriteCamera(size_t 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();
|
||||
mOutput << startstr << "<optics>" << endstr;
|
||||
PushTag();
|
||||
|
@ -411,10 +444,11 @@ void ColladaExporter::WriteLightsLibrary() {
|
|||
void ColladaExporter::WriteLight(size_t 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=\""
|
||||
<< idstrEscaped << "_name\" >" << endstr;
|
||||
mOutput << startstr << "<light id=\"" << lightId << "-light\" name=\""
|
||||
<< lightName << "\" >" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<technique_common>" << endstr;
|
||||
PushTag();
|
||||
|
@ -585,7 +619,7 @@ static bool isalnum_C(char c) {
|
|||
void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd) {
|
||||
if( !pSurface.texture.empty() )
|
||||
{
|
||||
mOutput << startstr << "<image id=\"" << XMLEscape(pNameAdd) << "\">" << endstr;
|
||||
mOutput << startstr << "<image id=\"" << XMLIDEncode(pNameAdd) << "\">" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<init_from>";
|
||||
|
||||
|
@ -618,7 +652,7 @@ void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std
|
|||
}
|
||||
else
|
||||
{
|
||||
mOutput << startstr << "<texture texture=\"" << XMLEscape(pImageName) << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
|
||||
mOutput << startstr << "<texture texture=\"" << XMLIDEncode(pImageName) << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr;
|
||||
}
|
||||
PopTag();
|
||||
mOutput << startstr << "</" << pTypeName << ">" << endstr;
|
||||
|
@ -632,21 +666,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( !pSurface.texture.empty() )
|
||||
{
|
||||
mOutput << startstr << "<newparam sid=\"" << XMLEscape(pMatName) << "-" << pTypeName << "-surface\">" << endstr;
|
||||
mOutput << startstr << "<newparam sid=\"" << XMLIDEncode(pMatName) << "-" << pTypeName << "-surface\">" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<surface type=\"2D\">" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<init_from>" << XMLEscape(pMatName) << "-" << pTypeName << "-image</init_from>" << endstr;
|
||||
mOutput << startstr << "<init_from>" << XMLIDEncode(pMatName) << "-" << pTypeName << "-image</init_from>" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "</surface>" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "</newparam>" << endstr;
|
||||
|
||||
mOutput << startstr << "<newparam sid=\"" << XMLEscape(pMatName) << "-" << pTypeName << "-sampler\">" << endstr;
|
||||
mOutput << startstr << "<newparam sid=\"" << XMLIDEncode(pMatName) << "-" << pTypeName << "-sampler\">" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<sampler2D>" << endstr;
|
||||
PushTag();
|
||||
mOutput << startstr << "<source>" << XMLEscape(pMatName) << "-" << pTypeName << "-surface</source>" << endstr;
|
||||
mOutput << startstr << "<source>" << XMLIDEncode(pMatName) << "-" << pTypeName << "-surface</source>" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "</sampler2D>" << endstr;
|
||||
PopTag();
|
||||
|
@ -698,11 +732,6 @@ void ColladaExporter::WriteMaterials()
|
|||
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;
|
||||
materials[a].shading_model = "phong";
|
||||
|
@ -767,7 +796,7 @@ void ColladaExporter::WriteMaterials()
|
|||
{
|
||||
const Material& mat = *it;
|
||||
// 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();
|
||||
mOutput << startstr << "<profile_COMMON>" << endstr;
|
||||
PushTag();
|
||||
|
@ -818,9 +847,9 @@ void ColladaExporter::WriteMaterials()
|
|||
for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++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();
|
||||
mOutput << startstr << "<instance_effect url=\"#" << XMLEscape(mat.name) << "-fx\"/>" << endstr;
|
||||
mOutput << startstr << "<instance_effect url=\"#" << XMLIDEncode(mat.name) << "-fx\"/>" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "</material>" << endstr;
|
||||
}
|
||||
|
@ -849,8 +878,8 @@ void ColladaExporter::WriteControllerLibrary()
|
|||
void ColladaExporter::WriteController( size_t pIndex)
|
||||
{
|
||||
const aiMesh* mesh = mScene->mMeshes[pIndex];
|
||||
const std::string idstr = GetMeshId( pIndex);
|
||||
const std::string idstrEscaped = XMLEscape(idstr);
|
||||
const std::string idstr = mesh->mName.length == 0 ? GetMeshId(pIndex) : mesh->mName.C_Str();
|
||||
const std::string idstrEscaped = XMLIDEncode(idstr);
|
||||
|
||||
if ( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
|
||||
return;
|
||||
|
@ -885,7 +914,7 @@ void ColladaExporter::WriteController( size_t pIndex)
|
|||
mOutput << startstr << "<Name_array id=\"" << idstrEscaped << "-skin-joints-array\" count=\"" << mesh->mNumBones << "\">";
|
||||
|
||||
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;
|
||||
|
||||
|
@ -1020,14 +1049,15 @@ void ColladaExporter::WriteGeometryLibrary()
|
|||
void ColladaExporter::WriteGeometry( size_t pIndex)
|
||||
{
|
||||
const aiMesh* mesh = mScene->mMeshes[pIndex];
|
||||
const std::string idstr = GetMeshId( pIndex);
|
||||
const std::string idstrEscaped = XMLEscape(idstr);
|
||||
const std::string idstr = mesh->mName.length == 0 ? GetMeshId(pIndex) : mesh->mName.C_Str();
|
||||
const std::string geometryName = XMLEscape(idstr);
|
||||
const std::string geometryId = XMLIDEncode(idstr);
|
||||
|
||||
if ( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
|
||||
return;
|
||||
|
||||
// opening tag
|
||||
mOutput << startstr << "<geometry id=\"" << idstrEscaped << "\" name=\"" << idstrEscaped << "_name\" >" << endstr;
|
||||
mOutput << startstr << "<geometry id=\"" << geometryId << "\" name=\"" << geometryName << "\" >" << endstr;
|
||||
PushTag();
|
||||
|
||||
mOutput << startstr << "<mesh>" << endstr;
|
||||
|
@ -1058,9 +1088,9 @@ void ColladaExporter::WriteGeometry( size_t pIndex)
|
|||
|
||||
// assemble vertex structure
|
||||
// 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();
|
||||
mOutput << startstr << "<input semantic=\"POSITION\" source=\"#" << idstrEscaped << "-positions\" />" << endstr;
|
||||
mOutput << startstr << "<input semantic=\"POSITION\" source=\"#" << geometryId << "-positions\" />" << endstr;
|
||||
PopTag();
|
||||
mOutput << startstr << "</vertices>" << endstr;
|
||||
|
||||
|
@ -1078,18 +1108,18 @@ void ColladaExporter::WriteGeometry( size_t pIndex)
|
|||
{
|
||||
mOutput << startstr << "<lines count=\"" << countLines << "\" material=\"defaultMaterial\">" << endstr;
|
||||
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() )
|
||||
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 )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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>";
|
||||
|
@ -1112,18 +1142,18 @@ void ColladaExporter::WriteGeometry( size_t pIndex)
|
|||
{
|
||||
mOutput << startstr << "<polylist count=\"" << countPoly << "\" material=\"defaultMaterial\">" << endstr;
|
||||
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() )
|
||||
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 )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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>";
|
||||
|
@ -1172,13 +1202,13 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy
|
|||
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();
|
||||
|
||||
// source array
|
||||
mOutput << startstr << "<float_array id=\"" << XMLEscape(arrayId) << "\" count=\"" << pElementCount * floatsPerElement << "\"> ";
|
||||
mOutput << startstr << "<float_array id=\"" << arrayId << "\" count=\"" << pElementCount * floatsPerElement << "\"> ";
|
||||
PushTag();
|
||||
|
||||
if( pType == FloatType_TexCoord2 )
|
||||
|
@ -1264,11 +1294,12 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy
|
|||
// Writes the scene library
|
||||
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;
|
||||
PushTag();
|
||||
mOutput << startstr << "<visual_scene id=\"" + scene_name_escaped + "\" name=\"" + scene_name_escaped + "\">" << endstr;
|
||||
mOutput << startstr << "<visual_scene id=\"" + sceneId + "\" name=\"" + sceneName + "\">" << endstr;
|
||||
PushTag();
|
||||
|
||||
// start recursive write at the root node
|
||||
|
@ -1299,7 +1330,7 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
|
|||
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;
|
||||
PushTag();
|
||||
|
@ -1371,13 +1402,13 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
|
|||
}
|
||||
|
||||
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();
|
||||
|
||||
// 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 ) {
|
||||
mOutput << names[a] << " ";
|
||||
}
|
||||
|
@ -1386,7 +1417,7 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
|
|||
mOutput << startstr << "<technique_common>" << endstr;
|
||||
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();
|
||||
|
||||
mOutput << startstr << "<param name=\"INTERPOLATION\" type=\"name\"></param>" << endstr;
|
||||
|
@ -1408,12 +1439,12 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
|
|||
{
|
||||
// samplers
|
||||
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();
|
||||
|
||||
mOutput << startstr << "<input semantic=\"INPUT\" source=\"#" << XMLEscape( 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=\"INTERPOLATION\" source=\"#" << XMLEscape( nodeAnim->mNodeName.data + std::string("_matrix-interpolation") ) << "\"/>" << endstr;
|
||||
mOutput << startstr << "<input semantic=\"INPUT\" source=\"#" << XMLIDEncode( nodeAnim->mNodeName.data + std::string("_matrix-input") ) << "\"/>" << endstr;
|
||||
mOutput << startstr << "<input semantic=\"OUTPUT\" source=\"#" << XMLIDEncode( nodeAnim->mNodeName.data + std::string("_matrix-output") ) << "\"/>" << endstr;
|
||||
mOutput << startstr << "<input semantic=\"INTERPOLATION\" source=\"#" << XMLIDEncode( nodeAnim->mNodeName.data + std::string("_matrix-interpolation") ) << "\"/>" << endstr;
|
||||
|
||||
PopTag();
|
||||
mOutput << startstr << "</sampler>" << endstr;
|
||||
|
@ -1425,7 +1456,7 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
|
|||
|
||||
{
|
||||
// channels
|
||||
mOutput << startstr << "<channel source=\"#" << XMLEscape( nodeAnim->mNodeName.data + std::string("_matrix-sampler") ) << "\" target=\"" << XMLEscape(nodeAnim->mNodeName.data) << "/matrix\"/>" << endstr;
|
||||
mOutput << startstr << "<channel source=\"#" << XMLIDEncode( nodeAnim->mNodeName.data + std::string("_matrix-sampler") ) << "\" target=\"" << XMLIDEncode(nodeAnim->mNodeName.data) << "/matrix\"/>" << endstr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1436,8 +1467,6 @@ void ColladaExporter::WriteAnimationLibrary(size_t pIndex)
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
void ColladaExporter::WriteAnimationsLibrary()
|
||||
{
|
||||
const std::string scene_name_escaped = XMLEscape(mScene->mRootNode->mName.C_Str());
|
||||
|
||||
if ( mScene->mNumAnimations > 0 ) {
|
||||
mOutput << startstr << "<library_animations>" << endstr;
|
||||
PushTag();
|
||||
|
@ -1545,16 +1574,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 ";
|
||||
if(is_skeleton_root) {
|
||||
mOutput << "id=\"" << node_name_escaped << "\" " << (is_joint ? "sid=\"" + node_name_escaped +"\"" : "") ; // For now, only support one skeleton in a scene.
|
||||
mFoundSkeletonRootNodeID = node_name_escaped;
|
||||
mOutput << "id=\"" << node_id << "\" " << (is_joint ? "sid=\"" + node_id +"\"" : "") ; // For now, only support one skeleton in a scene.
|
||||
mFoundSkeletonRootNodeID = node_id;
|
||||
} 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
|
||||
<< "\">" << endstr;
|
||||
PushTag();
|
||||
|
@ -1593,14 +1623,14 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
|
|||
//check if it is a camera node
|
||||
for(size_t i=0; i<mScene->mNumCameras; i++){
|
||||
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;
|
||||
}
|
||||
}
|
||||
//check if it is a light node
|
||||
for(size_t i=0; i<mScene->mNumLights; i++){
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1614,15 +1644,17 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
|
|||
if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 )
|
||||
continue;
|
||||
|
||||
const std::string meshName = mesh->mName.length == 0 ? GetMeshId(pNode->mMeshes[a]) : mesh->mName.C_Str();
|
||||
|
||||
if( mesh->mNumBones == 0 )
|
||||
{
|
||||
mOutput << startstr << "<instance_geometry url=\"#" << XMLEscape(GetMeshId( pNode->mMeshes[a])) << "\">" << endstr;
|
||||
mOutput << startstr << "<instance_geometry url=\"#" << XMLIDEncode(meshName) << "\">" << endstr;
|
||||
PushTag();
|
||||
}
|
||||
else
|
||||
{
|
||||
mOutput << startstr
|
||||
<< "<instance_controller url=\"#" << XMLEscape(GetMeshId( pNode->mMeshes[a])) << "-skin\">"
|
||||
<< "<instance_controller url=\"#" << XMLIDEncode(meshName) << "-skin\">"
|
||||
<< endstr;
|
||||
PushTag();
|
||||
|
||||
|
@ -1630,7 +1662,7 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
|
|||
// use the first bone to find skeleton root
|
||||
const aiNode * skeletonRootBoneNode = findSkeletonRootNode( pScene, mesh );
|
||||
if ( skeletonRootBoneNode ) {
|
||||
mFoundSkeletonRootNodeID = XMLEscape( skeletonRootBoneNode->mName.C_Str() );
|
||||
mFoundSkeletonRootNodeID = XMLIDEncode( skeletonRootBoneNode->mName.C_Str() );
|
||||
}
|
||||
mOutput << startstr << "<skeleton>#" << mFoundSkeletonRootNodeID << "</skeleton>" << endstr;
|
||||
}
|
||||
|
@ -1638,7 +1670,7 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode)
|
|||
PushTag();
|
||||
mOutput << startstr << "<technique_common>" << endstr;
|
||||
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();
|
||||
for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a )
|
||||
{
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
/** Helper structures for the Collada loader */
|
||||
|
||||
/*
|
||||
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 "ColladaHelper.h"
|
||||
|
||||
#include <assimp/commonMetaData.h>
|
||||
#include <assimp/ParsingUtils.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace Collada {
|
||||
|
||||
const MetaKeyPairVector MakeColladaAssimpMetaKeys() {
|
||||
MetaKeyPairVector result;
|
||||
result.emplace_back("authoring_tool", AI_METADATA_SOURCE_GENERATOR);
|
||||
result.emplace_back("copyright", AI_METADATA_SOURCE_COPYRIGHT);
|
||||
return result;
|
||||
};
|
||||
|
||||
const MetaKeyPairVector &GetColladaAssimpMetaKeys() {
|
||||
static const MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
|
||||
return result;
|
||||
}
|
||||
|
||||
const MetaKeyPairVector MakeColladaAssimpMetaKeysCamelCase() {
|
||||
MetaKeyPairVector result = MakeColladaAssimpMetaKeys();
|
||||
for (auto &val : result)
|
||||
{
|
||||
ToCamelCase(val.first);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase()
|
||||
{
|
||||
static const MetaKeyPairVector result = MakeColladaAssimpMetaKeysCamelCase();
|
||||
return result;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert underscore_separated to CamelCase: "authoring_tool" becomes "AuthoringTool"
|
||||
void ToCamelCase(std::string &text)
|
||||
{
|
||||
if (text.empty())
|
||||
return;
|
||||
// Capitalise first character
|
||||
auto it = text.begin();
|
||||
(*it) = ToUpper(*it);
|
||||
++it;
|
||||
for (/*started above*/ ; it != text.end(); /*iterated below*/)
|
||||
{
|
||||
if ((*it) == '_')
|
||||
{
|
||||
it = text.erase(it);
|
||||
if (it != text.end())
|
||||
(*it) = ToUpper(*it);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make lower case
|
||||
(*it) = ToLower(*it);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Collada
|
||||
} // namespace Assimp
|
|
@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <stdint.h>
|
||||
#include <assimp/light.h>
|
||||
#include <assimp/mesh.h>
|
||||
|
@ -104,6 +105,17 @@ enum MorphMethod
|
|||
Relative
|
||||
};
|
||||
|
||||
/** Common metadata keys as <Collada, Assimp> */
|
||||
typedef std::pair<std::string, std::string> MetaKeyPair;
|
||||
typedef std::vector<MetaKeyPair> MetaKeyPairVector;
|
||||
|
||||
// Collada as lower_case (native)
|
||||
const MetaKeyPairVector &GetColladaAssimpMetaKeys();
|
||||
// Collada as CamelCase (used by Assimp for consistency)
|
||||
const MetaKeyPairVector &GetColladaAssimpMetaKeysCamelCase();
|
||||
|
||||
/** Convert underscore_separated to CamelCase "authoring_tool" becomes "AuthoringTool" */
|
||||
void ToCamelCase(std::string &text);
|
||||
|
||||
/** Contains all data for one of the different transformation types */
|
||||
struct Transform
|
||||
|
@ -580,15 +592,11 @@ struct Image
|
|||
{
|
||||
std::string mFileName;
|
||||
|
||||
/** If image file name is zero, embedded image data
|
||||
*/
|
||||
/** Embedded image data */
|
||||
std::vector<uint8_t> mImageData;
|
||||
|
||||
/** If image file name is zero, file format of
|
||||
* embedded image data.
|
||||
*/
|
||||
/** File format hint of embedded image data */
|
||||
std::string mEmbeddedFormat;
|
||||
|
||||
};
|
||||
|
||||
/** An animation channel. */
|
||||
|
@ -650,24 +658,38 @@ struct Animation
|
|||
}
|
||||
|
||||
void CombineSingleChannelAnimationsRecursively(Animation *pParent)
|
||||
{
|
||||
std::set<std::string> childrenTargets;
|
||||
bool childrenAnimationsHaveDifferentChannels = true;
|
||||
|
||||
for (std::vector<Animation*>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();)
|
||||
{
|
||||
Animation *anim = *it;
|
||||
CombineSingleChannelAnimationsRecursively(anim);
|
||||
|
||||
if (childrenAnimationsHaveDifferentChannels && anim->mChannels.size() == 1 &&
|
||||
childrenTargets.find(anim->mChannels[0].mTarget) == childrenTargets.end()) {
|
||||
childrenTargets.insert(anim->mChannels[0].mTarget);
|
||||
} else {
|
||||
childrenAnimationsHaveDifferentChannels = false;
|
||||
}
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
// We only want to combine animations if they have different channels
|
||||
if (childrenAnimationsHaveDifferentChannels)
|
||||
{
|
||||
for (std::vector<Animation*>::iterator it = pParent->mSubAnims.begin(); it != pParent->mSubAnims.end();)
|
||||
{
|
||||
Animation *anim = *it;
|
||||
|
||||
CombineSingleChannelAnimationsRecursively(anim);
|
||||
|
||||
if (anim->mChannels.size() == 1)
|
||||
{
|
||||
pParent->mChannels.push_back(anim->mChannels[0]);
|
||||
|
||||
it = pParent->mSubAnims.erase(it);
|
||||
|
||||
delete anim;
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -94,20 +94,20 @@ public:
|
|||
public:
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details. */
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const;
|
||||
bool CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const override;
|
||||
|
||||
protected:
|
||||
/** Return importer meta information.
|
||||
* See #BaseImporter::GetInfo for the details
|
||||
*/
|
||||
const aiImporterDesc* GetInfo () const;
|
||||
const aiImporterDesc* GetInfo () const override;
|
||||
|
||||
void SetupProperties(const Importer* pImp);
|
||||
void SetupProperties(const Importer* pImp) override;
|
||||
|
||||
/** Imports the given file into the given scene structure.
|
||||
* See BaseImporter::InternReadFile() for details
|
||||
*/
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler);
|
||||
void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) override;
|
||||
|
||||
/** Recursively constructs a scene node for the given parser node and returns it. */
|
||||
aiNode* BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode);
|
||||
|
@ -120,7 +120,7 @@ protected:
|
|||
void BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode,
|
||||
aiNode* pTarget);
|
||||
|
||||
aiMesh *findMesh(std::string meshid);
|
||||
aiMesh *findMesh(const std::string& meshid);
|
||||
|
||||
/** Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh */
|
||||
aiMesh* CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh,
|
||||
|
@ -184,9 +184,6 @@ protected:
|
|||
aiString FindFilenameForEffectTexture( const ColladaParser& pParser,
|
||||
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.
|
||||
* @param pAccessor The accessor to use for reading
|
||||
* @param pData The data array to read from
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -54,6 +54,7 @@
|
|||
|
||||
namespace Assimp
|
||||
{
|
||||
class ZipArchiveIOSystem;
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
/** Parser helper class for the Collada loader.
|
||||
|
@ -65,16 +66,22 @@ namespace Assimp
|
|||
{
|
||||
friend class ColladaLoader;
|
||||
|
||||
/** Converts a path read from a collada file to the usual representation */
|
||||
static void UriDecodePath(aiString& ss);
|
||||
|
||||
protected:
|
||||
/** Map for generic metadata as aiString */
|
||||
typedef std::map<std::string, aiString> StringMetaData;
|
||||
|
||||
/** Constructor from XML file */
|
||||
ColladaParser( IOSystem* pIOHandler, const std::string& pFile);
|
||||
ColladaParser(IOSystem* pIOHandler, const std::string& pFile);
|
||||
|
||||
/** Destructor */
|
||||
~ColladaParser();
|
||||
|
||||
/** Attempts to read the ZAE manifest and returns the DAE to open */
|
||||
static std::string ReadZaeManifest(ZipArchiveIOSystem &zip_archive);
|
||||
|
||||
/** Reads the contents of the file */
|
||||
void ReadContents();
|
||||
|
||||
|
@ -87,12 +94,9 @@ namespace Assimp
|
|||
/** Reads contributor information such as author and legal blah */
|
||||
void ReadContributorInfo();
|
||||
|
||||
/** Reads generic metadata into provided map */
|
||||
/** Reads generic metadata into provided map and renames keys for Assimp */
|
||||
void ReadMetaDataItem(StringMetaData &metadata);
|
||||
|
||||
/** Convert underscore_seperated to CamelCase "authoring_tool" becomes "AuthoringTool" */
|
||||
static void ToCamelCase(std::string &text);
|
||||
|
||||
/** Reads the animation library */
|
||||
void ReadAnimationLibrary();
|
||||
|
||||
|
@ -235,6 +239,9 @@ namespace Assimp
|
|||
// Processes bind_vertex_input and bind elements
|
||||
void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl);
|
||||
|
||||
/** Reads embedded textures from a ZAE archive*/
|
||||
void ReadEmbeddedTextures(ZipArchiveIOSystem &zip_archive);
|
||||
|
||||
protected:
|
||||
/** Aborts the file reading with an exception */
|
||||
AI_WONT_RETURN void ThrowException( const std::string& pError) const AI_WONT_RETURN_SUFFIX;
|
||||
|
|
|
@ -67,7 +67,20 @@ using namespace Assimp;
|
|||
// Constructor to be privately used by Importer
|
||||
BaseImporter::BaseImporter() AI_NO_EXCEPT
|
||||
: m_progress() {
|
||||
// nothing to do here
|
||||
/**
|
||||
* Assimp Importer
|
||||
* unit conversions available
|
||||
* if you need another measurment unit add it below.
|
||||
* it's currently defined in assimp that we prefer meters.
|
||||
*
|
||||
* NOTE: Initialised here rather than in the header file
|
||||
* to workaround a VS2013 bug with brace initialisers
|
||||
* */
|
||||
importerUnits[ImporterUnits::M] = 1.0;
|
||||
importerUnits[ImporterUnits::CM] = 0.01;
|
||||
importerUnits[ImporterUnits::MM] = 0.001;
|
||||
importerUnits[ImporterUnits::INCHES] = 0.0254;
|
||||
importerUnits[ImporterUnits::FEET] = 0.3048;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -76,9 +89,25 @@ BaseImporter::~BaseImporter() {
|
|||
// nothing to do here
|
||||
}
|
||||
|
||||
void BaseImporter::UpdateImporterScale( Importer* pImp )
|
||||
{
|
||||
ai_assert(pImp != nullptr);
|
||||
ai_assert(importerScale != 0.0);
|
||||
ai_assert(fileScale != 0.0);
|
||||
|
||||
double activeScale = importerScale * fileScale;
|
||||
|
||||
// Set active scaling
|
||||
pImp->SetPropertyFloat( AI_CONFIG_APP_SCALE_KEY, static_cast<float>( activeScale) );
|
||||
|
||||
ASSIMP_LOG_DEBUG_F("UpdateImporterScale scale set: %f", activeScale );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file and returns the imported data.
|
||||
aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, IOSystem* pIOHandler) {
|
||||
aiScene* BaseImporter::ReadFile(Importer* pImp, const std::string& pFile, IOSystem* pIOHandler) {
|
||||
|
||||
|
||||
m_progress = pImp->GetProgressHandler();
|
||||
if (nullptr == m_progress) {
|
||||
return nullptr;
|
||||
|
@ -100,6 +129,11 @@ aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile,
|
|||
{
|
||||
InternReadFile( pFile, sc.get(), &filter);
|
||||
|
||||
// Calculate import scale hook - required because pImp not available anywhere else
|
||||
// passes scale into ScaleProcess
|
||||
UpdateImporterScale(pImp);
|
||||
|
||||
|
||||
} catch( const std::exception& err ) {
|
||||
// extract error description
|
||||
m_ErrorText = err.what();
|
||||
|
@ -112,7 +146,7 @@ aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile,
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BaseImporter::SetupProperties(const Importer* /*pImp*/)
|
||||
void BaseImporter::SetupProperties(const Importer* pImp)
|
||||
{
|
||||
// the default implementation does nothing
|
||||
}
|
||||
|
@ -588,6 +622,8 @@ aiScene* BatchLoader::GetImport( unsigned int which )
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void BatchLoader::LoadAll()
|
||||
{
|
||||
|
|
|
@ -52,6 +52,35 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
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()
|
||||
{
|
||||
|
@ -93,7 +122,7 @@ aiReturn DefaultIOStream::Seek(size_t pOffset,
|
|||
aiOrigin_END == SEEK_END && aiOrigin_SET == SEEK_SET");
|
||||
|
||||
// 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) {
|
||||
return 0;
|
||||
}
|
||||
return ::ftell(mFile);
|
||||
return select_ftell<sizeof(void*)>(mFile);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
|
|
@ -61,83 +61,66 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
using namespace Assimp;
|
||||
|
||||
// maximum path length
|
||||
// XXX http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
|
||||
#ifdef PATH_MAX
|
||||
# define PATHLIMIT PATH_MAX
|
||||
#else
|
||||
# define PATHLIMIT 4096
|
||||
#ifdef _WIN32
|
||||
static std::wstring Utf8ToWide(const char* in)
|
||||
{
|
||||
int size = MultiByteToWideChar(CP_UTF8, 0, in, -1, nullptr, 0);
|
||||
// size includes terminating null; std::wstring adds null automatically
|
||||
std::wstring out(static_cast<size_t>(size) - 1, L'\0');
|
||||
MultiByteToWideChar(CP_UTF8, 0, in, -1, &out[0], size);
|
||||
return out;
|
||||
}
|
||||
|
||||
static std::string WideToUtf8(const wchar_t* in)
|
||||
{
|
||||
int size = WideCharToMultiByte(CP_UTF8, 0, in, -1, nullptr, 0, nullptr, nullptr);
|
||||
// size includes terminating null; std::string adds null automatically
|
||||
std::string out(static_cast<size_t>(size) - 1, '\0');
|
||||
WideCharToMultiByte(CP_UTF8, 0, in, -1, &out[0], size, nullptr, nullptr);
|
||||
return out;
|
||||
}
|
||||
#endif
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Tests for the existence of a file at the given path.
|
||||
bool DefaultIOSystem::Exists( const char* pFile) const
|
||||
bool DefaultIOSystem::Exists(const char* pFile) const
|
||||
{
|
||||
#ifdef _WIN32
|
||||
wchar_t fileName16[PATHLIMIT];
|
||||
|
||||
#ifndef WindowsStore
|
||||
bool isUnicode = IsTextUnicode(pFile, static_cast<int>(strlen(pFile)), NULL) != 0;
|
||||
if (isUnicode) {
|
||||
|
||||
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, pFile, -1, fileName16, PATHLIMIT);
|
||||
struct __stat64 filestat;
|
||||
if (0 != _wstat64(fileName16, &filestat)) {
|
||||
if (_wstat64(Utf8ToWide(pFile).c_str(), &filestat) != 0) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
#else
|
||||
FILE* file = ::fopen(pFile, "rb");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
::fclose(file);
|
||||
#ifndef WindowsStore
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
FILE* file = ::fopen( pFile, "rb");
|
||||
if( !file)
|
||||
return false;
|
||||
|
||||
::fclose( file);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Open a new file with a given path.
|
||||
IOStream* DefaultIOSystem::Open( const char* strFile, const char* strMode)
|
||||
IOStream* DefaultIOSystem::Open(const char* strFile, const char* strMode)
|
||||
{
|
||||
ai_assert(NULL != strFile);
|
||||
ai_assert(NULL != strMode);
|
||||
ai_assert(strFile != nullptr);
|
||||
ai_assert(strMode != nullptr);
|
||||
FILE* file;
|
||||
#ifdef _WIN32
|
||||
wchar_t fileName16[PATHLIMIT];
|
||||
#ifndef WindowsStore
|
||||
bool isUnicode = IsTextUnicode(strFile, static_cast<int>(strlen(strFile)), NULL) != 0;
|
||||
if (isUnicode) {
|
||||
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, strFile, -1, fileName16, PATHLIMIT);
|
||||
std::string mode8(strMode);
|
||||
file = ::_wfopen(fileName16, std::wstring(mode8.begin(), mode8.end()).c_str());
|
||||
} else {
|
||||
#endif
|
||||
file = ::fopen(strFile, strMode);
|
||||
#ifndef WindowsStore
|
||||
}
|
||||
#endif
|
||||
file = ::_wfopen(Utf8ToWide(strFile).c_str(), Utf8ToWide(strMode).c_str());
|
||||
#else
|
||||
file = ::fopen(strFile, strMode);
|
||||
#endif
|
||||
if (nullptr == file)
|
||||
if (!file)
|
||||
return nullptr;
|
||||
|
||||
return new DefaultIOStream(file, (std::string) strFile);
|
||||
return new DefaultIOStream(file, strFile);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Closes the given file and releases all resources associated with it.
|
||||
void DefaultIOSystem::Close( IOStream* pFile)
|
||||
void DefaultIOSystem::Close(IOStream* pFile)
|
||||
{
|
||||
delete pFile;
|
||||
}
|
||||
|
@ -155,78 +138,56 @@ char DefaultIOSystem::getOsSeparator() const
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// IOSystem default implementation (ComparePaths isn't a pure virtual function)
|
||||
bool IOSystem::ComparePaths (const char* one, const char* second) const
|
||||
bool IOSystem::ComparePaths(const char* one, const char* second) const
|
||||
{
|
||||
return !ASSIMP_stricmp(one,second);
|
||||
return !ASSIMP_stricmp(one, second);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Convert a relative path into an absolute path
|
||||
inline static void MakeAbsolutePath (const char* in, char* _out)
|
||||
inline static std::string MakeAbsolutePath(const char* in)
|
||||
{
|
||||
ai_assert(in && _out);
|
||||
#if defined( _MSC_VER ) || defined( __MINGW32__ )
|
||||
#ifndef WindowsStore
|
||||
bool isUnicode = IsTextUnicode(in, static_cast<int>(strlen(in)), NULL) != 0;
|
||||
if (isUnicode) {
|
||||
wchar_t out16[PATHLIMIT];
|
||||
wchar_t in16[PATHLIMIT];
|
||||
MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, in, -1, out16, PATHLIMIT);
|
||||
wchar_t* ret = ::_wfullpath(out16, in16, PATHLIMIT);
|
||||
ai_assert(in);
|
||||
std::string out;
|
||||
#ifdef _WIN32
|
||||
wchar_t* ret = ::_wfullpath(nullptr, Utf8ToWide(in).c_str(), 0);
|
||||
if (ret) {
|
||||
WideCharToMultiByte(CP_UTF8, MB_PRECOMPOSED, out16, -1, _out, PATHLIMIT, nullptr, nullptr);
|
||||
out = WideToUtf8(ret);
|
||||
free(ret);
|
||||
}
|
||||
if (!ret) {
|
||||
// preserve the input path, maybe someone else is able to fix
|
||||
// the path before it is accessed (e.g. our file system filter)
|
||||
ASSIMP_LOG_WARN_F("Invalid path: ", std::string(in));
|
||||
strcpy(_out, in);
|
||||
}
|
||||
|
||||
} else {
|
||||
#endif
|
||||
char* ret = :: _fullpath(_out, in, PATHLIMIT);
|
||||
if (!ret) {
|
||||
// preserve the input path, maybe someone else is able to fix
|
||||
// the path before it is accessed (e.g. our file system filter)
|
||||
ASSIMP_LOG_WARN_F("Invalid path: ", std::string(in));
|
||||
strcpy(_out, in);
|
||||
}
|
||||
#ifndef WindowsStore
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
// use realpath
|
||||
char* ret = realpath(in, _out);
|
||||
if(!ret) {
|
||||
char* ret = realpath(in, nullptr);
|
||||
if (ret) {
|
||||
out = ret;
|
||||
free(ret);
|
||||
}
|
||||
#endif
|
||||
if (!ret) {
|
||||
// preserve the input path, maybe someone else is able to fix
|
||||
// the path before it is accessed (e.g. our file system filter)
|
||||
ASSIMP_LOG_WARN_F("Invalid path: ", std::string(in));
|
||||
strcpy(_out,in);
|
||||
out = in;
|
||||
}
|
||||
#endif
|
||||
return out;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// DefaultIOSystem's more specialized implementation
|
||||
bool DefaultIOSystem::ComparePaths (const char* one, const char* second) const
|
||||
bool DefaultIOSystem::ComparePaths(const char* one, const char* second) const
|
||||
{
|
||||
// chances are quite good both paths are formatted identically,
|
||||
// so we can hopefully return here already
|
||||
if( !ASSIMP_stricmp(one,second) )
|
||||
if (!ASSIMP_stricmp(one, second))
|
||||
return true;
|
||||
|
||||
char temp1[PATHLIMIT];
|
||||
char temp2[PATHLIMIT];
|
||||
std::string temp1 = MakeAbsolutePath(one);
|
||||
std::string temp2 = MakeAbsolutePath(second);
|
||||
|
||||
MakeAbsolutePath (one, temp1);
|
||||
MakeAbsolutePath (second, temp2);
|
||||
|
||||
return !ASSIMP_stricmp(temp1,temp2);
|
||||
return !ASSIMP_stricmp(temp1, temp2);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string DefaultIOSystem::fileName( const std::string &path )
|
||||
std::string DefaultIOSystem::fileName(const std::string& path)
|
||||
{
|
||||
std::string ret = path;
|
||||
std::size_t last = ret.find_last_of("\\/");
|
||||
|
@ -235,16 +196,16 @@ std::string DefaultIOSystem::fileName( const std::string &path )
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string DefaultIOSystem::completeBaseName( const std::string &path )
|
||||
std::string DefaultIOSystem::completeBaseName(const std::string& path)
|
||||
{
|
||||
std::string ret = fileName(path);
|
||||
std::size_t pos = ret.find_last_of('.');
|
||||
if(pos != ret.npos) ret = ret.substr(0, pos);
|
||||
if (pos != std::string::npos) ret = ret.substr(0, pos);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::string DefaultIOSystem::absolutePath( const std::string &path )
|
||||
std::string DefaultIOSystem::absolutePath(const std::string& path)
|
||||
{
|
||||
std::string ret = path;
|
||||
std::size_t last = ret.find_last_of("\\/");
|
||||
|
@ -253,5 +214,3 @@ std::string DefaultIOSystem::absolutePath( const std::string &path )
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
#undef PATHLIMIT
|
||||
|
|
|
@ -121,7 +121,7 @@ LogStream* LogStream::createDefaultStream(aiDefaultLogStream streams,
|
|||
};
|
||||
|
||||
// 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 ExportSceneFBXA(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 ExportSceneM3DA(const char*, IOSystem*, const aiScene*, const ExportProperties*);
|
||||
void ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// global array of all export formats which Assimp supports in its current build
|
||||
Exporter::ExportFormatEntry gExporters[] =
|
||||
{
|
||||
|
||||
static void setupExporterArray(std::vector<Exporter::ExportFormatEntry> &exporters) {
|
||||
#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
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_X_EXPORTER
|
||||
Exporter::ExportFormatEntry( "x", "X Files", "x", &ExportSceneXFile,
|
||||
aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs ),
|
||||
exporters.push_back(Exporter::ExportFormatEntry("x", "X Files", "x", &ExportSceneXFile,
|
||||
aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_FlipUVs));
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_OBJ_EXPORTER
|
||||
Exporter::ExportFormatEntry( "obj", "Wavefront OBJ format", "obj", &ExportSceneObj,
|
||||
aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */ ),
|
||||
Exporter::ExportFormatEntry( "objnomtl", "Wavefront OBJ format without material file", "obj", &ExportSceneObjNoMtl,
|
||||
aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */ ),
|
||||
exporters.push_back(Exporter::ExportFormatEntry("obj", "Wavefront OBJ format", "obj", &ExportSceneObj,
|
||||
aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */));
|
||||
exporters.push_back(Exporter::ExportFormatEntry("objnomtl", "Wavefront OBJ format without material file", "obj", &ExportSceneObjNoMtl,
|
||||
aiProcess_GenSmoothNormals /*| aiProcess_PreTransformVertices */));
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_STL_EXPORTER
|
||||
Exporter::ExportFormatEntry( "stl", "Stereolithography", "stl" , &ExportSceneSTL,
|
||||
aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
|
||||
),
|
||||
Exporter::ExportFormatEntry( "stlb", "Stereolithography (binary)", "stl" , &ExportSceneSTLBinary,
|
||||
aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices
|
||||
),
|
||||
exporters.push_back(Exporter::ExportFormatEntry("stl", "Stereolithography", "stl", &ExportSceneSTL,
|
||||
aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices));
|
||||
exporters.push_back(Exporter::ExportFormatEntry("stlb", "Stereolithography (binary)", "stl", &ExportSceneSTLBinary,
|
||||
aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_PreTransformVertices));
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_PLY_EXPORTER
|
||||
Exporter::ExportFormatEntry( "ply", "Stanford Polygon Library", "ply" , &ExportScenePly,
|
||||
aiProcess_PreTransformVertices
|
||||
),
|
||||
Exporter::ExportFormatEntry( "plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary,
|
||||
aiProcess_PreTransformVertices
|
||||
),
|
||||
exporters.push_back(Exporter::ExportFormatEntry("ply", "Stanford Polygon Library", "ply", &ExportScenePly,
|
||||
aiProcess_PreTransformVertices));
|
||||
exporters.push_back(Exporter::ExportFormatEntry("plyb", "Stanford Polygon Library (binary)", "ply", &ExportScenePlyBinary,
|
||||
aiProcess_PreTransformVertices));
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_3DS_EXPORTER
|
||||
Exporter::ExportFormatEntry( "3ds", "Autodesk 3DS (legacy)", "3ds" , &ExportScene3DS,
|
||||
aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices ),
|
||||
exporters.push_back(Exporter::ExportFormatEntry("3ds", "Autodesk 3DS (legacy)", "3ds", &ExportScene3DS,
|
||||
aiProcess_Triangulate | aiProcess_SortByPType | aiProcess_JoinIdenticalVertices));
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER
|
||||
Exporter::ExportFormatEntry( "gltf2", "GL Transmission Format v. 2", "gltf", &ExportSceneGLTF2,
|
||||
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
|
||||
Exporter::ExportFormatEntry( "glb2", "GL Transmission Format v. 2 (binary)", "glb", &ExportSceneGLB2,
|
||||
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
|
||||
Exporter::ExportFormatEntry( "gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF,
|
||||
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
|
||||
Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
|
||||
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType ),
|
||||
exporters.push_back(Exporter::ExportFormatEntry("gltf2", "GL Transmission Format v. 2", "gltf", &ExportSceneGLTF2,
|
||||
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType));
|
||||
exporters.push_back(Exporter::ExportFormatEntry("glb2", "GL Transmission Format v. 2 (binary)", "glb", &ExportSceneGLB2,
|
||||
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType));
|
||||
exporters.push_back(Exporter::ExportFormatEntry("gltf", "GL Transmission Format", "gltf", &ExportSceneGLTF,
|
||||
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType));
|
||||
exporters.push_back(Exporter::ExportFormatEntry("glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB,
|
||||
aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType));
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER
|
||||
Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0 ),
|
||||
exporters.push_back(Exporter::ExportFormatEntry("assbin", "Assimp Binary File", "assbin", &ExportSceneAssbin, 0));
|
||||
#endif
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER
|
||||
Exporter::ExportFormatEntry( "assxml", "Assxml Document", "assxml" , &ExportSceneAssxml, 0 ),
|
||||
exporters.push_back(Exporter::ExportFormatEntry("assxml", "Assimp XML Document", "assxml", &ExportSceneAssxml, 0));
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_FBX_EXPORTER
|
||||
Exporter::ExportFormatEntry( "fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 0 ),
|
||||
Exporter::ExportFormatEntry( "fbxa", "Autodesk FBX (ascii)", "fbx", &ExportSceneFBXA, 0 ),
|
||||
exporters.push_back(Exporter::ExportFormatEntry("fbx", "Autodesk FBX (binary)", "fbx", &ExportSceneFBX, 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("m3da", "Model 3D (ascii)", "a3d", &ExportSceneM3DA, 0));
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER
|
||||
Exporter::ExportFormatEntry("json", "Plain JSON representation of the Assimp scene data structure", "json", &ExportAssimp2Json, 0)
|
||||
exporters.push_back(Exporter::ExportFormatEntry("assjson", "Assimp JSON Document", "json", &ExportAssimp2Json, 0));
|
||||
#endif
|
||||
};
|
||||
|
||||
#define ASSIMP_NUM_EXPORTERS (sizeof(gExporters)/sizeof(gExporters[0]))
|
||||
|
||||
}
|
||||
|
||||
class ExporterPimpl {
|
||||
public:
|
||||
|
@ -205,10 +203,7 @@ public:
|
|||
GetPostProcessingStepInstanceList(mPostProcessingSteps);
|
||||
|
||||
// grab all built-in exporters
|
||||
if ( 0 != ( ASSIMP_NUM_EXPORTERS ) ) {
|
||||
mExporters.resize( ASSIMP_NUM_EXPORTERS );
|
||||
std::copy( gExporters, gExporters + ASSIMP_NUM_EXPORTERS, mExporters.begin() );
|
||||
}
|
||||
setupExporterArray(mExporters);
|
||||
}
|
||||
|
||||
~ExporterPimpl() {
|
||||
|
@ -252,23 +247,27 @@ Exporter :: Exporter()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
Exporter::~Exporter() {
|
||||
ai_assert(nullptr != pimpl);
|
||||
FreeBlob();
|
||||
delete pimpl;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Exporter::SetIOHandler( IOSystem* pIOHandler) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
pimpl->mIsDefaultIOHandler = !pIOHandler;
|
||||
pimpl->mIOSystem.reset(pIOHandler);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
IOSystem* Exporter::GetIOHandler() const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
return pimpl->mIOSystem.get();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool Exporter::IsDefaultIOHandler() const {
|
||||
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,
|
||||
unsigned int pPreprocessing, const ExportProperties* pProperties) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
if (pimpl->blob) {
|
||||
delete pimpl->blob;
|
||||
pimpl->blob = nullptr;
|
||||
|
@ -315,44 +315,16 @@ const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const cha
|
|||
return pimpl->blob;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool IsVerboseFormat(const aiMesh* mesh) {
|
||||
// avoid slow vector<bool> specialization
|
||||
std::vector<unsigned int> seen(mesh->mNumVertices,0);
|
||||
for(unsigned int i = 0; i < mesh->mNumFaces; ++i) {
|
||||
const aiFace& f = mesh->mFaces[i];
|
||||
for(unsigned int j = 0; j < f.mNumIndices; ++j) {
|
||||
if(++seen[f.mIndices[j]] == 2) {
|
||||
// found a duplicate index
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
bool IsVerboseFormat(const aiScene* pScene) {
|
||||
for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) {
|
||||
if(!IsVerboseFormat(pScene->mMeshes[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const char* pPath,
|
||||
unsigned int pPreprocessing, const ExportProperties* pProperties) {
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
ai_assert(nullptr != pimpl);
|
||||
// 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
|
||||
// this, however. To avoid surprises and bug reports, we check for duplicates in
|
||||
// meshes upfront.
|
||||
const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || IsVerboseFormat(pScene);
|
||||
const bool is_verbose_format = !(pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) || MakeVerboseFormatProcess::IsVerboseFormat(pScene);
|
||||
|
||||
pimpl->mProgressHandler->UpdateFileWrite(0, 4);
|
||||
|
||||
|
@ -472,7 +444,9 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
|
|||
}
|
||||
|
||||
ExportProperties emptyProperties; // Never pass NULL ExportProperties so Exporters don't have to worry.
|
||||
exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProperties ? pProperties : &emptyProperties);
|
||||
ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties;
|
||||
pProp->SetPropertyBool("bJoinIdenticalVertices", pp & aiProcess_JoinIdenticalVertices);
|
||||
exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp);
|
||||
|
||||
pimpl->mProgressHandler->UpdateFileWrite(4, 4);
|
||||
} catch (DeadlyExportError& err) {
|
||||
|
@ -491,11 +465,13 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const char* Exporter::GetErrorString() const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
return pimpl->mError.c_str();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void Exporter::FreeBlob() {
|
||||
ai_assert(nullptr != pimpl);
|
||||
delete pimpl->blob;
|
||||
pimpl->blob = nullptr;
|
||||
|
||||
|
@ -504,30 +480,34 @@ void Exporter::FreeBlob() {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiExportDataBlob* Exporter::GetBlob() const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
return pimpl->blob;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiExportDataBlob* Exporter::GetOrphanedBlob() const {
|
||||
const aiExportDataBlob* tmp = pimpl->blob;
|
||||
ai_assert(nullptr != pimpl);
|
||||
const aiExportDataBlob *tmp = pimpl->blob;
|
||||
pimpl->blob = nullptr;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
size_t Exporter::GetExportFormatCount() const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
return pimpl->mExporters.size();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiExportFormatDesc* Exporter::GetExportFormatDescription( size_t index ) const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
if (index >= GetExportFormatCount()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Return from static storage if the requested index is built-in.
|
||||
if (index < sizeof(gExporters) / sizeof(gExporters[0])) {
|
||||
return &gExporters[index].mDescription;
|
||||
if (index < pimpl->mExporters.size()) {
|
||||
return &pimpl->mExporters[index].mDescription;
|
||||
}
|
||||
|
||||
return &pimpl->mExporters[index].mDescription;
|
||||
|
@ -535,7 +515,8 @@ const aiExportFormatDesc* Exporter::GetExportFormatDescription( size_t index ) c
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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)) {
|
||||
return aiReturn_FAILURE;
|
||||
}
|
||||
|
@ -547,7 +528,8 @@ aiReturn Exporter::RegisterExporter(const ExportFormatEntry& desc) {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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) {
|
||||
if (!strcmp((*it).mDescription.id,id)) {
|
||||
pimpl->mExporters.erase(it);
|
||||
|
|
|
@ -5,8 +5,6 @@ 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,
|
||||
|
@ -78,6 +76,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/TinyFormatter.h>
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <assimp/Profiler.h>
|
||||
#include <assimp/commonMetaData.h>
|
||||
|
||||
#include <set>
|
||||
#include <memory>
|
||||
#include <cctype>
|
||||
|
@ -119,7 +119,7 @@ void* AllocateFromAssimpHeap::operator new ( size_t num_bytes, const std::nothro
|
|||
return AllocateFromAssimpHeap::operator new( num_bytes );
|
||||
}
|
||||
catch( ... ) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,9 +134,8 @@ void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes) {
|
|||
void* AllocateFromAssimpHeap::operator new[] ( size_t num_bytes, const std::nothrow_t& ) throw() {
|
||||
try {
|
||||
return AllocateFromAssimpHeap::operator new[]( num_bytes );
|
||||
}
|
||||
catch( ... ) {
|
||||
return NULL;
|
||||
} catch( ... ) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,7 +147,7 @@ void AllocateFromAssimpHeap::operator delete[] ( void* data) {
|
|||
// Importer constructor.
|
||||
Importer::Importer()
|
||||
: pimpl( new ImporterPimpl ) {
|
||||
pimpl->mScene = NULL;
|
||||
pimpl->mScene = nullptr;
|
||||
pimpl->mErrorString = "";
|
||||
|
||||
// Allocate a default IO handler
|
||||
|
@ -174,14 +173,14 @@ Importer::Importer()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor of Importer
|
||||
Importer::~Importer()
|
||||
{
|
||||
Importer::~Importer() {
|
||||
// Delete all import plugins
|
||||
DeleteImporterInstanceList(pimpl->mImporter);
|
||||
|
||||
// Delete all post-processing plug-ins
|
||||
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++)
|
||||
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); ++a ) {
|
||||
delete pimpl->mPostProcessingSteps[a];
|
||||
}
|
||||
|
||||
// Delete the assigned IO and progress handler
|
||||
delete pimpl->mIOHandler;
|
||||
|
@ -199,9 +198,9 @@ Importer::~Importer()
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Register a custom post-processing step
|
||||
aiReturn Importer::RegisterPPStep(BaseProcess* pImp)
|
||||
{
|
||||
ai_assert(NULL != pImp);
|
||||
aiReturn Importer::RegisterPPStep(BaseProcess* pImp) {
|
||||
ai_assert( nullptr != pImp );
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
pimpl->mPostProcessingSteps.push_back(pImp);
|
||||
|
@ -213,9 +212,9 @@ aiReturn Importer::RegisterPPStep(BaseProcess* pImp)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Register a custom loader plugin
|
||||
aiReturn Importer::RegisterLoader(BaseImporter* pImp)
|
||||
{
|
||||
ai_assert(NULL != pImp);
|
||||
aiReturn Importer::RegisterLoader(BaseImporter* pImp) {
|
||||
ai_assert(nullptr != pImp);
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
@ -242,13 +241,13 @@ aiReturn Importer::RegisterLoader(BaseImporter* pImp)
|
|||
pimpl->mImporter.push_back(pImp);
|
||||
ASSIMP_LOG_INFO_F("Registering custom importer for these file extensions: ", baked);
|
||||
ASSIMP_END_EXCEPTION_REGION(aiReturn);
|
||||
|
||||
return AI_SUCCESS;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Unregister a custom loader plugin
|
||||
aiReturn Importer::UnregisterLoader(BaseImporter* pImp)
|
||||
{
|
||||
aiReturn Importer::UnregisterLoader(BaseImporter* pImp) {
|
||||
if(!pImp) {
|
||||
// unregistering a NULL importer is no problem for us ... really!
|
||||
return AI_SUCCESS;
|
||||
|
@ -265,13 +264,13 @@ aiReturn Importer::UnregisterLoader(BaseImporter* pImp)
|
|||
}
|
||||
ASSIMP_LOG_WARN("Unable to remove custom importer: I can't find you ...");
|
||||
ASSIMP_END_EXCEPTION_REGION(aiReturn);
|
||||
|
||||
return AI_FAILURE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Unregister a custom loader plugin
|
||||
aiReturn Importer::UnregisterPPStep(BaseProcess* pImp)
|
||||
{
|
||||
aiReturn Importer::UnregisterPPStep(BaseProcess* pImp) {
|
||||
if(!pImp) {
|
||||
// unregistering a NULL ppstep is no problem for us ... really!
|
||||
return AI_SUCCESS;
|
||||
|
@ -288,24 +287,22 @@ aiReturn Importer::UnregisterPPStep(BaseProcess* pImp)
|
|||
}
|
||||
ASSIMP_LOG_WARN("Unable to remove custom post-processing step: I can't find you ..");
|
||||
ASSIMP_END_EXCEPTION_REGION(aiReturn);
|
||||
|
||||
return AI_FAILURE;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Supplies a custom IO handler to the importer to open and access files.
|
||||
void Importer::SetIOHandler( IOSystem* pIOHandler)
|
||||
{
|
||||
void Importer::SetIOHandler( IOSystem* pIOHandler) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
// If the new handler is zero, allocate a default IO implementation.
|
||||
if (!pIOHandler)
|
||||
{
|
||||
if (!pIOHandler) {
|
||||
// Release pointer in the possession of the caller
|
||||
pimpl->mIOHandler = new DefaultIOSystem();
|
||||
pimpl->mIsDefaultHandler = true;
|
||||
}
|
||||
// Otherwise register the custom handler
|
||||
else if (pimpl->mIOHandler != pIOHandler)
|
||||
{
|
||||
} else if (pimpl->mIOHandler != pIOHandler) { // Otherwise register the custom handler
|
||||
delete pimpl->mIOHandler;
|
||||
pimpl->mIOHandler = pIOHandler;
|
||||
pimpl->mIsDefaultHandler = false;
|
||||
|
@ -316,29 +313,32 @@ void Importer::SetIOHandler( IOSystem* pIOHandler)
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Get the currently set IO handler
|
||||
IOSystem* Importer::GetIOHandler() const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
return pimpl->mIOHandler;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check whether a custom IO handler is currently set
|
||||
bool Importer::IsDefaultIOHandler() const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
return pimpl->mIsDefaultHandler;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Supplies a custom progress handler to get regular callbacks during importing
|
||||
void Importer::SetProgressHandler ( ProgressHandler* pHandler ) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// If the new handler is zero, allocate a default implementation.
|
||||
if (!pHandler)
|
||||
{
|
||||
if (!pHandler) {
|
||||
// Release pointer in the possession of the caller
|
||||
pimpl->mProgressHandler = new DefaultProgressHandler();
|
||||
pimpl->mIsDefaultProgressHandler = true;
|
||||
}
|
||||
// Otherwise register the custom handler
|
||||
else if (pimpl->mProgressHandler != pHandler)
|
||||
{
|
||||
} else if (pimpl->mProgressHandler != pHandler) { // Otherwise register the custom handler
|
||||
delete pimpl->mProgressHandler;
|
||||
pimpl->mProgressHandler = pHandler;
|
||||
pimpl->mIsDefaultProgressHandler = false;
|
||||
|
@ -349,19 +349,22 @@ void Importer::SetProgressHandler ( ProgressHandler* pHandler ) {
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Get the currently set progress handler
|
||||
ProgressHandler* Importer::GetProgressHandler() const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
return pimpl->mProgressHandler;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Check whether a custom progress handler is currently set
|
||||
bool Importer::IsDefaultProgressHandler() const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
return pimpl->mIsDefaultProgressHandler;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Validate post process step flags
|
||||
bool _ValidateFlags(unsigned int pFlags)
|
||||
{
|
||||
bool _ValidateFlags(unsigned int pFlags) {
|
||||
if (pFlags & aiProcess_GenSmoothNormals && pFlags & aiProcess_GenNormals) {
|
||||
ASSIMP_LOG_ERROR("#aiProcess_GenSmoothNormals and #aiProcess_GenNormals are incompatible");
|
||||
return false;
|
||||
|
@ -375,12 +378,13 @@ bool _ValidateFlags(unsigned int pFlags)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Free the current scene
|
||||
void Importer::FreeScene( )
|
||||
{
|
||||
void Importer::FreeScene( ) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
delete pimpl->mScene;
|
||||
pimpl->mScene = NULL;
|
||||
pimpl->mScene = nullptr;
|
||||
|
||||
pimpl->mErrorString = "";
|
||||
ASSIMP_END_EXCEPTION_REGION(void);
|
||||
|
@ -388,44 +392,48 @@ void Importer::FreeScene( )
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get the current error string, if any
|
||||
const char* Importer::GetErrorString() const
|
||||
{
|
||||
/* Must remain valid as long as ReadFile() or FreeFile() are not called */
|
||||
const char* Importer::GetErrorString() const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
// Must remain valid as long as ReadFile() or FreeFile() are not called
|
||||
return pimpl->mErrorString.c_str();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Enable extra-verbose mode
|
||||
void Importer::SetExtraVerbose(bool bDo)
|
||||
{
|
||||
void Importer::SetExtraVerbose(bool bDo) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
pimpl->bExtraVerbose = bDo;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get the current scene
|
||||
const aiScene* Importer::GetScene() const
|
||||
{
|
||||
const aiScene* Importer::GetScene() const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
return pimpl->mScene;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Orphan the current scene and return it.
|
||||
aiScene* Importer::GetOrphanedScene()
|
||||
{
|
||||
aiScene* Importer::GetOrphanedScene() {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
aiScene* s = pimpl->mScene;
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
pimpl->mScene = NULL;
|
||||
pimpl->mScene = nullptr;
|
||||
|
||||
pimpl->mErrorString = ""; /* reset error string */
|
||||
pimpl->mErrorString = ""; // reset error string
|
||||
ASSIMP_END_EXCEPTION_REGION(aiScene*);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Validate post-processing flags
|
||||
bool Importer::ValidateFlags(unsigned int pFlags) const
|
||||
{
|
||||
bool Importer::ValidateFlags(unsigned int pFlags) const {
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
// run basic checks for mutually exclusive flags
|
||||
if(!_ValidateFlags(pFlags)) {
|
||||
|
@ -467,8 +475,9 @@ bool Importer::ValidateFlags(unsigned int pFlags) const
|
|||
const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
|
||||
size_t pLength,
|
||||
unsigned int pFlags,
|
||||
const char* pHint /*= ""*/)
|
||||
{
|
||||
const char* pHint /*= ""*/) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
if (!pHint) {
|
||||
pHint = "";
|
||||
|
@ -476,12 +485,12 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
|
|||
|
||||
if (!pBuffer || !pLength || strlen(pHint) > MaxLenHint ) {
|
||||
pimpl->mErrorString = "Invalid parameters passed to ReadFileFromMemory()";
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// prevent deletion of the previous IOHandler
|
||||
IOSystem* io = pimpl->mIOHandler;
|
||||
pimpl->mIOHandler = NULL;
|
||||
pimpl->mIOHandler = nullptr;
|
||||
|
||||
SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io));
|
||||
|
||||
|
@ -493,13 +502,13 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer,
|
|||
ReadFile(fbuff,pFlags);
|
||||
SetIOHandler(io);
|
||||
|
||||
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
|
||||
ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString);
|
||||
return pimpl->mScene;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void WriteLogOpening(const std::string& file)
|
||||
{
|
||||
void WriteLogOpening(const std::string& file) {
|
||||
|
||||
ASSIMP_LOG_INFO_F("Load ", file);
|
||||
|
||||
// print a full version dump. This is nice because we don't
|
||||
|
@ -550,8 +559,9 @@ void WriteLogOpening(const std::string& file)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Reads the given file and returns its contents if successful.
|
||||
const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
|
||||
{
|
||||
const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
const std::string pFile(_pFile);
|
||||
|
||||
|
@ -580,7 +590,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
|
|||
|
||||
pimpl->mErrorString = "Unable to open file \"" + pFile + "\".";
|
||||
ASSIMP_LOG_ERROR(pimpl->mErrorString);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL);
|
||||
|
@ -589,7 +599,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
|
|||
}
|
||||
|
||||
// Find an worker class which can handle the file
|
||||
BaseImporter* imp = NULL;
|
||||
BaseImporter* imp = nullptr;
|
||||
SetPropertyInteger("importerIndex", -1);
|
||||
for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) {
|
||||
|
||||
|
@ -617,7 +627,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
|
|||
if( !imp) {
|
||||
pimpl->mErrorString = "No suitable reader found for the file format of file \"" + pFile + "\".";
|
||||
ASSIMP_LOG_ERROR(pimpl->mErrorString);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -633,7 +643,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
|
|||
// Dispatch the reading to the worker class for this format
|
||||
const aiImporterDesc *desc( imp->GetInfo() );
|
||||
std::string ext( "unknown" );
|
||||
if ( NULL != desc ) {
|
||||
if ( nullptr != desc ) {
|
||||
ext = desc->mName;
|
||||
}
|
||||
ASSIMP_LOG_INFO("Found a matching importer for this file format: " + ext + "." );
|
||||
|
@ -654,15 +664,20 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
|
|||
|
||||
// If successful, apply all active post processing steps to the imported data
|
||||
if( pimpl->mScene) {
|
||||
if (!pimpl->mScene->mMetaData || !pimpl->mScene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT)) {
|
||||
if (!pimpl->mScene->mMetaData) {
|
||||
pimpl->mScene->mMetaData = new aiMetadata;
|
||||
}
|
||||
pimpl->mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT, aiString(ext));
|
||||
}
|
||||
|
||||
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
|
||||
// The ValidateDS process is an exception. It is executed first, even before ScenePreprocessor is called.
|
||||
if (pFlags & aiProcess_ValidateDataStructure)
|
||||
{
|
||||
if (pFlags & aiProcess_ValidateDataStructure) {
|
||||
ValidateDSProcess ds;
|
||||
ds.ExecuteOnScene (this);
|
||||
if (!pimpl->mScene) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#endif // no validation
|
||||
|
@ -695,8 +710,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
|
|||
}
|
||||
}
|
||||
#ifdef ASSIMP_CATCH_GLOBAL_EXCEPTIONS
|
||||
catch (std::exception &e)
|
||||
{
|
||||
catch (std::exception &e) {
|
||||
#if (defined _MSC_VER) && (defined _CPPRTTI)
|
||||
// if we have RTTI get the full name of the exception that occurred
|
||||
pimpl->mErrorString = std::string(typeid( e ).name()) + ": " + e.what();
|
||||
|
@ -705,24 +719,26 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags)
|
|||
#endif
|
||||
|
||||
ASSIMP_LOG_ERROR(pimpl->mErrorString);
|
||||
delete pimpl->mScene; pimpl->mScene = NULL;
|
||||
delete pimpl->mScene; pimpl->mScene = nullptr;
|
||||
}
|
||||
#endif // ! ASSIMP_CATCH_GLOBAL_EXCEPTIONS
|
||||
|
||||
// either successful or failure - the pointer expresses it anyways
|
||||
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
|
||||
ASSIMP_END_EXCEPTION_REGION_WITH_ERROR_STRING(const aiScene*, pimpl->mErrorString);
|
||||
|
||||
return pimpl->mScene;
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Apply post-processing to the currently bound scene
|
||||
const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
|
||||
{
|
||||
const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
// Return immediately if no scene is active
|
||||
if (!pimpl->mScene) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If no flags are given, return the current scene with no further action
|
||||
|
@ -737,12 +753,11 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
|
|||
#ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS
|
||||
// The ValidateDS process plays an exceptional role. It isn't contained in the global
|
||||
// list of post-processing steps, so we need to call it manually.
|
||||
if (pFlags & aiProcess_ValidateDataStructure)
|
||||
{
|
||||
if (pFlags & aiProcess_ValidateDataStructure) {
|
||||
ValidateDSProcess ds;
|
||||
ds.ExecuteOnScene (this);
|
||||
if (!pimpl->mScene) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#endif // no validation
|
||||
|
@ -762,11 +777,9 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
|
|||
|
||||
std::unique_ptr<Profiler> profiler(GetPropertyInteger(AI_CONFIG_GLOB_MEASURE_TIME,0)?new Profiler():NULL);
|
||||
for( unsigned int a = 0; a < pimpl->mPostProcessingSteps.size(); a++) {
|
||||
|
||||
BaseProcess* process = pimpl->mPostProcessingSteps[a];
|
||||
pimpl->mProgressHandler->UpdatePostProcess(static_cast<int>(a), static_cast<int>(pimpl->mPostProcessingSteps.size()) );
|
||||
if( process->IsActive( pFlags)) {
|
||||
|
||||
if (profiler) {
|
||||
profiler->BeginRegion("postprocess");
|
||||
}
|
||||
|
@ -803,24 +816,28 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags)
|
|||
static_cast<int>(pimpl->mPostProcessingSteps.size()) );
|
||||
|
||||
// update private scene flags
|
||||
if( pimpl->mScene )
|
||||
if( pimpl->mScene ) {
|
||||
ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags;
|
||||
}
|
||||
|
||||
// clear any data allocated by post-process steps
|
||||
pimpl->mPPShared->Clean();
|
||||
ASSIMP_LOG_INFO("Leaving post processing pipeline");
|
||||
|
||||
ASSIMP_END_EXCEPTION_REGION(const aiScene*);
|
||||
|
||||
return pimpl->mScene;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess, bool requestValidation ) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
||||
// Return immediately if no scene is active
|
||||
if ( NULL == pimpl->mScene ) {
|
||||
return NULL;
|
||||
if ( nullptr == pimpl->mScene ) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// If no flags are given, return the current scene with no further action
|
||||
|
@ -839,7 +856,7 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess
|
|||
ValidateDSProcess ds;
|
||||
ds.ExecuteOnScene( this );
|
||||
if ( !pimpl->mScene ) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#endif // no validation
|
||||
|
@ -890,46 +907,50 @@ const aiScene* Importer::ApplyCustomizedPostProcessing( BaseProcess *rootProcess
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Helper function to check whether an extension is supported by ASSIMP
|
||||
bool Importer::IsExtensionSupported(const char* szExtension) const
|
||||
{
|
||||
bool Importer::IsExtensionSupported(const char* szExtension) const {
|
||||
return nullptr != GetImporter(szExtension);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
size_t Importer::GetImporterCount() const
|
||||
{
|
||||
size_t Importer::GetImporterCount() const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
return pimpl->mImporter.size();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
const aiImporterDesc* Importer::GetImporterInfo(size_t index) const
|
||||
{
|
||||
const aiImporterDesc* Importer::GetImporterInfo(size_t index) const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
if (index >= pimpl->mImporter.size()) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return pimpl->mImporter[index]->GetInfo();
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
BaseImporter* Importer::GetImporter (size_t index) const
|
||||
{
|
||||
BaseImporter* Importer::GetImporter (size_t index) const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
if (index >= pimpl->mImporter.size()) {
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
return pimpl->mImporter[index];
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Find a loader plugin for a given file extension
|
||||
BaseImporter* Importer::GetImporter (const char* szExtension) const
|
||||
{
|
||||
BaseImporter* Importer::GetImporter (const char* szExtension) const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
return GetImporter(GetImporterIndex(szExtension));
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Find a loader plugin for a given file extension
|
||||
size_t Importer::GetImporterIndex (const char* szExtension) const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
ai_assert(nullptr != szExtension);
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
|
@ -960,8 +981,9 @@ size_t Importer::GetImporterIndex (const char* szExtension) const {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Helper function to build a list of all file extensions supported by ASSIMP
|
||||
void Importer::GetExtensionList(aiString& szOut) const
|
||||
{
|
||||
void Importer::GetExtensionList(aiString& szOut) const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
std::set<std::string> str;
|
||||
for (std::vector<BaseImporter*>::const_iterator i = pimpl->mImporter.begin();i != pimpl->mImporter.end();++i) {
|
||||
|
@ -985,8 +1007,9 @@ void Importer::GetExtensionList(aiString& szOut) const
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Set a configuration property
|
||||
bool Importer::SetPropertyInteger(const char* szName, int iValue)
|
||||
{
|
||||
bool Importer::SetPropertyInteger(const char* szName, int iValue) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
bool existing;
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
existing = SetGenericProperty<int>(pimpl->mIntProperties, szName,iValue);
|
||||
|
@ -996,8 +1019,9 @@ bool Importer::SetPropertyInteger(const char* szName, int iValue)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Set a configuration property
|
||||
bool Importer::SetPropertyFloat(const char* szName, ai_real iValue)
|
||||
{
|
||||
bool Importer::SetPropertyFloat(const char* szName, ai_real iValue) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
bool existing;
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
existing = SetGenericProperty<ai_real>(pimpl->mFloatProperties, szName,iValue);
|
||||
|
@ -1007,8 +1031,9 @@ bool Importer::SetPropertyFloat(const char* szName, ai_real iValue)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Set a configuration property
|
||||
bool Importer::SetPropertyString(const char* szName, const std::string& value)
|
||||
{
|
||||
bool Importer::SetPropertyString(const char* szName, const std::string& value) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
bool existing;
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
existing = SetGenericProperty<std::string>(pimpl->mStringProperties, szName,value);
|
||||
|
@ -1018,8 +1043,9 @@ bool Importer::SetPropertyString(const char* szName, const std::string& value)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Set a configuration property
|
||||
bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value)
|
||||
{
|
||||
bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value) {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
bool existing;
|
||||
ASSIMP_BEGIN_EXCEPTION_REGION();
|
||||
existing = SetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties, szName,value);
|
||||
|
@ -1029,40 +1055,43 @@ bool Importer::SetPropertyMatrix(const char* szName, const aiMatrix4x4& value)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a configuration property
|
||||
int Importer::GetPropertyInteger(const char* szName,
|
||||
int iErrorReturn /*= 0xffffffff*/) const
|
||||
{
|
||||
int Importer::GetPropertyInteger(const char* szName, int iErrorReturn /*= 0xffffffff*/) const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
return GetGenericProperty<int>(pimpl->mIntProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a configuration property
|
||||
ai_real Importer::GetPropertyFloat(const char* szName,
|
||||
ai_real iErrorReturn /*= 10e10*/) const
|
||||
{
|
||||
ai_real Importer::GetPropertyFloat(const char* szName, ai_real iErrorReturn /*= 10e10*/) const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
return GetGenericProperty<ai_real>(pimpl->mFloatProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a configuration property
|
||||
const std::string Importer::GetPropertyString(const char* szName,
|
||||
const std::string& iErrorReturn /*= ""*/) const
|
||||
{
|
||||
const std::string Importer::GetPropertyString(const char* szName, const std::string& iErrorReturn /*= ""*/) const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
return GetGenericProperty<std::string>(pimpl->mStringProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a configuration property
|
||||
const aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName,
|
||||
const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const
|
||||
{
|
||||
const aiMatrix4x4 Importer::GetPropertyMatrix(const char* szName, const aiMatrix4x4& iErrorReturn /*= aiMatrix4x4()*/) const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
return GetGenericProperty<aiMatrix4x4>(pimpl->mMatrixProperties,szName,iErrorReturn);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get the memory requirements of a single node
|
||||
inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)
|
||||
{
|
||||
inline
|
||||
void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode) {
|
||||
if ( nullptr == pcNode ) {
|
||||
return;
|
||||
}
|
||||
iScene += sizeof(aiNode);
|
||||
iScene += sizeof(unsigned int) * pcNode->mNumMeshes;
|
||||
iScene += sizeof(void*) * pcNode->mNumChildren;
|
||||
|
@ -1074,8 +1103,9 @@ inline void AddNodeWeight(unsigned int& iScene,const aiNode* pcNode)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get the memory requirements of the scene
|
||||
void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
|
||||
{
|
||||
void Importer::GetMemoryRequirements(aiMemoryInfo& in) const {
|
||||
ai_assert(nullptr != pimpl);
|
||||
|
||||
in = aiMemoryInfo();
|
||||
aiScene* mScene = pimpl->mScene;
|
||||
|
||||
|
@ -1087,8 +1117,7 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
|
|||
in.total = sizeof(aiScene);
|
||||
|
||||
// add all meshes
|
||||
for (unsigned int i = 0; i < mScene->mNumMeshes;++i)
|
||||
{
|
||||
for (unsigned int i = 0; i < mScene->mNumMeshes;++i) {
|
||||
in.meshes += sizeof(aiMesh);
|
||||
if (mScene->mMeshes[i]->HasPositions()) {
|
||||
in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
|
||||
|
@ -1105,14 +1134,16 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
|
|||
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) {
|
||||
if (mScene->mMeshes[i]->HasVertexColors(a)) {
|
||||
in.meshes += sizeof(aiColor4D) * mScene->mMeshes[i]->mNumVertices;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) {
|
||||
if (mScene->mMeshes[i]->HasTextureCoords(a)) {
|
||||
in.meshes += sizeof(aiVector3D) * mScene->mMeshes[i]->mNumVertices;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
if (mScene->mMeshes[i]->HasBones()) {
|
||||
in.meshes += sizeof(void*) * mScene->mMeshes[i]->mNumBones;
|
||||
|
@ -1131,8 +1162,9 @@ void Importer::GetMemoryRequirements(aiMemoryInfo& in) const
|
|||
in.textures += sizeof(aiTexture);
|
||||
if (pc->mHeight) {
|
||||
in.textures += 4 * pc->mHeight * pc->mWidth;
|
||||
} else {
|
||||
in.textures += pc->mWidth;
|
||||
}
|
||||
else in.textures += pc->mWidth;
|
||||
}
|
||||
in.total += in.textures;
|
||||
|
||||
|
|
|
@ -197,6 +197,9 @@ corresponding preprocessor flag to selectively disable formats.
|
|||
#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER
|
||||
# include "MMD/MMDImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
|
||||
# include "M3D/M3DImporter.h"
|
||||
#endif
|
||||
#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER
|
||||
# include "Importer/StepFile/StepFileImporter.h"
|
||||
#endif
|
||||
|
@ -223,6 +226,9 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out)
|
|||
#if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER)
|
||||
out.push_back( new Discreet3DSImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_M3D_IMPORTER)
|
||||
out.push_back( new M3DImporter());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_MD3_IMPORTER)
|
||||
out.push_back( new MD3Importer());
|
||||
#endif
|
||||
|
|
|
@ -131,11 +131,15 @@ corresponding preprocessor flag to selectively disable steps.
|
|||
#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
|
||||
# include "PostProcessing/ScaleProcess.h"
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS)
|
||||
# include "PostProcessing/ArmaturePopulate.h"
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS)
|
||||
# include "PostProcessing/GenBoundingBoxesProcess.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -180,6 +184,9 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out)
|
|||
#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS)
|
||||
out.push_back( new ScaleProcess());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_ARMATUREPOPULATE_PROCESS)
|
||||
out.push_back( new ArmaturePopulate());
|
||||
#endif
|
||||
#if (!defined ASSIMP_BUILD_NO_PRETRANSFORMVERTICES_PROCESS)
|
||||
out.push_back( new PretransformVertices());
|
||||
#endif
|
||||
|
|
|
@ -1091,6 +1091,35 @@ void SceneCombiner::Copy( aiMesh** _dest, const aiMesh* src ) {
|
|||
aiFace& f = dest->mFaces[i];
|
||||
GetArrayCopy(f.mIndices,f.mNumIndices);
|
||||
}
|
||||
|
||||
// make a deep copy of all blend shapes
|
||||
CopyPtrArray(dest->mAnimMeshes, dest->mAnimMeshes, dest->mNumAnimMeshes);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void SceneCombiner::Copy(aiAnimMesh** _dest, const aiAnimMesh* src) {
|
||||
if (nullptr == _dest || nullptr == src) {
|
||||
return;
|
||||
}
|
||||
|
||||
aiAnimMesh* dest = *_dest = new aiAnimMesh();
|
||||
|
||||
// get a flat copy
|
||||
::memcpy(dest, src, sizeof(aiAnimMesh));
|
||||
|
||||
// and reallocate all arrays
|
||||
GetArrayCopy(dest->mVertices, dest->mNumVertices);
|
||||
GetArrayCopy(dest->mNormals, dest->mNumVertices);
|
||||
GetArrayCopy(dest->mTangents, dest->mNumVertices);
|
||||
GetArrayCopy(dest->mBitangents, dest->mNumVertices);
|
||||
|
||||
unsigned int n = 0;
|
||||
while (dest->HasTextureCoords(n))
|
||||
GetArrayCopy(dest->mTextureCoords[n++], dest->mNumVertices);
|
||||
|
||||
n = 0;
|
||||
while (dest->HasVertexColors(n))
|
||||
GetArrayCopy(dest->mColors[n++], dest->mNumVertices);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -1167,6 +1196,7 @@ void SceneCombiner::Copy( aiAnimation** _dest, const aiAnimation* src ) {
|
|||
|
||||
// and reallocate all arrays
|
||||
CopyPtrArray( dest->mChannels, src->mChannels, dest->mNumChannels );
|
||||
CopyPtrArray( dest->mMorphMeshChannels, src->mMorphMeshChannels, dest->mNumMorphMeshChannels );
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -1186,6 +1216,26 @@ void SceneCombiner::Copy(aiNodeAnim** _dest, const aiNodeAnim* src) {
|
|||
GetArrayCopy( dest->mRotationKeys, dest->mNumRotationKeys );
|
||||
}
|
||||
|
||||
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) {
|
||||
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 "ScenePrivate.h"
|
||||
|
||||
static const unsigned int MajorVersion = 4;
|
||||
static const unsigned int MinorVersion = 1;
|
||||
#include "revision.h"
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
// Legal information string - don't remove this.
|
||||
|
@ -56,9 +55,9 @@ static const char* LEGAL_INFORMATION =
|
|||
"Open Asset Import Library (Assimp).\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"
|
||||
"http://assimp.sourceforge.net\n"
|
||||
"http://assimp.org\n"
|
||||
;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -67,16 +66,22 @@ ASSIMP_API const char* aiGetLegalString () {
|
|||
return LEGAL_INFORMATION;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get Assimp patch version
|
||||
ASSIMP_API unsigned int aiGetVersionPatch() {
|
||||
return VER_PATCH;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get Assimp minor version
|
||||
ASSIMP_API unsigned int aiGetVersionMinor () {
|
||||
return MinorVersion;
|
||||
return VER_MINOR;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get Assimp major version
|
||||
ASSIMP_API unsigned int aiGetVersionMajor () {
|
||||
return MajorVersion;
|
||||
return VER_MAJOR;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -104,9 +109,6 @@ ASSIMP_API unsigned int aiGetCompileFlags () {
|
|||
return flags;
|
||||
}
|
||||
|
||||
// include current build revision, which is even updated from time to time -- :-)
|
||||
#include "revision.h"
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ASSIMP_API unsigned int aiGetVersionRevision() {
|
||||
return GitVersion;
|
||||
|
|
|
@ -58,7 +58,7 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
|
|||
{
|
||||
// compute the number of referenced vertices if it wasn't specified by the caller
|
||||
const aiFace* const pcFaceEnd = pcFaces + iNumFaces;
|
||||
if (!iNumVertices) {
|
||||
if (0 == iNumVertices) {
|
||||
for (aiFace* pcFace = pcFaces; pcFace != pcFaceEnd; ++pcFace) {
|
||||
ai_assert( nullptr != pcFace );
|
||||
ai_assert(3 == pcFace->mNumIndices);
|
||||
|
@ -68,7 +68,7 @@ VertexTriangleAdjacency::VertexTriangleAdjacency(aiFace *pcFaces,
|
|||
}
|
||||
}
|
||||
|
||||
mNumVertices = iNumVertices;
|
||||
mNumVertices = iNumVertices + 1;
|
||||
|
||||
unsigned int* pi;
|
||||
|
||||
|
|
|
@ -0,0 +1,539 @@
|
|||
/*
|
||||
Open Asset Import Library (assimp)
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file ZipArchiveIOSystem.cpp
|
||||
* @brief Zip File I/O implementation for #Importer
|
||||
*/
|
||||
|
||||
#include <assimp/ZipArchiveIOSystem.h>
|
||||
#include <assimp/BaseImporter.h>
|
||||
|
||||
#include <assimp/ai_assert.h>
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#ifdef ASSIMP_USE_HUNTER
|
||||
# include <minizip/unzip.h>
|
||||
#else
|
||||
# include <unzip.h>
|
||||
#endif
|
||||
|
||||
namespace Assimp {
|
||||
// ----------------------------------------------------------------
|
||||
// Wraps an existing Assimp::IOSystem for unzip
|
||||
class IOSystem2Unzip {
|
||||
public:
|
||||
static voidpf open(voidpf opaque, const char* filename, int mode);
|
||||
static uLong read(voidpf opaque, voidpf stream, void* buf, uLong size);
|
||||
static uLong write(voidpf opaque, voidpf stream, const void* buf, uLong size);
|
||||
static long tell(voidpf opaque, voidpf stream);
|
||||
static long seek(voidpf opaque, voidpf stream, uLong offset, int origin);
|
||||
static int close(voidpf opaque, voidpf stream);
|
||||
static int testerror(voidpf opaque, voidpf stream);
|
||||
static zlib_filefunc_def get(IOSystem* pIOHandler);
|
||||
};
|
||||
|
||||
voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) {
|
||||
IOSystem* io_system = reinterpret_cast<IOSystem*>(opaque);
|
||||
|
||||
const char* mode_fopen = nullptr;
|
||||
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ) {
|
||||
mode_fopen = "rb";
|
||||
}
|
||||
else {
|
||||
if (mode & ZLIB_FILEFUNC_MODE_EXISTING) {
|
||||
mode_fopen = "r+b";
|
||||
}
|
||||
else {
|
||||
if (mode & ZLIB_FILEFUNC_MODE_CREATE) {
|
||||
mode_fopen = "wb";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (voidpf)io_system->Open(filename, mode_fopen);
|
||||
}
|
||||
|
||||
uLong IOSystem2Unzip::read(voidpf /*opaque*/, voidpf stream, void* buf, uLong size) {
|
||||
IOStream* io_stream = (IOStream*)stream;
|
||||
|
||||
return static_cast<uLong>(io_stream->Read(buf, 1, size));
|
||||
}
|
||||
|
||||
uLong IOSystem2Unzip::write(voidpf /*opaque*/, voidpf stream, const void* buf, uLong size) {
|
||||
IOStream* io_stream = (IOStream*)stream;
|
||||
|
||||
return static_cast<uLong>(io_stream->Write(buf, 1, size));
|
||||
}
|
||||
|
||||
long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) {
|
||||
IOStream* io_stream = (IOStream*)stream;
|
||||
|
||||
return static_cast<long>(io_stream->Tell());
|
||||
}
|
||||
|
||||
long IOSystem2Unzip::seek(voidpf /*opaque*/, voidpf stream, uLong offset, int origin) {
|
||||
IOStream* io_stream = (IOStream*)stream;
|
||||
|
||||
aiOrigin assimp_origin;
|
||||
switch (origin) {
|
||||
default:
|
||||
case ZLIB_FILEFUNC_SEEK_CUR:
|
||||
assimp_origin = aiOrigin_CUR;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_END:
|
||||
assimp_origin = aiOrigin_END;
|
||||
break;
|
||||
case ZLIB_FILEFUNC_SEEK_SET:
|
||||
assimp_origin = aiOrigin_SET;
|
||||
break;
|
||||
}
|
||||
|
||||
return (io_stream->Seek(offset, assimp_origin) == aiReturn_SUCCESS ? 0 : -1);
|
||||
}
|
||||
|
||||
int IOSystem2Unzip::close(voidpf opaque, voidpf stream) {
|
||||
IOSystem* io_system = (IOSystem*)opaque;
|
||||
IOStream* io_stream = (IOStream*)stream;
|
||||
|
||||
io_system->Close(io_stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IOSystem2Unzip::testerror(voidpf /*opaque*/, voidpf /*stream*/) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) {
|
||||
zlib_filefunc_def mapping;
|
||||
|
||||
#ifdef ASSIMP_USE_HUNTER
|
||||
mapping.zopen_file = (open_file_func)open;
|
||||
mapping.zread_file = (read_file_func)read;
|
||||
mapping.zwrite_file = (write_file_func)write;
|
||||
mapping.ztell_file = (tell_file_func)tell;
|
||||
mapping.zseek_file = (seek_file_func)seek;
|
||||
mapping.zclose_file = (close_file_func)close;
|
||||
mapping.zerror_file = (error_file_func)testerror;
|
||||
#else
|
||||
mapping.zopen_file = open;
|
||||
mapping.zread_file = read;
|
||||
mapping.zwrite_file = write;
|
||||
mapping.ztell_file = tell;
|
||||
mapping.zseek_file = seek;
|
||||
mapping.zclose_file = close;
|
||||
mapping.zerror_file = testerror;
|
||||
#endif
|
||||
mapping.opaque = reinterpret_cast<voidpf>(pIOHandler);
|
||||
|
||||
return mapping;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// A read-only file inside a ZIP
|
||||
|
||||
class ZipFile : public IOStream {
|
||||
friend class ZipFileInfo;
|
||||
explicit ZipFile(size_t size);
|
||||
public:
|
||||
virtual ~ZipFile();
|
||||
|
||||
// IOStream interface
|
||||
size_t Read(void* pvBuffer, size_t pSize, size_t pCount) override;
|
||||
size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) override { return 0; }
|
||||
size_t FileSize() const override;
|
||||
aiReturn Seek(size_t pOffset, aiOrigin pOrigin) override;
|
||||
size_t Tell() const override;
|
||||
void Flush() override {}
|
||||
|
||||
private:
|
||||
size_t m_Size = 0;
|
||||
size_t m_SeekPtr = 0;
|
||||
std::unique_ptr<uint8_t[]> m_Buffer;
|
||||
};
|
||||
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// Info about a read-only file inside a ZIP
|
||||
class ZipFileInfo
|
||||
{
|
||||
public:
|
||||
explicit ZipFileInfo(unzFile zip_handle, size_t size);
|
||||
|
||||
// Allocate and Extract data from the ZIP
|
||||
ZipFile * Extract(unzFile zip_handle) const;
|
||||
|
||||
private:
|
||||
size_t m_Size = 0;
|
||||
unz_file_pos_s m_ZipFilePos;
|
||||
};
|
||||
|
||||
ZipFileInfo::ZipFileInfo(unzFile zip_handle, size_t size)
|
||||
: m_Size(size) {
|
||||
ai_assert(m_Size != 0);
|
||||
// Workaround for MSVC 2013 - C2797
|
||||
m_ZipFilePos.num_of_file = 0;
|
||||
m_ZipFilePos.pos_in_zip_directory = 0;
|
||||
unzGetFilePos(zip_handle, &(m_ZipFilePos));
|
||||
}
|
||||
|
||||
ZipFile * ZipFileInfo::Extract(unzFile zip_handle) const {
|
||||
// Find in the ZIP. This cannot fail
|
||||
unz_file_pos_s *filepos = const_cast<unz_file_pos_s*>(&(m_ZipFilePos));
|
||||
if (unzGoToFilePos(zip_handle, filepos) != UNZ_OK)
|
||||
return nullptr;
|
||||
|
||||
if (unzOpenCurrentFile(zip_handle) != UNZ_OK)
|
||||
return nullptr;
|
||||
|
||||
ZipFile *zip_file = new ZipFile(m_Size);
|
||||
|
||||
if (unzReadCurrentFile(zip_handle, zip_file->m_Buffer.get(), static_cast<unsigned int>(m_Size)) != static_cast<int>(m_Size))
|
||||
{
|
||||
// Failed, release the memory
|
||||
delete zip_file;
|
||||
zip_file = nullptr;
|
||||
}
|
||||
|
||||
ai_assert(unzCloseCurrentFile(zip_handle) == UNZ_OK);
|
||||
return zip_file;
|
||||
}
|
||||
|
||||
ZipFile::ZipFile(size_t size)
|
||||
: m_Size(size) {
|
||||
ai_assert(m_Size != 0);
|
||||
m_Buffer = std::unique_ptr<uint8_t[]>(new uint8_t[m_Size]);
|
||||
}
|
||||
|
||||
ZipFile::~ZipFile() {
|
||||
}
|
||||
|
||||
size_t ZipFile::Read(void* pvBuffer, size_t pSize, size_t pCount) {
|
||||
// Should be impossible
|
||||
ai_assert(m_Buffer != nullptr);
|
||||
ai_assert(NULL != pvBuffer && 0 != pSize && 0 != pCount);
|
||||
|
||||
// Clip down to file size
|
||||
size_t byteSize = pSize * pCount;
|
||||
if ((byteSize + m_SeekPtr) > m_Size)
|
||||
{
|
||||
pCount = (m_Size - m_SeekPtr) / pSize;
|
||||
byteSize = pSize * pCount;
|
||||
if (byteSize == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::memcpy(pvBuffer, m_Buffer.get() + m_SeekPtr, byteSize);
|
||||
|
||||
m_SeekPtr += byteSize;
|
||||
|
||||
return pCount;
|
||||
}
|
||||
|
||||
size_t ZipFile::FileSize() const {
|
||||
return m_Size;
|
||||
}
|
||||
|
||||
aiReturn ZipFile::Seek(size_t pOffset, aiOrigin pOrigin) {
|
||||
switch (pOrigin)
|
||||
{
|
||||
case aiOrigin_SET: {
|
||||
if (pOffset > m_Size) return aiReturn_FAILURE;
|
||||
m_SeekPtr = pOffset;
|
||||
return aiReturn_SUCCESS;
|
||||
}
|
||||
|
||||
case aiOrigin_CUR: {
|
||||
if ((pOffset + m_SeekPtr) > m_Size) return aiReturn_FAILURE;
|
||||
m_SeekPtr += pOffset;
|
||||
return aiReturn_SUCCESS;
|
||||
}
|
||||
|
||||
case aiOrigin_END: {
|
||||
if (pOffset > m_Size) return aiReturn_FAILURE;
|
||||
m_SeekPtr = m_Size - pOffset;
|
||||
return aiReturn_SUCCESS;
|
||||
}
|
||||
default:;
|
||||
}
|
||||
|
||||
return aiReturn_FAILURE;
|
||||
}
|
||||
|
||||
size_t ZipFile::Tell() const {
|
||||
return m_SeekPtr;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// pImpl of the Zip Archive IO
|
||||
class ZipArchiveIOSystem::Implement {
|
||||
public:
|
||||
static const unsigned int FileNameSize = 256;
|
||||
|
||||
Implement(IOSystem* pIOHandler, const char* pFilename, const char* pMode);
|
||||
~Implement();
|
||||
|
||||
bool isOpen() const;
|
||||
void getFileList(std::vector<std::string>& rFileList);
|
||||
void getFileListExtension(std::vector<std::string>& rFileList, const std::string& extension);
|
||||
bool Exists(std::string& filename);
|
||||
IOStream* OpenFile(std::string& filename);
|
||||
|
||||
static void SimplifyFilename(std::string& filename);
|
||||
|
||||
private:
|
||||
void MapArchive();
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, ZipFileInfo> ZipFileInfoMap;
|
||||
|
||||
unzFile m_ZipFileHandle = nullptr;
|
||||
ZipFileInfoMap m_ArchiveMap;
|
||||
};
|
||||
|
||||
ZipArchiveIOSystem::Implement::Implement(IOSystem* pIOHandler, const char* pFilename, const char* pMode) {
|
||||
ai_assert(strcmp(pMode, "r") == 0);
|
||||
ai_assert(pFilename != nullptr);
|
||||
if (pFilename[0] == 0)
|
||||
return;
|
||||
|
||||
zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler);
|
||||
m_ZipFileHandle = unzOpen2(pFilename, &mapping);
|
||||
}
|
||||
|
||||
ZipArchiveIOSystem::Implement::~Implement() {
|
||||
m_ArchiveMap.clear();
|
||||
|
||||
if (m_ZipFileHandle != nullptr) {
|
||||
unzClose(m_ZipFileHandle);
|
||||
m_ZipFileHandle = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void ZipArchiveIOSystem::Implement::MapArchive() {
|
||||
if (m_ZipFileHandle == nullptr)
|
||||
return;
|
||||
|
||||
if (!m_ArchiveMap.empty())
|
||||
return;
|
||||
|
||||
// At first ensure file is already open
|
||||
if (unzGoToFirstFile(m_ZipFileHandle) != UNZ_OK)
|
||||
return;
|
||||
|
||||
// Loop over all files
|
||||
do {
|
||||
char filename[FileNameSize];
|
||||
unz_file_info fileInfo;
|
||||
|
||||
if (unzGetCurrentFileInfo(m_ZipFileHandle, &fileInfo, filename, FileNameSize, nullptr, 0, nullptr, 0) == UNZ_OK) {
|
||||
if (fileInfo.uncompressed_size != 0) {
|
||||
std::string filename_string(filename, fileInfo.size_filename);
|
||||
SimplifyFilename(filename_string);
|
||||
m_ArchiveMap.emplace(filename_string, ZipFileInfo(m_ZipFileHandle, fileInfo.uncompressed_size));
|
||||
}
|
||||
}
|
||||
} while (unzGoToNextFile(m_ZipFileHandle) != UNZ_END_OF_LIST_OF_FILE);
|
||||
}
|
||||
|
||||
bool ZipArchiveIOSystem::Implement::isOpen() const {
|
||||
return (m_ZipFileHandle != nullptr);
|
||||
}
|
||||
|
||||
void ZipArchiveIOSystem::Implement::getFileList(std::vector<std::string>& rFileList) {
|
||||
MapArchive();
|
||||
rFileList.clear();
|
||||
|
||||
for (const auto &file : m_ArchiveMap) {
|
||||
rFileList.push_back(file.first);
|
||||
}
|
||||
}
|
||||
|
||||
void ZipArchiveIOSystem::Implement::getFileListExtension(std::vector<std::string>& rFileList, const std::string& extension) {
|
||||
MapArchive();
|
||||
rFileList.clear();
|
||||
|
||||
for (const auto &file : m_ArchiveMap) {
|
||||
if (extension == BaseImporter::GetExtension(file.first))
|
||||
rFileList.push_back(file.first);
|
||||
}
|
||||
}
|
||||
|
||||
bool ZipArchiveIOSystem::Implement::Exists(std::string& filename) {
|
||||
MapArchive();
|
||||
|
||||
ZipFileInfoMap::const_iterator it = m_ArchiveMap.find(filename);
|
||||
return (it != m_ArchiveMap.end());
|
||||
}
|
||||
|
||||
IOStream * ZipArchiveIOSystem::Implement::OpenFile(std::string& filename) {
|
||||
MapArchive();
|
||||
|
||||
SimplifyFilename(filename);
|
||||
|
||||
// Find in the map
|
||||
ZipFileInfoMap::const_iterator zip_it = m_ArchiveMap.find(filename);
|
||||
if (zip_it == m_ArchiveMap.cend())
|
||||
return nullptr;
|
||||
|
||||
const ZipFileInfo &zip_file = (*zip_it).second;
|
||||
return zip_file.Extract(m_ZipFileHandle);
|
||||
}
|
||||
|
||||
inline void ReplaceAll(std::string& data, const std::string& before, const std::string& after) {
|
||||
size_t pos = data.find(before);
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
data.replace(pos, before.size(), after);
|
||||
pos = data.find(before, pos + after.size());
|
||||
}
|
||||
}
|
||||
|
||||
inline void ReplaceAllChar(std::string& data, const char before, const char after) {
|
||||
size_t pos = data.find(before);
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
data[pos] = after;
|
||||
pos = data.find(before, pos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void ZipArchiveIOSystem::Implement::SimplifyFilename(std::string& filename)
|
||||
{
|
||||
ReplaceAllChar(filename, '\\', '/');
|
||||
|
||||
// Remove all . and / from the beginning of the path
|
||||
size_t pos = filename.find_first_not_of("./");
|
||||
if (pos != 0)
|
||||
filename.erase(0, pos);
|
||||
|
||||
// Simplify "my/folder/../file.png" constructions, if any
|
||||
static const std::string relative("/../");
|
||||
const size_t relsize = relative.size() - 1;
|
||||
pos = filename.find(relative);
|
||||
while (pos != std::string::npos)
|
||||
{
|
||||
// Previous slash
|
||||
size_t prevpos = filename.rfind('/', pos - 1);
|
||||
if (prevpos == pos)
|
||||
filename.erase(0, pos + relative.size());
|
||||
else
|
||||
filename.erase(prevpos, pos + relsize - prevpos);
|
||||
|
||||
pos = filename.find(relative);
|
||||
}
|
||||
}
|
||||
|
||||
ZipArchiveIOSystem::ZipArchiveIOSystem(IOSystem* pIOHandler, const char* pFilename, const char* pMode)
|
||||
: pImpl(new Implement(pIOHandler, pFilename, pMode)) {
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// The ZipArchiveIO
|
||||
ZipArchiveIOSystem::ZipArchiveIOSystem(IOSystem* pIOHandler, const std::string& rFilename, const char* pMode)
|
||||
: pImpl(new Implement(pIOHandler, rFilename.c_str(), pMode))
|
||||
{
|
||||
}
|
||||
|
||||
ZipArchiveIOSystem::~ZipArchiveIOSystem() {
|
||||
delete pImpl;
|
||||
}
|
||||
|
||||
bool ZipArchiveIOSystem::Exists(const char* pFilename) const {
|
||||
ai_assert(pFilename != nullptr);
|
||||
|
||||
if (pFilename == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string filename(pFilename);
|
||||
return pImpl->Exists(filename);
|
||||
}
|
||||
|
||||
// This is always '/' in a ZIP
|
||||
char ZipArchiveIOSystem::getOsSeparator() const {
|
||||
return '/';
|
||||
}
|
||||
|
||||
// Only supports Reading
|
||||
IOStream * ZipArchiveIOSystem::Open(const char* pFilename, const char* pMode) {
|
||||
ai_assert(pFilename != nullptr);
|
||||
|
||||
for (size_t i = 0; pMode[i] != 0; ++i)
|
||||
{
|
||||
ai_assert(pMode[i] != 'w');
|
||||
if (pMode[i] == 'w')
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string filename(pFilename);
|
||||
return pImpl->OpenFile(filename);
|
||||
}
|
||||
|
||||
void ZipArchiveIOSystem::Close(IOStream* pFile) {
|
||||
delete pFile;
|
||||
}
|
||||
|
||||
bool ZipArchiveIOSystem::isOpen() const {
|
||||
return (pImpl->isOpen());
|
||||
}
|
||||
|
||||
void ZipArchiveIOSystem::getFileList(std::vector<std::string>& rFileList) const {
|
||||
return pImpl->getFileList(rFileList);
|
||||
}
|
||||
|
||||
void ZipArchiveIOSystem::getFileListExtension(std::vector<std::string>& rFileList, const std::string& extension) const {
|
||||
return pImpl->getFileListExtension(rFileList, extension);
|
||||
}
|
||||
|
||||
bool ZipArchiveIOSystem::isZipArchive(IOSystem* pIOHandler, const char* pFilename) {
|
||||
Implement tmp(pIOHandler, pFilename, "r");
|
||||
return tmp.isOpen();
|
||||
}
|
||||
|
||||
bool ZipArchiveIOSystem::isZipArchive(IOSystem* pIOHandler, const std::string& rFilename) {
|
||||
return isZipArchive(pIOHandler, rFilename.c_str());
|
||||
}
|
||||
|
||||
}
|
|
@ -44,23 +44,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
aiNode::aiNode()
|
||||
: mName("")
|
||||
, mParent(NULL)
|
||||
, mParent(nullptr)
|
||||
, mNumChildren(0)
|
||||
, mChildren(NULL)
|
||||
, mChildren(nullptr)
|
||||
, mNumMeshes(0)
|
||||
, mMeshes(NULL)
|
||||
, mMetaData(NULL) {
|
||||
, mMeshes(nullptr)
|
||||
, mMetaData(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
aiNode::aiNode(const std::string& name)
|
||||
: mName(name)
|
||||
, mParent(NULL)
|
||||
, mParent(nullptr)
|
||||
, mNumChildren(0)
|
||||
, mChildren(NULL)
|
||||
, mChildren(nullptr)
|
||||
, mNumMeshes(0)
|
||||
, mMeshes(NULL)
|
||||
, mMetaData(NULL) {
|
||||
, mMeshes(nullptr)
|
||||
, mMetaData(nullptr) {
|
||||
// empty
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ aiNode::aiNode(const std::string& name)
|
|||
aiNode::~aiNode() {
|
||||
// delete all children recursively
|
||||
// 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++)
|
||||
delete mChildren[a];
|
||||
|
|
|
@ -50,9 +50,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
namespace Assimp {
|
||||
namespace FBX
|
||||
{
|
||||
const std::string NULL_RECORD = { // 13 null bytes
|
||||
'\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0'
|
||||
}; // who knows why
|
||||
const std::string 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'
|
||||
}; // 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 MAGIC_NODE_TAG = "_$AssimpFbx$"; // from import
|
||||
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
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
//
|
||||
#if _MSC_VER > 1500 || (defined __GNUC___)
|
||||
|
@ -54,16 +55,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
# else
|
||||
# define fbx_unordered_map map
|
||||
# define fbx_unordered_multimap multimap
|
||||
# define fbx_unordered_set set
|
||||
# define fbx_unordered_multiset multiset
|
||||
#endif
|
||||
|
||||
#ifdef ASSIMP_FBX_USE_UNORDERED_MULTIMAP
|
||||
# include <unordered_map>
|
||||
# include <unordered_set>
|
||||
# if _MSC_VER > 1600
|
||||
# define fbx_unordered_map unordered_map
|
||||
# define fbx_unordered_multimap unordered_multimap
|
||||
# define fbx_unordered_set unordered_set
|
||||
# define fbx_unordered_multiset unordered_multiset
|
||||
# else
|
||||
# define fbx_unordered_map tr1::unordered_map
|
||||
# define fbx_unordered_multimap tr1::unordered_multimap
|
||||
# define fbx_unordered_set tr1::unordered_set
|
||||
# define fbx_unordered_multiset tr1::unordered_multiset
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -55,10 +55,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "FBXImporter.h"
|
||||
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/MathFunctions.h>
|
||||
|
||||
#include <assimp/scene.h>
|
||||
|
||||
#include <assimp/CreateAnimMesh.h>
|
||||
#include <assimp/commonMetaData.h>
|
||||
#include <assimp/StringUtils.h>
|
||||
|
||||
#include <tuple>
|
||||
#include <memory>
|
||||
|
@ -66,7 +69,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
|
@ -75,9 +80,9 @@ namespace Assimp {
|
|||
|
||||
#define MAGIC_NODE_TAG "_$AssimpFbx$"
|
||||
|
||||
#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000L
|
||||
#define CONVERT_FBX_TIME(time) static_cast<double>(time) / 46186158000LL
|
||||
|
||||
FBXConverter::FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit )
|
||||
FBXConverter::FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones )
|
||||
: defaultMaterialIndex()
|
||||
, lights()
|
||||
, cameras()
|
||||
|
@ -89,13 +94,19 @@ namespace Assimp {
|
|||
, mNodeNames()
|
||||
, anim_fps()
|
||||
, out(out)
|
||||
, doc(doc)
|
||||
, mRemoveEmptyBones( removeEmptyBones )
|
||||
, mCurrentUnit(FbxUnit::cm) {
|
||||
, doc(doc) {
|
||||
// animations need to be converted first since this will
|
||||
// populate the node_anim_chain_bits map, which is needed
|
||||
// to determine which nodes need to be generated.
|
||||
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();
|
||||
|
||||
if (doc.Settings().readAllMaterials) {
|
||||
|
@ -119,7 +130,6 @@ namespace Assimp {
|
|||
|
||||
ConvertGlobalSettings();
|
||||
TransferDataToScene();
|
||||
ConvertToUnitScale(unit);
|
||||
|
||||
// if we didn't read any meshes set the AI_SCENE_FLAGS_INCOMPLETE
|
||||
// to make sure the scene passes assimp's validation. FBX files
|
||||
|
@ -146,7 +156,7 @@ namespace Assimp {
|
|||
out->mRootNode->mName.Set(unique_name);
|
||||
|
||||
// root has ID 0
|
||||
ConvertNodes(0L, *out->mRootNode);
|
||||
ConvertNodes(0L, out->mRootNode, out->mRootNode);
|
||||
}
|
||||
|
||||
static std::string getAncestorBaseName(const aiNode* node)
|
||||
|
@ -180,8 +190,11 @@ namespace Assimp {
|
|||
GetUniqueName(original_name, unique_name);
|
||||
return unique_name;
|
||||
}
|
||||
|
||||
void FBXConverter::ConvertNodes(uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform) {
|
||||
/// todo: pre-build node hierarchy
|
||||
/// 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");
|
||||
|
||||
std::vector<aiNode*> nodes;
|
||||
|
@ -192,62 +205,69 @@ namespace Assimp {
|
|||
|
||||
try {
|
||||
for (const Connection* con : conns) {
|
||||
|
||||
// ignore object-property links
|
||||
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();
|
||||
if (nullptr == object) {
|
||||
FBXImporter::LogWarn("failed to convert source object for Model link");
|
||||
FBXImporter::LogError("failed to convert source object for Model link");
|
||||
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);
|
||||
|
||||
if (nullptr != model) {
|
||||
nodes_chain.clear();
|
||||
post_nodes_chain.clear();
|
||||
|
||||
aiMatrix4x4 new_abs_transform = parent_transform;
|
||||
|
||||
std::string unique_name = MakeUniqueNodeName(model, parent);
|
||||
|
||||
aiMatrix4x4 new_abs_transform = parent->mTransformation;
|
||||
std::string node_name = FixNodeName(model->Name());
|
||||
// even though there is only a single input node, the design of
|
||||
// assimp (or rather: the complicated transformation chain that
|
||||
// is employed by fbx) means that we may need multiple aiNode's
|
||||
// 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());
|
||||
|
||||
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
|
||||
SetupNodeMetadata(*model, *nodes_chain.back());
|
||||
|
||||
// link all nodes in a row
|
||||
aiNode* last_parent = &parent;
|
||||
for (aiNode* prenode : nodes_chain) {
|
||||
ai_assert(prenode);
|
||||
aiNode* last_parent = parent;
|
||||
for (aiNode* child : nodes_chain) {
|
||||
ai_assert(child);
|
||||
|
||||
if (last_parent != &parent) {
|
||||
if (last_parent != parent) {
|
||||
last_parent->mNumChildren = 1;
|
||||
last_parent->mChildren = new aiNode*[1];
|
||||
last_parent->mChildren[0] = prenode;
|
||||
last_parent->mChildren[0] = child;
|
||||
}
|
||||
|
||||
prenode->mParent = last_parent;
|
||||
last_parent = prenode;
|
||||
child->mParent = last_parent;
|
||||
last_parent = child;
|
||||
|
||||
new_abs_transform *= prenode->mTransformation;
|
||||
new_abs_transform *= child->mTransformation;
|
||||
}
|
||||
|
||||
// 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
|
||||
const std::vector<const Connection*>& child_conns
|
||||
|
@ -259,7 +279,7 @@ namespace Assimp {
|
|||
for (aiNode* postnode : post_nodes_chain) {
|
||||
ai_assert(postnode);
|
||||
|
||||
if (last_parent != &parent) {
|
||||
if (last_parent != parent) {
|
||||
last_parent->mNumChildren = 1;
|
||||
last_parent->mChildren = new aiNode*[1];
|
||||
last_parent->mChildren[0] = postnode;
|
||||
|
@ -281,15 +301,15 @@ namespace Assimp {
|
|||
);
|
||||
}
|
||||
|
||||
// attach sub-nodes (if any)
|
||||
ConvertNodes(model->ID(), *last_parent, new_abs_transform);
|
||||
// recursion call - child nodes
|
||||
ConvertNodes(model->ID(), last_parent, root_node);
|
||||
|
||||
if (doc.Settings().readLights) {
|
||||
ConvertLights(*model, unique_name);
|
||||
ConvertLights(*model, node_name);
|
||||
}
|
||||
|
||||
if (doc.Settings().readCameras) {
|
||||
ConvertCameras(*model, unique_name);
|
||||
ConvertCameras(*model, node_name);
|
||||
}
|
||||
|
||||
nodes.push_back(nodes_chain.front());
|
||||
|
@ -298,11 +318,17 @@ namespace Assimp {
|
|||
}
|
||||
|
||||
if (nodes.size()) {
|
||||
parent.mChildren = new aiNode*[nodes.size()]();
|
||||
parent.mNumChildren = static_cast<unsigned int>(nodes.size());
|
||||
parent->mChildren = new aiNode*[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&) {
|
||||
Util::delete_fun<aiNode> deleter;
|
||||
|
@ -555,7 +581,7 @@ namespace Assimp {
|
|||
return;
|
||||
}
|
||||
|
||||
const float angle_epsilon = 1e-6f;
|
||||
const float angle_epsilon = Math::getEpsilon<float>();
|
||||
|
||||
out = aiMatrix4x4();
|
||||
|
||||
|
@ -685,30 +711,37 @@ namespace Assimp {
|
|||
bool ok;
|
||||
|
||||
aiMatrix4x4 chain[TransformationComp_MAXIMUM];
|
||||
|
||||
ai_assert(TransformationComp_MAXIMUM < 32);
|
||||
std::uint32_t chainBits = 0;
|
||||
// A node won't need a node chain if it only has these.
|
||||
const std::uint32_t chainMaskSimple = (1 << TransformationComp_Translation) + (1 << TransformationComp_Scaling) + (1 << TransformationComp_Rotation);
|
||||
// A node will need a node chain if it has any of these.
|
||||
const std::uint32_t chainMaskComplex = ((1 << (TransformationComp_MAXIMUM)) - 1) - chainMaskSimple;
|
||||
|
||||
std::fill_n(chain, static_cast<unsigned int>(TransformationComp_MAXIMUM), aiMatrix4x4());
|
||||
|
||||
// generate transformation matrices for all the different transformation components
|
||||
const float zero_epsilon = 1e-6f;
|
||||
const float zero_epsilon = Math::getEpsilon<float>();
|
||||
const aiVector3D all_ones(1.0f, 1.0f, 1.0f);
|
||||
bool is_complex = false;
|
||||
|
||||
const aiVector3D& PreRotation = PropertyGet<aiVector3D>(props, "PreRotation", ok);
|
||||
if (ok && PreRotation.SquareLength() > zero_epsilon) {
|
||||
is_complex = true;
|
||||
chainBits = chainBits | (1 << TransformationComp_PreRotation);
|
||||
|
||||
GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PreRotation, chain[TransformationComp_PreRotation]);
|
||||
}
|
||||
|
||||
const aiVector3D& PostRotation = PropertyGet<aiVector3D>(props, "PostRotation", ok);
|
||||
if (ok && PostRotation.SquareLength() > zero_epsilon) {
|
||||
is_complex = true;
|
||||
chainBits = chainBits | (1 << TransformationComp_PostRotation);
|
||||
|
||||
GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PostRotation, chain[TransformationComp_PostRotation]);
|
||||
}
|
||||
|
||||
const aiVector3D& RotationPivot = PropertyGet<aiVector3D>(props, "RotationPivot", ok);
|
||||
if (ok && RotationPivot.SquareLength() > zero_epsilon) {
|
||||
is_complex = true;
|
||||
chainBits = chainBits | (1 << TransformationComp_RotationPivot) | (1 << TransformationComp_RotationPivotInverse);
|
||||
|
||||
aiMatrix4x4::Translation(RotationPivot, chain[TransformationComp_RotationPivot]);
|
||||
aiMatrix4x4::Translation(-RotationPivot, chain[TransformationComp_RotationPivotInverse]);
|
||||
|
@ -716,21 +749,21 @@ namespace Assimp {
|
|||
|
||||
const aiVector3D& RotationOffset = PropertyGet<aiVector3D>(props, "RotationOffset", ok);
|
||||
if (ok && RotationOffset.SquareLength() > zero_epsilon) {
|
||||
is_complex = true;
|
||||
chainBits = chainBits | (1 << TransformationComp_RotationOffset);
|
||||
|
||||
aiMatrix4x4::Translation(RotationOffset, chain[TransformationComp_RotationOffset]);
|
||||
}
|
||||
|
||||
const aiVector3D& ScalingOffset = PropertyGet<aiVector3D>(props, "ScalingOffset", ok);
|
||||
if (ok && ScalingOffset.SquareLength() > zero_epsilon) {
|
||||
is_complex = true;
|
||||
chainBits = chainBits | (1 << TransformationComp_ScalingOffset);
|
||||
|
||||
aiMatrix4x4::Translation(ScalingOffset, chain[TransformationComp_ScalingOffset]);
|
||||
}
|
||||
|
||||
const aiVector3D& ScalingPivot = PropertyGet<aiVector3D>(props, "ScalingPivot", ok);
|
||||
if (ok && ScalingPivot.SquareLength() > zero_epsilon) {
|
||||
is_complex = true;
|
||||
chainBits = chainBits | (1 << TransformationComp_ScalingPivot) | (1 << TransformationComp_ScalingPivotInverse);
|
||||
|
||||
aiMatrix4x4::Translation(ScalingPivot, chain[TransformationComp_ScalingPivot]);
|
||||
aiMatrix4x4::Translation(-ScalingPivot, chain[TransformationComp_ScalingPivotInverse]);
|
||||
|
@ -738,22 +771,28 @@ namespace Assimp {
|
|||
|
||||
const aiVector3D& Translation = PropertyGet<aiVector3D>(props, "Lcl Translation", ok);
|
||||
if (ok && Translation.SquareLength() > zero_epsilon) {
|
||||
chainBits = chainBits | (1 << TransformationComp_Translation);
|
||||
|
||||
aiMatrix4x4::Translation(Translation, chain[TransformationComp_Translation]);
|
||||
}
|
||||
|
||||
const aiVector3D& Scaling = PropertyGet<aiVector3D>(props, "Lcl Scaling", ok);
|
||||
if (ok && (Scaling - all_ones).SquareLength() > zero_epsilon) {
|
||||
chainBits = chainBits | (1 << TransformationComp_Scaling);
|
||||
|
||||
aiMatrix4x4::Scaling(Scaling, chain[TransformationComp_Scaling]);
|
||||
}
|
||||
|
||||
const aiVector3D& Rotation = PropertyGet<aiVector3D>(props, "Lcl Rotation", ok);
|
||||
if (ok && Rotation.SquareLength() > zero_epsilon) {
|
||||
chainBits = chainBits | (1 << TransformationComp_Rotation);
|
||||
|
||||
GetRotationMatrix(rot, Rotation, chain[TransformationComp_Rotation]);
|
||||
}
|
||||
|
||||
const aiVector3D& GeometricScaling = PropertyGet<aiVector3D>(props, "GeometricScaling", ok);
|
||||
if (ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon) {
|
||||
is_complex = true;
|
||||
chainBits = chainBits | (1 << TransformationComp_GeometricScaling);
|
||||
aiMatrix4x4::Scaling(GeometricScaling, chain[TransformationComp_GeometricScaling]);
|
||||
aiVector3D GeometricScalingInverse = GeometricScaling;
|
||||
bool canscale = true;
|
||||
|
@ -768,13 +807,14 @@ namespace Assimp {
|
|||
}
|
||||
}
|
||||
if (canscale) {
|
||||
chainBits = chainBits | (1 << TransformationComp_GeometricScalingInverse);
|
||||
aiMatrix4x4::Scaling(GeometricScalingInverse, chain[TransformationComp_GeometricScalingInverse]);
|
||||
}
|
||||
}
|
||||
|
||||
const aiVector3D& GeometricRotation = PropertyGet<aiVector3D>(props, "GeometricRotation", ok);
|
||||
if (ok && GeometricRotation.SquareLength() > zero_epsilon) {
|
||||
is_complex = true;
|
||||
chainBits = chainBits | (1 << TransformationComp_GeometricRotation) | (1 << TransformationComp_GeometricRotationInverse);
|
||||
GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotation]);
|
||||
GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotationInverse]);
|
||||
chain[TransformationComp_GeometricRotationInverse].Inverse();
|
||||
|
@ -782,7 +822,7 @@ namespace Assimp {
|
|||
|
||||
const aiVector3D& GeometricTranslation = PropertyGet<aiVector3D>(props, "GeometricTranslation", ok);
|
||||
if (ok && GeometricTranslation.SquareLength() > zero_epsilon) {
|
||||
is_complex = true;
|
||||
chainBits = chainBits | (1 << TransformationComp_GeometricTranslation) | (1 << TransformationComp_GeometricTranslationInverse);
|
||||
aiMatrix4x4::Translation(GeometricTranslation, chain[TransformationComp_GeometricTranslation]);
|
||||
aiMatrix4x4::Translation(-GeometricTranslation, chain[TransformationComp_GeometricTranslationInverse]);
|
||||
}
|
||||
|
@ -790,12 +830,12 @@ namespace Assimp {
|
|||
// is_complex needs to be consistent with NeedsComplexTransformationChain()
|
||||
// or the interplay between this code and the animation converter would
|
||||
// not be guaranteed.
|
||||
ai_assert(NeedsComplexTransformationChain(model) == is_complex);
|
||||
//ai_assert(NeedsComplexTransformationChain(model) == ((chainBits & chainMaskComplex) != 0));
|
||||
|
||||
// now, if we have more than just Translation, Scaling and Rotation,
|
||||
// we need to generate a full node chain to accommodate for assimp's
|
||||
// lack to express pivots and offsets.
|
||||
if (is_complex && doc.Settings().preservePivots) {
|
||||
if ((chainBits & chainMaskComplex) && doc.Settings().preservePivots) {
|
||||
FBXImporter::LogInfo("generating full transformation chain for node: " + name);
|
||||
|
||||
// query the anim_chain_bits dictionary to find out which chain elements
|
||||
|
@ -808,7 +848,7 @@ namespace Assimp {
|
|||
for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) {
|
||||
const TransformationComp comp = static_cast<TransformationComp>(i);
|
||||
|
||||
if (chain[i].IsIdentity() && (anim_chain_bitmask & bit) == 0) {
|
||||
if ((chainBits & bit) == 0 && (anim_chain_bitmask & bit) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -892,7 +932,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();
|
||||
|
||||
|
@ -904,11 +945,12 @@ namespace Assimp {
|
|||
const MeshGeometry* const mesh = dynamic_cast<const MeshGeometry*>(geo);
|
||||
const LineGeometry* const line = dynamic_cast<const LineGeometry*>(geo);
|
||||
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));
|
||||
}
|
||||
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));
|
||||
}
|
||||
else {
|
||||
|
@ -917,15 +959,16 @@ namespace Assimp {
|
|||
}
|
||||
|
||||
if (meshes.size()) {
|
||||
nd.mMeshes = new unsigned int[meshes.size()]();
|
||||
nd.mNumMeshes = static_cast<unsigned int>(meshes.size());
|
||||
parent->mMeshes = new 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,
|
||||
const aiMatrix4x4& node_global_transform, aiNode& nd)
|
||||
std::vector<unsigned int>
|
||||
FBXConverter::ConvertMesh(const MeshGeometry &mesh, const Model &model, aiNode *parent, aiNode *root_node,
|
||||
const aiMatrix4x4 &absolute_transform)
|
||||
{
|
||||
std::vector<unsigned int> temp;
|
||||
|
||||
|
@ -949,18 +992,18 @@ namespace Assimp {
|
|||
const MatIndexArray::value_type base = mindices[0];
|
||||
for (MatIndexArray::value_type index : mindices) {
|
||||
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
|
||||
temp.push_back(ConvertMeshSingleMaterial(mesh, model, node_global_transform, nd));
|
||||
temp.push_back(ConvertMeshSingleMaterial(mesh, model, absolute_transform, parent, root_node));
|
||||
return temp;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -971,7 +1014,7 @@ namespace Assimp {
|
|||
return temp;
|
||||
}
|
||||
|
||||
aiMesh* const out_mesh = SetupEmptyMesh(line, nd);
|
||||
aiMesh* const out_mesh = SetupEmptyMesh(line, root_node);
|
||||
out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE;
|
||||
|
||||
// copy vertices
|
||||
|
@ -1006,7 +1049,7 @@ namespace Assimp {
|
|||
return temp;
|
||||
}
|
||||
|
||||
aiMesh* FBXConverter::SetupEmptyMesh(const Geometry& mesh, aiNode& nd)
|
||||
aiMesh* FBXConverter::SetupEmptyMesh(const Geometry& mesh, aiNode *parent)
|
||||
{
|
||||
aiMesh* const out_mesh = new aiMesh();
|
||||
meshes.push_back(out_mesh);
|
||||
|
@ -1023,17 +1066,18 @@ namespace Assimp {
|
|||
}
|
||||
else
|
||||
{
|
||||
out_mesh->mName = nd.mName;
|
||||
out_mesh->mName = parent->mName;
|
||||
}
|
||||
|
||||
return out_mesh;
|
||||
}
|
||||
|
||||
unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry& mesh, const Model& model,
|
||||
const aiMatrix4x4& node_global_transform, aiNode& nd)
|
||||
unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model,
|
||||
const aiMatrix4x4 &absolute_transform, aiNode *parent,
|
||||
aiNode *root_node)
|
||||
{
|
||||
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<unsigned int>& faces = mesh.GetFaceIndexCounts();
|
||||
|
@ -1100,7 +1144,7 @@ namespace Assimp {
|
|||
binormals = &tempBinormals;
|
||||
}
|
||||
else {
|
||||
binormals = NULL;
|
||||
binormals = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1150,8 +1194,9 @@ namespace Assimp {
|
|||
ConvertMaterialForMesh(out_mesh, model, mesh, mindices[0]);
|
||||
}
|
||||
|
||||
if (doc.Settings().readWeights && mesh.DeformerSkin() != NULL) {
|
||||
ConvertWeights(out_mesh, model, mesh, node_global_transform, NO_MATERIAL_SEPARATION);
|
||||
if (doc.Settings().readWeights && mesh.DeformerSkin() != nullptr) {
|
||||
ConvertWeights(out_mesh, model, mesh, absolute_transform, parent, root_node, NO_MATERIAL_SEPARATION,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
std::vector<aiAnimMesh*> animMeshes;
|
||||
|
@ -1196,8 +1241,10 @@ namespace Assimp {
|
|||
return static_cast<unsigned int>(meshes.size() - 1);
|
||||
}
|
||||
|
||||
std::vector<unsigned int> FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model,
|
||||
const aiMatrix4x4& node_global_transform, aiNode& nd)
|
||||
std::vector<unsigned int>
|
||||
FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, aiNode *parent,
|
||||
aiNode *root_node,
|
||||
const aiMatrix4x4 &absolute_transform)
|
||||
{
|
||||
const MatIndexArray& mindices = mesh.GetMaterialIndices();
|
||||
ai_assert(mindices.size());
|
||||
|
@ -1208,7 +1255,7 @@ namespace Assimp {
|
|||
for (MatIndexArray::value_type index : mindices) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1216,18 +1263,18 @@ namespace Assimp {
|
|||
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,
|
||||
const aiMatrix4x4& node_global_transform,
|
||||
aiNode& nd)
|
||||
aiNode *parent, aiNode *root_node,
|
||||
const aiMatrix4x4 &absolute_transform)
|
||||
{
|
||||
aiMesh* const out_mesh = SetupEmptyMesh(mesh, nd);
|
||||
aiMesh* const out_mesh = SetupEmptyMesh(mesh, parent);
|
||||
|
||||
const MatIndexArray& mindices = mesh.GetMaterialIndices();
|
||||
const std::vector<aiVector3D>& vertices = mesh.GetVertices();
|
||||
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_vertices = 0;
|
||||
|
@ -1287,7 +1334,7 @@ namespace Assimp {
|
|||
binormals = &tempBinormals;
|
||||
}
|
||||
else {
|
||||
binormals = NULL;
|
||||
binormals = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1386,7 +1433,7 @@ namespace Assimp {
|
|||
ConvertMaterialForMesh(out_mesh, model, mesh, index);
|
||||
|
||||
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;
|
||||
|
@ -1436,10 +1483,10 @@ namespace Assimp {
|
|||
return static_cast<unsigned int>(meshes.size() - 1);
|
||||
}
|
||||
|
||||
void FBXConverter::ConvertWeights(aiMesh* out, const Model& model, const MeshGeometry& geo,
|
||||
const aiMatrix4x4& node_global_transform,
|
||||
unsigned int materialIndex,
|
||||
std::vector<unsigned int>* outputVertStartIndices)
|
||||
void FBXConverter::ConvertWeights(aiMesh *out, const Model &model, const MeshGeometry &geo,
|
||||
const aiMatrix4x4 &absolute_transform,
|
||||
aiNode *parent, aiNode *root_node, unsigned int materialIndex,
|
||||
std::vector<unsigned int> *outputVertStartIndices)
|
||||
{
|
||||
ai_assert(geo.DeformerSkin());
|
||||
|
||||
|
@ -1450,41 +1497,35 @@ namespace Assimp {
|
|||
const Skin& sk = *geo.DeformerSkin();
|
||||
|
||||
std::vector<aiBone*> bones;
|
||||
bones.reserve(sk.Clusters().size());
|
||||
|
||||
const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION;
|
||||
ai_assert(no_mat_check || outputVertStartIndices);
|
||||
|
||||
try {
|
||||
|
||||
// iterate over the sub deformers
|
||||
for (const Cluster* cluster : sk.Clusters()) {
|
||||
ai_assert(cluster);
|
||||
|
||||
const WeightIndexArray& indices = cluster->GetIndices();
|
||||
|
||||
if (indices.empty() && mRemoveEmptyBones ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const MatIndexArray& mats = geo.GetMaterialIndices();
|
||||
|
||||
bool ok = false;
|
||||
|
||||
const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
|
||||
|
||||
count_out_indices.clear();
|
||||
index_out_indices.clear();
|
||||
out_indices.clear();
|
||||
|
||||
|
||||
// now check if *any* of these weights is contained in the output mesh,
|
||||
// taking notes so we don't need to do it twice.
|
||||
for (WeightIndexArray::value_type index : indices) {
|
||||
|
||||
unsigned int count = 0;
|
||||
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
|
||||
ai_assert(out_idx != NULL);
|
||||
ai_assert(out_idx != nullptr);
|
||||
|
||||
index_out_indices.push_back(no_index_sentinel);
|
||||
count_out_indices.push_back(0);
|
||||
|
@ -1510,7 +1551,6 @@ namespace Assimp {
|
|||
}
|
||||
|
||||
++count_out_indices.back();
|
||||
ok = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1518,49 +1558,74 @@ namespace Assimp {
|
|||
// if we found at least one, generate the output bones
|
||||
// XXX this could be heavily simplified by collecting the bone
|
||||
// data in a single step.
|
||||
if (ok && mRemoveEmptyBones) {
|
||||
ConvertCluster(bones, model, *cluster, out_indices, index_out_indices,
|
||||
count_out_indices, node_global_transform);
|
||||
ConvertCluster(bones, cluster, out_indices, index_out_indices,
|
||||
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>());
|
||||
throw;
|
||||
}
|
||||
|
||||
if (bones.empty()) {
|
||||
out->mBones = nullptr;
|
||||
out->mNumBones = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
out->mBones = new aiBone*[bones.size()]();
|
||||
} else {
|
||||
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,
|
||||
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)
|
||||
const aiNode* FBXConverter::GetNodeByName( const aiString& name, aiNode *current_node )
|
||||
{
|
||||
aiNode * iter = current_node;
|
||||
//printf("Child count: %d", iter->mNumChildren);
|
||||
return iter;
|
||||
}
|
||||
|
||||
aiBone* const bone = new aiBone();
|
||||
bones.push_back(bone);
|
||||
void FBXConverter::ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
|
||||
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)) {
|
||||
ASSIMP_LOG_DEBUG_F("retrieved bone from lookup ", bone_name.C_Str(), ". Deformer:", deformer_name);
|
||||
bone = bone_map[deformer_name];
|
||||
} else {
|
||||
ASSIMP_LOG_DEBUG_F("created new bone ", bone_name.C_Str(), ". Deformer: ", deformer_name);
|
||||
bone = new aiBone();
|
||||
bone->mName = bone_name;
|
||||
|
||||
// store local transform link for post processing
|
||||
bone->mOffsetMatrix = cl->TransformLink();
|
||||
bone->mOffsetMatrix.Inverse();
|
||||
|
||||
bone->mOffsetMatrix = bone->mOffsetMatrix * node_global_transform;
|
||||
aiMatrix4x4 matrix = (aiMatrix4x4)absolute_transform;
|
||||
|
||||
bone->mOffsetMatrix = bone->mOffsetMatrix * matrix; // * mesh_offset
|
||||
|
||||
|
||||
//
|
||||
// Now calculate the aiVertexWeights
|
||||
//
|
||||
|
||||
aiVertexWeight *cursor = nullptr;
|
||||
|
||||
bone->mNumWeights = static_cast<unsigned int>(out_indices.size());
|
||||
aiVertexWeight* cursor = bone->mWeights = new aiVertexWeight[out_indices.size()];
|
||||
cursor = bone->mWeights = new aiVertexWeight[out_indices.size()];
|
||||
|
||||
const size_t no_index_sentinel = std::numeric_limits<size_t>::max();
|
||||
const WeightArray& weights = cl.GetWeights();
|
||||
const WeightArray& weights = cl->GetWeights();
|
||||
|
||||
const size_t c = index_out_indices.size();
|
||||
for (size_t i = 0; i < c; ++i) {
|
||||
|
@ -1572,12 +1637,23 @@ namespace Assimp {
|
|||
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
||||
bone_map.insert(std::pair<const std::string, aiBone *>(deformer_name, bone));
|
||||
}
|
||||
|
||||
ASSIMP_LOG_DEBUG_F("bone research: Indicies size: ", out_indices.size());
|
||||
|
||||
// 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,
|
||||
|
@ -1707,7 +1783,7 @@ namespace Assimp {
|
|||
bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found)
|
||||
unsigned int index;
|
||||
|
||||
VideoMap::const_iterator it = textures_converted.find(media);
|
||||
VideoMap::const_iterator it = textures_converted.find(*media);
|
||||
if (it != textures_converted.end()) {
|
||||
index = (*it).second;
|
||||
textureReady = true;
|
||||
|
@ -1715,7 +1791,7 @@ namespace Assimp {
|
|||
else {
|
||||
if (media->ContentLength() > 0) {
|
||||
index = ConvertVideo(*media);
|
||||
textures_converted[media] = index;
|
||||
textures_converted[*media] = index;
|
||||
textureReady = true;
|
||||
}
|
||||
}
|
||||
|
@ -1998,6 +2074,28 @@ namespace Assimp {
|
|||
TrySetTextureProperties(out_mat, textures, "Maya|SpecularTexture", aiTextureType_SPECULAR, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "Maya|FalloffTexture", aiTextureType_OPACITY, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "Maya|ReflectionMapTexture", aiTextureType_REFLECTION, mesh);
|
||||
|
||||
// Maya PBR
|
||||
TrySetTextureProperties(out_mat, textures, "Maya|baseColor|file", aiTextureType_BASE_COLOR, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "Maya|normalCamera|file", aiTextureType_NORMAL_CAMERA, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "Maya|emissionColor|file", aiTextureType_EMISSION_COLOR, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "Maya|metalness|file", aiTextureType_METALNESS, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "Maya|diffuseRoughness|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
|
||||
|
||||
// Maya stingray
|
||||
TrySetTextureProperties(out_mat, textures, "Maya|TEX_color_map|file", aiTextureType_BASE_COLOR, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "Maya|TEX_normal_map|file", aiTextureType_NORMAL_CAMERA, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "Maya|TEX_emissive_map|file", aiTextureType_EMISSION_COLOR, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "Maya|TEX_metallic_map|file", aiTextureType_METALNESS, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "Maya|TEX_roughness_map|file", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "Maya|TEX_ao_map|file", aiTextureType_AMBIENT_OCCLUSION, mesh);
|
||||
|
||||
// 3DSMax PBR
|
||||
TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|base_color_map", aiTextureType_BASE_COLOR, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|bump_map", aiTextureType_NORMAL_CAMERA, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|emission_map", aiTextureType_EMISSION_COLOR, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|metalness_map", aiTextureType_METALNESS, mesh);
|
||||
TrySetTextureProperties(out_mat, textures, "3dsMax|Parameters|roughness_map", aiTextureType_DIFFUSE_ROUGHNESS, mesh);
|
||||
}
|
||||
|
||||
void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh)
|
||||
|
@ -2224,13 +2322,13 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
|||
if (media != nullptr && media->ContentLength() > 0) {
|
||||
unsigned int index;
|
||||
|
||||
VideoMap::const_iterator it = textures_converted.find(media);
|
||||
VideoMap::const_iterator it = textures_converted.find(*media);
|
||||
if (it != textures_converted.end()) {
|
||||
index = (*it).second;
|
||||
}
|
||||
else {
|
||||
index = ConvertVideo(*media);
|
||||
textures_converted[media] = index;
|
||||
textures_converted[*media] = index;
|
||||
}
|
||||
|
||||
// setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture)
|
||||
|
@ -2658,7 +2756,7 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
|||
// sanity check whether the input is ok
|
||||
static void validateAnimCurveNodes(const std::vector<const AnimationCurveNode*>& curves,
|
||||
bool strictMode) {
|
||||
const Object* target(NULL);
|
||||
const Object* target(nullptr);
|
||||
for (const AnimationCurveNode* node : curves) {
|
||||
if (!target) {
|
||||
target = node->Target();
|
||||
|
@ -2689,7 +2787,7 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
|||
#ifdef ASSIMP_BUILD_DEBUG
|
||||
validateAnimCurveNodes(curves, doc.Settings().strictMode);
|
||||
#endif
|
||||
const AnimationCurveNode* curve_node = NULL;
|
||||
const AnimationCurveNode* curve_node = nullptr;
|
||||
for (const AnimationCurveNode* node : curves) {
|
||||
ai_assert(node);
|
||||
|
||||
|
@ -2949,7 +3047,7 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
|||
TransformationCompDefaultValue(comp)
|
||||
);
|
||||
|
||||
const float epsilon = 1e-6f;
|
||||
const float epsilon = Math::getEpsilon<float>();
|
||||
return (dyn_val - static_val).SquareLength() < epsilon;
|
||||
}
|
||||
|
||||
|
@ -3514,7 +3612,9 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
|||
return;
|
||||
}
|
||||
|
||||
out->mMetaData = aiMetadata::Alloc(15);
|
||||
const bool hasGenerator = !doc.Creator().empty();
|
||||
|
||||
out->mMetaData = aiMetadata::Alloc(16 + (hasGenerator ? 1 : 0));
|
||||
out->mMetaData->Set(0, "UpAxis", doc.GlobalSettings().UpAxis());
|
||||
out->mMetaData->Set(1, "UpAxisSign", doc.GlobalSettings().UpAxisSign());
|
||||
out->mMetaData->Set(2, "FrontAxis", doc.GlobalSettings().FrontAxis());
|
||||
|
@ -3530,45 +3630,10 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
|||
out->mMetaData->Set(12, "TimeSpanStart", doc.GlobalSettings().TimeSpanStart());
|
||||
out->mMetaData->Set(13, "TimeSpanStop", doc.GlobalSettings().TimeSpanStop());
|
||||
out->mMetaData->Set(14, "CustomFrameRate", doc.GlobalSettings().CustomFrameRate());
|
||||
}
|
||||
|
||||
void FBXConverter::ConvertToUnitScale( FbxUnit unit ) {
|
||||
if (mCurrentUnit == unit) {
|
||||
return;
|
||||
}
|
||||
|
||||
ai_real scale = 1.0;
|
||||
if (mCurrentUnit == FbxUnit::cm) {
|
||||
if (unit == FbxUnit::m) {
|
||||
scale = (ai_real)0.01;
|
||||
} else if (unit == FbxUnit::km) {
|
||||
scale = (ai_real)0.00001;
|
||||
}
|
||||
} else if (mCurrentUnit == FbxUnit::m) {
|
||||
if (unit == FbxUnit::cm) {
|
||||
scale = (ai_real)100.0;
|
||||
} else if (unit == FbxUnit::km) {
|
||||
scale = (ai_real)0.001;
|
||||
}
|
||||
} else if (mCurrentUnit == FbxUnit::km) {
|
||||
if (unit == FbxUnit::cm) {
|
||||
scale = (ai_real)100000.0;
|
||||
} else if (unit == FbxUnit::m) {
|
||||
scale = (ai_real)1000.0;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto mesh : meshes) {
|
||||
if (nullptr == mesh) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (mesh->HasPositions()) {
|
||||
for (unsigned int i = 0; i < mesh->mNumVertices; ++i) {
|
||||
aiVector3D &pos = mesh->mVertices[i];
|
||||
pos *= scale;
|
||||
}
|
||||
}
|
||||
out->mMetaData->Set(15, AI_METADATA_SOURCE_FORMAT_VERSION, aiString(to_string(doc.FBXVersion())));
|
||||
if (hasGenerator)
|
||||
{
|
||||
out->mMetaData->Set(16, AI_METADATA_SOURCE_GENERATOR, aiString(doc.Creator()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3577,7 +3642,7 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
|||
ai_assert(!out->mMeshes);
|
||||
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
|
||||
// confusion why this code works.
|
||||
|
||||
|
@ -3624,10 +3689,51 @@ void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTa
|
|||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit)
|
||||
void FBXConverter::ConvertOrphantEmbeddedTextures()
|
||||
{
|
||||
FBXConverter converter(out, doc, removeEmptyBones, unit);
|
||||
// in C++14 it could be:
|
||||
// for (auto&& [id, object] : objects)
|
||||
for (auto&& id_and_object : doc.Objects())
|
||||
{
|
||||
auto&& id = std::get<0>(id_and_object);
|
||||
auto&& object = std::get<1>(id_and_object);
|
||||
// If an object doesn't have parent
|
||||
if (doc.ConnectionsBySource().count(id) == 0)
|
||||
{
|
||||
const Texture* realTexture = nullptr;
|
||||
try
|
||||
{
|
||||
const auto& element = object->GetElement();
|
||||
const Token& key = element.KeyToken();
|
||||
const char* obtype = key.begin();
|
||||
const size_t length = static_cast<size_t>(key.end() - key.begin());
|
||||
if (strncmp(obtype, "Texture", length) == 0)
|
||||
{
|
||||
const Texture* texture = static_cast<const Texture*>(object->Get());
|
||||
if (texture->Media() && texture->Media()->ContentLength() > 0)
|
||||
{
|
||||
realTexture = texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
if (realTexture)
|
||||
{
|
||||
const Video* media = realTexture->Media();
|
||||
unsigned int index = ConvertVideo(*media);
|
||||
textures_converted[*media] = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones)
|
||||
{
|
||||
FBXConverter converter(out, doc, removeEmptyBones);
|
||||
}
|
||||
|
||||
} // !FBX
|
||||
|
|
|
@ -76,23 +76,13 @@ namespace Assimp {
|
|||
namespace FBX {
|
||||
|
||||
class Document;
|
||||
|
||||
enum class FbxUnit {
|
||||
cm = 0,
|
||||
m,
|
||||
km,
|
||||
NumUnits,
|
||||
|
||||
Undefined
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a FBX #Document to #aiScene
|
||||
* @param out Empty scene to be populated
|
||||
* @param doc Parsed FBX document
|
||||
* @param removeEmptyBones Will remove bones, which do not have any references to vertices.
|
||||
*/
|
||||
void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit);
|
||||
void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones);
|
||||
|
||||
/** Dummy class to encapsulate the conversion process */
|
||||
class FBXConverter {
|
||||
|
@ -123,7 +113,7 @@ public:
|
|||
};
|
||||
|
||||
public:
|
||||
FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones, FbxUnit unit);
|
||||
FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones);
|
||||
~FBXConverter();
|
||||
|
||||
private:
|
||||
|
@ -133,7 +123,7 @@ private:
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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 );
|
||||
|
@ -189,32 +179,35 @@ private:
|
|||
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
|
||||
std::vector<unsigned int> ConvertMesh(const MeshGeometry& mesh, const Model& model,
|
||||
const aiMatrix4x4& node_global_transform, aiNode& nd);
|
||||
std::vector<unsigned int>
|
||||
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,
|
||||
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,
|
||||
const aiMatrix4x4& node_global_transform, aiNode& nd);
|
||||
unsigned int ConvertMeshSingleMaterial(const MeshGeometry &mesh, const Model &model,
|
||||
const aiMatrix4x4 &absolute_transform, aiNode *parent,
|
||||
aiNode *root_node);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
std::vector<unsigned int> ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model,
|
||||
const aiMatrix4x4& node_global_transform, aiNode& nd);
|
||||
std::vector<unsigned int>
|
||||
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,
|
||||
MatIndexArray::value_type index,
|
||||
const aiMatrix4x4& node_global_transform, aiNode& nd);
|
||||
unsigned int ConvertMeshMultiMaterial(const MeshGeometry &mesh, const Model &model, MatIndexArray::value_type index,
|
||||
aiNode *parent, aiNode *root_node, const aiMatrix4x4 &absolute_transform);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
static const unsigned int NO_MATERIAL_SEPARATION = /* std::numeric_limits<unsigned int>::max() */
|
||||
|
@ -227,17 +220,17 @@ private:
|
|||
* - outputVertStartIndices is only used when a material index is specified, it gives for
|
||||
* each output vertex the DOM index it maps to.
|
||||
*/
|
||||
void ConvertWeights(aiMesh* out, const Model& model, const MeshGeometry& geo,
|
||||
const aiMatrix4x4& node_global_transform = aiMatrix4x4(),
|
||||
void ConvertWeights(aiMesh *out, const Model &model, const MeshGeometry &geo, const aiMatrix4x4 &absolute_transform,
|
||||
aiNode *parent = NULL, aiNode *root_node = NULL,
|
||||
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,
|
||||
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);
|
||||
void ConvertCluster(std::vector<aiBone *> &local_mesh_bones, const Cluster *cl,
|
||||
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);
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
void ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo,
|
||||
|
@ -428,16 +421,18 @@ private:
|
|||
double& minTime,
|
||||
Model::RotOrder order);
|
||||
|
||||
void ConvertGlobalSettings();
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Will perform the conversion from a given unit to the requested unit.
|
||||
void ConvertToUnitScale(FbxUnit unit);
|
||||
// Copy global geometric data and some information about the source asset into scene metadata.
|
||||
void ConvertGlobalSettings();
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// copy generated meshes, animations, lights, cameras and textures to the output scene
|
||||
void TransferDataToScene();
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// FBX file could have embedded textures not connected to anything
|
||||
void ConvertOrphantEmbeddedTextures();
|
||||
|
||||
private:
|
||||
// 0: not assigned yet, others: index is value - 1
|
||||
unsigned int defaultMaterialIndex;
|
||||
|
@ -449,31 +444,47 @@ private:
|
|||
std::vector<aiCamera*> cameras;
|
||||
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;
|
||||
|
||||
using VideoMap = std::map<const Video*, unsigned int>;
|
||||
using VideoMap = std::fbx_unordered_map<const Video, unsigned int>;
|
||||
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;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
aiScene* const out;
|
||||
const FBX::Document& doc;
|
||||
|
||||
bool mRemoveEmptyBones;
|
||||
static void BuildBoneList(aiNode *current_node, const aiNode *root_node, const aiScene *scene,
|
||||
std::vector<aiBone*>& bones);
|
||||
|
||||
FbxUnit mCurrentUnit;
|
||||
void BuildBoneStack(aiNode *current_node, const aiNode *root_node, const aiScene *scene,
|
||||
const std::vector<aiBone *> &bones,
|
||||
std::map<aiBone *, aiNode *> &bone_stack,
|
||||
std::vector<aiNode*> &node_stack );
|
||||
|
||||
static void BuildNodeList(aiNode *current_node, std::vector<aiNode *> &nodes);
|
||||
|
||||
static aiNode *GetNodeFromStack(const aiString &node_name, std::vector<aiNode *> &nodes);
|
||||
|
||||
static aiNode *GetArmatureRoot(aiNode *bone_node, std::vector<aiBone*> &bone_list);
|
||||
|
||||
static bool IsBoneNode(const aiString &bone_name, std::vector<aiBone *> &bones);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -90,14 +90,6 @@ const Object* LazyObject::Get(bool dieOnError)
|
|||
return object.get();
|
||||
}
|
||||
|
||||
// if this is the root object, we return a dummy since there
|
||||
// is no root object int he fbx file - it is just referenced
|
||||
// with id 0.
|
||||
if(id == 0L) {
|
||||
object.reset(new Object(id, element, "Model::RootNode"));
|
||||
return object.get();
|
||||
}
|
||||
|
||||
const Token& key = element.KeyToken();
|
||||
const TokenList& tokens = element.Tokens();
|
||||
|
||||
|
|
|
@ -637,6 +637,20 @@ public:
|
|||
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:
|
||||
std::string type;
|
||||
std::string relativeFileName;
|
||||
|
@ -1005,10 +1019,10 @@ public:
|
|||
// during their entire lifetime (Document). FBX files have
|
||||
// up to many thousands of objects (most of which we never use),
|
||||
// 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::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
|
||||
* be accessed via Document.Globals(). */
|
||||
|
@ -1177,4 +1191,25 @@ private:
|
|||
} // Namespace FBX
|
||||
} // 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
|
||||
|
|
|
@ -325,9 +325,9 @@ void FBX::Node::BeginBinary(Assimp::StreamWriterLE &s)
|
|||
this->start_pos = s.Tell();
|
||||
|
||||
// placeholders for end pos and property section info
|
||||
s.PutU4(0); // end pos
|
||||
s.PutU4(0); // number of properties
|
||||
s.PutU4(0); // total property section length
|
||||
s.PutU8(0); // end pos
|
||||
s.PutU8(0); // number of properties
|
||||
s.PutU8(0); // total property section length
|
||||
|
||||
// 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();
|
||||
ai_assert(pos > property_start);
|
||||
size_t property_section_size = pos - property_start;
|
||||
s.Seek(start_pos + 4);
|
||||
s.PutU4(uint32_t(num_properties));
|
||||
s.PutU4(uint32_t(property_section_size));
|
||||
s.Seek(start_pos + 8); // 8 bytes of uint64_t of end_pos
|
||||
s.PutU8(num_properties);
|
||||
s.PutU8(property_section_size);
|
||||
s.Seek(pos);
|
||||
}
|
||||
|
||||
|
@ -375,7 +375,7 @@ void FBX::Node::EndBinary(
|
|||
// now go back and write initial pos
|
||||
this->end_pos = s.Tell();
|
||||
s.Seek(start_pos);
|
||||
s.PutU4(uint32_t(end_pos));
|
||||
s.PutU8(end_pos);
|
||||
s.Seek(end_pos);
|
||||
}
|
||||
|
||||
|
|
|
@ -59,11 +59,7 @@ namespace FBX {
|
|||
|
||||
FBXExportProperty::FBXExportProperty(bool v)
|
||||
: type('C')
|
||||
, data(1) {
|
||||
data = {
|
||||
uint8_t(v)
|
||||
};
|
||||
}
|
||||
, data(1, uint8_t(v)) {}
|
||||
|
||||
FBXExportProperty::FBXExportProperty(int16_t v)
|
||||
: type('Y')
|
||||
|
|
|
@ -67,6 +67,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <vector>
|
||||
#include <array>
|
||||
#include <unordered_set>
|
||||
#include <numeric>
|
||||
|
||||
// RESOURCES:
|
||||
// https://code.blender.org/2013/08/fbx-binary-file-format-specification/
|
||||
|
@ -80,8 +81,8 @@ using namespace Assimp::FBX;
|
|||
// some constants that we'll use for writing metadata
|
||||
namespace Assimp {
|
||||
namespace FBX {
|
||||
const std::string EXPORT_VERSION_STR = "7.4.0";
|
||||
const uint32_t EXPORT_VERSION_INT = 7400; // 7.4 == 2014/2015
|
||||
const std::string EXPORT_VERSION_STR = "7.5.0";
|
||||
const uint32_t EXPORT_VERSION_INT = 7500; // 7.5 == 2016+
|
||||
// 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.
|
||||
// what we can do is set them to a known-working version.
|
||||
|
@ -1005,6 +1006,9 @@ void FBXExporter::WriteObjects ()
|
|||
object_node.EndProperties(outstream, binary, indent);
|
||||
object_node.BeginChildren(outstream, binary, indent);
|
||||
|
||||
bool bJoinIdenticalVertices = mProperties->GetPropertyBool("bJoinIdenticalVertices", true);
|
||||
std::vector<std::vector<int32_t>> vVertexIndice;//save vertex_indices as it is needed later
|
||||
|
||||
// geometry (aiMesh)
|
||||
mesh_uids.clear();
|
||||
indent = 1;
|
||||
|
@ -1031,6 +1035,7 @@ void FBXExporter::WriteObjects ()
|
|||
std::vector<int32_t> vertex_indices;
|
||||
// map of vertex value to its index in the data vector
|
||||
std::map<aiVector3D,size_t> index_by_vertex_value;
|
||||
if(bJoinIdenticalVertices){
|
||||
int32_t index = 0;
|
||||
for (size_t vi = 0; vi < m->mNumVertices; ++vi) {
|
||||
aiVector3D vtx = m->mVertices[vi];
|
||||
|
@ -1046,6 +1051,19 @@ void FBXExporter::WriteObjects ()
|
|||
vertex_indices.push_back(int32_t(elem->second));
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // do not join vertex, respect the export flag
|
||||
vertex_indices.resize(m->mNumVertices);
|
||||
std::iota(vertex_indices.begin(), vertex_indices.end(), 0);
|
||||
for(unsigned int v = 0; v < m->mNumVertices; ++ v) {
|
||||
aiVector3D vtx = m->mVertices[v];
|
||||
flattened_vertices.push_back(vtx.x);
|
||||
flattened_vertices.push_back(vtx.y);
|
||||
flattened_vertices.push_back(vtx.z);
|
||||
}
|
||||
}
|
||||
vVertexIndice.push_back(vertex_indices);
|
||||
|
||||
FBX::Node::WritePropertyNode(
|
||||
"Vertices", flattened_vertices, outstream, binary, indent
|
||||
);
|
||||
|
@ -1116,6 +1134,51 @@ void FBXExporter::WriteObjects ()
|
|||
normals.End(outstream, binary, indent, true);
|
||||
}
|
||||
|
||||
// colors, if any
|
||||
// TODO only one color channel currently
|
||||
const int32_t colorChannelIndex = 0;
|
||||
if (m->HasVertexColors(colorChannelIndex)) {
|
||||
FBX::Node vertexcolors("LayerElementColor", int32_t(colorChannelIndex));
|
||||
vertexcolors.Begin(outstream, binary, indent);
|
||||
vertexcolors.DumpProperties(outstream, binary, indent);
|
||||
vertexcolors.EndProperties(outstream, binary, indent);
|
||||
vertexcolors.BeginChildren(outstream, binary, indent);
|
||||
indent = 3;
|
||||
FBX::Node::WritePropertyNode(
|
||||
"Version", int32_t(101), outstream, binary, indent
|
||||
);
|
||||
char layerName[8];
|
||||
sprintf(layerName, "COLOR_%d", colorChannelIndex);
|
||||
FBX::Node::WritePropertyNode(
|
||||
"Name", (const char*)layerName, outstream, binary, indent
|
||||
);
|
||||
FBX::Node::WritePropertyNode(
|
||||
"MappingInformationType", "ByPolygonVertex",
|
||||
outstream, binary, indent
|
||||
);
|
||||
FBX::Node::WritePropertyNode(
|
||||
"ReferenceInformationType", "Direct",
|
||||
outstream, binary, indent
|
||||
);
|
||||
std::vector<double> color_data;
|
||||
color_data.reserve(4 * polygon_data.size());
|
||||
for (size_t fi = 0; fi < m->mNumFaces; ++fi) {
|
||||
const aiFace &f = m->mFaces[fi];
|
||||
for (size_t pvi = 0; pvi < f.mNumIndices; ++pvi) {
|
||||
const aiColor4D &c = m->mColors[colorChannelIndex][f.mIndices[pvi]];
|
||||
color_data.push_back(c.r);
|
||||
color_data.push_back(c.g);
|
||||
color_data.push_back(c.b);
|
||||
color_data.push_back(c.a);
|
||||
}
|
||||
}
|
||||
FBX::Node::WritePropertyNode(
|
||||
"Colors", color_data, outstream, binary, indent
|
||||
);
|
||||
indent = 2;
|
||||
vertexcolors.End(outstream, binary, indent, true);
|
||||
}
|
||||
|
||||
// uvs, if any
|
||||
for (size_t uvi = 0; uvi < m->GetNumUVChannels(); ++uvi) {
|
||||
if (m->mNumUVComponents[uvi] > 2) {
|
||||
|
@ -1209,6 +1272,11 @@ void FBXExporter::WriteObjects ()
|
|||
le.AddChild("Type", "LayerElementNormal");
|
||||
le.AddChild("TypedIndex", int32_t(0));
|
||||
layer.AddChild(le);
|
||||
// TODO only 1 color channel currently
|
||||
le = FBX::Node("LayerElement");
|
||||
le.AddChild("Type", "LayerElementColor");
|
||||
le.AddChild("TypedIndex", int32_t(0));
|
||||
layer.AddChild(le);
|
||||
le = FBX::Node("LayerElement");
|
||||
le.AddChild("Type", "LayerElementMaterial");
|
||||
le.AddChild("TypedIndex", int32_t(0));
|
||||
|
@ -1219,6 +1287,16 @@ void FBXExporter::WriteObjects ()
|
|||
layer.AddChild(le);
|
||||
layer.Dump(outstream, binary, indent);
|
||||
|
||||
for(unsigned int lr = 1; lr < m->GetNumUVChannels(); ++ lr)
|
||||
{
|
||||
FBX::Node layerExtra("Layer", int32_t(lr));
|
||||
layerExtra.AddChild("Version", int32_t(100));
|
||||
FBX::Node leExtra("LayerElement");
|
||||
leExtra.AddChild("Type", "LayerElementUV");
|
||||
leExtra.AddChild("TypedIndex", int32_t(lr));
|
||||
layerExtra.AddChild(leExtra);
|
||||
layerExtra.Dump(outstream, binary, indent);
|
||||
}
|
||||
// finish the node record
|
||||
indent = 1;
|
||||
n.End(outstream, binary, indent, true);
|
||||
|
@ -1617,6 +1695,17 @@ void FBXExporter::WriteObjects ()
|
|||
// at the same time we can build a list of all the skeleton nodes,
|
||||
// which will be used later to mark them as type "limbNode".
|
||||
std::unordered_set<const aiNode*> limbnodes;
|
||||
|
||||
//actual bone nodes in fbx, without parenting-up
|
||||
std::unordered_set<std::string> setAllBoneNamesInScene;
|
||||
for(unsigned int m = 0; m < mScene->mNumMeshes; ++ m)
|
||||
{
|
||||
aiMesh* pMesh = mScene->mMeshes[m];
|
||||
for(unsigned int b = 0; b < pMesh->mNumBones; ++ b)
|
||||
setAllBoneNamesInScene.insert(pMesh->mBones[b]->mName.data);
|
||||
}
|
||||
aiMatrix4x4 mxTransIdentity;
|
||||
|
||||
// and a map of nodes by bone name, as finding them is annoying.
|
||||
std::map<std::string,aiNode*> node_by_bone;
|
||||
for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) {
|
||||
|
@ -1660,6 +1749,11 @@ void FBXExporter::WriteObjects ()
|
|||
if (node_name.find(MAGIC_NODE_TAG) != std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
//not a bone in scene && no effect in transform
|
||||
if(setAllBoneNamesInScene.find(node_name)==setAllBoneNamesInScene.end()
|
||||
&& parent->mTransformation == mxTransIdentity) {
|
||||
continue;
|
||||
}
|
||||
// otherwise check if this is the root of the skeleton
|
||||
bool end = false;
|
||||
// is the mesh part of this node?
|
||||
|
@ -1680,8 +1774,7 @@ void FBXExporter::WriteObjects ()
|
|||
}
|
||||
if (end) { break; }
|
||||
}
|
||||
limbnodes.insert(parent);
|
||||
skeleton.insert(parent);
|
||||
|
||||
// if it was the skeleton root we can finish here
|
||||
if (end) { break; }
|
||||
}
|
||||
|
@ -1723,28 +1816,8 @@ void FBXExporter::WriteObjects ()
|
|||
// connect it
|
||||
connections.emplace_back("C", "OO", deformer_uid, mesh_uids[mi]);
|
||||
|
||||
// we will be indexing by vertex...
|
||||
// but there might be a different number of "vertices"
|
||||
// between assimp and our output FBX.
|
||||
// this code is cut-and-pasted from the geometry section above...
|
||||
// ideally this should not be so.
|
||||
// ---
|
||||
// index of original vertex in vertex data vector
|
||||
std::vector<int32_t> vertex_indices;
|
||||
// map of vertex value to its index in the data vector
|
||||
std::map<aiVector3D,size_t> index_by_vertex_value;
|
||||
int32_t index = 0;
|
||||
for (size_t vi = 0; vi < m->mNumVertices; ++vi) {
|
||||
aiVector3D vtx = m->mVertices[vi];
|
||||
auto elem = index_by_vertex_value.find(vtx);
|
||||
if (elem == index_by_vertex_value.end()) {
|
||||
vertex_indices.push_back(index);
|
||||
index_by_vertex_value[vtx] = index;
|
||||
++index;
|
||||
} else {
|
||||
vertex_indices.push_back(int32_t(elem->second));
|
||||
}
|
||||
}
|
||||
//computed before
|
||||
std::vector<int32_t>& vertex_indices = vVertexIndice[mi];
|
||||
|
||||
// TODO, FIXME: this won't work if anything is not in the bind pose.
|
||||
// for now if such a situation is detected, we throw an exception.
|
||||
|
@ -1787,6 +1860,7 @@ void FBXExporter::WriteObjects ()
|
|||
sdnode.AddChild("Version", int32_t(100));
|
||||
sdnode.AddChild("UserData", "", "");
|
||||
|
||||
std::set<int32_t> setWeightedVertex;
|
||||
// add indices and weights, if any
|
||||
if (b) {
|
||||
std::vector<int32_t> subdef_indices;
|
||||
|
@ -1794,7 +1868,8 @@ void FBXExporter::WriteObjects ()
|
|||
int32_t last_index = -1;
|
||||
for (size_t wi = 0; wi < b->mNumWeights; ++wi) {
|
||||
int32_t vi = vertex_indices[b->mWeights[wi].mVertexId];
|
||||
if (vi == last_index) {
|
||||
bool bIsWeightedAlready = (setWeightedVertex.find(vi) != setWeightedVertex.end());
|
||||
if (vi == last_index || bIsWeightedAlready) {
|
||||
// only for vertices we exported to fbx
|
||||
// TODO, FIXME: this assumes identically-located vertices
|
||||
// will always deform in the same way.
|
||||
|
@ -1804,6 +1879,7 @@ void FBXExporter::WriteObjects ()
|
|||
// identical vertex.
|
||||
continue;
|
||||
}
|
||||
setWeightedVertex.insert(vi);
|
||||
subdef_indices.push_back(vi);
|
||||
subdef_weights.push_back(b->mWeights[wi].mWeight);
|
||||
last_index = vi;
|
||||
|
@ -1822,41 +1898,10 @@ void FBXExporter::WriteObjects ()
|
|||
inverse_bone_xform.Inverse();
|
||||
aiMatrix4x4 tr = inverse_bone_xform * mesh_xform;
|
||||
|
||||
// this should be the same as the bone's mOffsetMatrix.
|
||||
// if it's not the same, the skeleton isn't in the bind pose.
|
||||
const float epsilon = 1e-4f; // some error is to be expected
|
||||
bool bone_xform_okay = true;
|
||||
if (b && ! tr.Equal(b->mOffsetMatrix, epsilon)) {
|
||||
not_in_bind_pose.insert(b);
|
||||
bone_xform_okay = false;
|
||||
}
|
||||
|
||||
// if we have a bone we should use the mOffsetMatrix,
|
||||
// otherwise try to just use the calculated transform.
|
||||
if (b) {
|
||||
sdnode.AddChild("Transform", b->mOffsetMatrix);
|
||||
} else {
|
||||
sdnode.AddChild("Transform", tr);
|
||||
}
|
||||
// note: it doesn't matter if we mix these,
|
||||
// because if they disagree we'll throw an exception later.
|
||||
// it could be that the skeleton is not in the bone pose
|
||||
// but all bones are still defined,
|
||||
// in which case this would use the mOffsetMatrix for everything
|
||||
// and a correct skeleton would still be output.
|
||||
|
||||
// transformlink should be the position of the bone in world space.
|
||||
// if the bone is in the bind pose (or nonexistent),
|
||||
// we can just use the matrix we already calculated
|
||||
if (bone_xform_okay) {
|
||||
|
||||
sdnode.AddChild("TransformLink", bone_xform);
|
||||
// otherwise we can only work it out using the mesh position.
|
||||
} else {
|
||||
aiMatrix4x4 trl = b->mOffsetMatrix;
|
||||
trl.Inverse();
|
||||
trl *= mesh_xform;
|
||||
sdnode.AddChild("TransformLink", trl);
|
||||
}
|
||||
// note: this means we ALWAYS rely on the mesh node transform
|
||||
// being unchanged from the time the skeleton was bound.
|
||||
// there's not really any way around this at the moment.
|
||||
|
@ -2441,7 +2486,7 @@ void FBXExporter::WriteModelNodes(
|
|||
void FBXExporter::WriteAnimationCurveNode(
|
||||
StreamWriterLE& outstream,
|
||||
int64_t uid,
|
||||
std::string name, // "T", "R", or "S"
|
||||
const std::string& name, // "T", "R", or "S"
|
||||
aiVector3D default_value,
|
||||
std::string property_name, // "Lcl Translation" etc
|
||||
int64_t layer_uid,
|
||||
|
|
|
@ -156,7 +156,7 @@ namespace Assimp
|
|||
void WriteAnimationCurveNode(
|
||||
StreamWriterLE& outstream,
|
||||
int64_t uid,
|
||||
std::string name, // "T", "R", or "S"
|
||||
const std::string& name, // "T", "R", or "S"
|
||||
aiVector3D default_value,
|
||||
std::string property_name, // "Lcl Translation" etc
|
||||
int64_t animation_layer_uid,
|
||||
|
|
|
@ -48,26 +48,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
#include "FBXImporter.h"
|
||||
|
||||
#include "FBXTokenizer.h"
|
||||
#include "FBXParser.h"
|
||||
#include "FBXUtil.h"
|
||||
#include "FBXDocument.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/Importer.hpp>
|
||||
#include <assimp/StreamReader.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
template<>
|
||||
const char* LogFunctions<FBXImporter>::Prefix() {
|
||||
template <>
|
||||
const char *LogFunctions<FBXImporter>::Prefix() {
|
||||
static auto prefix = "FBX: ";
|
||||
return prefix;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Assimp
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace Assimp::Formatter;
|
||||
|
@ -91,44 +91,39 @@ static const aiImporterDesc desc = {
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by #Importer
|
||||
FBXImporter::FBXImporter()
|
||||
{
|
||||
FBXImporter::FBXImporter() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
FBXImporter::~FBXImporter()
|
||||
{
|
||||
FBXImporter::~FBXImporter() {
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the class can handle the format of the given file.
|
||||
bool FBXImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
||||
{
|
||||
const std::string& extension = GetExtension(pFile);
|
||||
if (extension == std::string( desc.mFileExtensions ) ) {
|
||||
bool FBXImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const {
|
||||
const std::string &extension = GetExtension(pFile);
|
||||
if (extension == std::string(desc.mFileExtensions)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
else if ((!extension.length() || checkSig) && pIOHandler) {
|
||||
// at least ASCII-FBX files usually have a 'FBX' somewhere in their head
|
||||
const char* tokens[] = {"fbx"};
|
||||
return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1);
|
||||
const char *tokens[] = { "fbx" };
|
||||
return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// List all extensions handled by this loader
|
||||
const aiImporterDesc* FBXImporter::GetInfo () const
|
||||
{
|
||||
const aiImporterDesc *FBXImporter::GetInfo() const {
|
||||
return &desc;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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.readAllMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_ALL_MATERIALS, false);
|
||||
settings.readMaterials = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_READ_MATERIALS, true);
|
||||
|
@ -146,9 +141,8 @@ void FBXImporter::SetupProperties(const Importer* pImp)
|
|||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Imports the given file into the given scene structure.
|
||||
void FBXImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler)
|
||||
{
|
||||
std::unique_ptr<IOStream> stream(pIOHandler->Open(pFile,"rb"));
|
||||
void FBXImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
|
||||
std::unique_ptr<IOStream> stream(pIOHandler->Open(pFile, "rb"));
|
||||
if (!stream) {
|
||||
ThrowException("Could not open file for reading");
|
||||
}
|
||||
|
@ -159,10 +153,10 @@ void FBXImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
|
|||
// streaming for its output data structures so the net win with
|
||||
// streaming input data would be very low.
|
||||
std::vector<char> contents;
|
||||
contents.resize(stream->FileSize()+1);
|
||||
stream->Read( &*contents.begin(), 1, contents.size()-1 );
|
||||
contents[ contents.size() - 1 ] = 0;
|
||||
const char* const begin = &*contents.begin();
|
||||
contents.resize(stream->FileSize() + 1);
|
||||
stream->Read(&*contents.begin(), 1, contents.size() - 1);
|
||||
contents[contents.size() - 1] = 0;
|
||||
const char *const begin = &*contents.begin();
|
||||
|
||||
// broadphase tokenizing pass in which we identify the core
|
||||
// syntax elements of FBX (brackets, commas, key:value mappings)
|
||||
|
@ -170,12 +164,11 @@ void FBXImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
|
|||
try {
|
||||
|
||||
bool is_binary = false;
|
||||
if (!strncmp(begin,"Kaydara FBX Binary",18)) {
|
||||
if (!strncmp(begin, "Kaydara FBX Binary", 18)) {
|
||||
is_binary = true;
|
||||
TokenizeBinary(tokens,begin,contents.size());
|
||||
}
|
||||
else {
|
||||
Tokenize(tokens,begin);
|
||||
TokenizeBinary(tokens, begin, contents.size());
|
||||
} else {
|
||||
Tokenize(tokens, begin);
|
||||
}
|
||||
|
||||
// use this information to construct a very rudimentary
|
||||
|
@ -183,19 +176,21 @@ void FBXImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
|
|||
Parser parser(tokens, is_binary);
|
||||
|
||||
// take the raw parse-tree and convert it to a FBX DOM
|
||||
Document doc(parser,settings);
|
||||
Document doc(parser, settings);
|
||||
|
||||
FbxUnit unit(FbxUnit::cm);
|
||||
if (settings.convertToMeters) {
|
||||
unit = FbxUnit::m;
|
||||
}
|
||||
// convert the FBX DOM to aiScene
|
||||
ConvertToAssimpScene(pScene,doc, settings.removeEmptyBones, unit);
|
||||
ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones);
|
||||
|
||||
std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
|
||||
}
|
||||
catch(std::exception&) {
|
||||
std::for_each(tokens.begin(),tokens.end(),Util::delete_fun<Token>());
|
||||
// size relative to cm
|
||||
float size_relative_to_cm = doc.GlobalSettings().UnitScaleFactor();
|
||||
|
||||
// Set FBX file scale is relative to CM must be converted to M for
|
||||
// assimp universal format (M)
|
||||
SetFileScale(size_relative_to_cm * 0.01f);
|
||||
|
||||
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
|
||||
} catch (std::exception &) {
|
||||
std::for_each(tokens.begin(), tokens.end(), Util::delete_fun<Token>());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,7 +115,6 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
|
|||
|
||||
if(tempVerts.empty()) {
|
||||
FBXImporter::LogWarn("encountered mesh with no vertices");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<int> tempFaces;
|
||||
|
@ -123,7 +122,6 @@ MeshGeometry::MeshGeometry(uint64_t id, const Element& element, const std::strin
|
|||
|
||||
if(tempFaces.empty()) {
|
||||
FBXImporter::LogWarn("encountered mesh with no faces");
|
||||
return;
|
||||
}
|
||||
|
||||
m_vertices.reserve(tempFaces.size());
|
||||
|
@ -612,7 +610,10 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, cons
|
|||
const std::string& ReferenceInformationType)
|
||||
{
|
||||
const size_t face_count = m_faces.size();
|
||||
ai_assert(face_count);
|
||||
if( 0 == face_count )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// materials are handled separately. First of all, they are assigned per-face
|
||||
// and not per polyvert. Secondly, ReferenceInformationType=IndexToDirect
|
||||
|
@ -624,16 +625,14 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, cons
|
|||
if (materials_out.empty()) {
|
||||
FBXImporter::LogError(Formatter::format("expected material index, ignoring"));
|
||||
return;
|
||||
}
|
||||
else if (materials_out.size() > 1) {
|
||||
} else if (materials_out.size() > 1) {
|
||||
FBXImporter::LogWarn(Formatter::format("expected only a single material index, ignoring all except the first one"));
|
||||
materials_out.clear();
|
||||
}
|
||||
|
||||
materials_out.resize(m_vertices.size());
|
||||
std::fill(materials_out.begin(), materials_out.end(), materials_out.at(0));
|
||||
}
|
||||
else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") {
|
||||
} else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") {
|
||||
materials_out.resize(face_count);
|
||||
|
||||
if(materials_out.size() != face_count) {
|
||||
|
@ -642,18 +641,16 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector<int>& materials_out, cons
|
|||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
FBXImporter::LogError(Formatter::format("ignoring material assignments, access type not implemented: ")
|
||||
<< MappingInformationType << "," << ReferenceInformationType);
|
||||
}
|
||||
}
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
ShapeGeometry::ShapeGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc)
|
||||
: Geometry(id, element, name, doc)
|
||||
{
|
||||
const Scope* sc = element.Compound();
|
||||
if (!sc) {
|
||||
: Geometry(id, element, name, doc) {
|
||||
const Scope *sc = element.Compound();
|
||||
if (nullptr == sc) {
|
||||
DOMError("failed to read Geometry object (class: Shape), no data scope found");
|
||||
}
|
||||
const Element& Indexes = GetRequiredElement(*sc, "Indexes", &element);
|
||||
|
|
|
@ -311,10 +311,9 @@ class TrimmedCurve : public BoundedCurve {
|
|||
public:
|
||||
// --------------------------------------------------
|
||||
TrimmedCurve(const Schema_2x3::IfcTrimmedCurve& entity, ConversionData& conv)
|
||||
: BoundedCurve(entity,conv)
|
||||
: BoundedCurve(entity,conv),
|
||||
base(std::shared_ptr<const Curve>(Curve::Convert(entity.BasisCurve,conv)))
|
||||
{
|
||||
base = std::shared_ptr<const Curve>(Curve::Convert(entity.BasisCurve,conv));
|
||||
|
||||
typedef std::shared_ptr<const STEP::EXPRESS::DataType> Entry;
|
||||
|
||||
// for some reason, trimmed curves can either specify a parametric value
|
||||
|
@ -500,7 +499,7 @@ bool Curve::InRange(IfcFloat u) const {
|
|||
if (IsClosed()) {
|
||||
return true;
|
||||
}
|
||||
const IfcFloat epsilon = 1e-5;
|
||||
const IfcFloat epsilon = Math::getEpsilon<float>();
|
||||
return u - range.first > -epsilon && range.second - u > -epsilon;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -128,7 +128,7 @@ void ProcessPolygonBoundaries(TempMesh& result, const TempMesh& inmesh, size_t m
|
|||
outer_polygon_it = begin + master_bounds;
|
||||
}
|
||||
else {
|
||||
for(iit = begin; iit != end; iit++) {
|
||||
for(iit = begin; iit != end; ++iit) {
|
||||
// find the polygon with the largest area and take it as the outer bound.
|
||||
IfcVector3& n = normals[std::distance(begin,iit)];
|
||||
const IfcFloat area = n.SquareLength();
|
||||
|
@ -138,8 +138,9 @@ void ProcessPolygonBoundaries(TempMesh& result, const TempMesh& inmesh, size_t m
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
ai_assert(outer_polygon_it != end);
|
||||
if (outer_polygon_it == end) {
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t outer_polygon_size = *outer_polygon_it;
|
||||
const IfcVector3& master_normal = normals[std::distance(begin, outer_polygon_it)];
|
||||
|
|
|
@ -593,7 +593,7 @@ typedef std::vector<std::pair<
|
|||
bool BoundingBoxesAdjacent(const BoundingBox& bb, const BoundingBox& ibb)
|
||||
{
|
||||
// TODO: I'm pretty sure there is a much more compact way to check this
|
||||
const IfcFloat epsilon = 1e-5f;
|
||||
const IfcFloat epsilon = Math::getEpsilon<float>();
|
||||
return (std::fabs(bb.second.x - ibb.first.x) < epsilon && bb.first.y <= ibb.second.y && bb.second.y >= ibb.first.y) ||
|
||||
(std::fabs(bb.first.x - ibb.second.x) < epsilon && ibb.first.y <= bb.second.y && ibb.second.y >= bb.first.y) ||
|
||||
(std::fabs(bb.second.y - ibb.first.y) < epsilon && bb.first.x <= ibb.second.x && bb.second.x >= ibb.first.x) ||
|
||||
|
@ -681,7 +681,7 @@ bool IntersectingLineSegments(const IfcVector2& n0, const IfcVector2& n1,
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
void FindAdjacentContours(ContourVector::iterator current, const ContourVector& contours)
|
||||
{
|
||||
const IfcFloat sqlen_epsilon = static_cast<IfcFloat>(1e-8);
|
||||
const IfcFloat sqlen_epsilon = static_cast<IfcFloat>(Math::getEpsilon<float>());
|
||||
const BoundingBox& bb = (*current).bb;
|
||||
|
||||
// What is to be done here is to populate the skip lists for the contour
|
||||
|
@ -758,7 +758,7 @@ void FindAdjacentContours(ContourVector::iterator current, const ContourVector&
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
AI_FORCE_INLINE bool LikelyBorder(const IfcVector2& vdelta)
|
||||
{
|
||||
const IfcFloat dot_point_epsilon = static_cast<IfcFloat>(1e-5);
|
||||
const IfcFloat dot_point_epsilon = static_cast<IfcFloat>(Math::getEpsilon<float>());
|
||||
return std::fabs(vdelta.x * vdelta.y) < dot_point_epsilon;
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/material.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/Macros.h>
|
||||
|
||||
using namespace Assimp;
|
||||
using namespace irr;
|
||||
|
|
|
@ -586,7 +586,6 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
|
|||
root->mName.Set("<LWORoot>");
|
||||
|
||||
//Set parent of all children, inserting pivots
|
||||
//std::cout << "Set parent of all children" << std::endl;
|
||||
std::map<uint16_t, aiNode*> mapPivot;
|
||||
for (auto itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
|
||||
|
||||
|
@ -618,7 +617,6 @@ void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
|
|||
}
|
||||
|
||||
//Merge pivot map into node map
|
||||
//std::cout << "Merge pivot map into node map" << std::endl;
|
||||
for (auto itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) {
|
||||
apcNodes[itMapPivot->first] = itMapPivot->second;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,437 @@
|
|||
/*
|
||||
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
|
||||
#ifndef ASSIMP_BUILD_NO_M3D_IMPORTER
|
||||
#define M3D_NODUP
|
||||
#endif
|
||||
|
||||
// Header files, standard library.
|
||||
#include <memory> // shared_ptr
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <assimp/Exceptional.h> // DeadlyExportError
|
||||
#include <assimp/StreamWriter.h> // StreamWriterLE
|
||||
#include <assimp/material.h> // aiTextureType
|
||||
#include <assimp/mesh.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/version.h> // aiGetVersion
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/Exporter.hpp>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
|
||||
#include "M3DWrapper.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)
|
||||
*/
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Conversion functions
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// helper to add a vertex (private to NodeWalk)
|
||||
m3dv_t *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 *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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// convert aiColor4D into uint32_t
|
||||
uint32_t 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 property to the output
|
||||
void 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;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// convert aiString to identifier safe C string. This is a duplication of _m3d_safestr
|
||||
char *SafeStr(aiString str, bool isStrict)
|
||||
{
|
||||
char *s = (char *)&str.data;
|
||||
char *d, *ret;
|
||||
int i, len;
|
||||
|
||||
for(len = str.length + 1; *s && (*s == ' ' || *s == '\t'); s++, len--);
|
||||
if(len > 255) len = 255;
|
||||
ret = (char *)M3D_MALLOC(len + 1);
|
||||
if (!ret) {
|
||||
throw DeadlyExportError("memory allocation error");
|
||||
}
|
||||
for(i = 0, d = ret; i < len && *s && *s != '\r' && *s != '\n'; s++, d++, i++) {
|
||||
*d = isStrict && (*s == ' ' || *s == '\t' || *s == '/' || *s == '\\') ? '_' : (*s == '\t' ? ' ' : *s);
|
||||
}
|
||||
for(; d > ret && (*(d-1) == ' ' || *(d-1) == '\t'); d--);
|
||||
*d = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// add a material to the output
|
||||
M3D_INDEX addMaterial(const Assimp::M3DWrapper &m3d, const aiMaterial *mat) {
|
||||
unsigned int mi = M3D_NOTDEFINED;
|
||||
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 == M3D_NOTDEFINED) {
|
||||
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 = SafeStr(name, true);
|
||||
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 = SafeStr(name, true);
|
||||
for (j = 0, i = M3D_NOTDEFINED; j < m3d->numtexture; j++)
|
||||
if (!strcmp(fn, m3d->texture[j].name)) {
|
||||
i = j;
|
||||
free(fn);
|
||||
break;
|
||||
}
|
||||
if (i == M3D_NOTDEFINED) {
|
||||
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;
|
||||
}
|
||||
|
||||
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 ExportSceneM3DA(
|
||||
const char *pFile,
|
||||
IOSystem *pIOSystem,
|
||||
const aiScene *pScene,
|
||||
const ExportProperties *pProperties
|
||||
|
||||
) {
|
||||
#ifdef M3D_ASCII
|
||||
// initialize the exporter
|
||||
M3DExporter exporter(pScene, pProperties);
|
||||
|
||||
// perform ascii export
|
||||
exporter.doExport(pFile, pIOSystem, true);
|
||||
#else
|
||||
throw DeadlyExportError("Assimp configured without M3D_ASCII support");
|
||||
#endif
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
M3DExporter::M3DExporter(const aiScene *pScene, const ExportProperties *pProperties) :
|
||||
mScene(pScene),
|
||||
mProperties(pProperties),
|
||||
outfile() {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
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));
|
||||
}
|
||||
|
||||
M3DWrapper m3d;
|
||||
if (!m3d) {
|
||||
throw DeadlyExportError("memory allocation error");
|
||||
}
|
||||
m3d->name = SafeStr(mScene->mRootNode->mName, false);
|
||||
|
||||
// Create a model from assimp structures
|
||||
aiMatrix4x4 m;
|
||||
NodeWalk(m3d, mScene->mRootNode, m);
|
||||
|
||||
// serialize the structures
|
||||
unsigned int size;
|
||||
unsigned char *output = m3d.Save(M3D_EXP_FLOAT, M3D_EXP_EXTRA | (toAscii ? M3D_EXP_ASCII : 0), size);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// recursive node walker
|
||||
void M3DExporter::NodeWalk(const M3DWrapper &m3d, 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_NOTDEFINED;
|
||||
if (mScene->mMaterials) {
|
||||
// get the material for this mesh
|
||||
mi = addMaterial(m3d, 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] = M3D_UNDEF;
|
||||
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 = M3D_UNDEF;
|
||||
// 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(m3d, pNode->mChildren[i], nm);
|
||||
}
|
||||
}
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_M3D_EXPORTER
|
||||
#endif // ASSIMP_BUILD_NO_EXPORT
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
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 <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;
|
||||
|
||||
class M3DWrapper;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
/** 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
|
||||
|
||||
// helper to do the recursive walking
|
||||
void NodeWalk(const M3DWrapper &m3d, const aiNode* pNode, aiMatrix4x4 m);
|
||||
};
|
||||
}
|
||||
|
||||
#endif // ASSIMP_BUILD_NO_M3D_EXPORTER
|
||||
|
||||
#endif // AI_M3DEXPORTER_H_INC
|
|
@ -0,0 +1,770 @@
|
|||
/*
|
||||
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_NONORMALS /* leave the post-processing to Assimp */
|
||||
#define M3D_NOWEIGHTS
|
||||
#define M3D_NOANIMATION
|
||||
|
||||
#include <assimp/DefaultIOSystem.h>
|
||||
#include <assimp/IOStreamBuffer.h>
|
||||
#include <assimp/ai_assert.h>
|
||||
#include <assimp/importerdesc.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <memory>
|
||||
|
||||
#include "M3DWrapper.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_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
#ifdef M3D_ASCII
|
||||
"m3d a3d"
|
||||
#else
|
||||
"m3d"
|
||||
#endif
|
||||
};
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
using namespace std;
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Default constructor
|
||||
M3DImporter::M3DImporter() :
|
||||
mScene(nullptr) {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// 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"
|
||||
#ifdef M3D_ASCII
|
||||
|| extension == "a3d"
|
||||
#endif
|
||||
)
|
||||
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 */
|
||||
#ifdef M3D_ASCII
|
||||
|| !memcmp(data, "3dmo", 4) /* ASCII */
|
||||
#endif
|
||||
;
|
||||
}
|
||||
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::vector<unsigned char> buffer(fileSize);
|
||||
if (fileSize != pStream->Read(buffer.data(), 1, fileSize)) {
|
||||
throw DeadlyImportError("Failed to read the file " + file + ".");
|
||||
}
|
||||
// extra check for binary format's first 8 bytes. Not done for the ASCII variant
|
||||
if(!memcmp(buffer.data(), "3DMO", 4) && memcmp(buffer.data() + 4, &fileSize, 4)) {
|
||||
throw DeadlyImportError("Bad binary header in file " + file + ".");
|
||||
}
|
||||
#ifdef M3D_ASCII
|
||||
// make sure there's a terminator zero character, as input must be ASCIIZ
|
||||
if(!memcmp(buffer.data(), "3dmo", 4)) {
|
||||
buffer.push_back(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
//DefaultLogger::create("/dev/stderr", Logger::VERBOSE);
|
||||
ASSIMP_LOG_DEBUG_F("M3D: loading ", file);
|
||||
|
||||
// let the C SDK do the hard work for us
|
||||
M3DWrapper m3d(pIOHandler, buffer);
|
||||
|
||||
if (!m3d) {
|
||||
throw DeadlyImportError("Unable to parse " + file + " as M3D.");
|
||||
}
|
||||
|
||||
// create the root node
|
||||
pScene->mRootNode = new aiNode;
|
||||
pScene->mRootNode->mName = aiString(m3d.Name());
|
||||
pScene->mRootNode->mTransformation = aiMatrix4x4();
|
||||
pScene->mRootNode->mNumChildren = 0;
|
||||
mScene = pScene;
|
||||
|
||||
ASSIMP_LOG_DEBUG("M3D: root node " + m3d.Name());
|
||||
|
||||
// now we just have to fill up the Assimp structures in pScene
|
||||
importMaterials(m3d);
|
||||
importTextures(m3d);
|
||||
importBones(m3d, M3D_NOTDEFINED, pScene->mRootNode);
|
||||
importMeshes(m3d);
|
||||
importAnimations(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(const M3DWrapper &m3d_wrap) {
|
||||
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_wrap);
|
||||
|
||||
mScene->mNumMaterials = m3d_wrap->nummaterial + 1;
|
||||
mScene->mMaterials = new aiMaterial *[mScene->mNumMaterials];
|
||||
|
||||
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.0f;
|
||||
c.b = c.g = c.r = 0.6f;
|
||||
mat->AddProperty(&c, 1, AI_MATKEY_COLOR_DIFFUSE);
|
||||
mScene->mMaterials[0] = mat;
|
||||
|
||||
for (i = 0; i < m3d_wrap->nummaterial; i++) {
|
||||
m = &m3d_wrap->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_wrap->numtexture &&
|
||||
m3d_wrap->texture[m->prop[j].value.textureid].name) {
|
||||
name.Set(std::string(std::string(m3d_wrap->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(const M3DWrapper &m3d) {
|
||||
unsigned int i;
|
||||
const char *formatHint[] = { "rgba0800", "rgba0808", "rgba8880", "rgba8888" };
|
||||
m3dtx_t *t;
|
||||
|
||||
ai_assert(mScene != nullptr);
|
||||
ai_assert(m3d);
|
||||
|
||||
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];
|
||||
aiTexture *tx = new aiTexture;
|
||||
tx->mFilename = aiString(std::string(t->name) + ".png");
|
||||
if (!t->w || !t->h || !t->f || !t->d) {
|
||||
/* without ASSIMP_USE_M3D_READFILECB, we only have the filename, but no texture data ever */
|
||||
tx->mWidth = 0;
|
||||
tx->mHeight = 0;
|
||||
memcpy(tx->achFormatHint, "png\000", 4);
|
||||
tx->pcData = nullptr;
|
||||
} else {
|
||||
/* if we have the texture loaded, set format hint and pcData too */
|
||||
tx->mWidth = t->w;
|
||||
tx->mHeight = t->h;
|
||||
strcpy(tx->achFormatHint, formatHint[t->f - 1]);
|
||||
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(const M3DWrapper &m3d) {
|
||||
unsigned int i, j, k, l, numpoly = 3, lastMat = M3D_INDEXMAX;
|
||||
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);
|
||||
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(m3d, 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 = static_cast<unsigned int>(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 != M3D_UNDEF && m3d->vertex[l].skinid != M3D_INDEXMAX && 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 != M3D_UNDEF) {
|
||||
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 != M3D_UNDEF) {
|
||||
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(m3d, pMesh, faces, vertices, normals, texcoords, colors, vertexids);
|
||||
meshes->push_back(pMesh);
|
||||
}
|
||||
|
||||
// create global mesh list in scene
|
||||
mScene->mNumMeshes = static_cast<unsigned int>(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 = static_cast<unsigned int>(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(const M3DWrapper &m3d, unsigned int parentid, aiNode *pParent) {
|
||||
unsigned int i, n;
|
||||
|
||||
ai_assert(pParent != nullptr);
|
||||
ai_assert(mScene != nullptr);
|
||||
ai_assert(m3d);
|
||||
|
||||
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(m3d, &pChild->mTransformation, m3d->bone[i].pos, m3d->bone[i].ori);
|
||||
pChild->mNumChildren = 0;
|
||||
pParent->mChildren[pParent->mNumChildren] = pChild;
|
||||
pParent->mNumChildren++;
|
||||
importBones(m3d, 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(const M3DWrapper &m3d) {
|
||||
unsigned int i, j, k, l, pos, ori;
|
||||
double t;
|
||||
m3da_t *a;
|
||||
|
||||
ai_assert(mScene != nullptr);
|
||||
ai_assert(m3d);
|
||||
|
||||
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(const M3DWrapper &m3d, aiMatrix4x4 *m, unsigned int posid, unsigned int orientid) {
|
||||
ai_assert(m != nullptr);
|
||||
ai_assert(m3d);
|
||||
ai_assert(posid != M3D_UNDEF && posid < m3d->numvertex);
|
||||
ai_assert(orientid != M3D_UNDEF && 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(const M3DWrapper &m3d, 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);
|
||||
|
||||
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 = static_cast<unsigned int>(faces->size());
|
||||
pMesh->mFaces = new aiFace[pMesh->mNumFaces];
|
||||
std::copy(faces->begin(), faces->end(), pMesh->mFaces);
|
||||
pMesh->mNumVertices = static_cast<unsigned int>(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 != M3D_UNDEF && s != M3D_INDEXMAX) {
|
||||
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 != M3D_UNDEF && s != M3D_INDEXMAX) {
|
||||
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,103 @@
|
|||
/*
|
||||
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 <assimp/BaseImporter.h>
|
||||
#include <assimp/material.h>
|
||||
#include <vector>
|
||||
|
||||
struct aiMesh;
|
||||
struct aiNode;
|
||||
struct aiMaterial;
|
||||
struct aiFace;
|
||||
|
||||
namespace Assimp {
|
||||
|
||||
class M3DWrapper;
|
||||
|
||||
class M3DImporter : public BaseImporter {
|
||||
public:
|
||||
/// \brief Default constructor
|
||||
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 = nullptr; // the scene to import to
|
||||
|
||||
//! \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(const M3DWrapper &m3d);
|
||||
void importTextures(const M3DWrapper &m3d);
|
||||
void importMeshes(const M3DWrapper &m3d);
|
||||
void importBones(const M3DWrapper &m3d, unsigned int parentid, aiNode *pParent);
|
||||
void importAnimations(const M3DWrapper &m3d);
|
||||
|
||||
// helper functions
|
||||
aiColor4D mkColor(uint32_t c);
|
||||
void convertPose(const M3DWrapper &m3d, aiMatrix4x4 *m, unsigned int posid, unsigned int orientid);
|
||||
aiNode *findNode(aiNode *pNode, aiString name);
|
||||
void calculateOffsetMatrix(aiNode *pNode, aiMatrix4x4 *m);
|
||||
void populateMesh(const M3DWrapper &m3d, 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(aiTextureType_AMBIENT_OCCLUSION,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_NORMALS(0) }, /* m3dp_map_N */
|
||||
|
||||
{ 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_REFLECTION,0) }, /* m3dp_map_Ni */
|
||||
{ NULL, 0, 0 }, /* m3dp_map_Nt */
|
||||
{ NULL, 0, 0 },
|
||||
{ NULL, 0, 0 },
|
||||
{ NULL, 0, 0 }
|
||||
};
|
||||
|
||||
#endif // AI_M3DMATERIALS_H_INC
|
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
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.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER) || !ASSIMP_BUILD_NO_M3D_IMPORTER
|
||||
|
||||
#include "M3DWrapper.h"
|
||||
|
||||
#include <assimp/DefaultIOSystem.h>
|
||||
#include <assimp/IOStreamBuffer.h>
|
||||
#include <assimp/ai_assert.h>
|
||||
|
||||
#ifdef ASSIMP_USE_M3D_READFILECB
|
||||
|
||||
# if (__cplusplus >= 201103L) || !defined(_MSC_VER) || (_MSC_VER >= 1900) // C++11 and MSVC 2015 onwards
|
||||
# define threadlocal thread_local
|
||||
# else
|
||||
# if defined(_MSC_VER) && (_MSC_VER >= 1800) // there's an alternative for MSVC 2013
|
||||
# define threadlocal __declspec(thread)
|
||||
# else
|
||||
# define threadlocal
|
||||
# endif
|
||||
# endif
|
||||
|
||||
extern "C" {
|
||||
|
||||
// workaround: the M3D SDK expects a C callback, but we want to use Assimp::IOSystem to implement that
|
||||
threadlocal 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 in a single-threaded scenario too 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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace Assimp {
|
||||
M3DWrapper::M3DWrapper() {
|
||||
// use malloc() here because m3d_free() will call free()
|
||||
m3d_ = (m3d_t *)calloc(1, sizeof(m3d_t));
|
||||
}
|
||||
|
||||
M3DWrapper::M3DWrapper(IOSystem *pIOHandler, const std::vector<unsigned char> &buffer) {
|
||||
#ifdef ASSIMP_USE_M3D_READFILECB
|
||||
// pass this IOHandler to the C callback in a thread-local pointer
|
||||
m3dimporter_pIOHandler = pIOHandler;
|
||||
m3d_ = m3d_load(const_cast<unsigned char *>(buffer.data()), m3dimporter_readfile, free, nullptr);
|
||||
// Clear the C callback
|
||||
m3dimporter_pIOHandler = nullptr;
|
||||
#else
|
||||
m3d_ = m3d_load(const_cast<unsigned char *>(buffer.data()), nullptr, nullptr, nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
M3DWrapper::~M3DWrapper() {
|
||||
reset();
|
||||
}
|
||||
|
||||
void M3DWrapper::reset() {
|
||||
ClearSave();
|
||||
if (m3d_)
|
||||
m3d_free(m3d_);
|
||||
m3d_ = nullptr;
|
||||
}
|
||||
|
||||
unsigned char *M3DWrapper::Save(int quality, int flags, unsigned int &size) {
|
||||
#if (!(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER))
|
||||
ClearSave();
|
||||
saved_output_ = m3d_save(m3d_, quality, flags, &size);
|
||||
return saved_output_;
|
||||
#else
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void M3DWrapper::ClearSave() {
|
||||
if (saved_output_)
|
||||
M3D_FREE(saved_output_);
|
||||
saved_output_ = nullptr;
|
||||
}
|
||||
} // namespace Assimp
|
||||
|
||||
#endif
|
|
@ -0,0 +1,101 @@
|
|||
#pragma once
|
||||
/*
|
||||
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 M3DWrapper.h
|
||||
* @brief Declares a class to wrap the C m3d SDK
|
||||
*/
|
||||
#ifndef AI_M3DWRAPPER_H_INC
|
||||
#define AI_M3DWRAPPER_H_INC
|
||||
#if !(ASSIMP_BUILD_NO_EXPORT || ASSIMP_BUILD_NO_M3D_EXPORTER) || !ASSIMP_BUILD_NO_M3D_IMPORTER
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// Assimp specific M3D configuration. Comment out these defines to remove functionality
|
||||
//#define ASSIMP_USE_M3D_READFILECB
|
||||
//#define M3D_ASCII
|
||||
|
||||
#include "m3d.h"
|
||||
|
||||
namespace Assimp {
|
||||
class IOSystem;
|
||||
|
||||
class M3DWrapper {
|
||||
m3d_t *m3d_ = nullptr;
|
||||
unsigned char *saved_output_ = nullptr;
|
||||
|
||||
public:
|
||||
// Construct an empty M3D model
|
||||
explicit M3DWrapper();
|
||||
|
||||
// Construct an M3D model from provided buffer
|
||||
// NOTE: The m3d.h SDK function does not mark the data as const. Have assumed it does not write.
|
||||
// BUG: SECURITY: The m3d.h SDK cannot be informed of the buffer size. BUFFER OVERFLOW IS CERTAIN
|
||||
explicit M3DWrapper(IOSystem *pIOHandler, const std::vector<unsigned char> &buffer);
|
||||
|
||||
~M3DWrapper();
|
||||
|
||||
void reset();
|
||||
|
||||
// Name
|
||||
inline std::string Name() const {
|
||||
if (m3d_) return std::string(m3d_->name);
|
||||
return std::string();
|
||||
}
|
||||
|
||||
// Execute a save
|
||||
unsigned char *Save(int quality, int flags, unsigned int &size);
|
||||
void ClearSave();
|
||||
|
||||
inline explicit operator bool() const { return m3d_ != nullptr; }
|
||||
|
||||
// Allow direct access to M3D API
|
||||
inline m3d_t *operator->() const { return m3d_; }
|
||||
inline m3d_t *M3D() const { return m3d_; }
|
||||
};
|
||||
} // namespace Assimp
|
||||
|
||||
#endif
|
||||
|
||||
#endif // AI_M3DWRAPPER_H_INC
|
File diff suppressed because it is too large
Load Diff
|
@ -344,7 +344,7 @@ void MD2Importer::InternReadFile( const std::string& pFile,
|
|||
if (pcSkins->name[0])
|
||||
{
|
||||
aiString szString;
|
||||
const size_t iLen = ::strlen(pcSkins->name);
|
||||
const ai_uint32 iLen = (ai_uint32) ::strlen(pcSkins->name);
|
||||
::memcpy(szString.data,pcSkins->name,iLen);
|
||||
szString.data[iLen] = '\0';
|
||||
szString.length = iLen;
|
||||
|
|
|
@ -973,7 +973,7 @@ void MD3Importer::InternReadFile( const std::string& pFile, aiScene* pScene, IOS
|
|||
AI_SWAP2( pcVertices[i].Z );
|
||||
|
||||
AI_SWAP4( pcUVs[i].U );
|
||||
AI_SWAP4( pcUVs[i].U );
|
||||
AI_SWAP4( pcUVs[i].V );
|
||||
}
|
||||
for (uint32_t i = 0; i < pcSurfaces->NUM_TRIANGLES;++i) {
|
||||
AI_SWAP4(pcTriangles[i].INDEXES[0]);
|
||||
|
|
|
@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "MD5Loader.h"
|
||||
#include <assimp/StringComparison.h>
|
||||
#include <assimp/fast_atof.h>
|
||||
#include <assimp/MathFunctions.h>
|
||||
#include <assimp/SkeletonMeshBuilder.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/scene.h>
|
||||
|
@ -64,7 +65,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
using namespace Assimp;
|
||||
|
||||
// Minimum weight value. Weights inside [-n ... n] are ignored
|
||||
#define AI_MD5_WEIGHT_EPSILON 1e-5f
|
||||
#define AI_MD5_WEIGHT_EPSILON Math::getEpsilon<float>()
|
||||
|
||||
|
||||
static const aiImporterDesc desc = {
|
||||
|
|
|
@ -235,7 +235,7 @@ bool MD5Parser::ParseSection(Section& out)
|
|||
const char* szStart = ++sz; \
|
||||
while('\"'!=*sz)++sz; \
|
||||
const char* szEnd = (sz++); \
|
||||
out.length = (size_t)(szEnd - szStart); \
|
||||
out.length = (ai_uint32) (szEnd - szStart); \
|
||||
::memcpy(out.data,szStart,out.length); \
|
||||
out.data[out.length] = '\0';
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
|
|
@ -355,7 +355,7 @@ void MDCImporter::InternReadFile(
|
|||
// swap all texture coordinates
|
||||
for (unsigned int i = 0; i < pcSurface->ulNumVertices;++i)
|
||||
{
|
||||
AI_SWAP4( pcUVs->v );
|
||||
AI_SWAP4( pcUVs->u );
|
||||
AI_SWAP4( pcUVs->v );
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,600 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file HL1FileData.h
|
||||
* @brief Definition of in-memory structures for the
|
||||
* Half-Life 1 MDL file format.
|
||||
*/
|
||||
|
||||
#ifndef AI_HL1FILEDATA_INCLUDED
|
||||
#define AI_HL1FILEDATA_INCLUDED
|
||||
|
||||
#include "HalfLifeMDLBaseHeader.h"
|
||||
|
||||
#include <assimp/Compiler/pushpack1.h>
|
||||
#include <assimp/types.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace MDL {
|
||||
namespace HalfLife {
|
||||
|
||||
using vec3_t = float[3];
|
||||
|
||||
/** \struct Header_HL1
|
||||
* \brief Data structure for the HL1 MDL file header.
|
||||
*/
|
||||
struct Header_HL1 : HalfLifeMDLBaseHeader {
|
||||
//! The model name.
|
||||
char name[64];
|
||||
|
||||
//! The total file size in bytes.
|
||||
int32_t length;
|
||||
|
||||
//! Ideal eye position.
|
||||
vec3_t eyeposition;
|
||||
|
||||
//! Ideal movement hull size.
|
||||
vec3_t min;
|
||||
vec3_t max;
|
||||
|
||||
//! Clipping bounding box.
|
||||
vec3_t bbmin;
|
||||
vec3_t bbmax;
|
||||
|
||||
//! Was "flags".
|
||||
int32_t unused;
|
||||
|
||||
//! The number of bones.
|
||||
int32_t numbones;
|
||||
|
||||
//! Offset to the first bone chunk.
|
||||
int32_t boneindex;
|
||||
|
||||
//! The number of bone controllers.
|
||||
int32_t numbonecontrollers;
|
||||
|
||||
//! Offset to the first bone controller chunk.
|
||||
int32_t bonecontrollerindex;
|
||||
|
||||
//! The number of hitboxes.
|
||||
int32_t numhitboxes;
|
||||
|
||||
//! Offset to the first hitbox chunk.
|
||||
int32_t hitboxindex;
|
||||
|
||||
//! The number of sequences.
|
||||
int32_t numseq;
|
||||
|
||||
//! Offset to the first sequence description chunk.
|
||||
int32_t seqindex;
|
||||
|
||||
//! The number of sequence groups.
|
||||
int32_t numseqgroups;
|
||||
|
||||
//! Offset to the first sequence group chunk.
|
||||
int32_t seqgroupindex;
|
||||
|
||||
//! The number of textures.
|
||||
int32_t numtextures;
|
||||
|
||||
//! Offset to the first texture chunk.
|
||||
int32_t textureindex;
|
||||
|
||||
//! Offset to the first texture's image data.
|
||||
int32_t texturedataindex;
|
||||
|
||||
//! The number of replaceable textures.
|
||||
int32_t numskinref;
|
||||
|
||||
//! The number of skin families.
|
||||
int32_t numskinfamilies;
|
||||
|
||||
//! Offset to the first replaceable texture.
|
||||
int32_t skinindex;
|
||||
|
||||
//! The number of bodyparts.
|
||||
int32_t numbodyparts;
|
||||
|
||||
//! Offset the the first bodypart.
|
||||
int32_t bodypartindex;
|
||||
|
||||
//! The number of attachments.
|
||||
int32_t numattachments;
|
||||
|
||||
//! Offset the the first attachment chunk.
|
||||
int32_t attachmentindex;
|
||||
|
||||
//! Was "soundtable".
|
||||
int32_t unused2;
|
||||
|
||||
//! Was "soundindex".
|
||||
int32_t unused3;
|
||||
|
||||
//! Was "soundgroups".
|
||||
int32_t unused4;
|
||||
|
||||
//! Was "soundgroupindex".
|
||||
int32_t unused5;
|
||||
|
||||
//! The number of nodes in the sequence transition graph.
|
||||
int32_t numtransitions;
|
||||
|
||||
//! Offset the the first sequence transition.
|
||||
int32_t transitionindex;
|
||||
} PACK_STRUCT;
|
||||
|
||||
/** \struct SequenceHeader_HL1
|
||||
* \brief Data structure for the file header of a demand loaded
|
||||
* HL1 MDL sequence group file.
|
||||
*/
|
||||
struct SequenceHeader_HL1 : HalfLifeMDLBaseHeader {
|
||||
//! The sequence group file name.
|
||||
char name[64];
|
||||
|
||||
//! The total file size in bytes.
|
||||
int32_t length;
|
||||
} PACK_STRUCT;
|
||||
|
||||
/** \struct Bone_HL1
|
||||
* \brief Data structure for a bone in HL1 MDL files.
|
||||
*/
|
||||
struct Bone_HL1 {
|
||||
//! The bone name.
|
||||
char name[32];
|
||||
|
||||
//! The parent bone index. (-1) If it has no parent.
|
||||
int32_t parent;
|
||||
|
||||
//! Was "flags".
|
||||
int32_t unused;
|
||||
|
||||
//! Available bone controller per motion type.
|
||||
//! (-1) if no controller is available.
|
||||
int32_t bonecontroller[6];
|
||||
|
||||
/*! Default position and rotation values where
|
||||
* scale[0] = position.X
|
||||
* scale[1] = position.Y
|
||||
* scale[2] = position.Z
|
||||
* scale[3] = rotation.X
|
||||
* scale[4] = rotation.Y
|
||||
* scale[5] = rotation.Z
|
||||
*/
|
||||
float value[6];
|
||||
|
||||
/*! Compressed scale values where
|
||||
* scale[0] = position.X scale
|
||||
* scale[1] = position.Y scale
|
||||
* scale[2] = position.Z scale
|
||||
* scale[3] = rotation.X scale
|
||||
* scale[4] = rotation.Y scale
|
||||
* scale[5] = rotation.Z scale
|
||||
*/
|
||||
float scale[6];
|
||||
} PACK_STRUCT;
|
||||
|
||||
/** \struct BoneController_HL1
|
||||
* \brief Data structure for a bone controller in HL1 MDL files.
|
||||
*/
|
||||
struct BoneController_HL1 {
|
||||
//! Bone affected by this controller.
|
||||
int32_t bone;
|
||||
|
||||
//! The motion type.
|
||||
int32_t type;
|
||||
|
||||
//! The minimum and maximum values.
|
||||
float start;
|
||||
float end;
|
||||
|
||||
// Was "rest".
|
||||
int32_t unused;
|
||||
|
||||
// The bone controller channel.
|
||||
int32_t index;
|
||||
} PACK_STRUCT;
|
||||
|
||||
/** \struct Hitbox_HL1
|
||||
* \brief Data structure for a hitbox in HL1 MDL files.
|
||||
*/
|
||||
struct Hitbox_HL1 {
|
||||
//! The bone this hitbox follows.
|
||||
int32_t bone;
|
||||
|
||||
//! The hit group.
|
||||
int32_t group;
|
||||
|
||||
//! The hitbox minimum and maximum extents.
|
||||
vec3_t bbmin;
|
||||
vec3_t bbmax;
|
||||
} PACK_STRUCT;
|
||||
|
||||
/** \struct SequenceGroup_HL1
|
||||
* \brief Data structure for a sequence group in HL1 MDL files.
|
||||
*/
|
||||
struct SequenceGroup_HL1 {
|
||||
//! A textual name for this sequence group.
|
||||
char label[32];
|
||||
|
||||
//! The file name.
|
||||
char name[64];
|
||||
|
||||
//! Was "cache".
|
||||
int32_t unused;
|
||||
|
||||
//! Was "data".
|
||||
int32_t unused2;
|
||||
} PACK_STRUCT;
|
||||
|
||||
//! The type of blending for a sequence.
|
||||
enum SequenceBlendMode_HL1 {
|
||||
NoBlend = 1,
|
||||
TwoWayBlending = 2,
|
||||
FourWayBlending = 4,
|
||||
};
|
||||
|
||||
/** \struct SequenceDesc_HL1
|
||||
* \brief Data structure for a sequence description in HL1 MDL files.
|
||||
*/
|
||||
struct SequenceDesc_HL1 {
|
||||
//! The sequence name.
|
||||
char label[32];
|
||||
|
||||
//! Frames per second.
|
||||
float fps;
|
||||
|
||||
//! looping/non-looping flags.
|
||||
int32_t flags;
|
||||
|
||||
//! The sequence activity.
|
||||
int32_t activity;
|
||||
|
||||
//! The sequence activity weight.
|
||||
int32_t actweight;
|
||||
|
||||
//! The number of animation events.
|
||||
int32_t numevents;
|
||||
|
||||
//! Offset the the first animation event chunk.
|
||||
int32_t eventindex;
|
||||
|
||||
//! The number of frames in the sequence.
|
||||
int32_t numframes;
|
||||
|
||||
//! Was "numpivots".
|
||||
int32_t unused;
|
||||
|
||||
//! Was "pivotindex".
|
||||
int32_t unused2;
|
||||
|
||||
//! Linear motion type.
|
||||
int32_t motiontype;
|
||||
|
||||
//! Linear motion bone.
|
||||
int32_t motionbone;
|
||||
|
||||
//! Linear motion.
|
||||
vec3_t linearmovement;
|
||||
|
||||
//! Was "automoveposindex".
|
||||
int32_t unused3;
|
||||
|
||||
//! Was "automoveangleindex".
|
||||
int32_t unused4;
|
||||
|
||||
//! The sequence minimum and maximum extents.
|
||||
vec3_t bbmin;
|
||||
vec3_t bbmax;
|
||||
|
||||
//! The number of blend animations.
|
||||
int32_t numblends;
|
||||
|
||||
//! Offset to first the AnimValueOffset_HL1 chunk.
|
||||
//! This offset is relative to the SequenceHeader_HL1 of the file
|
||||
//! that contains the animation data.
|
||||
int32_t animindex;
|
||||
|
||||
//! The motion type of each blend controller.
|
||||
int32_t blendtype[2];
|
||||
|
||||
//! The starting value of each blend controller.
|
||||
float blendstart[2];
|
||||
|
||||
//! The ending value of each blend controller.
|
||||
float blendend[2];
|
||||
|
||||
//! Was "blendparent".
|
||||
int32_t unused5;
|
||||
|
||||
//! The sequence group.
|
||||
int32_t seqgroup;
|
||||
|
||||
//! The node at entry in the sequence transition graph.
|
||||
int32_t entrynode;
|
||||
|
||||
//! The node at exit in the sequence transition graph.
|
||||
int32_t exitnode;
|
||||
|
||||
//! Transition rules.
|
||||
int32_t nodeflags;
|
||||
|
||||
//! Was "nextseq"
|
||||
int32_t unused6;
|
||||
} PACK_STRUCT;
|
||||
|
||||
/** \struct AnimEvent_HL1
|
||||
* \brief Data structure for an animation event in HL1 MDL files.
|
||||
*/
|
||||
struct AnimEvent_HL1 {
|
||||
//! The frame at which this animation event occurs.
|
||||
int32_t frame;
|
||||
|
||||
//! The script event type.
|
||||
int32_t event;
|
||||
|
||||
//! was "type"
|
||||
int32_t unused;
|
||||
|
||||
//! Options. Could be path to sound WAVE files.
|
||||
char options[64];
|
||||
} PACK_STRUCT;
|
||||
|
||||
/** \struct Attachment_HL1
|
||||
* \brief Data structure for an attachment in HL1 MDL files.
|
||||
*/
|
||||
struct Attachment_HL1 {
|
||||
//! Was "name".
|
||||
char unused[32];
|
||||
|
||||
//! Was "type".
|
||||
int32_t unused2;
|
||||
|
||||
//! The bone this attachment follows.
|
||||
int32_t bone;
|
||||
|
||||
//! The attachment origin.
|
||||
vec3_t org;
|
||||
|
||||
//! Was "vectors"
|
||||
vec3_t unused3[3];
|
||||
} PACK_STRUCT;
|
||||
|
||||
/** \struct AnimValueOffset_HL1
|
||||
* \brief Data structure to hold offsets (one per motion type)
|
||||
* to the first animation frame value for a single bone
|
||||
* in HL1 MDL files.
|
||||
*/
|
||||
struct AnimValueOffset_HL1 {
|
||||
unsigned short offset[6];
|
||||
} PACK_STRUCT;
|
||||
|
||||
/** \struct AnimValue_HL1
|
||||
* \brief Data structure for an animation frame in HL1 MDL files.
|
||||
*/
|
||||
union AnimValue_HL1 {
|
||||
struct {
|
||||
uint8_t valid;
|
||||
uint8_t total;
|
||||
} num;
|
||||
short value;
|
||||
} PACK_STRUCT;
|
||||
|
||||
/** \struct Bodypart_HL1
|
||||
* \brief Data structure for a bodypart in HL1 MDL files.
|
||||
*/
|
||||
struct Bodypart_HL1 {
|
||||
//! The bodypart name.
|
||||
char name[64];
|
||||
|
||||
//! The number of available models for this bodypart.
|
||||
int32_t nummodels;
|
||||
|
||||
//! Used to convert from a global model index
|
||||
//! to a local bodypart model index.
|
||||
int32_t base;
|
||||
|
||||
//! The offset to the first model chunk.
|
||||
int32_t modelindex;
|
||||
} PACK_STRUCT;
|
||||
|
||||
/** \struct Texture_HL1
|
||||
* \brief Data structure for a texture in HL1 MDL files.
|
||||
*/
|
||||
struct Texture_HL1 {
|
||||
//! Texture file name.
|
||||
char name[64];
|
||||
|
||||
//! Texture flags.
|
||||
int32_t flags;
|
||||
|
||||
//! Texture width in pixels.
|
||||
int32_t width;
|
||||
|
||||
//! Texture height in pixels.
|
||||
int32_t height;
|
||||
|
||||
//! Offset to the image data.
|
||||
//! This offset is relative to the texture file header.
|
||||
int32_t index;
|
||||
} PACK_STRUCT;
|
||||
|
||||
/** \struct Model_HL1
|
||||
* \brief Data structure for a model in HL1 MDL files.
|
||||
*/
|
||||
struct Model_HL1 {
|
||||
//! Model name.
|
||||
char name[64];
|
||||
|
||||
//! Was "type".
|
||||
int32_t unused;
|
||||
|
||||
//! Was "boundingradius".
|
||||
float unused2;
|
||||
|
||||
//! The number of meshes in the model.
|
||||
int32_t nummesh;
|
||||
|
||||
//! Offset to the first mesh chunk.
|
||||
int32_t meshindex;
|
||||
|
||||
//! The number of unique vertices.
|
||||
int32_t numverts;
|
||||
|
||||
//! Offset to the vertex bone array.
|
||||
int32_t vertinfoindex;
|
||||
|
||||
//! Offset to the vertex array.
|
||||
int32_t vertindex;
|
||||
|
||||
//! The number of unique normals.
|
||||
int32_t numnorms;
|
||||
|
||||
//! Offset to the normal bone array.
|
||||
int32_t norminfoindex;
|
||||
|
||||
//! Offset to the normal array.
|
||||
int32_t normindex;
|
||||
|
||||
//! Was "numgroups".
|
||||
int32_t unused3;
|
||||
|
||||
//! Was "groupindex".
|
||||
int32_t unused4;
|
||||
} PACK_STRUCT;
|
||||
|
||||
/** \struct Mesh_HL1
|
||||
* \brief Data structure for a mesh in HL1 MDL files.
|
||||
*/
|
||||
struct Mesh_HL1 {
|
||||
//! Can be interpreted as the number of triangles in the mesh.
|
||||
int32_t numtris;
|
||||
|
||||
//! Offset to the start of the tris sequence.
|
||||
int32_t triindex;
|
||||
|
||||
//! The skin index.
|
||||
int32_t skinref;
|
||||
|
||||
//! The number of normals in the mesh.
|
||||
int32_t numnorms;
|
||||
|
||||
//! Was "normindex".
|
||||
int32_t unused;
|
||||
} PACK_STRUCT;
|
||||
|
||||
/** \struct Trivert
|
||||
* \brief Data structure for a trivert in HL1 MDL files.
|
||||
*/
|
||||
struct Trivert {
|
||||
//! Index into Model_HL1 vertex array.
|
||||
short vertindex;
|
||||
|
||||
//! Index into Model_HL1 normal array.
|
||||
short normindex;
|
||||
|
||||
//! Texture coordinates in absolute space (unnormalized).
|
||||
short s, t;
|
||||
} PACK_STRUCT;
|
||||
|
||||
#include <assimp/Compiler/poppack1.h>
|
||||
|
||||
#if (!defined AI_MDL_HL1_VERSION)
|
||||
#define AI_MDL_HL1_VERSION 10
|
||||
#endif
|
||||
#if (!defined AI_MDL_HL1_MAX_TRIANGLES)
|
||||
#define AI_MDL_HL1_MAX_TRIANGLES 20000
|
||||
#endif
|
||||
#if (!defined AI_MDL_HL1_MAX_VERTICES)
|
||||
#define AI_MDL_HL1_MAX_VERTICES 2048
|
||||
#endif
|
||||
#if (!defined AI_MDL_HL1_MAX_SEQUENCES)
|
||||
#define AI_MDL_HL1_MAX_SEQUENCES 2048
|
||||
#endif
|
||||
#if (!defined AI_MDL_HL1_MAX_SEQUENCE_GROUPS)
|
||||
#define AI_MDL_HL1_MAX_SEQUENCE_GROUPS 32
|
||||
#endif
|
||||
#if (!defined AI_MDL_HL1_MAX_TEXTURES)
|
||||
#define AI_MDL_HL1_MAX_TEXTURES 100
|
||||
#endif
|
||||
#if (!defined AI_MDL_HL1_MAX_SKIN_FAMILIES)
|
||||
#define AI_MDL_HL1_MAX_SKIN_FAMILIES 100
|
||||
#endif
|
||||
#if (!defined AI_MDL_HL1_MAX_BONES)
|
||||
#define AI_MDL_HL1_MAX_BONES 128
|
||||
#endif
|
||||
#if (!defined AI_MDL_HL1_MAX_BODYPARTS)
|
||||
#define AI_MDL_HL1_MAX_BODYPARTS 32
|
||||
#endif
|
||||
#if (!defined AI_MDL_HL1_MAX_MODELS)
|
||||
#define AI_MDL_HL1_MAX_MODELS 32
|
||||
#endif
|
||||
#if (!defined AI_MDL_HL1_MAX_MESHES)
|
||||
#define AI_MDL_HL1_MAX_MESHES 256
|
||||
#endif
|
||||
#if (!defined AI_MDL_HL1_MAX_EVENTS)
|
||||
#define AI_MDL_HL1_MAX_EVENTS 1024
|
||||
#endif
|
||||
#if (!defined AI_MDL_HL1_MAX_BONE_CONTROLLERS)
|
||||
#define AI_MDL_HL1_MAX_BONE_CONTROLLERS 8
|
||||
#endif
|
||||
#if (!defined AI_MDL_HL1_MAX_ATTACHMENTS)
|
||||
#define AI_MDL_HL1_MAX_ATTACHMENTS 512
|
||||
#endif
|
||||
|
||||
// lighting options
|
||||
#if (!defined AI_MDL_HL1_STUDIO_NF_FLATSHADE)
|
||||
#define AI_MDL_HL1_STUDIO_NF_FLATSHADE 0x0001
|
||||
#endif
|
||||
#if (!defined AI_MDL_HL1_STUDIO_NF_CHROME)
|
||||
#define AI_MDL_HL1_STUDIO_NF_CHROME 0x0002
|
||||
#endif
|
||||
#if (!defined AI_MDL_HL1_STUDIO_NF_ADDITIVE)
|
||||
#define AI_MDL_HL1_STUDIO_NF_ADDITIVE 0x0020
|
||||
#endif
|
||||
#if (!defined AI_MDL_HL1_STUDIO_NF_MASKED)
|
||||
#define AI_MDL_HL1_STUDIO_NF_MASKED 0x0040
|
||||
#endif
|
||||
|
||||
} // namespace HalfLife
|
||||
} // namespace MDL
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // AI_HL1FILEDATA_INCLUDED
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file HL1ImportDefinitions.h
|
||||
* @brief HL1 MDL loader specific definitions.
|
||||
*/
|
||||
|
||||
#ifndef AI_MDL_HL1_IMPORT_DEFINITIONS_INCLUDED
|
||||
#define AI_MDL_HL1_IMPORT_DEFINITIONS_INCLUDED
|
||||
|
||||
#define AI_MDL_HL1_NODE_ROOT "<MDL_root>"
|
||||
#define AI_MDL_HL1_NODE_BODYPARTS "<MDL_bodyparts>"
|
||||
#define AI_MDL_HL1_NODE_BONES "<MDL_bones>"
|
||||
#define AI_MDL_HL1_NODE_BONE_CONTROLLERS "<MDL_bone_controllers>"
|
||||
#define AI_MDL_HL1_NODE_SEQUENCE_INFOS "<MDL_sequence_infos>"
|
||||
#define AI_MDL_HL1_NODE_SEQUENCE_GROUPS "<MDL_sequence_groups>"
|
||||
#define AI_MDL_HL1_NODE_SEQUENCE_TRANSITION_GRAPH "<MDL_sequence_transition_graph>"
|
||||
#define AI_MDL_HL1_NODE_ATTACHMENTS "<MDL_attachments>"
|
||||
#define AI_MDL_HL1_NODE_HITBOXES "<MDL_hitboxes>"
|
||||
#define AI_MDL_HL1_NODE_GLOBAL_INFO "<MDL_global_info>"
|
||||
#define AI_MDL_HL1_NODE_ANIMATION_EVENTS "AnimationEvents"
|
||||
#define AI_MDL_HL1_NODE_BLEND_CONTROLLERS "BlendControllers"
|
||||
|
||||
#define AI_MDL_HL1_MATKEY_CHROME(type, N) "$mat.HL1.chrome", type, N
|
||||
|
||||
#endif // AI_MDL_HL1_IMPORT_DEFINITIONS_INCLUDED
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file HL1ImportSettings.h
|
||||
* @brief Half-Life 1 MDL loader configuration settings.
|
||||
*/
|
||||
|
||||
#ifndef AI_HL1IMPORTSETTINGS_INCLUDED
|
||||
#define AI_HL1IMPORTSETTINGS_INCLUDED
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Assimp {
|
||||
namespace MDL {
|
||||
namespace HalfLife {
|
||||
|
||||
struct HL1ImportSettings {
|
||||
HL1ImportSettings() :
|
||||
read_animations(false),
|
||||
read_animation_events(false),
|
||||
read_blend_controllers(false),
|
||||
read_sequence_groups_info(false),
|
||||
read_sequence_transitions(false),
|
||||
read_attachments(false),
|
||||
read_bone_controllers(false),
|
||||
read_hitboxes(false),
|
||||
read_textures(false),
|
||||
read_misc_global_info(false) {
|
||||
}
|
||||
|
||||
bool read_animations;
|
||||
bool read_animation_events;
|
||||
bool read_blend_controllers;
|
||||
bool read_sequence_groups_info;
|
||||
bool read_sequence_transitions;
|
||||
bool read_attachments;
|
||||
bool read_bone_controllers;
|
||||
bool read_hitboxes;
|
||||
bool read_textures;
|
||||
bool read_misc_global_info;
|
||||
};
|
||||
|
||||
} // namespace HalfLife
|
||||
} // namespace MDL
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // AI_HL1IMPORTSETTINGS_INCLUDED
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,241 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file HL1MDLLoader.h
|
||||
* @brief Declaration of the Half-Life 1 MDL loader.
|
||||
*/
|
||||
|
||||
#ifndef AI_HL1MDLLOADER_INCLUDED
|
||||
#define AI_HL1MDLLOADER_INCLUDED
|
||||
|
||||
#include "HL1FileData.h"
|
||||
#include "HL1ImportSettings.h"
|
||||
#include "UniqueNameGenerator.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <assimp/types.h>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/texture.h>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#include <assimp/DefaultIOSystem.h>
|
||||
#include <assimp/Exceptional.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace MDL {
|
||||
namespace HalfLife {
|
||||
|
||||
class HL1MDLLoader {
|
||||
public:
|
||||
HL1MDLLoader() = delete;
|
||||
HL1MDLLoader(const HL1MDLLoader &) = delete;
|
||||
|
||||
/** See variables descriptions at the end for more details. */
|
||||
HL1MDLLoader(
|
||||
aiScene *scene,
|
||||
IOSystem *io,
|
||||
const unsigned char *buffer,
|
||||
const std::string &file_path,
|
||||
const HL1ImportSettings &import_settings);
|
||||
|
||||
~HL1MDLLoader();
|
||||
|
||||
void load_file();
|
||||
|
||||
protected:
|
||||
/** \brief Validate the header data structure of a Half-Life 1 MDL file.
|
||||
* \param[in] header Input header to be validated.
|
||||
* \param[in] is_texture_header Whether or not we are reading an MDL
|
||||
* texture file.
|
||||
*/
|
||||
void validate_header(const Header_HL1 *header, bool is_texture_header);
|
||||
|
||||
void load_texture_file();
|
||||
void load_sequence_groups_files();
|
||||
void read_textures();
|
||||
void read_skins();
|
||||
void read_bones();
|
||||
void read_meshes();
|
||||
void read_animations();
|
||||
void read_sequence_groups_info();
|
||||
void read_sequence_infos();
|
||||
void read_sequence_transitions();
|
||||
void read_attachments();
|
||||
void read_hitboxes();
|
||||
void read_bone_controllers();
|
||||
void read_global_info();
|
||||
|
||||
private:
|
||||
void release_resources();
|
||||
|
||||
/** \brief Load a file and copy it's content to a buffer.
|
||||
* \param file_path The path to the file to be loaded.
|
||||
* \param buffer A pointer to a buffer to receive the data.
|
||||
*/
|
||||
template <typename MDLFileHeader>
|
||||
void load_file_into_buffer(const std::string &file_path, unsigned char *&buffer);
|
||||
|
||||
/** \brief Read an MDL texture.
|
||||
* \param[in] ptexture A pointer to an MDL texture.
|
||||
* \param[in] data A pointer to the data from \p ptexture.
|
||||
* \param[in] pal A pointer to the texture palette from \p ptexture.
|
||||
* \param[in,out] pResult A pointer to the output resulting Assimp texture.
|
||||
* \param[in,out] last_palette_color The last color from the image palette.
|
||||
*/
|
||||
void read_texture(const Texture_HL1 *ptexture,
|
||||
uint8_t *data, uint8_t *pal, aiTexture *pResult,
|
||||
aiColor3D &last_palette_color);
|
||||
|
||||
/** \brief This method reads a compressed anim value.
|
||||
* \param[in] panimvalue A pointer to the animation data.
|
||||
* \param[in] frame The frame to look for.
|
||||
* \param[in] bone_scale The current bone scale to apply to the compressed value.
|
||||
* \param[in,out] value The decompressed anim value at \p frame.
|
||||
*/
|
||||
void extract_anim_value(const AnimValue_HL1 *panimvalue,
|
||||
int frame, float bone_scale, float &value);
|
||||
|
||||
/**
|
||||
* \brief Given the number of blend animations, determine the number of blend controllers.
|
||||
*
|
||||
* \param[in] num_blend_animations The number of blend animations.
|
||||
* \param[out] num_blend_controllers The number of blend controllers.
|
||||
* \return True if the number of blend controllers was determined. False otherwise.
|
||||
*/
|
||||
static bool get_num_blend_controllers(const int num_blend_animations, int &num_blend_controllers);
|
||||
|
||||
/** Output scene to be filled */
|
||||
aiScene *scene_;
|
||||
|
||||
/** Output I/O handler. Required for additional IO operations. */
|
||||
IOSystem *io_;
|
||||
|
||||
/** Buffer from MDLLoader class. */
|
||||
const unsigned char *buffer_;
|
||||
|
||||
/** The full file path to the MDL file we are trying to load.
|
||||
* Used to locate other MDL files since MDL may store resources
|
||||
* in external MDL files. */
|
||||
const std::string &file_path_;
|
||||
|
||||
/** Configuration for HL1 MDL */
|
||||
const HL1ImportSettings &import_settings_;
|
||||
|
||||
/** Main MDL header. */
|
||||
const Header_HL1 *header_;
|
||||
|
||||
/** External MDL texture header. */
|
||||
const Header_HL1 *texture_header_;
|
||||
|
||||
/** External MDL animation headers.
|
||||
* One for each loaded animation file. */
|
||||
SequenceHeader_HL1 **anim_headers_;
|
||||
|
||||
/** Texture file data. */
|
||||
unsigned char *texture_buffer_;
|
||||
|
||||
/** Animation files data. */
|
||||
unsigned char **anim_buffers_;
|
||||
|
||||
/** The number of sequence groups. */
|
||||
int num_sequence_groups_;
|
||||
|
||||
/** The list of children to be appended to the scene's root node. */
|
||||
std::vector<aiNode *> rootnode_children_;
|
||||
|
||||
/** A unique name generator. Used to generate names for MDL values
|
||||
* that may have empty/duplicate names. */
|
||||
UniqueNameGenerator unique_name_generator_;
|
||||
|
||||
/** The list of unique sequence names. */
|
||||
std::vector<std::string> unique_sequence_names_;
|
||||
|
||||
/** The list of unique sequence groups names. */
|
||||
std::vector<std::string> unique_sequence_groups_names_;
|
||||
|
||||
/** Structure to store temporary bone information. */
|
||||
struct TempBone {
|
||||
|
||||
TempBone() :
|
||||
node(nullptr),
|
||||
absolute_transform(),
|
||||
offset_matrix() {}
|
||||
|
||||
aiNode *node;
|
||||
aiMatrix4x4 absolute_transform;
|
||||
aiMatrix4x4 offset_matrix;
|
||||
};
|
||||
|
||||
std::vector<TempBone> temp_bones_;
|
||||
|
||||
/** The number of available bone controllers in the model. */
|
||||
int num_blend_controllers_;
|
||||
|
||||
/** Self explanatory. */
|
||||
int total_models_;
|
||||
};
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
template <typename MDLFileHeader>
|
||||
void HL1MDLLoader::load_file_into_buffer(const std::string &file_path, unsigned char *&buffer) {
|
||||
if (!io_->Exists(file_path))
|
||||
throw DeadlyImportError("Missing file " + DefaultIOSystem::fileName(file_path) + ".");
|
||||
|
||||
std::unique_ptr<IOStream> file(io_->Open(file_path));
|
||||
|
||||
if (file.get() == NULL)
|
||||
throw DeadlyImportError("Failed to open MDL file " + DefaultIOSystem::fileName(file_path) + ".");
|
||||
|
||||
const size_t file_size = file->FileSize();
|
||||
if (file_size < sizeof(MDLFileHeader))
|
||||
throw DeadlyImportError("MDL file is too small.");
|
||||
|
||||
buffer = new unsigned char[1 + file_size];
|
||||
file->Read((void *)buffer, 1, file_size);
|
||||
buffer[file_size] = '\0';
|
||||
}
|
||||
|
||||
} // namespace HalfLife
|
||||
} // namespace MDL
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // AI_HL1MDLLOADER_INCLUDED
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file HL1MeshTrivert.h
|
||||
* @brief This file contains the class declaration for the
|
||||
* HL1 mesh trivert class.
|
||||
*/
|
||||
|
||||
#ifndef AI_HL1MESHTRIVERT_INCLUDED
|
||||
#define AI_HL1MESHTRIVERT_INCLUDED
|
||||
|
||||
#include "HL1FileData.h"
|
||||
|
||||
namespace Assimp {
|
||||
namespace MDL {
|
||||
namespace HalfLife {
|
||||
|
||||
/* A class to help map model triverts to mesh triverts. */
|
||||
struct HL1MeshTrivert {
|
||||
HL1MeshTrivert() :
|
||||
vertindex(-1),
|
||||
normindex(-1),
|
||||
s(0),
|
||||
t(0),
|
||||
localindex(-1) {
|
||||
}
|
||||
|
||||
HL1MeshTrivert(short vertindex, short normindex, short s, short t, short localindex) :
|
||||
vertindex(vertindex),
|
||||
normindex(normindex),
|
||||
s(s),
|
||||
t(t),
|
||||
localindex() {
|
||||
}
|
||||
|
||||
HL1MeshTrivert(const Trivert &a) :
|
||||
vertindex(a.vertindex),
|
||||
normindex(a.normindex),
|
||||
s(a.s),
|
||||
t(a.t),
|
||||
localindex(-1) {
|
||||
}
|
||||
|
||||
inline bool operator==(const Trivert &a) const {
|
||||
return vertindex == a.vertindex &&
|
||||
normindex == a.normindex &&
|
||||
s == a.s &&
|
||||
t == a.t;
|
||||
}
|
||||
|
||||
inline bool operator!=(const Trivert &a) const {
|
||||
return !(*this == a);
|
||||
}
|
||||
|
||||
inline bool operator==(const HL1MeshTrivert &a) const {
|
||||
return localindex == a.localindex &&
|
||||
vertindex == a.vertindex &&
|
||||
normindex == a.normindex &&
|
||||
s == a.s &&
|
||||
t == a.t;
|
||||
}
|
||||
|
||||
inline bool operator!=(const HL1MeshTrivert &a) const {
|
||||
return !(*this == a);
|
||||
}
|
||||
|
||||
inline HL1MeshTrivert &operator=(const Trivert &other) {
|
||||
vertindex = other.vertindex;
|
||||
normindex = other.normindex;
|
||||
s = other.s;
|
||||
t = other.t;
|
||||
return *this;
|
||||
}
|
||||
|
||||
short vertindex;
|
||||
short normindex;
|
||||
short s, t;
|
||||
short localindex;
|
||||
};
|
||||
|
||||
struct HL1MeshFace {
|
||||
short v0, v1, v2;
|
||||
};
|
||||
|
||||
} // namespace HalfLife
|
||||
} // namespace MDL
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // AI_HL1MESHTRIVERT_INCLUDED
|
|
@ -39,11 +39,29 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/* Helper macro to set a pointer to NULL in debug builds
|
||||
*/
|
||||
#if (defined ASSIMP_BUILD_DEBUG)
|
||||
# define AI_DEBUG_INVALIDATE_PTR(x) x = NULL;
|
||||
#else
|
||||
# define AI_DEBUG_INVALIDATE_PTR(x)
|
||||
#endif
|
||||
/** @file HalfLifeMDLBaseHeader.h */
|
||||
|
||||
#ifndef AI_HALFLIFEMDLBASEHEADER_INCLUDED
|
||||
#define AI_HALFLIFEMDLBASEHEADER_INCLUDED
|
||||
|
||||
#include <assimp/types.h>
|
||||
|
||||
namespace Assimp {
|
||||
namespace MDL {
|
||||
namespace HalfLife {
|
||||
|
||||
/** Used to interface different Valve MDL formats. */
|
||||
struct HalfLifeMDLBaseHeader
|
||||
{
|
||||
//! Magic number: "IDST"/"IDSQ"
|
||||
char ident[4];
|
||||
|
||||
//! The file format version.
|
||||
int32_t version;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // AI_HALFLIFEMDLBASEHEADER_INCLUDED
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file LogFunctions.h */
|
||||
|
||||
#ifndef AI_MDL_HALFLIFE_LOGFUNCTIONS_INCLUDED
|
||||
#define AI_MDL_HALFLIFE_LOGFUNCTIONS_INCLUDED
|
||||
|
||||
#include <assimp/Logger.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace Assimp {
|
||||
namespace MDL {
|
||||
namespace HalfLife {
|
||||
|
||||
/**
|
||||
* \brief A function to log precise messages regarding limits exceeded.
|
||||
*
|
||||
* \param[in] subject Subject.
|
||||
* \param[in] current_amount Current amount.
|
||||
* \param[in] direct_object Direct object.
|
||||
* LIMIT Limit constant.
|
||||
*
|
||||
* Example: Model has 100 textures, which exceeds the limit (50)
|
||||
*
|
||||
* where \p subject is 'Model'
|
||||
* \p current_amount is '100'
|
||||
* \p direct_object is 'textures'
|
||||
* LIMIT is '50'
|
||||
*/
|
||||
template <int LIMIT>
|
||||
static inline void log_warning_limit_exceeded(
|
||||
const std::string &subject, int current_amount,
|
||||
const std::string &direct_object) {
|
||||
|
||||
ASSIMP_LOG_WARN(MDL_HALFLIFE_LOG_HEADER
|
||||
+ subject
|
||||
+ " has "
|
||||
+ std::to_string(current_amount) + " "
|
||||
+ direct_object
|
||||
+ ", which exceeds the limit ("
|
||||
+ std::to_string(LIMIT)
|
||||
+ ")");
|
||||
}
|
||||
|
||||
/** \brief Same as above, but uses 'Model' as the subject. */
|
||||
template <int LIMIT>
|
||||
static inline void log_warning_limit_exceeded(int current_amount,
|
||||
const std::string &direct_object) {
|
||||
log_warning_limit_exceeded<LIMIT>("Model", current_amount, direct_object);
|
||||
}
|
||||
|
||||
} // namespace HalfLife
|
||||
} // namespace MDL
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // AI_MDL_HALFLIFE_LOGFUNCTIONS_INCLUDED
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file UniqueNameGenerator.cpp
|
||||
* @brief Implementation for the unique name generator.
|
||||
*/
|
||||
|
||||
#include "UniqueNameGenerator.h"
|
||||
#include <algorithm>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <numeric>
|
||||
|
||||
namespace Assimp {
|
||||
namespace MDL {
|
||||
namespace HalfLife {
|
||||
|
||||
UniqueNameGenerator::UniqueNameGenerator() :
|
||||
template_name_("unnamed"),
|
||||
separator_("_") {
|
||||
}
|
||||
|
||||
UniqueNameGenerator::UniqueNameGenerator(const char *template_name) :
|
||||
template_name_(template_name),
|
||||
separator_("_") {
|
||||
}
|
||||
|
||||
UniqueNameGenerator::UniqueNameGenerator(const char *template_name, const char *separator) :
|
||||
template_name_(template_name),
|
||||
separator_(separator) {
|
||||
}
|
||||
|
||||
UniqueNameGenerator::~UniqueNameGenerator() {
|
||||
}
|
||||
|
||||
void UniqueNameGenerator::make_unique(std::vector<std::string> &names) {
|
||||
struct DuplicateInfo {
|
||||
DuplicateInfo() :
|
||||
indices(),
|
||||
next_id(0) {
|
||||
}
|
||||
|
||||
std::list<size_t> indices;
|
||||
size_t next_id;
|
||||
};
|
||||
|
||||
std::vector<size_t> empty_names_indices;
|
||||
std::vector<size_t> template_name_duplicates;
|
||||
std::map<std::string, DuplicateInfo> names_to_duplicates;
|
||||
|
||||
const std::string template_name_with_separator(template_name_ + separator_);
|
||||
|
||||
auto format_name = [&](const std::string &base_name, size_t id) -> std::string {
|
||||
return base_name + separator_ + std::to_string(id);
|
||||
};
|
||||
|
||||
auto generate_unique_name = [&](const std::string &base_name) -> std::string {
|
||||
auto *duplicate_info = &names_to_duplicates[base_name];
|
||||
|
||||
std::string new_name = "";
|
||||
|
||||
bool found_identical_name;
|
||||
bool tried_with_base_name_only = false;
|
||||
do {
|
||||
// Assume that no identical name exists.
|
||||
found_identical_name = false;
|
||||
|
||||
if (!tried_with_base_name_only) {
|
||||
// First try with only the base name.
|
||||
new_name = base_name;
|
||||
} else {
|
||||
// Create the name expected to be unique.
|
||||
new_name = format_name(base_name, duplicate_info->next_id);
|
||||
}
|
||||
|
||||
// Check in the list of duplicates for an identical name.
|
||||
for (size_t i = 0;
|
||||
i < names.size() &&
|
||||
!found_identical_name;
|
||||
++i) {
|
||||
if (new_name == names[i])
|
||||
found_identical_name = true;
|
||||
}
|
||||
|
||||
if (tried_with_base_name_only)
|
||||
++duplicate_info->next_id;
|
||||
|
||||
tried_with_base_name_only = true;
|
||||
|
||||
} while (found_identical_name);
|
||||
|
||||
return new_name;
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < names.size(); ++i) {
|
||||
// Check for empty names.
|
||||
if (names[i].find_first_not_of(' ') == std::string::npos) {
|
||||
empty_names_indices.push_back(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check for potential duplicate.
|
||||
a) Either if this name is the same as the template name or
|
||||
b) <template name><separator> is found at the beginning. */
|
||||
if (names[i] == template_name_ ||
|
||||
names[i].substr(0, template_name_with_separator.length()) == template_name_with_separator)
|
||||
template_name_duplicates.push_back(i);
|
||||
|
||||
// Map each unique name to it's duplicate.
|
||||
if (names_to_duplicates.count(names[i]) == 0)
|
||||
names_to_duplicates.insert({ names[i], DuplicateInfo()});
|
||||
else
|
||||
names_to_duplicates[names[i]].indices.push_back(i);
|
||||
}
|
||||
|
||||
// Make every non-empty name unique.
|
||||
for (auto it = names_to_duplicates.begin();
|
||||
it != names_to_duplicates.end(); ++it) {
|
||||
for (auto it2 = it->second.indices.begin();
|
||||
it2 != it->second.indices.end();
|
||||
++it2)
|
||||
names[*it2] = generate_unique_name(it->first);
|
||||
}
|
||||
|
||||
// Generate a unique name for every empty string.
|
||||
if (template_name_duplicates.size()) {
|
||||
// At least one string ressembles to <template name>.
|
||||
for (auto it = empty_names_indices.begin();
|
||||
it != empty_names_indices.end(); ++it)
|
||||
names[*it] = generate_unique_name(template_name_);
|
||||
} else {
|
||||
// No string alike <template name> exists.
|
||||
size_t i = 0;
|
||||
for (auto it = empty_names_indices.begin();
|
||||
it != empty_names_indices.end(); ++it, ++i)
|
||||
names[*it] = format_name(template_name_, i);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace HalfLife
|
||||
} // namespace MDL
|
||||
} // namespace Assimp
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Open Asset Import Library (assimp)
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
Copyright (c) 2006-2019, assimp team
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use of this software in source and binary forms,
|
||||
with or without modification, are permitted provided that the following
|
||||
conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer in the documentation and/or other
|
||||
materials provided with the distribution.
|
||||
|
||||
* Neither the name of the assimp team, nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior
|
||||
written permission of the assimp team.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/** @file UniqueNameGenerator.h
|
||||
* @brief Declaration of the unique name generator.
|
||||
*/
|
||||
|
||||
#ifndef AI_UNIQUENAMEGENERATOR_INCLUDED
|
||||
#define AI_UNIQUENAMEGENERATOR_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Assimp {
|
||||
namespace MDL {
|
||||
namespace HalfLife {
|
||||
|
||||
class UniqueNameGenerator {
|
||||
public:
|
||||
UniqueNameGenerator();
|
||||
UniqueNameGenerator(const char *template_name);
|
||||
UniqueNameGenerator(const char *template_name, const char *separator);
|
||||
~UniqueNameGenerator();
|
||||
|
||||
inline void set_template_name(const char *template_name) {
|
||||
template_name_ = template_name;
|
||||
}
|
||||
inline void set_separator(const char *separator) {
|
||||
separator_ = separator;
|
||||
}
|
||||
|
||||
void make_unique(std::vector<std::string> &names);
|
||||
|
||||
private:
|
||||
std::string template_name_;
|
||||
std::string separator_;
|
||||
};
|
||||
|
||||
} // namespace HalfLife
|
||||
} // namespace MDL
|
||||
} // namespace Assimp
|
||||
|
||||
#endif // AI_UNIQUENAMEGENERATOR_INCLUDED
|
|
@ -5,8 +5,6 @@ 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,
|
||||
|
@ -53,8 +51,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "MDL/MDLLoader.h"
|
||||
#include "MDL/MDLDefaultColorMap.h"
|
||||
#include "MD2/MD2FileData.h"
|
||||
#include "MDL/HalfLife/HL1MDLLoader.h"
|
||||
|
||||
#include <assimp/Macros.h>
|
||||
#include <assimp/qnan.h>
|
||||
#include <assimp/StringUtils.h>
|
||||
#include <assimp/Importer.hpp>
|
||||
|
@ -94,23 +92,24 @@ static const aiImporterDesc desc = {
|
|||
// ------------------------------------------------------------------------------------------------
|
||||
// Constructor to be privately used by Importer
|
||||
MDLImporter::MDLImporter()
|
||||
: configFrameID(),
|
||||
mBuffer(),
|
||||
iGSFileVersion(),
|
||||
pIOHandler(),
|
||||
pScene(),
|
||||
iFileSize()
|
||||
{}
|
||||
: configFrameID()
|
||||
, mBuffer()
|
||||
, iGSFileVersion()
|
||||
, pIOHandler()
|
||||
, pScene()
|
||||
, iFileSize() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor, private as well
|
||||
MDLImporter::~MDLImporter()
|
||||
{}
|
||||
MDLImporter::~MDLImporter() {
|
||||
// empty
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Returns whether the class can handle the format of the given file.
|
||||
bool MDLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
||||
{
|
||||
bool MDLImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const {
|
||||
const std::string extension = GetExtension(pFile);
|
||||
|
||||
// if check for extension is not enough, check for the magic tokens
|
||||
|
@ -144,6 +143,18 @@ void MDLImporter::SetupProperties(const Importer* pImp)
|
|||
|
||||
// AI_CONFIG_IMPORT_MDL_COLORMAP - palette file
|
||||
configPalette = pImp->GetPropertyString(AI_CONFIG_IMPORT_MDL_COLORMAP,"colormap.lmp");
|
||||
|
||||
// Read configuration specific to MDL (Half-Life 1).
|
||||
mHL1ImportSettings.read_animations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_ANIMATIONS, true);
|
||||
if (mHL1ImportSettings.read_animations) {
|
||||
mHL1ImportSettings.read_animation_events = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_ANIMATION_EVENTS, true);
|
||||
mHL1ImportSettings.read_blend_controllers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_BLEND_CONTROLLERS, true);
|
||||
mHL1ImportSettings.read_sequence_transitions = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_SEQUENCE_TRANSITIONS, true);
|
||||
}
|
||||
mHL1ImportSettings.read_attachments = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_ATTACHMENTS, true);
|
||||
mHL1ImportSettings.read_bone_controllers = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_BONE_CONTROLLERS, true);
|
||||
mHL1ImportSettings.read_hitboxes = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_HITBOXES, true);
|
||||
mHL1ImportSettings.read_misc_global_info = pImp->GetPropertyBool(AI_CONFIG_IMPORT_MDL_HL1_READ_MISC_GLOBAL_INFO, true);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
@ -168,9 +179,9 @@ void MDLImporter::InternReadFile( const std::string& pFile,
|
|||
}
|
||||
|
||||
// This should work for all other types of MDL files, too ...
|
||||
// the quake header is one of the smallest, afaik
|
||||
// the HL1 sequence group header is one of the smallest, afaik
|
||||
iFileSize = (unsigned int)file->FileSize();
|
||||
if( iFileSize < sizeof(MDL::Header)) {
|
||||
if( iFileSize < sizeof(MDL::HalfLife::SequenceHeader_HL1)) {
|
||||
throw DeadlyImportError( "MDL File is too small.");
|
||||
}
|
||||
|
||||
|
@ -226,10 +237,20 @@ void MDLImporter::InternReadFile( const std::string& pFile,
|
|||
else if (AI_MDL_MAGIC_NUMBER_BE_HL2a == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2a == iMagicWord ||
|
||||
AI_MDL_MAGIC_NUMBER_BE_HL2b == iMagicWord || AI_MDL_MAGIC_NUMBER_LE_HL2b == iMagicWord)
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("MDL subtype: Source(tm) Engine, magic word is IDST/IDSQ");
|
||||
iGSFileVersion = 0;
|
||||
|
||||
HalfLife::HalfLifeMDLBaseHeader *pHeader = (HalfLife::HalfLifeMDLBaseHeader *)mBuffer;
|
||||
if (pHeader->version == AI_MDL_HL1_VERSION)
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("MDL subtype: Half-Life 1/Goldsrc Engine, magic word is IDST/IDSQ");
|
||||
InternReadFile_HL1(pFile, iMagicWord);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSIMP_LOG_DEBUG("MDL subtype: Source(tm) Engine, magic word is IDST/IDSQ");
|
||||
InternReadFile_HL2();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// print the magic word to the log file
|
||||
throw DeadlyImportError( "Unknown MDL subformat " + pFile +
|
||||
|
@ -404,23 +425,15 @@ void MDLImporter::InternReadFile_Quake1() {
|
|||
|
||||
// now get a pointer to the first frame in the file
|
||||
BE_NCONST MDL::Frame* pcFrames = (BE_NCONST MDL::Frame*)szCurrent;
|
||||
BE_NCONST MDL::SimpleFrame* pcFirstFrame;
|
||||
MDL::SimpleFrame* pcFirstFrame;
|
||||
|
||||
if (0 == pcFrames->type) {
|
||||
// get address of single frame
|
||||
pcFirstFrame = &pcFrames->frame;
|
||||
pcFirstFrame =( MDL::SimpleFrame*) &pcFrames->frame;
|
||||
} else {
|
||||
// get the first frame in the group
|
||||
|
||||
#if 1
|
||||
// FIXME: the cast is wrong and cause a warning on clang 5.0
|
||||
// disable this code for now, fix it later
|
||||
ai_assert(false && "Bad pointer cast");
|
||||
pcFirstFrame = nullptr; // Workaround: msvc++ C4703 error
|
||||
#else
|
||||
BE_NCONST MDL::GroupFrame* pcFrames2 = (BE_NCONST MDL::GroupFrame*)pcFrames;
|
||||
pcFirstFrame = (BE_NCONST MDL::SimpleFrame*)(&pcFrames2->time + pcFrames->type);
|
||||
#endif
|
||||
BE_NCONST MDL::GroupFrame* pcFrames2 = (BE_NCONST MDL::GroupFrame*) pcFrames;
|
||||
pcFirstFrame = &(pcFrames2->frames[0]);
|
||||
}
|
||||
BE_NCONST MDL::Vertex* pcVertices = (BE_NCONST MDL::Vertex*) ((pcFirstFrame->name) + sizeof(pcFirstFrame->name));
|
||||
VALIDATE_FILE_SIZE((const unsigned char*)(pcVertices + pcHeader->num_verts));
|
||||
|
@ -1562,7 +1575,7 @@ void MDLImporter::InternReadFile_3DGS_MDL7( )
|
|||
const size_t maxSize(buffersize - (i*AI_MDL7_MAX_GROUPNAMESIZE));
|
||||
pcNode->mName.length = ai_snprintf(szBuffer, maxSize, "Group_%u", p);
|
||||
} else {
|
||||
pcNode->mName.length = ::strlen(szBuffer);
|
||||
pcNode->mName.length = (ai_uint32)::strlen(szBuffer);
|
||||
}
|
||||
::strncpy(pcNode->mName.data,szBuffer,MAXLEN-1);
|
||||
++p;
|
||||
|
@ -1965,6 +1978,23 @@ void MDLImporter::JoinSkins_3DGS_MDL7(
|
|||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read a Half-life 1 MDL
|
||||
void MDLImporter::InternReadFile_HL1(const std::string& pFile, const uint32_t iMagicWord)
|
||||
{
|
||||
// We can't correctly load an MDL from a MDL "sequence" file.
|
||||
if (iMagicWord == AI_MDL_MAGIC_NUMBER_BE_HL2b || iMagicWord == AI_MDL_MAGIC_NUMBER_LE_HL2b)
|
||||
throw DeadlyImportError("Impossible to properly load a model from an MDL sequence file.");
|
||||
|
||||
// Read the MDL file.
|
||||
HalfLife::HL1MDLLoader loader(
|
||||
pScene,
|
||||
pIOHandler,
|
||||
mBuffer,
|
||||
pFile,
|
||||
mHL1ImportSettings);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Read a half-life 2 MDL
|
||||
void MDLImporter::InternReadFile_HL2( )
|
||||
|
|
|
@ -51,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/BaseImporter.h>
|
||||
#include "MDLFileData.h"
|
||||
#include "HMP/HalfLifeFileData.h"
|
||||
#include "HalfLife/HL1ImportSettings.h"
|
||||
|
||||
struct aiNode;
|
||||
struct aiTexture;
|
||||
|
@ -77,6 +78,7 @@ using namespace MDL;
|
|||
* <li>3D Game Studio MDL3, MDL4</li>
|
||||
* <li>3D Game Studio MDL5</li>
|
||||
* <li>3D Game Studio MDL7</li>
|
||||
* <li>Halflife 1</li>
|
||||
* <li>Halflife 2</li>
|
||||
* </ul>
|
||||
* These formats are partially identical and it would be possible to load
|
||||
|
@ -89,16 +91,12 @@ public:
|
|||
MDLImporter();
|
||||
~MDLImporter();
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Returns whether the class can handle the format of the given file.
|
||||
* See BaseImporter::CanRead() for details. */
|
||||
bool CanRead( const std::string& pFile, IOSystem* pIOHandler,
|
||||
bool checkSig) const;
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Called prior to ReadFile().
|
||||
* The function is a request to the importer to update its configuration
|
||||
|
@ -107,8 +105,6 @@ public:
|
|||
void SetupProperties(const Importer* pImp);
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Return importer meta information.
|
||||
* See #BaseImporter::GetInfo for the details
|
||||
|
@ -122,8 +118,6 @@ protected:
|
|||
void InternReadFile( const std::string& pFile, aiScene* pScene,
|
||||
IOSystem* pIOHandler);
|
||||
|
||||
protected:
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Import a quake 1 MDL file (IDPO)
|
||||
*/
|
||||
|
@ -139,6 +133,11 @@ protected:
|
|||
*/
|
||||
void InternReadFile_3DGS_MDL7( );
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Import a Half-Life 1 MDL file
|
||||
*/
|
||||
void InternReadFile_HL1(const std::string& pFile, const uint32_t iMagicWord);
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Import a CS:S/HL2 MDL file (not fully implemented)
|
||||
*/
|
||||
|
@ -154,7 +153,6 @@ protected:
|
|||
void SizeCheck(const void* szPos);
|
||||
void SizeCheck(const void* szPos, const char* szFile, unsigned int iLine);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Validate the header data structure of a game studio MDL7 file
|
||||
* \param pcHeader Input header to be validated
|
||||
|
@ -167,7 +165,6 @@ protected:
|
|||
*/
|
||||
void ValidateHeader_Quake1(const MDL::Header* pcHeader);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Try to load a palette from the current directory (colormap.lmp)
|
||||
* If it is not found the default palette of Quake1 is returned
|
||||
|
@ -179,9 +176,8 @@ protected:
|
|||
*/
|
||||
void FreePalette(const unsigned char* pszColorMap);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Load a paletized texture from the file and convert it to 32bpp
|
||||
/** Load a palletized texture from the file and convert it to 32bpp
|
||||
*/
|
||||
void CreateTextureARGB8_3DGS_MDL3(const unsigned char* szData);
|
||||
|
||||
|
@ -195,7 +191,6 @@ protected:
|
|||
unsigned int iType,
|
||||
unsigned int* piSkip);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Used to load textures from MDL5
|
||||
* \param szData Input data
|
||||
|
@ -206,7 +201,6 @@ protected:
|
|||
unsigned int iType,
|
||||
unsigned int* piSkip);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Checks whether a texture can be replaced with a single color
|
||||
* This is useful for all file formats before MDL7 (all those
|
||||
|
@ -218,14 +212,12 @@ protected:
|
|||
*/
|
||||
aiColor4D ReplaceTextureWithColor(const aiTexture* pcTexture);
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Converts the absolute texture coordinates in MDL5 files to
|
||||
* relative in a range between 0 and 1
|
||||
*/
|
||||
void CalculateUVCoordinates_MDL5();
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Read an UV coordinate from the file. If the file format is not
|
||||
* MDL5, the function calculates relative texture coordinates
|
||||
|
@ -245,7 +237,6 @@ protected:
|
|||
*/
|
||||
void SetupMaterialProperties_3DGS_MDL5_Quake1( );
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
/** Parse a skin lump in a MDL7/HMP7 file with all of its features
|
||||
* variant 1: Current cursor position is the beginning of the skin header
|
||||
|
@ -452,6 +443,9 @@ protected:
|
|||
|
||||
/** Size of the input file in bytes */
|
||||
unsigned int iFileSize;
|
||||
|
||||
/* Configuration for HL1 MDL */
|
||||
HalfLife::HL1ImportSettings mHL1ImportSettings;
|
||||
};
|
||||
|
||||
} // end of namespace Assimp
|
||||
|
|
|
@ -541,7 +541,7 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
|
|||
size_t iLen2 = iLen+1;
|
||||
iLen2 = iLen2 > MAXLEN ? MAXLEN : iLen2;
|
||||
memcpy(szFile.data,(const char*)szCurrent,iLen2);
|
||||
szFile.length = iLen;
|
||||
szFile.length = (ai_uint32)iLen;
|
||||
|
||||
szCurrent += iLen2;
|
||||
|
||||
|
@ -710,7 +710,7 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
|
|||
aiString szFile;
|
||||
const size_t iLen = strlen((const char*)szCurrent);
|
||||
::memcpy(szFile.data,(const char*)szCurrent,iLen+1);
|
||||
szFile.length = iLen;
|
||||
szFile.length = (ai_uint32)iLen;
|
||||
|
||||
pcMatOut->AddProperty(&szFile,AI_MATKEY_TEXTURE_DIFFUSE(0));
|
||||
|
||||
|
@ -831,7 +831,7 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7(
|
|||
aiString szFile;
|
||||
::memcpy(szFile.data,pcSkin->texture_name,sizeof(pcSkin->texture_name));
|
||||
szFile.data[sizeof(pcSkin->texture_name)] = '\0';
|
||||
szFile.length = ::strlen(szFile.data);
|
||||
szFile.length = (ai_uint32)::strlen(szFile.data);
|
||||
|
||||
pcMatOut->AddProperty(&szFile,AI_MATKEY_NAME);
|
||||
}
|
||||
|
|
|
@ -51,7 +51,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <assimp/types.h>
|
||||
#include <assimp/material.h>
|
||||
#include <assimp/DefaultLogger.hpp>
|
||||
#include <assimp/Macros.h>
|
||||
|
||||
using namespace Assimp;
|
||||
|
||||
|
@ -274,14 +273,14 @@ aiReturn aiGetMaterialColor(const aiMaterial* pMat,
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Get a aiUVTransform (4 floats) from the material
|
||||
// Get a aiUVTransform (5 floats) from the material
|
||||
aiReturn aiGetMaterialUVTransform(const aiMaterial* pMat,
|
||||
const char* pKey,
|
||||
unsigned int type,
|
||||
unsigned int index,
|
||||
aiUVTransform* pOut)
|
||||
{
|
||||
unsigned int iMax = 4;
|
||||
unsigned int iMax = 5;
|
||||
return aiGetMaterialFloatArray(pMat,pKey,type,index,(ai_real*)pOut,&iMax);
|
||||
}
|
||||
|
||||
|
@ -472,12 +471,12 @@ aiReturn aiMaterial::AddBinaryProperty (const void* pInput,
|
|||
aiPropertyTypeInfo pType
|
||||
)
|
||||
{
|
||||
ai_assert( pInput != NULL );
|
||||
ai_assert( pKey != NULL );
|
||||
ai_assert( pInput != nullptr );
|
||||
ai_assert(pKey != nullptr );
|
||||
ai_assert( 0 != pSizeInBytes );
|
||||
|
||||
if ( 0 == pSizeInBytes ) {
|
||||
|
||||
return AI_FAILURE;
|
||||
}
|
||||
|
||||
// first search the list whether there is already an entry with this key
|
||||
|
@ -505,7 +504,7 @@ aiReturn aiMaterial::AddBinaryProperty (const void* pInput,
|
|||
pcNew->mData = new char[pSizeInBytes];
|
||||
memcpy (pcNew->mData,pInput,pSizeInBytes);
|
||||
|
||||
pcNew->mKey.length = ::strlen(pKey);
|
||||
pcNew->mKey.length = (ai_uint32)::strlen(pKey);
|
||||
ai_assert ( MAXLEN > pcNew->mKey.length);
|
||||
strcpy( pcNew->mKey.data, pKey );
|
||||
|
||||
|
@ -545,23 +544,7 @@ aiReturn aiMaterial::AddProperty (const aiString* pInput,
|
|||
unsigned int type,
|
||||
unsigned int index)
|
||||
{
|
||||
// We don't want to add the whole buffer .. write a 32 bit length
|
||||
// prefix followed by the zero-terminated UTF8 string.
|
||||
// (HACK) I don't want to break the ABI now, but we definitely
|
||||
// ought to change aiString::mLength to uint32_t one day.
|
||||
if (sizeof(size_t) == 8) {
|
||||
aiString copy = *pInput;
|
||||
uint32_t* s = reinterpret_cast<uint32_t*>(©.length);
|
||||
s[1] = static_cast<uint32_t>(pInput->length);
|
||||
|
||||
return AddBinaryProperty(s+1,
|
||||
static_cast<unsigned int>(pInput->length+1+4),
|
||||
pKey,
|
||||
type,
|
||||
index,
|
||||
aiPTI_String);
|
||||
}
|
||||
ai_assert(sizeof(size_t)==4);
|
||||
ai_assert(sizeof(ai_uint32)==4);
|
||||
return AddBinaryProperty(pInput,
|
||||
static_cast<unsigned int>(pInput->length+1+4),
|
||||
pKey,
|
||||
|
|
|
@ -79,10 +79,7 @@ using namespace std;
|
|||
ObjFileImporter::ObjFileImporter()
|
||||
: m_Buffer()
|
||||
, m_pRootObject( nullptr )
|
||||
, m_strAbsPath( "" ) {
|
||||
DefaultIOSystem io;
|
||||
m_strAbsPath = io.getOsSeparator();
|
||||
}
|
||||
, m_strAbsPath( std::string(1, DefaultIOSystem().getOsSeparator()) ) {}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
// Destructor.
|
||||
|
|
|
@ -244,8 +244,8 @@ void ObjFileParser::copyNextWord(char *pBuffer, size_t length) {
|
|||
size_t index = 0;
|
||||
m_DataIt = getNextWord<DataArrayIt>(m_DataIt, m_DataItEnd);
|
||||
if ( *m_DataIt == '\\' ) {
|
||||
m_DataIt++;
|
||||
m_DataIt++;
|
||||
++m_DataIt;
|
||||
++m_DataIt;
|
||||
m_DataIt = getNextWord<DataArrayIt>( m_DataIt, m_DataItEnd );
|
||||
}
|
||||
while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) {
|
||||
|
|
|
@ -373,10 +373,11 @@ void PlyExporter::WriteMeshIndices(const aiMesh* m, unsigned int offset)
|
|||
{
|
||||
for (unsigned int i = 0; i < m->mNumFaces; ++i) {
|
||||
const aiFace& f = m->mFaces[i];
|
||||
mOutput << f.mNumIndices << " ";
|
||||
mOutput << f.mNumIndices;
|
||||
for(unsigned int c = 0; c < f.mNumIndices; ++c) {
|
||||
mOutput << (f.mIndices[c] + offset) << (c == f.mNumIndices-1 ? endl : " ");
|
||||
mOutput << " " << (f.mIndices[c] + offset);
|
||||
}
|
||||
mOutput << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
// internal headers
|
||||
#include "PlyLoader.h"
|
||||
#include <assimp/IOStreamBuffer.h>
|
||||
#include <assimp/Macros.h>
|
||||
#include <memory>
|
||||
#include <assimp/IOSystem.hpp>
|
||||
#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_
|
|
@ -212,7 +212,7 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
// project tangent and bitangent into the plane formed by the vertex' normal
|
||||
aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]);
|
||||
aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]);
|
||||
localTangent.Normalize(); localBitangent.Normalize();
|
||||
localTangent.NormalizeSafe(); localBitangent.NormalizeSafe();
|
||||
|
||||
// reconstruct tangent/bitangent according to normal and bitangent/tangent when it's infinite or NaN.
|
||||
bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z);
|
||||
|
@ -220,10 +220,10 @@ bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex)
|
|||
if (invalid_tangent != invalid_bitangent) {
|
||||
if (invalid_tangent) {
|
||||
localTangent = meshNorm[p] ^ localBitangent;
|
||||
localTangent.Normalize();
|
||||
localTangent.NormalizeSafe();
|
||||
} else {
|
||||
localBitangent = localTangent ^ meshNorm[p];
|
||||
localBitangent.Normalize();
|
||||
localBitangent.NormalizeSafe();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -354,12 +354,12 @@ void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D&
|
|||
}
|
||||
else if (axis * base_axis_z >= angle_epsilon) {
|
||||
FindMeshCenter(mesh, center, min, max);
|
||||
diffu = max.y - min.y;
|
||||
diffv = max.z - min.z;
|
||||
diffu = max.x - min.x;
|
||||
diffv = max.y - min.y;
|
||||
|
||||
for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) {
|
||||
const aiVector3D& pos = mesh->mVertices[pnt];
|
||||
out[pnt].Set((pos.y - min.y) / diffu,(pos.x - min.x) / diffv,0.0);
|
||||
out[pnt].Set((pos.x - min.x) / diffu,(pos.y - min.y) / diffv,0.0);
|
||||
}
|
||||
}
|
||||
// slower code path in case the mapping axis is not one of the coordinate system axes
|
||||
|
|
|
@ -137,8 +137,9 @@ public:
|
|||
// -------------------------------------------------------------------
|
||||
void Execute( aiScene* pScene);
|
||||
|
||||
protected:
|
||||
void ProcessMesh( aiMesh* pMesh);
|
||||
public:
|
||||
/** Some other types of post-processing require winding order flips */
|
||||
static void ProcessMesh( aiMesh* pMesh);
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
@ -52,7 +52,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "FindInvalidDataProcess.h"
|
||||
#include "ProcessHelper.h"
|
||||
|
||||
#include <assimp/Macros.h>
|
||||
#include <assimp/Exceptional.h>
|
||||
#include <assimp/qnan.h>
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue