diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..e750822ab --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +patreon: assimp +ko_fi: kimkulling diff --git a/.gitignore b/.gitignore index d383f3ec8..9dcb6623d 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,12 @@ build *.sln *.ncb *.vcproj +*.vcxproj.user +*.VC.db +*.VC.db-shm +*.VC.db-wal +*.VC.opendb +*.ipch # Output bin/ @@ -17,6 +23,7 @@ CMakeLists.txt.user # Generated assimp.pc +assimp.aps revision.h contrib/zlib/zconf.h contrib/zlib/zlib.pc @@ -31,6 +38,7 @@ cmake_uninstall.cmake *.dir/ assimp-config.cmake assimp-config-version.cmake +assimpTargets*.cmake # MakeFile Makefile diff --git a/.travis.sh b/.travis.sh index fb42bd40d..f0f0f5d70 100755 --- a/.travis.sh +++ b/.travis.sh @@ -7,7 +7,8 @@ # function generate() { OPTIONS="-DASSIMP_WERROR=ON" - + OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=NO" + if [ "$DISABLE_EXPORTERS" = "YES" ] ; then OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=YES" else diff --git a/.travis.yml b/.travis.yml index e768c530c..8fe39d59c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,16 +27,11 @@ compiler: env: global: - # COVERITY_SCAN_TOKEN - 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} matrix: include: - # disabled until clang 5.0 analyzer issues are fixed - # - os: linux - # compiler: clang - # env: ANALYZE=ON - os: linux compiler: clang env: ASAN=ON @@ -51,7 +46,6 @@ matrix: env: ANALYZE=ON - os: linux compiler: gcc -# env: DISABLE_EXPORTERS=YES ENABLE_COVERALLS=ON env: ENABLE_COVERALLS=ON - os: linux compiler: gcc @@ -61,8 +55,7 @@ install: - if [ $ANDROID ]; then wget -c http://dl.google.com/android/ndk/android-ndk-${PV}-${PLATF}.tar.bz2 && tar xf android-ndk-${PV}-${PLATF}.tar.bz2 ; fi before_script: - # init coverage to 0 (optional) - - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && lcov --directory . --zerocounters ; fi + cmake . -DASSIMP_ENABLE_BOOST_WORKAROUND=YES script: - export COVERALLS_SERVICE_NAME=travis-ci @@ -77,6 +70,6 @@ addons: project: name: "assimp/assimp" notification_email: kim.kulling@googlemail.com - build_command_prepend: "cmake" - build_command: "make" + build_command_prepend: "cmake ./" + build_command: "make -j4" branch_pattern: coverity_scan diff --git a/BUILDBINARIES_EXAMPLE.bat b/BUILDBINARIES_EXAMPLE.bat new file mode 100644 index 000000000..2dd13a542 --- /dev/null +++ b/BUILDBINARIES_EXAMPLE.bat @@ -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 diff --git a/Build.md b/Build.md index d5b443a79..2db47798d 100644 --- a/Build.md +++ b/Build.md @@ -1,32 +1,46 @@ -# 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 +# Build Instructions + +## 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: -``` -> cmake CMakeLists.txt +```bash +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 -See https://stackoverflow.com/questions/40803170/cmake-uwp-using-cmake-to-build-universal-windows-app +### Build instructions for Windows with UWP +See - -# Build instrcutions 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 cmake CMakeLists.txt make -j4 ``` @@ -34,7 +48,23 @@ 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. -# CMake build options +### 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. + +Please see [CMake Cross Compiling](https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling) for general information on CMake Toolchains. + +Some users have had success building assimp using MinGW on Linux using [polly](https://github.com/ruslo/polly/). + +The following toolchain, which is not maintained by assimp, seems to work on Linux: [linux-mingw-w64-gnuxx11.cmake](https://github.com/ruslo/polly/blob/master/linux-mingw-w64-gnuxx11.cmake) + +The following toolchain may or may not be helpful for building assimp using MinGW on Windows (untested): + [mingw-cxx17.cmake](https://github.com/ruslo/polly/blob/master/mingw-cxx17.cmake) + +Besides the toolchain, compilation should be the same as for Linux / Unix. + +### 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 @@ -55,4 +85,3 @@ The cmake-build-environment provides options to configure the build. The followi - **INJECT_DEBUG_POSTFIX( default ON )**: Inject debug postfix in .a/.so lib names - **IGNORE_GIT_HASH ( default OFF )**: Don't call git to get the hash. - **ASSIMP_INSTALL_PDB ( default ON )**: Install MSVC debug files. - diff --git a/CMakeLists.txt b/CMakeLists.txt index 645d92689..dcafb649f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ # Open Asset Import Library (assimp) # ---------------------------------------------------------------------- -# Copyright (c) 2006-2018, assimp team - +# Copyright (c) 2006-2019, assimp team +# # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -34,9 +34,24 @@ # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #---------------------------------------------------------------------- -SET(CMAKE_LEGACY_CYGWIN_WIN32 0) # Remove when CMake >= 2.8.4 is required -CMAKE_MINIMUM_REQUIRED( VERSION 2.8 ) -PROJECT( Assimp ) +SET(CMAKE_POLICY_DEFAULT_CMP0074 NEW) + +CMAKE_MINIMUM_REQUIRED( VERSION 3.0 ) + +# Toggles the use of the hunter package manager +option(HUNTER_ENABLED "Enable Hunter package manager support" OFF) + +include("cmake/HunterGate.cmake") +HunterGate( + URL "https://github.com/ruslo/hunter/archive/v0.23.176.tar.gz" + SHA1 "2e9ae973d028660b735ac4c6142725ca36a0048a" +) + +IF(HUNTER_ENABLED) + add_definitions(-DASSIMP_USE_HUNTER) +ENDIF(HUNTER_ENABLED) + +PROJECT( Assimp VERSION 5.0.0 ) # All supported options ############################################### @@ -106,7 +121,7 @@ OPTION ( BUILD_DOCS OFF ) OPTION( INJECT_DEBUG_POSTFIX - "Inject debug postfix in .a/.so lib names" + "Inject debug postfix in .a/.so/.dll lib names" ON ) @@ -115,11 +130,12 @@ OPTION ( IGNORE_GIT_HASH OFF ) -IF (IOS) +IF (IOS AND NOT HUNTER_ENABLED) IF (NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE "Release") ENDIF (NOT CMAKE_BUILD_TYPE) -ENDIF (IOS) + ADD_DEFINITIONS(-DENABLE_BITCODE) +ENDIF (IOS AND NOT HUNTER_ENABLED) # Use subset of Windows.h if (WIN32) @@ -131,6 +147,10 @@ IF(MSVC) "Install MSVC debug files." ON ) + IF(NOT (MSVC_VERSION LESS 1900)) + # Multibyte character set is deprecated since at least MSVC2015 (possibly earlier) + ADD_DEFINITIONS( -DUNICODE -D_UNICODE ) + ENDIF() ENDIF(MSVC) IF (BUILD_FRAMEWORK) @@ -146,17 +166,17 @@ ELSE() ENDIF(NOT BUILD_SHARED_LIBS) # Define here the needed parameters -SET (ASSIMP_VERSION_MAJOR 4) -SET (ASSIMP_VERSION_MINOR 1) -SET (ASSIMP_VERSION_PATCH 0) +SET (ASSIMP_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) +SET (ASSIMP_VERSION_MINOR ${PROJECT_VERSION_MINOR}) +SET (ASSIMP_VERSION_PATCH ${PROJECT_VERSION_PATCH}) SET (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH}) -SET (ASSIMP_SOVERSION 4) -SET (PROJECT_VERSION "${ASSIMP_VERSION}") +SET (ASSIMP_SOVERSION 5) SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" ) - -# Enable C++1 globally -set_property( GLOBAL PROPERTY CXX_STANDARD 11 ) +if(NOT HUNTER_ENABLED) + # Enable C++11 support globally + set_property( GLOBAL PROPERTY CXX_STANDARD 11 ) +endif() IF(NOT IGNORE_GIT_HASH) # Get the current working branch @@ -196,8 +216,9 @@ CONFIGURE_FILE( ${CMAKE_CURRENT_BINARY_DIR}/include/assimp/config.h ) -INCLUDE_DIRECTORIES( +INCLUDE_DIRECTORIES( BEFORE ./ + code/ include ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/include @@ -216,9 +237,13 @@ ENDIF( UNIX ) # Grouped compiler settings IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW) + IF(NOT HUNTER_ENABLED) + SET(CMAKE_CXX_FLAGS "-fPIC -std=c++0x ${CMAKE_CXX_FLAGS}") + SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") + ENDIF() # hide all not-exported symbols - SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fPIC -fno-strict-aliasing -Wall -std=c++0x ${CMAKE_CXX_FLAGS}") - SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS}") + SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fno-strict-aliasing -Wall ${CMAKE_CXX_FLAGS}") + SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}") SET(LIBSTDC++_LIBRARIES -lstdc++) ELSEIF(MSVC) # enable multi-core compilation with MSVC @@ -228,26 +253,39 @@ ELSEIF(MSVC) IF(MSVC12) ADD_COMPILE_OPTIONS(/wd4351) ENDIF() + SET(CMAKE_CXX_FLAGS_DEBUG "/D_DEBUG /MDd /Ob2 /DEBUG:FULL /Zi") ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) - SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fPIC -fno-strict-aliasing -Wall -Wno-long-long -std=c++11 ${CMAKE_CXX_FLAGS}" ) - SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS}") + IF(NOT HUNTER_ENABLED) + SET(CMAKE_CXX_FLAGS "-fPIC -std=c++11 ${CMAKE_CXX_FLAGS}") + SET(CMAKE_C_FLAGS "-fPIC ${CMAKE_C_FLAGS}") + ENDIF() + SET(CMAKE_CXX_FLAGS "-g -fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long ${CMAKE_CXX_FLAGS}" ) + SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}") ELSEIF( CMAKE_COMPILER_IS_MINGW ) - SET( CMAKE_CXX_FLAGS "-fvisibility=hidden -fno-strict-aliasing -Wall -Wno-long-long -std=c++11 -Wa,-mbig-obj ${CMAKE_CXX_FLAGS}" ) - SET(CMAKE_C_FLAGS "-fPIC -fno-strict-aliasing ${CMAKE_C_FLAGS} ") + IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.0) + message(FATAL_ERROR "MinGW is too old to be supported. Please update MinGW and try again.") + ELSEIF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 7.3) + message(WARNING "MinGW is old, if you experience errors, update MinGW.") + ENDIF() + IF(NOT HUNTER_ENABLED) + 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 -O3 ${CMAKE_CXX_FLAGS}") + SET(CMAKE_C_FLAGS "-fno-strict-aliasing ${CMAKE_C_FLAGS}") ADD_DEFINITIONS( -U__STRICT_ANSI__ ) ENDIF() -IF ( IOS ) - -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() - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fembed-bitcode -O3") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode -O3") -ENDIF() - -ENDIF( IOS ) +IF ( IOS AND NOT HUNTER_ENABLED) + 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() + 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( IOS AND NOT HUNTER_ENABLED) IF (ASSIMP_COVERALLS) MESSAGE(STATUS "Coveralls enabled") @@ -299,7 +337,9 @@ SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE STRING SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE STRING "Path the tool executables are installed to." ) -IF (CMAKE_BUILD_TYPE STREQUAL "Debug") +get_cmake_property(is_multi_config GENERATOR_IS_MULTI_CONFIG) + +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") @@ -312,20 +352,67 @@ IF (NOT TARGET uninstall) ADD_CUSTOM_TARGET(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") ENDIF() -# cmake configuration files -CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE) -CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE) -CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-debug.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" @ONLY IMMEDIATE) -CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-release.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake" @ONLY IMMEDIATE) -CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE) -#we should generated these scripts after CMake VERSION 3.0.2 using export(EXPORT ...) and write_basic_package_version_file(...) -INSTALL(FILES - "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" - "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake" - DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT}) +IF(HUNTER_ENABLED) + set(CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}") + set(INCLUDE_INSTALL_DIR "include") + + set(GENERATED_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") + + # Configuration + set(VERSION_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}ConfigVersion.cmake") + set(PROJECT_CONFIG "${GENERATED_DIR}/${PROJECT_NAME}Config.cmake") + set(TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets") + set(NAMESPACE "${PROJECT_NAME}::") + + # Include module with fuction 'write_basic_package_version_file' + include(CMakePackageConfigHelpers) + + # Note: PROJECT_VERSION is used as a VERSION + write_basic_package_version_file("${VERSION_CONFIG}" COMPATIBILITY SameMajorVersion) + + # Use variables: + # * TARGETS_EXPORT_NAME + # * PROJECT_NAME + configure_package_config_file( + "cmake/assimp-hunter-config.cmake.in" + "${PROJECT_CONFIG}" + INSTALL_DESTINATION "${CONFIG_INSTALL_DIR}" + ) + + install( + FILES "${PROJECT_CONFIG}" "${VERSION_CONFIG}" + DESTINATION "${CONFIG_INSTALL_DIR}" + ) + + install( + EXPORT "${TARGETS_EXPORT_NAME}" + NAMESPACE "${NAMESPACE}" + DESTINATION "${CONFIG_INSTALL_DIR}" + ) +ELSE(HUNTER_ENABLED) + # cmake configuration files + CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE) + CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" @ONLY IMMEDIATE) + IF (is_multi_config) + CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-debug.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" @ONLY IMMEDIATE) + CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-release.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake" @ONLY IMMEDIATE) + SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake") + ELSEIF (CMAKE_BUILD_TYPE STREQUAL Debug) + CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-debug.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake" @ONLY IMMEDIATE) + SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-debug.cmake") + ELSE() + CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimpTargets-release.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake" @ONLY IMMEDIATE) + SET(PACKAGE_TARGETS_FILE "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets-release.cmake") + ENDIF() + CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE) + #we should generated these scripts after CMake VERSION 3.0.2 using export(EXPORT ...) and write_basic_package_version_file(...) + INSTALL(FILES + "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/assimpTargets.cmake" + ${PACKAGE_TARGETS_FILE} + DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT}) +ENDIF(HUNTER_ENABLED) FIND_PACKAGE( DirectX ) @@ -340,39 +427,57 @@ ENDIF( SYSTEM_IRRXML ) # Search for external dependencies, and build them from source if not found # Search for zlib -IF ( NOT ASSIMP_BUILD_ZLIB ) - FIND_PACKAGE(ZLIB) -ENDIF( NOT ASSIMP_BUILD_ZLIB ) +IF(HUNTER_ENABLED) + hunter_add_package(ZLIB) + find_package(ZLIB CONFIG REQUIRED) -IF( NOT ZLIB_FOUND ) - MESSAGE(STATUS "compiling zlib from sources") - INCLUDE(CheckIncludeFile) - INCLUDE(CheckTypeSize) - INCLUDE(CheckFunctionExists) - # compile from sources - ADD_SUBDIRECTORY(contrib/zlib) - SET(ZLIB_FOUND 1) - SET(ZLIB_LIBRARIES zlibstatic) - SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib) - # need to ensure we don't link with system zlib or minizip as well. - SET(ASSIMP_BUILD_MINIZIP 1) -ELSE(NOT ZLIB_FOUND) - ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB) - SET(ZLIB_LIBRARIES_LINKED -lz) -ENDIF(NOT ZLIB_FOUND) -INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR}) + add_definitions(-DASSIMP_BUILD_NO_OWN_ZLIB) + set(ZLIB_FOUND TRUE) + set(ZLIB_LIBRARIES ZLIB::zlib) + set(ASSIMP_BUILD_MINIZIP TRUE) +ELSE(HUNTER_ENABLED) + IF ( NOT ASSIMP_BUILD_ZLIB ) + FIND_PACKAGE(ZLIB) + ENDIF( NOT ASSIMP_BUILD_ZLIB ) -# Search for unzip -IF ( NOT IOS ) + IF( NOT ZLIB_FOUND ) + MESSAGE(STATUS "compiling zlib from sources") + INCLUDE(CheckIncludeFile) + INCLUDE(CheckTypeSize) + INCLUDE(CheckFunctionExists) + + # Explicitly turn off ASM686 and AMD64 cmake options. + # The AMD64 option causes a build failure on MSVC and the ASM builds seem to have problems: + # https://github.com/madler/zlib/issues/41#issuecomment-125848075 + # Also prevents these options from "polluting" the cmake options if assimp is being + # included as a submodule. + set( ASM686 FALSE CACHE INTERNAL "Override ZLIB flag to turn off assembly" FORCE ) + set( AMD64 FALSE CACHE INTERNAL "Override ZLIB flag to turn off assembly" FORCE ) + + # compile from sources + ADD_SUBDIRECTORY(contrib/zlib) + SET(ZLIB_FOUND 1) + SET(ZLIB_LIBRARIES zlibstatic) + SET(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib) + # need to ensure we don't link with system zlib or minizip as well. + SET(ASSIMP_BUILD_MINIZIP 1) + ELSE(NOT ZLIB_FOUND) + ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB) + SET(ZLIB_LIBRARIES_LINKED -lz) + ENDIF(NOT ZLIB_FOUND) + INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR}) +ENDIF(HUNTER_ENABLED) + +IF( NOT IOS ) IF( NOT ASSIMP_BUILD_MINIZIP ) - use_pkgconfig(UNZIP minizip) + use_pkgconfig(UNZIP minizip) ENDIF( NOT ASSIMP_BUILD_MINIZIP ) ELSE ( NOT IOS ) - IF(NOT BUILD_SHARED_LIBS) + IF( NOT BUILD_SHARED_LIBS ) IF( NOT ASSIMP_BUILD_MINIZIP ) - use_pkgconfig(UNZIP minizip) + use_pkgconfig(UNZIP minizip) ENDIF( NOT ASSIMP_BUILD_MINIZIP ) - ENDIF (NOT BUILD_SHARED_LIBS) + ENDIF ( NOT BUILD_SHARED_LIBS ) ENDIF ( NOT IOS ) IF ( ASSIMP_NO_EXPORT ) @@ -446,26 +551,27 @@ ELSE (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER ) ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) -ADD_SUBDIRECTORY(contrib) +IF(NOT HUNTER_ENABLED) + ADD_SUBDIRECTORY(contrib) +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) IF ( WIN32 ) ADD_SUBDIRECTORY( samples/SimpleTexturedOpenGL/ ) + ADD_SUBDIRECTORY( samples/SimpleTexturedDirectx11 ) ENDIF ( WIN32 ) ADD_SUBDIRECTORY( samples/SimpleOpenGL/ ) ENDIF ( ASSIMP_BUILD_SAMPLES ) @@ -531,18 +637,22 @@ if(WIN32) if (CMAKE_SIZEOF_VOID_P EQUAL 8) SET(BIN_DIR "${PROJECT_SOURCE_DIR}/bin64/") SET(LIB_DIR "${PROJECT_SOURCE_DIR}/lib64/") - elseif() + else() SET(BIN_DIR "${PROJECT_SOURCE_DIR}/bin32/") SET(LIB_DIR "${PROJECT_SOURCE_DIR}/lib32/") ENDIF() - IF(MSVC12) - SET(ASSIMP_MSVC_VERSION "vc120") - ELSEIF(MSVC14) - SET(ASSIMP_MSVC_VERSION "vc140") - ELSEIF(MSVC15) - SET(ASSIMP_MSVC_VERSION "vc141") - ENDIF(MSVC12) + IF(MSVC_TOOLSET_VERSION) + set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}") + ELSE() + IF(MSVC12) + SET(ASSIMP_MSVC_VERSION "vc120") + ELSEIF(MSVC14) + SET(ASSIMP_MSVC_VERSION "vc140") + ELSEIF(MSVC15) + SET(ASSIMP_MSVC_VERSION "vc141") + ENDIF(MSVC12) + ENDIF() IF(MSVC12 OR MSVC14 OR MSVC15 ) ADD_CUSTOM_TARGET(UpdateAssimpLibsDebugSymbolsAndDLLs COMMENT "Copying Assimp Libraries ..." VERBATIM) diff --git a/INSTALL b/INSTALL index 357918d6b..350a5f109 100644 --- a/INSTALL +++ b/INSTALL @@ -35,13 +35,16 @@ http://www.cmake.org/. For Unix: -1. cmake CMakeLists.txt -G 'Unix Makefiles' -2. make +1. mkdir build && cd build +2. cmake .. -G 'Unix Makefiles' +3. make -j4 For Windows: 1. Open a command prompt -2. cmake CMakeLists.txt -2. Open your default IDE and build it +2. mkdir build +3. cd build +4. cmake .. +5. cmake --build . For iOS: Just check the following project, which deploys a compiler toolchain for different iOS-versions: https://github.com/assimp/assimp/tree/master/port/iOS diff --git a/Readme.md b/Readme.md index 1ba026d5a..f749993fd 100644 --- a/Readme.md +++ b/Readme.md @@ -1,7 +1,7 @@ Open Asset Import Library (assimp) ================================== A library to import and export various 3d-model-formats including scene-post-processing to generate missing render data. -### Current build status ### +### Current project status ### [![Linux Build Status](https://travis-ci.org/assimp/assimp.svg)](https://travis-ci.org/assimp/assimp) [![Windows Build Status](https://ci.appveyor.com/api/projects/status/tmo433wax6u6cjp4?svg=true)](https://ci.appveyor.com/project/kimkulling/assimp) @@ -10,10 +10,15 @@ A library to import and export various 3d-model-formats including scene-post-pro [![Coverage Status](https://coveralls.io/repos/github/assimp/assimp/badge.svg?branch=master)](https://coveralls.io/github/assimp/assimp?branch=master) [![Join the chat at https://gitter.im/assimp/assimp](https://badges.gitter.im/assimp/assimp.svg)](https://gitter.im/assimp/assimp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/assimp/assimp.svg)](http://isitmaintained.com/project/assimp/assimp "Average time to resolve an issue") +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/5be56faac64f46fc941ac890fb4febef)](https://www.codacy.com/app/kimkulling/assimp?utm_source=github.com&utm_medium=referral&utm_content=assimp/assimp&utm_campaign=Badge_Grade) +[![Total alerts](https://img.shields.io/lgtm/alerts/g/assimp/assimp.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/assimp/assimp/alerts/)
APIs are provided for C and C++. There are various bindings to other languages (C#, Java, Python, Delphi, D). Assimp also runs on Android and iOS. +[Check the latest doc](https://assimp-docs.readthedocs.io/en/latest/). + Additionally, assimp features various __mesh post processing tools__: normals and tangent space generation, triangulation, vertex cache locality optimization, removal of degenerate primitives and duplicate vertices, sorting by primitive type, merging of redundant materials and many more. This is the development repo containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [Github Assimp Releases](https://github.com/assimp/assimp/releases). @@ -96,7 +101,7 @@ __Importers__: Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default): -- [C4D](https://en.wikipedia.org/wiki/Cinema_4D) (https://github.com/assimp/assimp/wiki/Cinema4D-&-Melange) +- [C4D](https://en.wikipedia.org/wiki/Cinema_4D) (https://github.com/assimp/assimp/wiki/Cinema4D-&-Melange) IMporting geometry + node hierarchy are currently supported __Exporters__: @@ -115,22 +120,23 @@ __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](port/AssimpNET/Readme.md) +* [.NET](https://github.com/kebby/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) * [JVM](https://github.com/kotlin-graphics/assimp) Full jvm port (current [status](https://github.com/kotlin-graphics/assimp/wiki/Status)) +* [HAXE-Port](https://github.com/longde123/assimp-haxe) The Assimp-HAXE-port. ### Other tools ### [open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities. #### Repository structure #### -Open Asset Import Library is implemented in C++. The directory structure is: +Open Asset Import Library is implemented in C++. The directory structure looks like: /code Source code /contrib Third-party libraries @@ -143,6 +149,11 @@ Open Asset Import Library is implemented in C++. The directory structure is: /samples A small number of samples to illustrate possible use cases for Assimp +The source code is organized in the following way: + + code/Common The base implementation for importers and the infrastructure + code/PostProcessing The post-processing steps + code/ Implementation for import and export for the format ### Where to get help ### For more information, visit [our website](http://assimp.org/). Or check out the `./doc`- folder, which contains the official documentation in HTML format. diff --git a/appveyor.yml b/appveyor.yml index 2b5f212f9..df16431bd 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,9 +14,10 @@ matrix: fast_finish: true image: - - Visual Studio 2013 - Visual Studio 2015 - Visual Studio 2017 + - Visual Studio 2019 + - MinGW platform: - Win32 @@ -27,11 +28,13 @@ configuration: Release install: - set PATH=C:\Ruby24-x64\bin;%PATH% - set CMAKE_DEFINES -DASSIMP_WERROR=ON - - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2013" set CMAKE_GENERATOR_NAME=Visual Studio 12 2013 + - if [%COMPILER%]==[MinGW] set PATH=C:\MinGW\bin;%PATH% - 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 + - 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 @@ -53,7 +56,13 @@ build: project: Assimp.sln after_build: - - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" iscc packaging\windows-innosetup\script.iss + - if "%APPVEYOR_BUILD_WORKER_IMAGE%"=="Visual Studio 2017" ( + if "%platform%"=="x64" ( + iscc packaging\windows-innosetup\script_x64.iss + ) else ( + iscc packaging\windows-innosetup\script_x86.iss + ) + ) - 7z a assimp.7z bin\%CONFIGURATION%\* lib\%CONFIGURATION%\* test_script: diff --git a/assimp.pc.in b/assimp.pc.in index 02cf59dc4..c659e19f2 100644 --- a/assimp.pc.in +++ b/assimp.pc.in @@ -1,7 +1,7 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@/ libdir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_LIB_INSTALL_DIR@ -includedir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_INCLUDE_INSTALL_DIR@ +includedir=@CMAKE_INSTALL_PREFIX@/../include/@ASSIMP_INCLUDE_INSTALL_DIR@ Name: @CMAKE_PROJECT_NAME@ Description: Import various well-known 3D model formats in an uniform manner. diff --git a/assimpTargets-debug.cmake.in b/assimpTargets-debug.cmake.in index a83e6c22d..ed98e777b 100644 --- a/assimpTargets-debug.cmake.in +++ b/assimpTargets-debug.cmake.in @@ -5,48 +5,83 @@ # Commands may need to know the format version. set(CMAKE_IMPORT_FILE_VERSION 1) +set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@) + if(MSVC) - if( MSVC70 OR MSVC71 ) - set(MSVC_PREFIX "vc70") - elseif( MSVC80 ) - set(MSVC_PREFIX "vc80") - elseif( MSVC90 ) - set(MSVC_PREFIX "vc90") - elseif( MSVC10 ) - set(MSVC_PREFIX "vc100") - elseif( MSVC11 ) - set(MSVC_PREFIX "vc110") - elseif( MSVC12 ) - set(MSVC_PREFIX "vc120") - elseif( MSVC14 ) - set(MSVC_PREFIX "vc140") + if(MSVC_TOOLSET_VERSION) + set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}") else() - set(MSVC_PREFIX "vc150") + if( MSVC70 OR MSVC71 ) + set(MSVC_PREFIX "vc70") + elseif( MSVC80 ) + set(MSVC_PREFIX "vc80") + elseif( MSVC90 ) + set(MSVC_PREFIX "vc90") + elseif( MSVC10 ) + set(MSVC_PREFIX "vc100") + elseif( MSVC11 ) + set(MSVC_PREFIX "vc110") + elseif( MSVC12 ) + set(MSVC_PREFIX "vc120") + elseif( MSVC_VERSION LESS 1910) + set(MSVC_PREFIX "vc140") + elseif( MSVC_VERSION LESS 1920) + set(MSVC_PREFIX "vc141") + elseif( MSVC_VERSION LESS 1930) + set(MSVC_PREFIX "vc142") + else() + set(MSVC_PREFIX "vc150") + endif() endif() set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" ) - 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@") + 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@") - # Import target "assimp::assimp" for configuration "Debug" - set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) - set_target_properties(assimp::assimp PROPERTIES - IMPORTED_IMPLIB_DEBUG "${_IMPORT_PREFIX}/lib/${importLibraryName}" - IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" - ) - list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${importLibraryName}") - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" ) + # Import target "assimp::assimp" for configuration "Debug" + set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(assimp::assimp PROPERTIES + IMPORTED_IMPLIB_DEBUG "${_IMPORT_PREFIX}/lib/${importLibraryName}" + IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" + ) + list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${importLibraryName}") + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" ) + else() + set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@") + + # Import target "assimp::assimp" for configuration "Debug" + set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) + set_target_properties(assimp::assimp PROPERTIES + IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${staticLibraryName}" + ) + list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}") + endif() else() - set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the openrave libraries" ) - set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@") - set_target_properties(assimp::assimp PROPERTIES - IMPORTED_SONAME_DEBUG "${sharedLibraryName}" - IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" + set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" ) + if(ASSIMP_BUILD_SHARED_LIBS) + if(APPLE) + set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@") + else(APPLE) + 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}" ) - list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" ) + list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" ) + else() + set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_DEBUG_POSTFIX@@CMAKE_STATIC_LIBRARY_SUFFIX@") + set_target_properties(assimp::assimp PROPERTIES + IMPORTED_LOCATION_DEBUG "${_IMPORT_PREFIX}/lib/${staticLibraryName}" + ) + list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}" ) + endif() endif() @@ -60,7 +95,11 @@ set( ASSIMP_CXX_FLAGS ) # dynamically linked library set( ASSIMP_LINK_FLAGS "" ) set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@") set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@") -set( ASSIMP_LIBRARIES ${sharedLibraryName}) +if(ASSIMP_BUILD_SHARED_LIBS) + set( ASSIMP_LIBRARIES ${sharedLibraryName}) +else() + set( ASSIMP_LIBRARIES ${staticLibraryName}) +endif() # for compatibility with pkg-config set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}") @@ -75,4 +114,5 @@ MARK_AS_ADVANCED( ASSIMP_CFLAGS_OTHER ASSIMP_LDFLAGS_OTHER ASSIMP_LIBRARY_SUFFIX + ASSIMP_BUILD_SHARED_LIBS ) diff --git a/assimpTargets-release.cmake.in b/assimpTargets-release.cmake.in index 0b38e4e92..a5fe74933 100644 --- a/assimpTargets-release.cmake.in +++ b/assimpTargets-release.cmake.in @@ -5,59 +5,99 @@ # Commands may need to know the format version. set(CMAKE_IMPORT_FILE_VERSION 1) +set(ASSIMP_BUILD_SHARED_LIBS @BUILD_SHARED_LIBS@) + if(MSVC) - if( MSVC70 OR MSVC71 ) - set(MSVC_PREFIX "vc70") - elseif( MSVC80 ) - set(MSVC_PREFIX "vc80") - elseif( MSVC90 ) - set(MSVC_PREFIX "vc90") - elseif( MSVC10 ) - set(MSVC_PREFIX "vc100") - elseif( MSVC11 ) - set(MSVC_PREFIX "vc110") - elseif( MSVC12 ) - set(MSVC_PREFIX "vc120") - elseif( MSVC14 ) - set(MSVC_PREFIX "vc140") + if(MSVC_TOOLSET_VERSION) + set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}") else() - set(MSVC_PREFIX "vc150") + if( MSVC70 OR MSVC71 ) + set(MSVC_PREFIX "vc70") + elseif( MSVC80 ) + set(MSVC_PREFIX "vc80") + elseif( MSVC90 ) + set(MSVC_PREFIX "vc90") + elseif( MSVC10 ) + set(MSVC_PREFIX "vc100") + elseif( MSVC11 ) + set(MSVC_PREFIX "vc110") + elseif( MSVC12 ) + set(MSVC_PREFIX "vc120") + elseif( MSVC_VERSION LESS 1910) + set(MSVC_PREFIX "vc140") + elseif( MSVC_VERSION LESS 1920) + set(MSVC_PREFIX "vc141") + elseif( MSVC_VERSION LESS 1930) + set(MSVC_PREFIX "vc142") + else() + set(MSVC_PREFIX "vc150") + endif() endif() set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" ) - set(sharedLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@") - set(importLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_IMPORT_LIBRARY_SUFFIX@") + 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@") - # Import target "assimp::assimp" for configuration "Release" - set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) - set_target_properties(assimp::assimp PROPERTIES - IMPORTED_IMPLIB_RELEASE "${_IMPORT_PREFIX}/lib/${importLibraryName}" - IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" + # Import target "assimp::assimp" for configuration "Release" + set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + set_target_properties(assimp::assimp PROPERTIES + IMPORTED_IMPLIB_RELEASE "${_IMPORT_PREFIX}/lib/${importLibraryName}" + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" ) - list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${importLibraryName}") - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" ) + list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${importLibraryName}") + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/bin/${sharedLibraryName}" ) + else() + set(staticLibraryName "assimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@") + + # Import target "assimp::assimp" for configuration "Release" + set_property(TARGET assimp::assimp APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE) + set_target_properties(assimp::assimp PROPERTIES + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${staticLibraryName}" + ) + list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}") + endif() else() - set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the openrave libraries" ) - set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_SHARED_LIBRARY_SUFFIX@.@ASSIMP_VERSION_MAJOR@") - set_target_properties(assimp::assimp PROPERTIES - IMPORTED_SONAME_RELEASE "${sharedLibraryName}" - IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" + set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the assimp libraries" ) + if(ASSIMP_BUILD_SHARED_LIBS) + if(APPLE) + set(sharedLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}.@ASSIMP_VERSION_MAJOR@@CMAKE_SHARED_LIBRARY_SUFFIX@") + else(APPLE) + 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 ) - list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" ) + list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${sharedLibraryName}" ) + else() + set(staticLibraryName "libassimp${ASSIMP_LIBRARY_SUFFIX}@CMAKE_STATIC_LIBRARY_SUFFIX@") + set_target_properties(assimp::assimp PROPERTIES + IMPORTED_LOCATION_RELEASE "${_IMPORT_PREFIX}/lib/${staticLibraryName}" + ) + list(APPEND _IMPORT_CHECK_TARGETS assimp::assimp ) + list(APPEND _IMPORT_CHECK_FILES_FOR_assimp::assimp "${_IMPORT_PREFIX}/lib/${staticLibraryName}" ) + endif() endif() # Commands beyond this point should not need to know the version. set(CMAKE_IMPORT_FILE_VERSION) get_filename_component(ASSIMP_ROOT_DIR "@CMAKE_INSTALL_PREFIX@" REALPATH) + set( ASSIMP_CXX_FLAGS ) # dynamically linked library set( ASSIMP_LINK_FLAGS "" ) set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@") set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@") -set( ASSIMP_LIBRARIES ${sharedLibraryName}) +if(ASSIMP_BUILD_SHARED_LIBS) + set( ASSIMP_LIBRARIES ${sharedLibraryName}) +else() + set( ASSIMP_LIBRARIES ${staticLibraryName}) +endif() # for compatibility with pkg-config set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}") @@ -72,4 +112,5 @@ MARK_AS_ADVANCED( ASSIMP_CFLAGS_OTHER ASSIMP_LDFLAGS_OTHER ASSIMP_LIBRARY_SUFFIX + ASSIMP_BUILD_SHARED_LIBS ) diff --git a/assimpTargets.cmake.in b/assimpTargets.cmake.in index 68e2c0dec..ab1a8d2c7 100644 --- a/assimpTargets.cmake.in +++ b/assimpTargets.cmake.in @@ -51,7 +51,11 @@ if(_IMPORT_PREFIX STREQUAL "/") endif() # Create imported target assimp::assimp -add_library(assimp::assimp SHARED IMPORTED) +if(@BUILD_SHARED_LIBS@) + add_library(assimp::assimp SHARED IMPORTED) +else() + add_library(assimp::assimp STATIC IMPORTED) +endif() set_target_properties(assimp::assimp PROPERTIES COMPATIBLE_INTERFACE_STRING "assimp_MAJOR_VERSION" diff --git a/cmake-modules/Findassimp.cmake b/cmake-modules/Findassimp.cmake index 95f3250b3..663645574 100644 --- a/cmake-modules/Findassimp.cmake +++ b/cmake-modules/Findassimp.cmake @@ -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) @@ -78,4 +82,4 @@ else(WIN32) endif (assimp_FIND_REQUIRED) endif (assimp_FOUND) -endif(WIN32) \ No newline at end of file +endif(WIN32) diff --git a/cmake/HunterGate.cmake b/cmake/HunterGate.cmake new file mode 100644 index 000000000..887557a58 --- /dev/null +++ b/cmake/HunterGate.cmake @@ -0,0 +1,540 @@ +# Copyright (c) 2013-2018, Ruslan Baratov +# All rights reserved. +# +# Redistribution and use 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. +# +# 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 HOLDER 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. + +# This is a gate file to Hunter package manager. +# Include this file using `include` command and add package you need, example: +# +# cmake_minimum_required(VERSION 3.2) +# +# include("cmake/HunterGate.cmake") +# HunterGate( +# URL "https://github.com/path/to/hunter/archive.tar.gz" +# SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d" +# ) +# +# project(MyProject) +# +# hunter_add_package(Foo) +# hunter_add_package(Boo COMPONENTS Bar Baz) +# +# Projects: +# * https://github.com/hunter-packages/gate/ +# * https://github.com/ruslo/hunter + +option(HUNTER_ENABLED "Enable Hunter package manager support" ON) + +if(HUNTER_ENABLED) + if(CMAKE_VERSION VERSION_LESS "3.2") + message( + FATAL_ERROR + "At least CMake version 3.2 required for Hunter dependency management." + " Update CMake or set HUNTER_ENABLED to OFF." + ) + endif() +endif() + +include(CMakeParseArguments) # cmake_parse_arguments + +option(HUNTER_STATUS_PRINT "Print working status" ON) +option(HUNTER_STATUS_DEBUG "Print a lot info" OFF) +option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON) + +set(HUNTER_WIKI "https://github.com/ruslo/hunter/wiki") + +function(hunter_gate_status_print) + if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG) + foreach(print_message ${ARGV}) + message(STATUS "[hunter] ${print_message}") + endforeach() + endif() +endfunction() + +function(hunter_gate_status_debug) + if(HUNTER_STATUS_DEBUG) + foreach(print_message ${ARGV}) + string(TIMESTAMP timestamp) + message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}") + endforeach() + endif() +endfunction() + +function(hunter_gate_wiki wiki_page) + message("------------------------------ WIKI -------------------------------") + message(" ${HUNTER_WIKI}/${wiki_page}") + message("-------------------------------------------------------------------") + message("") + message(FATAL_ERROR "") +endfunction() + +function(hunter_gate_internal_error) + message("") + foreach(print_message ${ARGV}) + message("[hunter ** INTERNAL **] ${print_message}") + endforeach() + message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") + message("") + hunter_gate_wiki("error.internal") +endfunction() + +function(hunter_gate_fatal_error) + cmake_parse_arguments(hunter "" "WIKI" "" "${ARGV}") + string(COMPARE EQUAL "${hunter_WIKI}" "" have_no_wiki) + if(have_no_wiki) + hunter_gate_internal_error("Expected wiki") + endif() + message("") + foreach(x ${hunter_UNPARSED_ARGUMENTS}) + message("[hunter ** FATAL ERROR **] ${x}") + endforeach() + message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") + message("") + hunter_gate_wiki("${hunter_WIKI}") +endfunction() + +function(hunter_gate_user_error) + hunter_gate_fatal_error(${ARGV} WIKI "error.incorrect.input.data") +endfunction() + +function(hunter_gate_self root version sha1 result) + string(COMPARE EQUAL "${root}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("root is empty") + endif() + + string(COMPARE EQUAL "${version}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("version is empty") + endif() + + string(COMPARE EQUAL "${sha1}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("sha1 is empty") + endif() + + string(SUBSTRING "${sha1}" 0 7 archive_id) + + if(EXISTS "${root}/cmake/Hunter") + set(hunter_self "${root}") + else() + set( + hunter_self + "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked" + ) + endif() + + set("${result}" "${hunter_self}" PARENT_SCOPE) +endfunction() + +# Set HUNTER_GATE_ROOT cmake variable to suitable value. +function(hunter_gate_detect_root) + # Check CMake variable + string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty) + if(not_empty) + set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable") + return() + endif() + + # Check environment variable + string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty) + if(not_empty) + set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT detected by environment variable") + return() + endif() + + # Check HOME environment variable + string(COMPARE NOTEQUAL "$ENV{HOME}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable") + return() + endif() + + # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only) + if(WIN32) + string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug( + "HUNTER_ROOT set using SYSTEMDRIVE environment variable" + ) + return() + endif() + + string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug( + "HUNTER_ROOT set using USERPROFILE environment variable" + ) + return() + endif() + endif() + + hunter_gate_fatal_error( + "Can't detect HUNTER_ROOT" + WIKI "error.detect.hunter.root" + ) +endfunction() + +function(hunter_gate_download dir) + string( + COMPARE + NOTEQUAL + "$ENV{HUNTER_DISABLE_AUTOINSTALL}" + "" + disable_autoinstall + ) + if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL) + hunter_gate_fatal_error( + "Hunter not found in '${dir}'" + "Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'" + "Settings:" + " HUNTER_ROOT: ${HUNTER_GATE_ROOT}" + " HUNTER_SHA1: ${HUNTER_GATE_SHA1}" + WIKI "error.run.install" + ) + endif() + string(COMPARE EQUAL "${dir}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("Empty 'dir' argument") + endif() + + string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("HUNTER_GATE_SHA1 empty") + endif() + + string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("HUNTER_GATE_URL empty") + endif() + + set(done_location "${dir}/DONE") + set(sha1_location "${dir}/SHA1") + + set(build_dir "${dir}/Build") + set(cmakelists "${dir}/CMakeLists.txt") + + hunter_gate_status_debug("Locking directory: ${dir}") + file(LOCK "${dir}" DIRECTORY GUARD FUNCTION) + hunter_gate_status_debug("Lock done") + + if(EXISTS "${done_location}") + # while waiting for lock other instance can do all the job + hunter_gate_status_debug("File '${done_location}' found, skip install") + return() + endif() + + file(REMOVE_RECURSE "${build_dir}") + file(REMOVE_RECURSE "${cmakelists}") + + file(MAKE_DIRECTORY "${build_dir}") # check directory permissions + + # Disabling languages speeds up a little bit, reduces noise in the output + # and avoids path too long windows error + file( + WRITE + "${cmakelists}" + "cmake_minimum_required(VERSION 3.2)\n" + "project(HunterDownload LANGUAGES NONE)\n" + "include(ExternalProject)\n" + "ExternalProject_Add(\n" + " Hunter\n" + " URL\n" + " \"${HUNTER_GATE_URL}\"\n" + " URL_HASH\n" + " SHA1=${HUNTER_GATE_SHA1}\n" + " DOWNLOAD_DIR\n" + " \"${dir}\"\n" + " TLS_VERIFY\n" + " ${HUNTER_TLS_VERIFY}\n" + " SOURCE_DIR\n" + " \"${dir}/Unpacked\"\n" + " CONFIGURE_COMMAND\n" + " \"\"\n" + " BUILD_COMMAND\n" + " \"\"\n" + " INSTALL_COMMAND\n" + " \"\"\n" + ")\n" + ) + + if(HUNTER_STATUS_DEBUG) + set(logging_params "") + else() + set(logging_params OUTPUT_QUIET) + endif() + + hunter_gate_status_debug("Run generate") + + # Need to add toolchain file too. + # Otherwise on Visual Studio + MDD this will fail with error: + # "Could not find an appropriate version of the Windows 10 SDK installed on this machine" + if(EXISTS "${CMAKE_TOOLCHAIN_FILE}") + get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE) + set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}") + else() + # 'toolchain_arg' can't be empty + set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=") + endif() + + string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make) + if(no_make) + set(make_arg "") + else() + # Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM + set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}") + endif() + + execute_process( + COMMAND + "${CMAKE_COMMAND}" + "-H${dir}" + "-B${build_dir}" + "-G${CMAKE_GENERATOR}" + "${toolchain_arg}" + ${make_arg} + WORKING_DIRECTORY "${dir}" + RESULT_VARIABLE download_result + ${logging_params} + ) + + if(NOT download_result EQUAL 0) + hunter_gate_internal_error( + "Configure project failed." + "To reproduce the error run: ${CMAKE_COMMAND} -H${dir} -B${build_dir} -G${CMAKE_GENERATOR} ${toolchain_arg} ${make_arg}" + "In directory ${dir}" + ) + endif() + + hunter_gate_status_print( + "Initializing Hunter workspace (${HUNTER_GATE_SHA1})" + " ${HUNTER_GATE_URL}" + " -> ${dir}" + ) + execute_process( + COMMAND "${CMAKE_COMMAND}" --build "${build_dir}" + WORKING_DIRECTORY "${dir}" + RESULT_VARIABLE download_result + ${logging_params} + ) + + if(NOT download_result EQUAL 0) + hunter_gate_internal_error("Build project failed") + endif() + + file(REMOVE_RECURSE "${build_dir}") + file(REMOVE_RECURSE "${cmakelists}") + + file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}") + file(WRITE "${done_location}" "DONE") + + hunter_gate_status_debug("Finished") +endfunction() + +# Must be a macro so master file 'cmake/Hunter' can +# apply all variables easily just by 'include' command +# (otherwise PARENT_SCOPE magic needed) +macro(HunterGate) + if(HUNTER_GATE_DONE) + # variable HUNTER_GATE_DONE set explicitly for external project + # (see `hunter_download`) + set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) + endif() + + # First HunterGate command will init Hunter, others will be ignored + get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET) + + if(NOT HUNTER_ENABLED) + # Empty function to avoid error "unknown function" + function(hunter_add_package) + endfunction() + + set( + _hunter_gate_disabled_mode_dir + "${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode" + ) + if(EXISTS "${_hunter_gate_disabled_mode_dir}") + hunter_gate_status_debug( + "Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}" + ) + list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}") + endif() + elseif(_hunter_gate_done) + hunter_gate_status_debug("Secondary HunterGate (use old settings)") + hunter_gate_self( + "${HUNTER_CACHED_ROOT}" + "${HUNTER_VERSION}" + "${HUNTER_SHA1}" + _hunter_self + ) + include("${_hunter_self}/cmake/Hunter") + else() + set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}") + + string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name) + if(_have_project_name) + hunter_gate_fatal_error( + "Please set HunterGate *before* 'project' command. " + "Detected project: ${PROJECT_NAME}" + WIKI "error.huntergate.before.project" + ) + endif() + + cmake_parse_arguments( + HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV} + ) + + string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1) + string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url) + string( + COMPARE + NOTEQUAL + "${HUNTER_GATE_UNPARSED_ARGUMENTS}" + "" + _have_unparsed + ) + string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global) + string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath) + + if(_have_unparsed) + hunter_gate_user_error( + "HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}" + ) + endif() + if(_empty_sha1) + hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory") + endif() + if(_empty_url) + hunter_gate_user_error("URL suboption of HunterGate is mandatory") + endif() + if(_have_global) + if(HUNTER_GATE_LOCAL) + hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)") + endif() + if(_have_filepath) + hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)") + endif() + endif() + if(HUNTER_GATE_LOCAL) + if(_have_global) + hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)") + endif() + if(_have_filepath) + hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)") + endif() + endif() + if(_have_filepath) + if(_have_global) + hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)") + endif() + if(HUNTER_GATE_LOCAL) + hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)") + endif() + endif() + + hunter_gate_detect_root() # set HUNTER_GATE_ROOT + + # Beautify path, fix probable problems with windows path slashes + get_filename_component( + HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE + ) + hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}") + if(NOT HUNTER_ALLOW_SPACES_IN_PATH) + string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces) + if(NOT _contain_spaces EQUAL -1) + hunter_gate_fatal_error( + "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces." + "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error" + "(Use at your own risk!)" + WIKI "error.spaces.in.hunter.root" + ) + endif() + endif() + + string( + REGEX + MATCH + "[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*" + HUNTER_GATE_VERSION + "${HUNTER_GATE_URL}" + ) + string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty) + if(_is_empty) + set(HUNTER_GATE_VERSION "unknown") + endif() + + hunter_gate_self( + "${HUNTER_GATE_ROOT}" + "${HUNTER_GATE_VERSION}" + "${HUNTER_GATE_SHA1}" + _hunter_self + ) + + set(_master_location "${_hunter_self}/cmake/Hunter") + if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter") + # Hunter downloaded manually (e.g. by 'git clone') + set(_unused "xxxxxxxxxx") + set(HUNTER_GATE_SHA1 "${_unused}") + set(HUNTER_GATE_VERSION "${_unused}") + else() + get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE) + set(_done_location "${_archive_id_location}/DONE") + set(_sha1_location "${_archive_id_location}/SHA1") + + # Check Hunter already downloaded by HunterGate + if(NOT EXISTS "${_done_location}") + hunter_gate_download("${_archive_id_location}") + endif() + + if(NOT EXISTS "${_done_location}") + hunter_gate_internal_error("hunter_gate_download failed") + endif() + + if(NOT EXISTS "${_sha1_location}") + hunter_gate_internal_error("${_sha1_location} not found") + endif() + file(READ "${_sha1_location}" _sha1_value) + string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal) + if(NOT _is_equal) + hunter_gate_internal_error( + "Short SHA1 collision:" + " ${_sha1_value} (from ${_sha1_location})" + " ${HUNTER_GATE_SHA1} (HunterGate)" + ) + endif() + if(NOT EXISTS "${_master_location}") + hunter_gate_user_error( + "Master file not found:" + " ${_master_location}" + "try to update Hunter/HunterGate" + ) + endif() + endif() + include("${_master_location}") + set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) + endif() +endmacro() diff --git a/cmake/assimp-hunter-config.cmake.in b/cmake/assimp-hunter-config.cmake.in new file mode 100644 index 000000000..34762ac54 --- /dev/null +++ b/cmake/assimp-hunter-config.cmake.in @@ -0,0 +1,14 @@ +@PACKAGE_INIT@ + +find_package(RapidJSON CONFIG REQUIRED) +find_package(ZLIB CONFIG REQUIRED) +find_package(utf8 CONFIG REQUIRED) +find_package(irrXML CONFIG REQUIRED) +find_package(minizip CONFIG REQUIRED) +find_package(openddlparser CONFIG REQUIRED) +find_package(poly2tri CONFIG REQUIRED) +find_package(polyclipping CONFIG REQUIRED) +find_package(zip CONFIG REQUIRED) + +include("${CMAKE_CURRENT_LIST_DIR}/@TARGETS_EXPORT_NAME@.cmake") +check_required_components("@PROJECT_NAME@") diff --git a/code/3DSConverter.cpp b/code/3DS/3DSConverter.cpp similarity index 99% rename from code/3DSConverter.cpp rename to code/3DS/3DSConverter.cpp index 7ec79ba64..2176b75fc 100644 --- a/code/3DSConverter.cpp +++ b/code/3DS/3DSConverter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers #include "3DSLoader.h" -#include "TargetAnimation.h" +#include "Common/TargetAnimation.h" #include #include #include diff --git a/code/3DSExporter.cpp b/code/3DS/3DSExporter.cpp similarity index 99% rename from code/3DSExporter.cpp rename to code/3DS/3DSExporter.cpp index 53976b16f..1117a52ef 100644 --- a/code/3DSExporter.cpp +++ b/code/3DS/3DSExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -43,15 +43,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_3DS_EXPORTER -#include "3DSExporter.h" -#include "3DSLoader.h" -#include "3DSHelper.h" +#include "3DS/3DSExporter.h" +#include "3DS/3DSLoader.h" +#include "3DS/3DSHelper.h" +#include "PostProcessing/SplitLargeMeshes.h" + #include -#include "SplitLargeMeshes.h" #include #include #include #include + #include using namespace Assimp; diff --git a/code/3DSExporter.h b/code/3DS/3DSExporter.h similarity index 98% rename from code/3DSExporter.h rename to code/3DS/3DSExporter.h index 5db58a4cb..035b562cf 100644 --- a/code/3DSExporter.h +++ b/code/3DS/3DSExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/3DSHelper.h b/code/3DS/3DSHelper.h similarity index 99% rename from code/3DSHelper.h rename to code/3DS/3DSHelper.h index d67a7c14c..8eb4cd97c 100644 --- a/code/3DSHelper.h +++ b/code/3DS/3DSHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/3DSLoader.cpp b/code/3DS/3DSLoader.cpp similarity index 99% rename from code/3DSLoader.cpp rename to code/3DS/3DSLoader.cpp index 34066e44b..3c659d0b0 100644 --- a/code/3DSLoader.cpp +++ b/code/3DS/3DSLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -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 #include #include #include @@ -249,13 +247,14 @@ void Discreet3DSImporter::ApplyMasterScale(aiScene* pScene) // Reads a new chunk from the file void Discreet3DSImporter::ReadChunk(Discreet3DS::Chunk* pcOut) { - ai_assert(pcOut != NULL); + ai_assert(pcOut != nullptr); pcOut->Flag = stream->GetI2(); pcOut->Size = stream->GetI4(); - if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSize()) + if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSize()) { throw DeadlyImportError("Chunk is too large"); + } if (pcOut->Size - sizeof(Discreet3DS::Chunk) > stream->GetRemainingSizeToLimit()) { ASSIMP_LOG_ERROR("3DS: Chunk overflow"); @@ -1343,15 +1342,16 @@ void Discreet3DSImporter::ParseTextureChunk(D3DS::Texture* pcOut) // ------------------------------------------------------------------------------------------------ // Read a percentage chunk -ai_real Discreet3DSImporter::ParsePercentageChunk() -{ +ai_real Discreet3DSImporter::ParsePercentageChunk() { Discreet3DS::Chunk chunk; ReadChunk(&chunk); - if (Discreet3DS::CHUNK_PERCENTF == chunk.Flag) - return stream->GetF4(); - else if (Discreet3DS::CHUNK_PERCENTW == chunk.Flag) + if (Discreet3DS::CHUNK_PERCENTF == chunk.Flag) { + return stream->GetF4() * ai_real(100) / ai_real(0xFFFF); + } else if (Discreet3DS::CHUNK_PERCENTW == chunk.Flag) { return (ai_real)((uint16_t)stream->GetI2()) / (ai_real)0xFFFF; + } + return get_qnan(); } diff --git a/code/3DSLoader.h b/code/3DS/3DSLoader.h similarity index 99% rename from code/3DSLoader.h rename to code/3DS/3DSLoader.h index eb311a81b..f57e6a8e3 100644 --- a/code/3DSLoader.h +++ b/code/3DS/3DSLoader.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/3MFXmlTags.h b/code/3MF/3MFXmlTags.h similarity index 99% rename from code/3MFXmlTags.h rename to code/3MF/3MFXmlTags.h index e869c33c1..ea6aeede0 100644 --- a/code/3MFXmlTags.h +++ b/code/3MF/3MFXmlTags.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/D3MFExporter.cpp b/code/3MF/D3MFExporter.cpp similarity index 98% rename from code/D3MFExporter.cpp rename to code/3MF/D3MFExporter.cpp index 99e2ff3f5..1f388ad3e 100644 --- a/code/D3MFExporter.cpp +++ b/code/3MF/D3MFExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -55,7 +55,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "3MFXmlTags.h" #include "D3MFOpcPackage.h" -#include +#ifdef ASSIMP_USE_HUNTER +# include +#else +# include +#endif namespace Assimp { diff --git a/code/D3MFExporter.h b/code/3MF/D3MFExporter.h similarity index 98% rename from code/D3MFExporter.h rename to code/3MF/D3MFExporter.h index 110862b99..e82120247 100644 --- a/code/D3MFExporter.h +++ b/code/3MF/D3MFExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/D3MFImporter.cpp b/code/3MF/D3MFImporter.cpp similarity index 99% rename from code/D3MFImporter.cpp rename to code/3MF/D3MFImporter.cpp index de5708149..682de684a 100644 --- a/code/D3MFImporter.cpp +++ b/code/3MF/D3MFImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -50,6 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include @@ -58,7 +59,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "D3MFOpcPackage.h" -#include #include #include "3MFXmlTags.h" #include @@ -449,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 ); diff --git a/code/D3MFImporter.h b/code/3MF/D3MFImporter.h similarity index 98% rename from code/D3MFImporter.h rename to code/3MF/D3MFImporter.h index 701d056e2..3dbdf07bf 100644 --- a/code/D3MFImporter.h +++ b/code/3MF/D3MFImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/3MF/D3MFOpcPackage.cpp b/code/3MF/D3MFOpcPackage.cpp new file mode 100644 index 000000000..873ba8ee8 --- /dev/null +++ b/code/3MF/D3MFOpcPackage.cpp @@ -0,0 +1,207 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2019, assimp team + + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ + +#ifndef ASSIMP_BUILD_NO_3MF_IMPORTER + +#include "D3MFOpcPackage.h" +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include "3MFXmlTags.h" + +namespace Assimp { + +namespace D3MF { +// ------------------------------------------------------------------------------------------------ + +typedef std::shared_ptr OpcPackageRelationshipPtr; + +class OpcPackageRelationshipReader { +public: + OpcPackageRelationshipReader(XmlReader* xmlReader) { + while(xmlReader->read()) { + if(xmlReader->getNodeType() == irr::io::EXN_ELEMENT && + xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_CONTAINER) + { + ParseRootNode(xmlReader); + } + } + } + + void ParseRootNode(XmlReader* xmlReader) + { + ParseAttributes(xmlReader); + + while(xmlReader->read()) + { + if(xmlReader->getNodeType() == irr::io::EXN_ELEMENT && + xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_NODE) + { + ParseChildNode(xmlReader); + } + } + } + + void ParseAttributes(XmlReader*) { + // empty + } + + bool validateRels( OpcPackageRelationshipPtr &relPtr ) { + if ( relPtr->id.empty() || relPtr->type.empty() || relPtr->target.empty() ) { + return false; + } + return true; + } + + void ParseChildNode(XmlReader* xmlReader) { + OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship()); + + relPtr->id = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_ID.c_str()); + relPtr->type = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TYPE.c_str()); + relPtr->target = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TARGET.c_str()); + if ( validateRels( relPtr ) ) { + m_relationShips.push_back( relPtr ); + } + } + + std::vector m_relationShips; +}; + +// ------------------------------------------------------------------------------------------------ +D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile) +: mRootStream(nullptr) +, mZipArchive() { + mZipArchive.reset( new ZipArchiveIOSystem( pIOHandler, rFile ) ); + if(!mZipArchive->isOpen()) { + throw DeadlyImportError("Failed to open file " + rFile+ "."); + } + + std::vector fileList; + mZipArchive->getFileList(fileList); + + for (auto& file: fileList) { + if(file == D3MF::XmlTag::ROOT_RELATIONSHIPS_ARCHIVE) { + //PkgRelationshipReader pkgRelReader(file, archive); + ai_assert(mZipArchive->Exists(file.c_str())); + + IOStream *fileStream = mZipArchive->Open(file.c_str()); + + ai_assert(fileStream != nullptr); + + std::string rootFile = ReadPackageRootRelationship(fileStream); + if ( rootFile.size() > 0 && rootFile[ 0 ] == '/' ) { + rootFile = rootFile.substr( 1 ); + if ( rootFile[ 0 ] == '/' ) { + // deal with zip-bug + rootFile = rootFile.substr( 1 ); + } + } + + 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 ); + } + + } else if( file == D3MF::XmlTag::CONTENT_TYPES_ARCHIVE) { + ASSIMP_LOG_WARN_F("Ignored file of unsupported type CONTENT_TYPES_ARCHIVES",file); + } else { + ASSIMP_LOG_WARN_F("Ignored file of unknown type: ",file); + } + + } +} + +D3MFOpcPackage::~D3MFOpcPackage() { + mZipArchive->Close(mRootStream); +} + +IOStream* D3MFOpcPackage::RootStream() const { + return mRootStream; +} + +static const std::string ModelRef = "3D/3dmodel.model"; + +bool D3MFOpcPackage::validate() { + if ( nullptr == mRootStream || nullptr == mZipArchive ) { + return false; + } + + return mZipArchive->Exists( ModelRef.c_str() ); +} + +std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) { + std::unique_ptr xmlStream(new CIrrXML_IOStreamReader(stream)); + std::unique_ptr xml(irr::io::createIrrXMLReader(xmlStream.get())); + + OpcPackageRelationshipReader reader(xml.get()); + + auto itr = std::find_if(reader.m_relationShips.begin(), reader.m_relationShips.end(), [](const OpcPackageRelationshipPtr& rel){ + return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE; + }); + + if ( itr == reader.m_relationShips.end() ) { + throw DeadlyImportError( "Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE ); + } + + return (*itr)->target; +} + +} // Namespace D3MF +} // Namespace Assimp + +#endif //ASSIMP_BUILD_NO_3MF_IMPORTER diff --git a/code/D3MFOpcPackage.h b/code/3MF/D3MFOpcPackage.h similarity index 92% rename from code/D3MFOpcPackage.h rename to code/3MF/D3MFOpcPackage.h index 6d7b3d478..87d172116 100644 --- a/code/D3MFOpcPackage.h +++ b/code/3MF/D3MFOpcPackage.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -49,6 +49,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include 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 mZipArchive; + std::unique_ptr mZipArchive; }; } // Namespace D3MF diff --git a/code/ACLoader.cpp b/code/AC/ACLoader.cpp similarity index 99% rename from code/ACLoader.cpp rename to code/AC/ACLoader.cpp index 7b8afbe9b..d4c4bd1a6 100644 --- a/code/ACLoader.cpp +++ b/code/AC/ACLoader.cpp @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -53,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include "Importer.h" +#include "Common/Importer.h" #include #include #include diff --git a/code/ACLoader.h b/code/AC/ACLoader.h similarity index 99% rename from code/ACLoader.h rename to code/AC/ACLoader.h index 86af9afb6..cab2c3ae5 100644 --- a/code/ACLoader.h +++ b/code/AC/ACLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/AMFImporter.cpp b/code/AMF/AMFImporter.cpp similarity index 99% rename from code/AMFImporter.cpp rename to code/AMF/AMFImporter.cpp index e5b41b3ad..dedb6dcdd 100644 --- a/code/AMFImporter.cpp +++ b/code/AMF/AMFImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -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; } diff --git a/code/AMFImporter.hpp b/code/AMF/AMFImporter.hpp similarity index 99% rename from code/AMFImporter.hpp rename to code/AMF/AMFImporter.hpp index b7e58362c..2b8086a06 100644 --- a/code/AMFImporter.hpp +++ b/code/AMF/AMFImporter.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/AMFImporter_Geometry.cpp b/code/AMF/AMFImporter_Geometry.cpp similarity index 99% rename from code/AMFImporter_Geometry.cpp rename to code/AMF/AMFImporter_Geometry.cpp index d4d648fbd..f1538e3fb 100644 --- a/code/AMFImporter_Geometry.cpp +++ b/code/AMF/AMFImporter_Geometry.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/AMFImporter_Macro.hpp b/code/AMF/AMFImporter_Macro.hpp similarity index 99% rename from code/AMFImporter_Macro.hpp rename to code/AMF/AMFImporter_Macro.hpp index ea8c17850..f60c5fbbb 100644 --- a/code/AMFImporter_Macro.hpp +++ b/code/AMF/AMFImporter_Macro.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/AMFImporter_Material.cpp b/code/AMF/AMFImporter_Material.cpp similarity index 99% rename from code/AMFImporter_Material.cpp rename to code/AMF/AMFImporter_Material.cpp index c9190bb92..2f36df061 100644 --- a/code/AMFImporter_Material.cpp +++ b/code/AMF/AMFImporter_Material.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/AMFImporter_Node.hpp b/code/AMF/AMFImporter_Node.hpp similarity index 99% rename from code/AMFImporter_Node.hpp rename to code/AMF/AMFImporter_Node.hpp index 22b8f58cb..a1bf9f008 100644 --- a/code/AMFImporter_Node.hpp +++ b/code/AMF/AMFImporter_Node.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/AMFImporter_Postprocess.cpp b/code/AMF/AMFImporter_Postprocess.cpp similarity index 98% rename from code/AMFImporter_Postprocess.cpp rename to code/AMF/AMFImporter_Postprocess.cpp index a6ee8fa2f..79b5e15e2 100644 --- a/code/AMFImporter_Postprocess.cpp +++ b/code/AMF/AMFImporter_Postprocess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -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 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& metadataList, aiNode& sceneNode) const @@ -712,7 +712,7 @@ std::list 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::const_iterator mit = mesh_idx.begin(); @@ -787,7 +787,7 @@ std::list ch_node; }// for(const CAMFImporter_NodeElement* ne: pConstellation.Child) // copy found aiNode's as children - if(ch_node.size() == 0) throw DeadlyImportError(" must have at least one ."); + if(ch_node.empty()) throw DeadlyImportError(" must have at least one ."); size_t ch_idx = 0; @@ -883,13 +883,13 @@ nl_clean_loop: if(node_list.size() > 1) { // walk through all nodes - for(std::list::iterator nl_it = node_list.begin(); nl_it != node_list.end(); nl_it++) + for(std::list::iterator nl_it = node_list.begin(); nl_it != node_list.end(); ++nl_it) { // and try to find them in another top nodes. std::list::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::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::const_iterator ml_it = mesh_list.begin(); diff --git a/code/ASELoader.cpp b/code/ASE/ASELoader.cpp similarity index 99% rename from code/ASELoader.cpp rename to code/ASE/ASELoader.cpp index 1808f25e2..8e99214a8 100644 --- a/code/ASELoader.cpp +++ b/code/ASE/ASELoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -53,7 +53,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ASELoader.h" #include #include -#include "TargetAnimation.h" +#include "Common/TargetAnimation.h" + #include #include #include @@ -88,23 +89,25 @@ ASEImporter::ASEImporter() , mBuffer() , pcScene() , configRecomputeNormals() -, noSkeletonMesh() -{} +, noSkeletonMesh() { + // empty +} // ------------------------------------------------------------------------------------------------ // Destructor, private as well -ASEImporter::~ASEImporter() -{} +ASEImporter::~ASEImporter() { + // empty +} // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const -{ +bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const { // check file extension const std::string extension = GetExtension(pFile); - if( extension == "ase" || extension == "ask") + if (extension == "ase" || extension == "ask") { return true; + } if ((!extension.length() || cs) && pIOHandler) { const char* tokens[] = {"*3dsmax_asciiexport"}; @@ -115,15 +118,13 @@ bool ASEImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool // ------------------------------------------------------------------------------------------------ // Loader meta information -const aiImporterDesc* ASEImporter::GetInfo () const -{ +const aiImporterDesc* ASEImporter::GetInfo () const { return &desc; } // ------------------------------------------------------------------------------------------------ // Setup configuration options -void ASEImporter::SetupProperties(const Importer* pImp) -{ +void ASEImporter::SetupProperties(const Importer* pImp) { configRecomputeNormals = (pImp->GetPropertyInteger( AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS,1) ? true : false); @@ -133,12 +134,11 @@ void ASEImporter::SetupProperties(const Importer* pImp) // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. void ASEImporter::InternReadFile( const std::string& pFile, - aiScene* pScene, IOSystem* pIOHandler) -{ + aiScene* pScene, IOSystem* pIOHandler) { std::unique_ptr file( pIOHandler->Open( pFile, "rb")); // Check whether we can read from the file - if( file.get() == NULL) { + if( file.get() == nullptr) { throw DeadlyImportError( "Failed to open ASE file " + pFile + "."); } @@ -1299,7 +1299,7 @@ void ASEImporter::BuildMaterialIndices() } } - // Dekete our temporary array + // Delete our temporary array delete[] pcIntMaterials; } diff --git a/code/ASELoader.h b/code/ASE/ASELoader.h similarity index 99% rename from code/ASELoader.h rename to code/ASE/ASELoader.h index 7f71bf49d..b497aa48b 100644 --- a/code/ASELoader.h +++ b/code/ASE/ASELoader.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/ASEParser.cpp b/code/ASE/ASEParser.cpp similarity index 99% rename from code/ASEParser.cpp rename to code/ASE/ASEParser.cpp index 298c6fe61..913e7b118 100644 --- a/code/ASEParser.cpp +++ b/code/ASE/ASEParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -45,20 +45,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of the ASE parser class */ - #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER // internal headers -#include "TextureTransform.h" +#include "PostProcessing/TextureTransform.h" #include "ASELoader.h" + #include #include using namespace Assimp; using namespace Assimp::ASE; - // ------------------------------------------------------------------------------------------------ // Begin an ASE parsing function diff --git a/code/ASEParser.h b/code/ASE/ASEParser.h similarity index 99% rename from code/ASEParser.h rename to code/ASE/ASEParser.h index 305a3f3d6..988cbda8d 100644 --- a/code/ASEParser.h +++ b/code/ASE/ASEParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -57,7 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include // ASE is quite similar to 3ds. We can reuse some structures -#include "3DSLoader.h" +#include "3DS/3DSLoader.h" namespace Assimp { namespace ASE { @@ -188,10 +188,11 @@ struct Animation { } mRotationType, mScalingType, mPositionType; Animation() AI_NO_EXCEPT - : mRotationType (TRACK) - , mScalingType (TRACK) - , mPositionType (TRACK) - {} + : mRotationType (TRACK) + , mScalingType (TRACK) + , mPositionType (TRACK) { + // empty + } //! List of track rotation keyframes std::vector< aiQuatKey > akeyRotations; @@ -243,7 +244,6 @@ struct BaseNode { mTargetPosition.x = qnan; } - //! Name of the mesh std::string mName; diff --git a/code/AssbinExporter.cpp b/code/Assbin/AssbinExporter.cpp similarity index 99% rename from code/AssbinExporter.cpp rename to code/Assbin/AssbinExporter.cpp index f49389f78..76c823f82 100644 --- a/code/AssbinExporter.cpp +++ b/code/Assbin/AssbinExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -46,12 +46,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER -#include "assbin_chunks.h" +#include "Common/assbin_chunks.h" +#include "PostProcessing/ProcessHelper.h" + #include #include #include #include -#include "ProcessHelper.h" #include #ifdef ASSIMP_BUILD_NO_OWN_ZLIB @@ -760,7 +761,12 @@ public: if (!out) return; time_t tt = time(NULL); +#if _WIN32 tm* p = gmtime(&tt); +#else + struct tm now; + tm* p = gmtime_r(&tt, &now); +#endif // header char s[64]; diff --git a/code/AssbinExporter.h b/code/Assbin/AssbinExporter.h similarity index 98% rename from code/AssbinExporter.h rename to code/Assbin/AssbinExporter.h index ee70d78b6..3e13639bb 100644 --- a/code/AssbinExporter.h +++ b/code/Assbin/AssbinExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/AssbinLoader.cpp b/code/Assbin/AssbinLoader.cpp similarity index 99% rename from code/AssbinLoader.cpp rename to code/Assbin/AssbinLoader.cpp index 321a0cfec..becc3f8fc 100644 --- a/code/AssbinLoader.cpp +++ b/code/Assbin/AssbinLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -50,8 +50,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER // internal headers -#include "AssbinLoader.h" -#include "assbin_chunks.h" +#include "Assbin/AssbinLoader.h" +#include "Common/assbin_chunks.h" #include #include #include @@ -68,7 +68,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; static const aiImporterDesc desc = { - ".assbin Importer", + "Assimp Binary Importer", "Gargaj / Conspiracy", "", "", @@ -708,7 +708,7 @@ void AssbinImporter::InternReadFile( const std::string& pFile, aiScene* pScene, unsigned char * uncompressedData = new unsigned char[ uncompressedSize ]; - int res = uncompress( uncompressedData, &uncompressedSize, compressedData, len ); + int res = uncompress( uncompressedData, &uncompressedSize, compressedData, (uLong) len ); if(res != Z_OK) { delete [] uncompressedData; diff --git a/code/AssbinLoader.h b/code/Assbin/AssbinLoader.h similarity index 98% rename from code/AssbinLoader.h rename to code/Assbin/AssbinLoader.h index 37799a2c8..9f2dde125 100644 --- a/code/AssbinLoader.h +++ b/code/Assbin/AssbinLoader.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/Assjson/cencode.c b/code/Assjson/cencode.c new file mode 100644 index 000000000..db99e7efa --- /dev/null +++ b/code/Assjson/cencode.c @@ -0,0 +1,109 @@ +/* +cencoder.c - c source to a base64 encoding algorithm implementation + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#include "cencode.h" // changed from + +const int CHARS_PER_LINE = 72; + +void base64_init_encodestate(base64_encodestate* state_in) +{ + state_in->step = step_A; + state_in->result = 0; + state_in->stepcount = 0; +} + +char base64_encode_value(char value_in) +{ + static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + if (value_in > 63) return '='; + return encoding[(int)value_in]; +} + +int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in) +{ + const char* plainchar = plaintext_in; + const char* const plaintextend = plaintext_in + length_in; + char* codechar = code_out; + char result; + char fragment; + + result = state_in->result; + + switch (state_in->step) + { + while (1) + { + case step_A: + if (plainchar == plaintextend) + { + state_in->result = result; + state_in->step = step_A; + return codechar - code_out; + } + fragment = *plainchar++; + result = (fragment & 0x0fc) >> 2; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x003) << 4; + case step_B: + if (plainchar == plaintextend) + { + state_in->result = result; + state_in->step = step_B; + return codechar - code_out; + } + fragment = *plainchar++; + result |= (fragment & 0x0f0) >> 4; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x00f) << 2; + case step_C: + if (plainchar == plaintextend) + { + state_in->result = result; + state_in->step = step_C; + return codechar - code_out; + } + fragment = *plainchar++; + result |= (fragment & 0x0c0) >> 6; + *codechar++ = base64_encode_value(result); + result = (fragment & 0x03f) >> 0; + *codechar++ = base64_encode_value(result); + + ++(state_in->stepcount); + if (state_in->stepcount == CHARS_PER_LINE/4) + { + *codechar++ = '\n'; + state_in->stepcount = 0; + } + } + } + /* control should not reach here */ + return codechar - code_out; +} + +int base64_encode_blockend(char* code_out, base64_encodestate* state_in) +{ + char* codechar = code_out; + + switch (state_in->step) + { + case step_B: + *codechar++ = base64_encode_value(state_in->result); + *codechar++ = '='; + *codechar++ = '='; + break; + case step_C: + *codechar++ = base64_encode_value(state_in->result); + *codechar++ = '='; + break; + case step_A: + break; + } + *codechar++ = '\n'; + + return codechar - code_out; +} + diff --git a/code/Assjson/cencode.h b/code/Assjson/cencode.h new file mode 100644 index 000000000..c1e3464af --- /dev/null +++ b/code/Assjson/cencode.h @@ -0,0 +1,31 @@ +/* +cencode.h - c header for a base64 encoding algorithm + +This is part of the libb64 project, and has been placed in the public domain. +For details, see http://sourceforge.net/projects/libb64 +*/ + +#ifndef BASE64_CENCODE_H +#define BASE64_CENCODE_H + +typedef enum +{ + step_A, step_B, step_C +} base64_encodestep; + +typedef struct +{ + base64_encodestep step; + char result; + int stepcount; +} base64_encodestate; + +void base64_init_encodestate(base64_encodestate* state_in); + +char base64_encode_value(char value_in); + +int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in); + +int base64_encode_blockend(char* code_out, base64_encodestate* state_in); + +#endif /* BASE64_CENCODE_H */ diff --git a/code/Assjson/json_exporter.cpp b/code/Assjson/json_exporter.cpp new file mode 100644 index 000000000..e9fa72496 --- /dev/null +++ b/code/Assjson/json_exporter.cpp @@ -0,0 +1,809 @@ +/* +Assimp2Json +Copyright (c) 2011, Alexander C. Gessler + +Licensed under a 3-clause BSD license. See the LICENSE file for more information. + +*/ + +#ifndef ASSIMP_BUILD_NO_EXPORT +#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define CURRENT_FORMAT_VERSION 100 + +// grab scoped_ptr from assimp to avoid a dependency on boost. +//#include + +#include "mesh_splitter.h" + +extern "C" { + #include "cencode.h" +} +namespace Assimp { + +void ExportAssimp2Json(const char*, Assimp::IOSystem*, const aiScene*, const Assimp::ExportProperties*); + +// small utility class to simplify serializing the aiScene to Json +class JSONWriter { +public: + enum { + Flag_DoNotIndent = 0x1, + Flag_WriteSpecialFloats = 0x2, + }; + + JSONWriter(Assimp::IOStream& out, unsigned int flags = 0u) + : out(out) + , first() + , flags(flags) { + // make sure that all formatting happens using the standard, C locale and not the user's current locale + buff.imbue(std::locale("C")); + } + + ~JSONWriter() { + Flush(); + } + + void Flush() { + const std::string s = buff.str(); + out.Write(s.c_str(), s.length(), 1); + buff.clear(); + } + + void PushIndent() { + indent += '\t'; + } + + void PopIndent() { + indent.erase(indent.end() - 1); + } + + void Key(const std::string& name) { + AddIndentation(); + Delimit(); + buff << '\"' + name + "\": "; + } + + template + void Element(const Literal& name) { + AddIndentation(); + Delimit(); + + LiteralToString(buff, name) << '\n'; + } + + template + void SimpleValue(const Literal& s) { + LiteralToString(buff, s) << '\n'; + } + + void SimpleValue(const void* buffer, size_t len) { + base64_encodestate s; + base64_init_encodestate(&s); + + char* const out = new char[std::max(len * 2, static_cast(16u))]; + const int n = base64_encode_block(reinterpret_cast(buffer), static_cast(len), out, &s); + out[n + base64_encode_blockend(out + n, &s)] = '\0'; + + // base64 encoding may add newlines, but JSON strings may not contain 'real' newlines + // (only escaped ones). Remove any newlines in out. + for (char* cur = out; *cur; ++cur) { + if (*cur == '\n') { + *cur = ' '; + } + } + + buff << '\"' << out << "\"\n"; + delete[] out; + } + + void StartObj(bool is_element = false) { + // if this appears as a plain array element, we need to insert a delimiter and we should also indent it + if (is_element) { + AddIndentation(); + if (!first) { + buff << ','; + } + } + first = true; + buff << "{\n"; + PushIndent(); + } + + void EndObj() { + PopIndent(); + AddIndentation(); + first = false; + buff << "}\n"; + } + + void StartArray(bool is_element = false) { + // if this appears as a plain array element, we need to insert a delimiter and we should also indent it + if (is_element) { + AddIndentation(); + if (!first) { + buff << ','; + } + } + first = true; + buff << "[\n"; + PushIndent(); + } + + void EndArray() { + PopIndent(); + AddIndentation(); + buff << "]\n"; + first = false; + } + + void AddIndentation() { + if (!(flags & Flag_DoNotIndent)) { + buff << indent; + } + } + + void Delimit() { + if (!first) { + buff << ','; + } + else { + buff << ' '; + first = false; + } + } + +private: + template + std::stringstream& LiteralToString(std::stringstream& stream, const Literal& s) { + stream << s; + return stream; + } + + std::stringstream& LiteralToString(std::stringstream& stream, const aiString& s) { + std::string t; + + // escape backslashes and single quotes, both would render the JSON invalid if left as is + t.reserve(s.length); + for (size_t i = 0; i < s.length; ++i) { + + if (s.data[i] == '\\' || s.data[i] == '\'' || s.data[i] == '\"') { + t.push_back('\\'); + } + + t.push_back(s.data[i]); + } + stream << "\""; + stream << t; + stream << "\""; + return stream; + } + + std::stringstream& LiteralToString(std::stringstream& stream, float f) { + if (!std::numeric_limits::is_iec559) { + // on a non IEEE-754 platform, we make no assumptions about the representation or existence + // of special floating-point numbers. + stream << f; + return stream; + } + + // JSON does not support writing Inf/Nan + // [RFC 4672: "Numeric values that cannot be represented as sequences of digits + // (such as Infinity and NaN) are not permitted."] + // Nevertheless, many parsers will accept the special keywords Infinity, -Infinity and NaN + if (std::numeric_limits::infinity() == fabs(f)) { + if (flags & Flag_WriteSpecialFloats) { + stream << (f < 0 ? "\"-" : "\"") + std::string("Infinity\""); + return stream; + } + // we should print this warning, but we can't - this is called from within a generic assimp exporter, we cannot use cerr + // std::cerr << "warning: cannot represent infinite number literal, substituting 0 instead (use -i flag to enforce Infinity/NaN)" << std::endl; + stream << "0.0"; + return stream; + } + // f!=f is the most reliable test for NaNs that I know of + else if (f != f) { + if (flags & Flag_WriteSpecialFloats) { + stream << "\"NaN\""; + return stream; + } + // we should print this warning, but we can't - this is called from within a generic assimp exporter, we cannot use cerr + // std::cerr << "warning: cannot represent infinite number literal, substituting 0 instead (use -i flag to enforce Infinity/NaN)" << std::endl; + stream << "0.0"; + return stream; + } + + stream << f; + return stream; + } + +private: + Assimp::IOStream& out; + std::string indent, newline; + std::stringstream buff; + bool first; + + unsigned int flags; +}; + +void Write(JSONWriter& out, const aiVector3D& ai, bool is_elem = true) { + out.StartArray(is_elem); + out.Element(ai.x); + out.Element(ai.y); + out.Element(ai.z); + out.EndArray(); +} + +void Write(JSONWriter& out, const aiQuaternion& ai, bool is_elem = true) { + out.StartArray(is_elem); + out.Element(ai.w); + out.Element(ai.x); + out.Element(ai.y); + out.Element(ai.z); + out.EndArray(); +} + +void Write(JSONWriter& out, const aiColor3D& ai, bool is_elem = true) { + out.StartArray(is_elem); + out.Element(ai.r); + out.Element(ai.g); + out.Element(ai.b); + out.EndArray(); +} + +void Write(JSONWriter& out, const aiMatrix4x4& ai, bool is_elem = true) { + out.StartArray(is_elem); + for (unsigned int x = 0; x < 4; ++x) { + for (unsigned int y = 0; y < 4; ++y) { + out.Element(ai[x][y]); + } + } + out.EndArray(); +} + +void Write(JSONWriter& out, const aiBone& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("name"); + out.SimpleValue(ai.mName); + + out.Key("offsetmatrix"); + Write(out, ai.mOffsetMatrix, false); + + out.Key("weights"); + out.StartArray(); + for (unsigned int i = 0; i < ai.mNumWeights; ++i) { + out.StartArray(true); + out.Element(ai.mWeights[i].mVertexId); + out.Element(ai.mWeights[i].mWeight); + out.EndArray(); + } + out.EndArray(); + out.EndObj(); +} + +void Write(JSONWriter& out, const aiFace& ai, bool is_elem = true) { + out.StartArray(is_elem); + for (unsigned int i = 0; i < ai.mNumIndices; ++i) { + out.Element(ai.mIndices[i]); + } + out.EndArray(); +} + +void Write(JSONWriter& out, const aiMesh& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("name"); + out.SimpleValue(ai.mName); + + out.Key("materialindex"); + out.SimpleValue(ai.mMaterialIndex); + + out.Key("primitivetypes"); + out.SimpleValue(ai.mPrimitiveTypes); + + out.Key("vertices"); + out.StartArray(); + for (unsigned int i = 0; i < ai.mNumVertices; ++i) { + out.Element(ai.mVertices[i].x); + out.Element(ai.mVertices[i].y); + out.Element(ai.mVertices[i].z); + } + out.EndArray(); + + if (ai.HasNormals()) { + out.Key("normals"); + out.StartArray(); + for (unsigned int i = 0; i < ai.mNumVertices; ++i) { + out.Element(ai.mNormals[i].x); + out.Element(ai.mNormals[i].y); + out.Element(ai.mNormals[i].z); + } + out.EndArray(); + } + + if (ai.HasTangentsAndBitangents()) { + out.Key("tangents"); + out.StartArray(); + for (unsigned int i = 0; i < ai.mNumVertices; ++i) { + out.Element(ai.mTangents[i].x); + out.Element(ai.mTangents[i].y); + out.Element(ai.mTangents[i].z); + } + out.EndArray(); + + out.Key("bitangents"); + out.StartArray(); + for (unsigned int i = 0; i < ai.mNumVertices; ++i) { + out.Element(ai.mBitangents[i].x); + out.Element(ai.mBitangents[i].y); + out.Element(ai.mBitangents[i].z); + } + out.EndArray(); + } + + if (ai.GetNumUVChannels()) { + out.Key("numuvcomponents"); + out.StartArray(); + for (unsigned int n = 0; n < ai.GetNumUVChannels(); ++n) { + out.Element(ai.mNumUVComponents[n]); + } + out.EndArray(); + + out.Key("texturecoords"); + out.StartArray(); + for (unsigned int n = 0; n < ai.GetNumUVChannels(); ++n) { + const unsigned int numc = ai.mNumUVComponents[n] ? ai.mNumUVComponents[n] : 2; + + out.StartArray(true); + for (unsigned int i = 0; i < ai.mNumVertices; ++i) { + for (unsigned int c = 0; c < numc; ++c) { + out.Element(ai.mTextureCoords[n][i][c]); + } + } + out.EndArray(); + } + out.EndArray(); + } + + if (ai.GetNumColorChannels()) { + out.Key("colors"); + out.StartArray(); + for (unsigned int n = 0; n < ai.GetNumColorChannels(); ++n) { + out.StartArray(true); + for (unsigned int i = 0; i < ai.mNumVertices; ++i) { + out.Element(ai.mColors[n][i].r); + out.Element(ai.mColors[n][i].g); + out.Element(ai.mColors[n][i].b); + out.Element(ai.mColors[n][i].a); + } + out.EndArray(); + } + out.EndArray(); + } + + if (ai.mNumBones) { + out.Key("bones"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumBones; ++n) { + Write(out, *ai.mBones[n]); + } + out.EndArray(); + } + + out.Key("faces"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumFaces; ++n) { + Write(out, ai.mFaces[n]); + } + out.EndArray(); + + out.EndObj(); +} + +void Write(JSONWriter& out, const aiNode& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("name"); + out.SimpleValue(ai.mName); + + out.Key("transformation"); + Write(out, ai.mTransformation, false); + + if (ai.mNumMeshes) { + out.Key("meshes"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumMeshes; ++n) { + out.Element(ai.mMeshes[n]); + } + out.EndArray(); + } + + if (ai.mNumChildren) { + out.Key("children"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumChildren; ++n) { + Write(out, *ai.mChildren[n]); + } + out.EndArray(); + } + + out.EndObj(); +} + +void Write(JSONWriter& out, const aiMaterial& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("properties"); + out.StartArray(); + for (unsigned int i = 0; i < ai.mNumProperties; ++i) { + const aiMaterialProperty* const prop = ai.mProperties[i]; + out.StartObj(true); + out.Key("key"); + out.SimpleValue(prop->mKey); + out.Key("semantic"); + out.SimpleValue(prop->mSemantic); + out.Key("index"); + out.SimpleValue(prop->mIndex); + + out.Key("type"); + out.SimpleValue(prop->mType); + + out.Key("value"); + switch (prop->mType) { + case aiPTI_Float: + if (prop->mDataLength / sizeof(float) > 1) { + out.StartArray(); + for (unsigned int i = 0; i < prop->mDataLength / sizeof(float); ++i) { + out.Element(reinterpret_cast(prop->mData)[i]); + } + out.EndArray(); + } + else { + out.SimpleValue(*reinterpret_cast(prop->mData)); + } + break; + + case aiPTI_Integer: + if (prop->mDataLength / sizeof(int) > 1) { + out.StartArray(); + for (unsigned int i = 0; i < prop->mDataLength / sizeof(int); ++i) { + out.Element(reinterpret_cast(prop->mData)[i]); + } + out.EndArray(); + } else { + out.SimpleValue(*reinterpret_cast(prop->mData)); + } + break; + + case aiPTI_String: + { + aiString s; + aiGetMaterialString(&ai, prop->mKey.data, prop->mSemantic, prop->mIndex, &s); + out.SimpleValue(s); + } + break; + case aiPTI_Buffer: + { + // binary data is written as series of hex-encoded octets + out.SimpleValue(prop->mData, prop->mDataLength); + } + break; + default: + assert(false); + } + + out.EndObj(); + } + + out.EndArray(); + out.EndObj(); +} + +void Write(JSONWriter& out, const aiTexture& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("width"); + out.SimpleValue(ai.mWidth); + + out.Key("height"); + out.SimpleValue(ai.mHeight); + + out.Key("formathint"); + out.SimpleValue(aiString(ai.achFormatHint)); + + out.Key("data"); + if (!ai.mHeight) { + out.SimpleValue(ai.pcData, ai.mWidth); + } + else { + out.StartArray(); + for (unsigned int y = 0; y < ai.mHeight; ++y) { + out.StartArray(true); + for (unsigned int x = 0; x < ai.mWidth; ++x) { + const aiTexel& tx = ai.pcData[y*ai.mWidth + x]; + out.StartArray(true); + out.Element(static_cast(tx.r)); + out.Element(static_cast(tx.g)); + out.Element(static_cast(tx.b)); + out.Element(static_cast(tx.a)); + out.EndArray(); + } + out.EndArray(); + } + out.EndArray(); + } + + out.EndObj(); +} + +void Write(JSONWriter& out, const aiLight& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("name"); + out.SimpleValue(ai.mName); + + out.Key("type"); + out.SimpleValue(ai.mType); + + if (ai.mType == aiLightSource_SPOT || ai.mType == aiLightSource_UNDEFINED) { + out.Key("angleinnercone"); + out.SimpleValue(ai.mAngleInnerCone); + + out.Key("angleoutercone"); + out.SimpleValue(ai.mAngleOuterCone); + } + + out.Key("attenuationconstant"); + out.SimpleValue(ai.mAttenuationConstant); + + out.Key("attenuationlinear"); + out.SimpleValue(ai.mAttenuationLinear); + + out.Key("attenuationquadratic"); + out.SimpleValue(ai.mAttenuationQuadratic); + + out.Key("diffusecolor"); + Write(out, ai.mColorDiffuse, false); + + out.Key("specularcolor"); + Write(out, ai.mColorSpecular, false); + + out.Key("ambientcolor"); + Write(out, ai.mColorAmbient, false); + + if (ai.mType != aiLightSource_POINT) { + out.Key("direction"); + Write(out, ai.mDirection, false); + + } + + if (ai.mType != aiLightSource_DIRECTIONAL) { + out.Key("position"); + Write(out, ai.mPosition, false); + } + + out.EndObj(); +} + +void Write(JSONWriter& out, const aiNodeAnim& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("name"); + out.SimpleValue(ai.mNodeName); + + out.Key("prestate"); + out.SimpleValue(ai.mPreState); + + out.Key("poststate"); + out.SimpleValue(ai.mPostState); + + if (ai.mNumPositionKeys) { + out.Key("positionkeys"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumPositionKeys; ++n) { + const aiVectorKey& pos = ai.mPositionKeys[n]; + out.StartArray(true); + out.Element(pos.mTime); + Write(out, pos.mValue); + out.EndArray(); + } + out.EndArray(); + } + + if (ai.mNumRotationKeys) { + out.Key("rotationkeys"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumRotationKeys; ++n) { + const aiQuatKey& rot = ai.mRotationKeys[n]; + out.StartArray(true); + out.Element(rot.mTime); + Write(out, rot.mValue); + out.EndArray(); + } + out.EndArray(); + } + + if (ai.mNumScalingKeys) { + out.Key("scalingkeys"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumScalingKeys; ++n) { + const aiVectorKey& scl = ai.mScalingKeys[n]; + out.StartArray(true); + out.Element(scl.mTime); + Write(out, scl.mValue); + out.EndArray(); + } + out.EndArray(); + } + out.EndObj(); +} + +void Write(JSONWriter& out, const aiAnimation& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("name"); + out.SimpleValue(ai.mName); + + out.Key("tickspersecond"); + out.SimpleValue(ai.mTicksPerSecond); + + out.Key("duration"); + out.SimpleValue(ai.mDuration); + + out.Key("channels"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumChannels; ++n) { + Write(out, *ai.mChannels[n]); + } + out.EndArray(); + out.EndObj(); +} + +void Write(JSONWriter& out, const aiCamera& ai, bool is_elem = true) { + out.StartObj(is_elem); + + out.Key("name"); + out.SimpleValue(ai.mName); + + out.Key("aspect"); + out.SimpleValue(ai.mAspect); + + out.Key("clipplanefar"); + out.SimpleValue(ai.mClipPlaneFar); + + out.Key("clipplanenear"); + out.SimpleValue(ai.mClipPlaneNear); + + out.Key("horizontalfov"); + out.SimpleValue(ai.mHorizontalFOV); + + out.Key("up"); + Write(out, ai.mUp, false); + + out.Key("lookat"); + Write(out, ai.mLookAt, false); + + out.EndObj(); +} + +void WriteFormatInfo(JSONWriter& out) { + out.StartObj(); + out.Key("format"); + out.SimpleValue("\"assimp2json\""); + out.Key("version"); + out.SimpleValue(CURRENT_FORMAT_VERSION); + out.EndObj(); +} + +void Write(JSONWriter& out, const aiScene& ai) { + out.StartObj(); + + out.Key("__metadata__"); + WriteFormatInfo(out); + + out.Key("rootnode"); + Write(out, *ai.mRootNode, false); + + out.Key("flags"); + out.SimpleValue(ai.mFlags); + + if (ai.HasMeshes()) { + out.Key("meshes"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumMeshes; ++n) { + Write(out, *ai.mMeshes[n]); + } + out.EndArray(); + } + + if (ai.HasMaterials()) { + out.Key("materials"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumMaterials; ++n) { + Write(out, *ai.mMaterials[n]); + } + out.EndArray(); + } + + if (ai.HasAnimations()) { + out.Key("animations"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumAnimations; ++n) { + Write(out, *ai.mAnimations[n]); + } + out.EndArray(); + } + + if (ai.HasLights()) { + out.Key("lights"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumLights; ++n) { + Write(out, *ai.mLights[n]); + } + out.EndArray(); + } + + if (ai.HasCameras()) { + out.Key("cameras"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumCameras; ++n) { + Write(out, *ai.mCameras[n]); + } + out.EndArray(); + } + + if (ai.HasTextures()) { + out.Key("textures"); + out.StartArray(); + for (unsigned int n = 0; n < ai.mNumTextures; ++n) { + Write(out, *ai.mTextures[n]); + } + out.EndArray(); + } + out.EndObj(); +} + + +void ExportAssimp2Json(const char* file, Assimp::IOSystem* io, const aiScene* scene, const Assimp::ExportProperties*) { + std::unique_ptr str(io->Open(file, "wt")); + if (!str) { + //throw Assimp::DeadlyExportError("could not open output file"); + } + + // get a copy of the scene so we can modify it + aiScene* scenecopy_tmp; + aiCopyScene(scene, &scenecopy_tmp); + + try { + // split meshes so they fit into a 16 bit index buffer + MeshSplitter splitter; + splitter.SetLimit(1 << 16); + splitter.Execute(scenecopy_tmp); + + // XXX Flag_WriteSpecialFloats is turned on by default, right now we don't have a configuration interface for exporters + JSONWriter s(*str, JSONWriter::Flag_WriteSpecialFloats); + Write(s, *scenecopy_tmp); + + } + catch (...) { + aiFreeScene(scenecopy_tmp); + throw; + } + aiFreeScene(scenecopy_tmp); +} + +} + +#endif // ASSIMP_BUILD_NO_ASSJSON_EXPORTER +#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/Assjson/mesh_splitter.cpp b/code/Assjson/mesh_splitter.cpp new file mode 100644 index 000000000..24385f9a0 --- /dev/null +++ b/code/Assjson/mesh_splitter.cpp @@ -0,0 +1,320 @@ +/* +Assimp2Json +Copyright (c) 2011, Alexander C. Gessler + +Licensed under a 3-clause BSD license. See the LICENSE file for more information. + +*/ + +#include "mesh_splitter.h" + +#include + +// ---------------------------------------------------------------------------- +// Note: this is largely based on assimp's SplitLargeMeshes_Vertex process. +// it is refactored and the coding style is slightly improved, though. +// ---------------------------------------------------------------------------- + +// ------------------------------------------------------------------------------------------------ +// Executes the post processing step on the given imported data. +void MeshSplitter::Execute( aiScene* pScene) { + std::vector > source_mesh_map; + + for( unsigned int a = 0; a < pScene->mNumMeshes; a++) { + SplitMesh(a, pScene->mMeshes[a],source_mesh_map); + } + + const unsigned int size = static_cast(source_mesh_map.size()); + if (size != pScene->mNumMeshes) { + // it seems something has been split. rebuild the mesh list + delete[] pScene->mMeshes; + pScene->mNumMeshes = size; + pScene->mMeshes = new aiMesh*[size](); + + for (unsigned int i = 0; i < size;++i) { + pScene->mMeshes[i] = source_mesh_map[i].first; + } + + // now we need to update all nodes + UpdateNode(pScene->mRootNode,source_mesh_map); + } +} + + +// ------------------------------------------------------------------------------------------------ +void MeshSplitter::UpdateNode(aiNode* pcNode, const std::vector >& source_mesh_map) { + // TODO: should better use std::(multi)set for source_mesh_map. + + // for every index in out list build a new entry + std::vector aiEntries; + aiEntries.reserve(pcNode->mNumMeshes + 1); + for (unsigned int i = 0; i < pcNode->mNumMeshes;++i) { + for (unsigned int a = 0, end = static_cast(source_mesh_map.size()); a < end;++a) { + if (source_mesh_map[a].second == pcNode->mMeshes[i]) { + aiEntries.push_back(a); + } + } + } + + // now build the new list + delete pcNode->mMeshes; + pcNode->mNumMeshes = static_cast(aiEntries.size()); + pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes]; + + for (unsigned int b = 0; b < pcNode->mNumMeshes;++b) { + pcNode->mMeshes[b] = aiEntries[b]; + } + + // recursively update children + for (unsigned int i = 0, end = pcNode->mNumChildren; i < end;++i) { + UpdateNode ( pcNode->mChildren[i], source_mesh_map ); + } + return; +} + +#define WAS_NOT_COPIED 0xffffffff + +typedef std::pair PerVertexWeight; +typedef std::vector VertexWeightTable; + +// ------------------------------------------------------------------------------------------------ +VertexWeightTable* ComputeVertexBoneWeightTable(const aiMesh* pMesh) { + if (!pMesh || !pMesh->mNumVertices || !pMesh->mNumBones) { + return nullptr; + } + + VertexWeightTable* const avPerVertexWeights = new VertexWeightTable[pMesh->mNumVertices]; + for (unsigned int i = 0; i < pMesh->mNumBones;++i) { + + aiBone* bone = pMesh->mBones[i]; + for (unsigned int a = 0; a < bone->mNumWeights;++a) { + const aiVertexWeight& weight = bone->mWeights[a]; + avPerVertexWeights[weight.mVertexId].push_back( std::make_pair(i,weight.mWeight) ); + } + } + return avPerVertexWeights; +} + +// ------------------------------------------------------------------------------------------------ +void MeshSplitter :: SplitMesh(unsigned int a, aiMesh* in_mesh, std::vector >& source_mesh_map) { + // TODO: should better use std::(multi)set for source_mesh_map. + + if (in_mesh->mNumVertices <= LIMIT) { + source_mesh_map.push_back(std::make_pair(in_mesh,a)); + return; + } + + // build a per-vertex weight list if necessary + VertexWeightTable* avPerVertexWeights = ComputeVertexBoneWeightTable(in_mesh); + + // we need to split this mesh into sub meshes. Estimate submesh size + const unsigned int sub_meshes = (in_mesh->mNumVertices / LIMIT) + 1; + + // create a std::vector to remember which vertices have already + // been copied and to which position (i.e. output index) + std::vector was_copied_to; + was_copied_to.resize(in_mesh->mNumVertices,WAS_NOT_COPIED); + + // Try to find a good estimate for the number of output faces + // per mesh. Add 12.5% as buffer + unsigned int size_estimated = in_mesh->mNumFaces / sub_meshes; + size_estimated += size_estimated / 8; + + // now generate all submeshes + unsigned int base = 0; + while (true) { + const unsigned int out_vertex_index = LIMIT; + + aiMesh* out_mesh = new aiMesh(); + out_mesh->mNumVertices = 0; + out_mesh->mMaterialIndex = in_mesh->mMaterialIndex; + + // the name carries the adjacency information between the meshes + out_mesh->mName = in_mesh->mName; + + typedef std::vector BoneWeightList; + if (in_mesh->HasBones()) { + out_mesh->mBones = new aiBone*[in_mesh->mNumBones](); + } + + // clear the temporary helper array + if (base) { + std::fill(was_copied_to.begin(), was_copied_to.end(), WAS_NOT_COPIED); + } + + std::vector vFaces; + + // reserve enough storage for most cases + if (in_mesh->HasPositions()) { + out_mesh->mVertices = new aiVector3D[out_vertex_index]; + } + + if (in_mesh->HasNormals()) { + out_mesh->mNormals = new aiVector3D[out_vertex_index]; + } + + if (in_mesh->HasTangentsAndBitangents()) { + out_mesh->mTangents = new aiVector3D[out_vertex_index]; + out_mesh->mBitangents = new aiVector3D[out_vertex_index]; + } + + for (unsigned int c = 0; in_mesh->HasVertexColors(c);++c) { + out_mesh->mColors[c] = new aiColor4D[out_vertex_index]; + } + + for (unsigned int c = 0; in_mesh->HasTextureCoords(c);++c) { + out_mesh->mNumUVComponents[c] = in_mesh->mNumUVComponents[c]; + out_mesh->mTextureCoords[c] = new aiVector3D[out_vertex_index]; + } + vFaces.reserve(size_estimated); + + // (we will also need to copy the array of indices) + while (base < in_mesh->mNumFaces) { + const unsigned int iNumIndices = in_mesh->mFaces[base].mNumIndices; + + // doesn't catch degenerates but is quite fast + unsigned int iNeed = 0; + for (unsigned int v = 0; v < iNumIndices;++v) { + unsigned int index = in_mesh->mFaces[base].mIndices[v]; + + // check whether we do already have this vertex + if (WAS_NOT_COPIED == was_copied_to[index]) { + iNeed++; + } + } + if (out_mesh->mNumVertices + iNeed > out_vertex_index) { + // don't use this face + break; + } + + vFaces.push_back(aiFace()); + aiFace& rFace = vFaces.back(); + + // setup face type and number of indices + rFace.mNumIndices = iNumIndices; + rFace.mIndices = new unsigned int[iNumIndices]; + + // need to update the output primitive types + switch (rFace.mNumIndices) + { + case 1: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; + break; + case 2: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; + break; + case 3: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; + break; + default: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; + } + + // and copy the contents of the old array, offset them by current base + for (unsigned int v = 0; v < iNumIndices;++v) { + const unsigned int index = in_mesh->mFaces[base].mIndices[v]; + + // check whether we do already have this vertex + if (WAS_NOT_COPIED != was_copied_to[index]) { + rFace.mIndices[v] = was_copied_to[index]; + continue; + } + + // copy positions + out_mesh->mVertices[out_mesh->mNumVertices] = (in_mesh->mVertices[index]); + + // copy normals + if (in_mesh->HasNormals()) { + out_mesh->mNormals[out_mesh->mNumVertices] = (in_mesh->mNormals[index]); + } + + // copy tangents/bi-tangents + if (in_mesh->HasTangentsAndBitangents()) { + out_mesh->mTangents[out_mesh->mNumVertices] = (in_mesh->mTangents[index]); + out_mesh->mBitangents[out_mesh->mNumVertices] = (in_mesh->mBitangents[index]); + } + + // texture coordinates + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) { + if (in_mesh->HasTextureCoords( c)) { + out_mesh->mTextureCoords[c][out_mesh->mNumVertices] = in_mesh->mTextureCoords[c][index]; + } + } + // vertex colors + for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_COLOR_SETS;++c) { + if (in_mesh->HasVertexColors( c)) { + out_mesh->mColors[c][out_mesh->mNumVertices] = in_mesh->mColors[c][index]; + } + } + // check whether we have bone weights assigned to this vertex + rFace.mIndices[v] = out_mesh->mNumVertices; + if (avPerVertexWeights) { + VertexWeightTable& table = avPerVertexWeights[ out_mesh->mNumVertices ]; + for (VertexWeightTable::const_iterator iter = table.begin(), end = table.end(); iter != end;++iter) { + // allocate the bone weight array if necessary and store it in the mBones field (HACK!) + BoneWeightList* weight_list = reinterpret_cast(out_mesh->mBones[(*iter).first]); + if (!weight_list) { + weight_list = new BoneWeightList(); + out_mesh->mBones[(*iter).first] = reinterpret_cast(weight_list); + } + weight_list->push_back(aiVertexWeight(out_mesh->mNumVertices,(*iter).second)); + } + } + + was_copied_to[index] = out_mesh->mNumVertices; + out_mesh->mNumVertices++; + } + base++; + if(out_mesh->mNumVertices == out_vertex_index) { + // break here. The face is only added if it was complete + break; + } + } + + // check which bones we'll need to create for this submesh + if (in_mesh->HasBones()) { + aiBone** ppCurrent = out_mesh->mBones; + for (unsigned int k = 0; k < in_mesh->mNumBones;++k) { + // check whether the bone exists + BoneWeightList* const weight_list = reinterpret_cast(out_mesh->mBones[k]); + + if (weight_list) { + const aiBone* const bone_in = in_mesh->mBones[k]; + aiBone* const bone_out = new aiBone(); + *ppCurrent++ = bone_out; + bone_out->mName = aiString(bone_in->mName); + bone_out->mOffsetMatrix =bone_in->mOffsetMatrix; + bone_out->mNumWeights = (unsigned int)weight_list->size(); + bone_out->mWeights = new aiVertexWeight[bone_out->mNumWeights]; + + // copy the vertex weights + ::memcpy(bone_out->mWeights, &(*weight_list)[0],bone_out->mNumWeights * sizeof(aiVertexWeight)); + + delete weight_list; + out_mesh->mNumBones++; + } + } + } + + // copy the face list to the mesh + out_mesh->mFaces = new aiFace[vFaces.size()]; + out_mesh->mNumFaces = (unsigned int)vFaces.size(); + + for (unsigned int p = 0; p < out_mesh->mNumFaces;++p) { + out_mesh->mFaces[p] = vFaces[p]; + } + + // add the newly created mesh to the list + source_mesh_map.push_back(std::make_pair(out_mesh,a)); + + if (base == in_mesh->mNumFaces) { + break; + } + } + + // delete the per-vertex weight list again + delete[] avPerVertexWeights; + + // now delete the old mesh data + delete in_mesh; +} diff --git a/code/Assjson/mesh_splitter.h b/code/Assjson/mesh_splitter.h new file mode 100644 index 000000000..326f73b41 --- /dev/null +++ b/code/Assjson/mesh_splitter.h @@ -0,0 +1,61 @@ +/* +Assimp2Json +Copyright (c) 2011, Alexander C. Gessler + +Licensed under a 3-clause BSD license. See the LICENSE file for more information. + +*/ + +#ifndef INCLUDED_MESH_SPLITTER +#define INCLUDED_MESH_SPLITTER + +// ---------------------------------------------------------------------------- +// Note: this is largely based on assimp's SplitLargeMeshes_Vertex process. +// it is refactored and the coding style is slightly improved, though. +// ---------------------------------------------------------------------------- + +#include + +struct aiScene; +struct aiMesh; +struct aiNode; + +// --------------------------------------------------------------------------- +/** Splits meshes of unique vertices into meshes with no more vertices than + * a given, configurable threshold value. + */ +class MeshSplitter +{ + +public: + + void SetLimit(unsigned int l) { + LIMIT = l; + } + + unsigned int GetLimit() const { + return LIMIT; + } + +public: + + // ------------------------------------------------------------------- + /** Executes the post processing step on the given imported data. + * At the moment a process is not supposed to fail. + * @param pScene The imported data to work at. + */ + void Execute( aiScene* pScene); + + +private: + + void UpdateNode(aiNode* pcNode, const std::vector >& source_mesh_map); + void SplitMesh (unsigned int index, aiMesh* mesh, std::vector >& source_mesh_map); + +public: + + unsigned int LIMIT; +}; + +#endif // INCLUDED_MESH_SPLITTER + diff --git a/code/AssxmlExporter.cpp b/code/Assxml/AssxmlExporter.cpp similarity index 99% rename from code/AssxmlExporter.cpp rename to code/Assxml/AssxmlExporter.cpp index c9e125d0d..afdecbaf6 100644 --- a/code/AssxmlExporter.cpp +++ b/code/Assxml/AssxmlExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -46,13 +46,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER -#include +#include "PostProcessing/ProcessHelper.h" + #include -#include "ProcessHelper.h" #include #include #include +#include + #ifdef ASSIMP_BUILD_NO_OWN_ZLIB # include #else @@ -184,8 +186,13 @@ static std::string encodeXML(const std::string& data) { static void WriteDump(const aiScene* scene, IOStream* io, bool shortened) { time_t tt = ::time( NULL ); - tm* p = ::gmtime( &tt ); - ai_assert( nullptr != p ); +#if _WIN32 + tm* p = gmtime(&tt); +#else + struct tm now; + tm* p = gmtime_r(&tt, &now); +#endif + ai_assert(nullptr != p); // write header std::string header( @@ -550,8 +557,6 @@ void WriteDump(const aiScene* scene, IOStream* io, bool shortened) { mesh->mNormals[n].z); } } - else { - } ioprintf(io,"\t\t\n"); } diff --git a/code/AssxmlExporter.h b/code/Assxml/AssxmlExporter.h similarity index 98% rename from code/AssxmlExporter.h rename to code/Assxml/AssxmlExporter.h index 3db496db2..8ca887eea 100644 --- a/code/AssxmlExporter.h +++ b/code/Assxml/AssxmlExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/B3DImporter.cpp b/code/B3D/B3DImporter.cpp similarity index 99% rename from code/B3DImporter.cpp rename to code/B3D/B3DImporter.cpp index ce8bd5159..ba484ca00 100644 --- a/code/B3DImporter.cpp +++ b/code/B3D/B3DImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -49,17 +49,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_B3D_IMPORTER // internal headers -#include "B3DImporter.h" -#include "TextureTransform.h" -#include "ConvertToLHProcess.h" +#include "B3D/B3DImporter.h" +#include "PostProcessing/TextureTransform.h" +#include "PostProcessing/ConvertToLHProcess.h" + #include -#include #include #include #include #include #include +#include + using namespace Assimp; using namespace std; diff --git a/code/B3DImporter.h b/code/B3D/B3DImporter.h similarity index 99% rename from code/B3DImporter.h rename to code/B3D/B3DImporter.h index 3cb66e5c7..d52dac34a 100644 --- a/code/B3DImporter.h +++ b/code/B3D/B3DImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/BVHLoader.cpp b/code/BVH/BVHLoader.cpp similarity index 99% rename from code/BVHLoader.cpp rename to code/BVH/BVHLoader.cpp index cba58d056..cd9ab0843 100644 --- a/code/BVHLoader.cpp +++ b/code/BVH/BVHLoader.cpp @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/BVHLoader.h b/code/BVH/BVHLoader.h similarity index 99% rename from code/BVHLoader.h rename to code/BVH/BVHLoader.h index a18ad81d9..33b4e2453 100644 --- a/code/BVHLoader.h +++ b/code/BVH/BVHLoader.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/BlenderBMesh.cpp b/code/Blender/BlenderBMesh.cpp similarity index 100% rename from code/BlenderBMesh.cpp rename to code/Blender/BlenderBMesh.cpp diff --git a/code/BlenderBMesh.h b/code/Blender/BlenderBMesh.h similarity index 100% rename from code/BlenderBMesh.h rename to code/Blender/BlenderBMesh.h diff --git a/code/BlenderCustomData.cpp b/code/Blender/BlenderCustomData.cpp similarity index 95% rename from code/BlenderCustomData.cpp rename to code/Blender/BlenderCustomData.cpp index 682186618..6561eaf22 100644 --- a/code/BlenderCustomData.cpp +++ b/code/Blender/BlenderCustomData.cpp @@ -28,7 +28,11 @@ namespace Assimp { #define IMPL_STRUCT_READ(ty) \ bool read##ty(ElemBase *v, const size_t cnt, const FileDatabase &db) { \ - return read(db.dna[#ty], dynamic_cast(v), cnt, db); \ + ty *ptr = dynamic_cast(v); \ + if (nullptr == ptr) { \ + return false; \ + } \ + return read(db.dna[#ty], ptr, cnt, db); \ } #define IMPL_STRUCT_CREATE(ty) \ diff --git a/code/BlenderCustomData.h b/code/Blender/BlenderCustomData.h similarity index 100% rename from code/BlenderCustomData.h rename to code/Blender/BlenderCustomData.h diff --git a/code/BlenderDNA.cpp b/code/Blender/BlenderDNA.cpp similarity index 99% rename from code/BlenderDNA.cpp rename to code/Blender/BlenderDNA.cpp index f84c45601..f274e02f9 100644 --- a/code/BlenderDNA.cpp +++ b/code/Blender/BlenderDNA.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/BlenderDNA.h b/code/Blender/BlenderDNA.h similarity index 99% rename from code/BlenderDNA.h rename to code/Blender/BlenderDNA.h index ecf606a3b..375d0c4bf 100644 --- a/code/BlenderDNA.h +++ b/code/Blender/BlenderDNA.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -416,7 +416,7 @@ template <> struct Structure :: _defaultInitializer { void operator ()(T& /*out*/,const char* = "") { // obviously, it is crucial that _DefaultInitializer is used // only from within a catch clause. - throw; + throw DeadlyImportError("Constructing BlenderDNA Structure encountered an error"); } }; diff --git a/code/BlenderDNA.inl b/code/Blender/BlenderDNA.inl similarity index 99% rename from code/BlenderDNA.inl rename to code/Blender/BlenderDNA.inl index 89c94e7bf..65bc1374c 100644 --- a/code/BlenderDNA.inl +++ b/code/Blender/BlenderDNA.inl @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/BlenderIntermediate.h b/code/Blender/BlenderIntermediate.h similarity index 99% rename from code/BlenderIntermediate.h rename to code/Blender/BlenderIntermediate.h index f3d34d1b2..95fdf0f03 100644 --- a/code/BlenderIntermediate.h +++ b/code/Blender/BlenderIntermediate.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/BlenderLoader.cpp b/code/Blender/BlenderLoader.cpp similarity index 97% rename from code/BlenderLoader.cpp rename to code/Blender/BlenderLoader.cpp index b0d273a5f..d39cb9699 100644 --- a/code/BlenderLoader.cpp +++ b/code/Blender/BlenderLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -1225,6 +1225,16 @@ aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, c case Lamp::Type_Local: out->mType = aiLightSource_POINT; break; + case Lamp::Type_Spot: + out->mType = aiLightSource_SPOT; + + // blender orients directional lights as facing toward -z + out->mDirection = aiVector3D(0.f, 0.f, -1.f); + out->mUp = aiVector3D(0.f, 1.f, 0.f); + + out->mAngleInnerCone = lamp->spotsize * (1.0f - lamp->spotblend); + out->mAngleOuterCone = lamp->spotsize; + break; case Lamp::Type_Sun: out->mType = aiLightSource_DIRECTIONAL; @@ -1255,6 +1265,23 @@ aiLight* BlenderImporter::ConvertLight(const Scene& /*in*/, const Object* obj, c out->mColorAmbient = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy; out->mColorSpecular = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy; out->mColorDiffuse = aiColor3D(lamp->r, lamp->g, lamp->b) * lamp->energy; + + // If default values are supplied, compute the coefficients from light's max distance + // Read this: https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/ + // + if (lamp->constant_coefficient == 1.0f && lamp->linear_coefficient == 0.0f && lamp->quadratic_coefficient == 0.0f && lamp->dist > 0.0f) + { + out->mAttenuationConstant = 1.0f; + out->mAttenuationLinear = 2.0f / lamp->dist; + out->mAttenuationQuadratic = 1.0f / (lamp->dist * lamp->dist); + } + else + { + out->mAttenuationConstant = lamp->constant_coefficient; + out->mAttenuationLinear = lamp->linear_coefficient; + out->mAttenuationQuadratic = lamp->quadratic_coefficient; + } + return out.release(); } diff --git a/code/BlenderLoader.h b/code/Blender/BlenderLoader.h similarity index 99% rename from code/BlenderLoader.h rename to code/Blender/BlenderLoader.h index 9f452a0aa..d85a82842 100644 --- a/code/BlenderLoader.h +++ b/code/Blender/BlenderLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/BlenderModifier.cpp b/code/Blender/BlenderModifier.cpp similarity index 99% rename from code/BlenderModifier.cpp rename to code/Blender/BlenderModifier.cpp index 1f32ee410..cc7acc929 100644 --- a/code/BlenderModifier.cpp +++ b/code/Blender/BlenderModifier.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/BlenderModifier.h b/code/Blender/BlenderModifier.h similarity index 99% rename from code/BlenderModifier.h rename to code/Blender/BlenderModifier.h index b8797691b..c260ba1f6 100644 --- a/code/BlenderModifier.h +++ b/code/Blender/BlenderModifier.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/BlenderScene.cpp b/code/Blender/BlenderScene.cpp similarity index 99% rename from code/BlenderScene.cpp rename to code/Blender/BlenderScene.cpp index 4fc353b15..39c2793d5 100644 --- a/code/BlenderScene.cpp +++ b/code/Blender/BlenderScene.cpp @@ -211,9 +211,12 @@ template <> void Structure :: Convert ( ReadField(dest.b,"b",db); ReadField(dest.k,"k",db); ReadField(dest.energy,"energy",db); - ReadField(dest.dist,"dist",db); + ReadField(dest.dist,"dist",db); ReadField(dest.spotsize,"spotsize",db); ReadField(dest.spotblend,"spotblend",db); + ReadField(dest.constant_coefficient, "coeff_const", db); + ReadField(dest.linear_coefficient, "coeff_lin", db); + ReadField(dest.quadratic_coefficient, "coeff_quad", db); ReadField(dest.att1,"att1",db); ReadField(dest.att2,"att2",db); ReadField(temp,"falloff_type",db); diff --git a/code/BlenderScene.h b/code/Blender/BlenderScene.h similarity index 99% rename from code/BlenderScene.h rename to code/Blender/BlenderScene.h index b74d7b198..dd3f1444c 100644 --- a/code/BlenderScene.h +++ b/code/Blender/BlenderScene.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -538,6 +538,10 @@ struct Lamp : ElemBase { float energy, dist, spotsize, spotblend; //float haint; + float constant_coefficient; + float linear_coefficient; + float quadratic_coefficient; + float att1, att2; //struct CurveMapping *curfalloff; FalloffType falloff_type; diff --git a/code/BlenderSceneGen.h b/code/Blender/BlenderSceneGen.h similarity index 100% rename from code/BlenderSceneGen.h rename to code/Blender/BlenderSceneGen.h diff --git a/code/BlenderTessellator.cpp b/code/Blender/BlenderTessellator.cpp similarity index 99% rename from code/BlenderTessellator.cpp rename to code/Blender/BlenderTessellator.cpp index afedbfb53..d98c2e865 100644 --- a/code/BlenderTessellator.cpp +++ b/code/Blender/BlenderTessellator.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/BlenderTessellator.h b/code/Blender/BlenderTessellator.h similarity index 97% rename from code/BlenderTessellator.h rename to code/Blender/BlenderTessellator.h index dab3ba8aa..518e56c72 100644 --- a/code/BlenderTessellator.h +++ b/code/Blender/BlenderTessellator.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -144,7 +144,11 @@ namespace Assimp #if ASSIMP_BLEND_WITH_POLY_2_TRI -#include "../contrib/poly2tri/poly2tri/poly2tri.h" +#ifdef ASSIMP_USE_HUNTER +# include +#else +# include "../contrib/poly2tri/poly2tri/poly2tri.h" +#endif namespace Assimp { diff --git a/code/C4DImporter.cpp b/code/C4D/C4DImporter.cpp similarity index 89% rename from code/C4DImporter.cpp rename to code/C4D/C4DImporter.cpp index 665d74633..6e5b7d39b 100644 --- a/code/C4DImporter.cpp +++ b/code/C4D/C4DImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -68,8 +68,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace melange; // overload this function and fill in your own unique data -void GetWriterInfo(int &id, String &appname) -{ +void GetWriterInfo(int &id, String &appname) { id = 2424226; appname = "Open Asset Import Library"; } @@ -78,7 +77,10 @@ using namespace Assimp; using namespace Assimp::Formatter; namespace Assimp { - template<> const std::string LogFunctions::log_prefix = "C4D: "; + template<> const char* LogFunctions::Prefix() { + static auto prefix = "C4D: "; + return prefix; + } } static const aiImporterDesc desc = { @@ -97,47 +99,44 @@ static const aiImporterDesc desc = { // ------------------------------------------------------------------------------------------------ C4DImporter::C4DImporter() -{} +: BaseImporter() { + // empty +} // ------------------------------------------------------------------------------------------------ -C4DImporter::~C4DImporter() -{} +C4DImporter::~C4DImporter() { + // empty +} // ------------------------------------------------------------------------------------------------ -bool C4DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const -{ +bool C4DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { const std::string& extension = GetExtension(pFile); if (extension == "c4d") { return true; - } - - else if ((!extension.length() || checkSig) && pIOHandler) { + } else if ((!extension.length() || checkSig) && pIOHandler) { // TODO } + return false; } // ------------------------------------------------------------------------------------------------ -const aiImporterDesc* C4DImporter::GetInfo () const -{ +const aiImporterDesc* C4DImporter::GetInfo () const { return &desc; } // ------------------------------------------------------------------------------------------------ -void C4DImporter::SetupProperties(const Importer* /*pImp*/) -{ +void C4DImporter::SetupProperties(const Importer* /*pImp*/) { // nothing to be done for the moment } // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. -void C4DImporter::InternReadFile( const std::string& pFile, - aiScene* pScene, IOSystem* pIOHandler) -{ +void C4DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { std::unique_ptr file( pIOHandler->Open( pFile)); - if( file.get() == NULL) { + if( file.get() == nullptr ) { ThrowException("failed to open file " + pFile); } @@ -151,7 +150,7 @@ void C4DImporter::InternReadFile( const std::string& pFile, // open document first BaseDocument* doc = LoadDocument(f, SCENEFILTER_OBJECTS | SCENEFILTER_MATERIALS); - if(doc == NULL) { + if(doc == nullptr ) { ThrowException("failed to read document " + pFile); } @@ -160,11 +159,10 @@ void C4DImporter::InternReadFile( const std::string& pFile, // first convert all materials ReadMaterials(doc->GetFirstMaterial()); - // process C4D scenegraph recursively + // process C4D scene-graph recursively try { RecurseHierarchy(doc->GetFirstObject(), pScene->mRootNode); - } - catch(...) { + } catch(...) { for(aiMesh* mesh : meshes) { delete mesh; } @@ -201,8 +199,7 @@ void C4DImporter::InternReadFile( const std::string& pFile, // ------------------------------------------------------------------------------------------------ -bool C4DImporter::ReadShader(aiMaterial* out, melange::BaseShader* shader) -{ +bool C4DImporter::ReadShader(aiMaterial* out, melange::BaseShader* shader) { // based on Melange sample code (C4DImportExport.cpp) while(shader) { if(shader->GetType() == Xlayer) { @@ -220,15 +217,12 @@ bool C4DImporter::ReadShader(aiMaterial* out, melange::BaseShader* shader) // Ignore the actual layer blending - models for real-time rendering should not // use them in a non-trivial way. Just try to find textures that we can apply // to the model. - while (lsl) - { - if (lsl->GetType() == TypeFolder) - { + while (lsl) { + if (lsl->GetType() == TypeFolder) { BlendFolder* const folder = dynamic_cast(lsl); LayerShaderLayer *subLsl = dynamic_cast(folder->m_Children.GetObject(0)); - while (subLsl) - { + while (subLsl) { if (subLsl->GetType() == TypeShader) { BlendShader* const shader = dynamic_cast(subLsl); if(ReadShader(out, static_cast(shader->m_pLink->GetLink()))) { @@ -238,8 +232,7 @@ bool C4DImporter::ReadShader(aiMaterial* out, melange::BaseShader* shader) subLsl = subLsl->GetNext(); } - } - else if (lsl->GetType() == TypeShader) { + } else if (lsl->GetType() == TypeShader) { BlendShader* const shader = dynamic_cast(lsl); if(ReadShader(out, static_cast(shader->m_pLink->GetLink()))) { return true; @@ -248,33 +241,27 @@ bool C4DImporter::ReadShader(aiMaterial* out, melange::BaseShader* shader) lsl = lsl->GetNext(); } - } - else if ( shader->GetType() == Xbitmap ) - { + } else if ( shader->GetType() == Xbitmap ) { aiString path; shader->GetFileName().GetString().GetCString(path.data, MAXLEN-1); path.length = ::strlen(path.data); out->AddProperty(&path, AI_MATKEY_TEXTURE_DIFFUSE(0)); return true; - } - else { + } else { LogWarn("ignoring shader type: " + std::string(GetObjectTypeName(shader->GetType()))); } shader = shader->GetNext(); } + return false; } - // ------------------------------------------------------------------------------------------------ -void C4DImporter::ReadMaterials(melange::BaseMaterial* mat) -{ +void C4DImporter::ReadMaterials(melange::BaseMaterial* mat) { // based on Melange sample code - while (mat) - { + while (mat) { const String& name = mat->GetName(); - if (mat->GetType() == Mmaterial) - { + if (mat->GetType() == Mmaterial) { aiMaterial* out = new aiMaterial(); material_mapping[mat] = static_cast(materials.size()); materials.push_back(out); @@ -286,8 +273,7 @@ void C4DImporter::ReadMaterials(melange::BaseMaterial* mat) Material& m = dynamic_cast(*mat); - if (m.GetChannelState(CHANNEL_COLOR)) - { + if (m.GetChannelState(CHANNEL_COLOR)) { GeData data; mat->GetParameter(MATERIAL_COLOR_COLOR, data); Vector color = data.GetVector(); @@ -307,9 +293,7 @@ void C4DImporter::ReadMaterials(melange::BaseMaterial* mat) if(shader) { ReadShader(out, shader); } - } - else - { + } else { LogWarn("ignoring plugin material: " + std::string(GetObjectTypeName(mat->GetType()))); } mat = mat->GetNext(); @@ -317,14 +301,12 @@ void C4DImporter::ReadMaterials(melange::BaseMaterial* mat) } // ------------------------------------------------------------------------------------------------ -void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent) -{ - ai_assert(parent != NULL); +void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent) { + ai_assert(parent != nullptr ); std::vector nodes; // based on Melange sample code - while (object) - { + while (object) { const String& name = object->GetName(); const LONG type = object->GetType(); const Matrix& ml = object->GetMl(); @@ -356,26 +338,20 @@ void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent) nodes.push_back(nd); GeData data; - if (type == Ocamera) - { + if (type == Ocamera) { object->GetParameter(CAMERAOBJECT_FOV, data); // TODO: read camera - } - else if (type == Olight) - { + } else if (type == Olight) { // TODO: read light - } - else if (type == Opolygon) - { + } else if (type == Opolygon) { aiMesh* const mesh = ReadMesh(object); - if(mesh != NULL) { + if(mesh != nullptr) { nd->mNumMeshes = 1; nd->mMeshes = new unsigned int[1]; nd->mMeshes[0] = static_cast(meshes.size()); meshes.push_back(mesh); } - } - else { + } else { LogWarn("ignoring object: " + std::string(GetObjectTypeName(type))); } @@ -389,28 +365,27 @@ void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent) std::copy(nodes.begin(), nodes.end(), parent->mChildren); } - // ------------------------------------------------------------------------------------------------ -aiMesh* C4DImporter::ReadMesh(BaseObject* object) -{ - ai_assert(object != NULL && object->GetType() == Opolygon); +aiMesh* C4DImporter::ReadMesh(BaseObject* object) { + ai_assert(object != nullptr); + ai_assert( object->GetType() == Opolygon ); // based on Melange sample code PolygonObject* const polyObject = dynamic_cast(object); - ai_assert(polyObject != NULL); + ai_assert(polyObject != nullptr); const LONG pointCount = polyObject->GetPointCount(); const LONG polyCount = polyObject->GetPolygonCount(); if(!polyObject || !pointCount) { LogWarn("ignoring mesh with zero vertices or faces"); - return NULL; + return nullptr; } const Vector* points = polyObject->GetPointR(); - ai_assert(points != NULL); + ai_assert(points != nullptr); const CPolygon* polys = polyObject->GetPolygonR(); - ai_assert(polys != NULL); + ai_assert(polys != nullptr); std::unique_ptr mesh(new aiMesh()); mesh->mNumFaces = static_cast(polyCount); @@ -443,14 +418,14 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object) // check if there are normals, tangents or UVW coordinates BaseTag* tag = object->GetTag(Tnormal); - NormalTag* normals_src = NULL; + NormalTag* normals_src = nullptr; if(tag) { normals_src = dynamic_cast(tag); normals = mesh->mNormals = new aiVector3D[mesh->mNumVertices](); } tag = object->GetTag(Ttangent); - TangentTag* tangents_src = NULL; + TangentTag* tangents_src = nullptr; if(tag) { tangents_src = dynamic_cast(tag); tangents = mesh->mTangents = new aiVector3D[mesh->mNumVertices](); @@ -458,15 +433,14 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object) } tag = object->GetTag(Tuvw); - UVWTag* uvs_src = NULL; + UVWTag* uvs_src = nullptr; if(tag) { uvs_src = dynamic_cast(tag); uvs = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices](); } // copy vertices and extra channels over and populate faces - for (LONG i = 0; i < polyCount; ++i, ++face) - { + for (LONG i = 0; i < polyCount; ++i, ++face) { ai_assert(polys[i].a < pointCount && polys[i].a >= 0); const Vector& pointA = points[polys[i].a]; verts->x = pointA.x; @@ -489,8 +463,7 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object) ++verts; // TODO: do we also need to handle lines or points with similar checks? - if (polys[i].c != polys[i].d) - { + if (polys[i].c != polys[i].d) { ai_assert(polys[i].d < pointCount && polys[i].d >= 0); face->mNumIndices = 4; @@ -500,8 +473,7 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object) verts->y = pointD.y; verts->z = pointD.z; ++verts; - } - else { + } else { face->mNumIndices = 3; } face->mIndices = new unsigned int[face->mNumIndices]; @@ -513,8 +485,7 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object) if (normals_src) { if(i >= normals_src->GetDataCount()) { LogError("unexpected number of normals, ignoring"); - } - else { + } else { ConstNormalHandle normal_handle = normals_src->GetDataAddressR(); NormalStruct nor; NormalTag::Get(normal_handle, i, nor); @@ -616,26 +587,25 @@ aiMesh* C4DImporter::ReadMesh(BaseObject* object) } mesh->mMaterialIndex = ResolveMaterial(polyObject); + return mesh.release(); } - // ------------------------------------------------------------------------------------------------ -unsigned int C4DImporter::ResolveMaterial(PolygonObject* obj) -{ - ai_assert(obj != NULL); +unsigned int C4DImporter::ResolveMaterial(PolygonObject* obj) { + ai_assert(obj != nullptr); const unsigned int mat_count = static_cast(materials.size()); BaseTag* tag = obj->GetTag(Ttexture); - if(tag == NULL) { + if(tag == nullptr) { return mat_count; } TextureTag& ttag = dynamic_cast(*tag); BaseMaterial* const mat = ttag.GetMaterial(); - ai_assert(mat != NULL); + ai_assert(mat != nullptr); const MaterialMap::const_iterator it = material_mapping.find(mat); if(it == material_mapping.end()) { @@ -643,6 +613,7 @@ unsigned int C4DImporter::ResolveMaterial(PolygonObject* obj) } ai_assert((*it).second < mat_count); + return (*it).second; } diff --git a/code/C4DImporter.h b/code/C4D/C4DImporter.h similarity index 97% rename from code/C4DImporter.h rename to code/C4D/C4DImporter.h index 2f67d90f3..f3b1351f6 100644 --- a/code/C4DImporter.h +++ b/code/C4D/C4DImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -48,6 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include + +// Forward declarations struct aiNode; struct aiMesh; struct aiMaterial; @@ -61,8 +63,7 @@ namespace melange { class BaseShader; } -namespace Assimp { - +namespace Assimp { // TinyFormatter.h namespace Formatter { template class basic_formatter; @@ -75,17 +76,10 @@ namespace Assimp { * * Note that Melange is not free software. */ // ------------------------------------------------------------------------------------------- -class C4DImporter : public BaseImporter, public LogFunctions -{ +class C4DImporter : public BaseImporter, public LogFunctions { public: - C4DImporter(); ~C4DImporter(); - - -public: - - // -------------------- bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; @@ -119,5 +113,5 @@ private: }; // !class C4DImporter } // end of namespace Assimp -#endif // INCLUDED_AI_CINEMA_4D_LOADER_H +#endif // INCLUDED_AI_CINEMA_4D_LOADER_H diff --git a/code/AssimpCExport.cpp b/code/CApi/AssimpCExport.cpp similarity index 98% rename from code/AssimpCExport.cpp rename to code/CApi/AssimpCExport.cpp index caf51a08c..7557edcfc 100644 --- a/code/AssimpCExport.cpp +++ b/code/CApi/AssimpCExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -49,7 +49,7 @@ Assimp C export interface. See Exporter.cpp for some notes. #include "CInterfaceIOWrapper.h" #include -#include "ScenePrivate.h" +#include "Common/ScenePrivate.h" #include using namespace Assimp; @@ -60,7 +60,6 @@ ASSIMP_API size_t aiGetExportFormatCount(void) return Exporter().GetExportFormatCount(); } - // ------------------------------------------------------------------------------------------------ ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t index) { diff --git a/code/CInterfaceIOWrapper.cpp b/code/CApi/CInterfaceIOWrapper.cpp similarity index 99% rename from code/CInterfaceIOWrapper.cpp rename to code/CApi/CInterfaceIOWrapper.cpp index 41dbba772..5a3a49565 100644 --- a/code/CInterfaceIOWrapper.cpp +++ b/code/CApi/CInterfaceIOWrapper.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/CInterfaceIOWrapper.h b/code/CApi/CInterfaceIOWrapper.h similarity index 98% rename from code/CInterfaceIOWrapper.h rename to code/CApi/CInterfaceIOWrapper.h index 6f0eb7957..216232030 100644 --- a/code/CInterfaceIOWrapper.h +++ b/code/CApi/CInterfaceIOWrapper.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 6b8d3d322..eec805b54 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1,9 +1,8 @@ # Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # -# Copyright (c) 2006-2018, assimp team - - +# Copyright (c) 2006-2019, assimp team +# # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -44,9 +43,14 @@ # 3) Add libassimp using the file lists (eliminates duplication of file names between # source groups and library command) # -cmake_minimum_required( VERSION 2.6 ) +cmake_minimum_required( VERSION 3.0 ) SET( HEADER_PATH ../include/assimp ) +if(NOT ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM) + message(WARNING "Requesting Android JNI I/O-System in non-Android toolchain. Resetting ASSIMP_ANDROID_JNIIOSYSTEM to OFF.") + set(ASSIMP_ANDROID_JNIIOSYSTEM OFF) +endif(NOT ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM) + SET( COMPILER_HEADERS ${HEADER_PATH}/Compiler/pushpack1.h ${HEADER_PATH}/Compiler/poppack1.h @@ -56,6 +60,7 @@ SOURCE_GROUP( Compiler FILES ${COMPILER_HEADERS}) SET( PUBLIC_HEADERS ${HEADER_PATH}/anim.h + ${HEADER_PATH}/aabb.h ${HEADER_PATH}/ai_assert.h ${HEADER_PATH}/camera.h ${HEADER_PATH}/color4.h @@ -99,6 +104,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 @@ -131,66 +137,75 @@ 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 ) SET( Core_SRCS - Assimp.cpp + Common/Assimp.cpp ) +IF(MSVC) + list(APPEND Core_SRCS "res/assimp.rc") +ENDIF(MSVC) + SET( Logging_SRCS ${HEADER_PATH}/DefaultLogger.hpp ${HEADER_PATH}/LogStream.hpp ${HEADER_PATH}/Logger.hpp ${HEADER_PATH}/NullLogger.hpp - Win32DebugLogStream.h - DefaultLogger.cpp - FileLogStream.h - StdOStreamLogStream.h + Common/Win32DebugLogStream.h + Common/DefaultLogger.cpp + Common/FileLogStream.h + Common/StdOStreamLogStream.h ) SOURCE_GROUP(Logging FILES ${Logging_SRCS}) SET( Common_SRCS - BaseImporter.cpp - BaseProcess.cpp - BaseProcess.h - Importer.h - ScenePrivate.h - PostStepRegistry.cpp - ImporterRegistry.cpp - DefaultProgressHandler.h - DefaultIOStream.cpp - DefaultIOSystem.cpp - CInterfaceIOWrapper.cpp - CInterfaceIOWrapper.h - Importer.cpp - IFF.h - SGSpatialSort.cpp - VertexTriangleAdjacency.cpp - VertexTriangleAdjacency.h - SpatialSort.cpp - SceneCombiner.cpp - ScenePreprocessor.cpp - ScenePreprocessor.h - SkeletonMeshBuilder.cpp - SplitByBoneCountProcess.cpp - SplitByBoneCountProcess.h - StandardShapes.cpp - TargetAnimation.cpp - TargetAnimation.h - RemoveComments.cpp - Subdivision.cpp - scene.cpp - Bitmap.cpp - Version.cpp - CreateAnimMesh.cpp - simd.h - simd.cpp + Common/BaseImporter.cpp + Common/BaseProcess.cpp + Common/BaseProcess.h + Common/Importer.h + Common/ScenePrivate.h + Common/PostStepRegistry.cpp + Common/ImporterRegistry.cpp + Common/DefaultProgressHandler.h + Common/DefaultIOStream.cpp + Common/DefaultIOSystem.cpp + Common/ZipArchiveIOSystem.cpp + Common/PolyTools.h + Common/Importer.cpp + Common/IFF.h + Common/SGSpatialSort.cpp + Common/VertexTriangleAdjacency.cpp + Common/VertexTriangleAdjacency.h + Common/SpatialSort.cpp + Common/SceneCombiner.cpp + Common/ScenePreprocessor.cpp + Common/ScenePreprocessor.h + Common/SkeletonMeshBuilder.cpp + Common/SplitByBoneCountProcess.cpp + Common/SplitByBoneCountProcess.h + Common/StandardShapes.cpp + Common/TargetAnimation.cpp + Common/TargetAnimation.h + Common/RemoveComments.cpp + Common/Subdivision.cpp + Common/scene.cpp + Common/Bitmap.cpp + Common/Version.cpp + Common/CreateAnimMesh.cpp + Common/simd.h + Common/simd.cpp ) SOURCE_GROUP(Common FILES ${Common_SRCS}) +SET( CApi_SRCS + CApi/CInterfaceIOWrapper.cpp + CApi/CInterfaceIOWrapper.h +) +SOURCE_GROUP(CApi FILES ${CApi_SRCS}) + SET( STEPParser_SRCS Importer/STEPParser/STEPFileReader.h Importer/STEPParser/STEPFileReader.cpp @@ -201,8 +216,8 @@ SOURCE_GROUP(STEPParser FILES ${STEPParser_SRCS}) IF ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER ) SET( C4D_SRCS - C4DImporter.cpp - C4DImporter.h + C4D/C4DImporter.cpp + C4D/C4DImporter.h ) SOURCE_GROUP( C4D FILES ${C4D_SRCS}) ENDIF ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER ) @@ -211,7 +226,7 @@ ENDIF ( ASSIMP_BUILD_NONFREE_C4D_IMPORTER ) # ASSIMP_BUILD_XXX_IMPORTER to FALSE for each importer # if this variable is set to FALSE, the user can manually enable importers by setting # ASSIMP_BUILD_XXX_IMPORTER to TRUE for each importer -OPTION(ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT "default value of all ASSIMP_BUILD_XXX_IMPORTER value" TRUE) +OPTION(ASSIMP_BUILD_ALL_IMPORTERS_BY_DEFAULT "default value of all ASSIMP_BUILD_XXX_IMPORTER values" TRUE) # macro to add the CMake Option ADD_ASSIMP_IMPORTER_ which enables compile of loader # this way selective loaders can be compiled (reduces filesize + compile time) @@ -227,258 +242,308 @@ MACRO(ADD_ASSIMP_IMPORTER name) IF (ASSIMP_IMPORTER_ENABLED) LIST(APPEND ASSIMP_LOADER_SRCS ${ARGN}) SET(ASSIMP_IMPORTERS_ENABLED "${ASSIMP_IMPORTERS_ENABLED} ${name}") - SET(${name}_SRCS ${ARGN}) SOURCE_GROUP(${name} FILES ${ARGN}) ELSE() SET(${name}_SRC "") SET(ASSIMP_IMPORTERS_DISABLED "${ASSIMP_IMPORTERS_DISABLED} ${name}") add_definitions(-DASSIMP_BUILD_NO_${name}_IMPORTER) + ENDIF() +ENDMACRO() + +# if this variable is set to TRUE, the user can manually disable exporters by setting +# ASSIMP_BUILD_XXX_EXPORTER to FALSE for each exporter +# if this variable is set to FALSE, the user can manually enable exporters by setting +# ASSIMP_BUILD_XXX_EXPORTER to TRUE for each exporter +OPTION(ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT "default value of all ASSIMP_BUILD_XXX_EXPORTER values" TRUE) + +# macro to add the CMake Option ADD_ASSIMP_IMPORTER_ which enables compile of loader +# this way selective loaders can be compiled (reduces filesize + compile time) +MACRO(ADD_ASSIMP_EXPORTER name) + IF (ASSIMP_NO_EXPORT) + set(ASSIMP_EXPORTER_ENABLED FALSE) + ELSEIF (ASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT) + set(ASSIMP_EXPORTER_ENABLED TRUE) + IF (DEFINED ASSIMP_BUILD_${name}_EXPORTER AND NOT ASSIMP_BUILD_${name}_EXPORTER) + set(ASSIMP_EXPORTER_ENABLED FALSE) + ENDIF () + ELSE () + set(ASSIMP_EXPORTER_ENABLED ${ASSIMP_BUILD_${name}_EXPORTER}) + ENDIF () + + IF (ASSIMP_EXPORTER_ENABLED) + SET(ASSIMP_EXPORTERS_ENABLED "${ASSIMP_EXPORTERS_ENABLED} ${name}") + LIST(APPEND ASSIMP_EXPORTER_SRCS ${ARGN}) + SOURCE_GROUP(${name}_EXPORTER FILES ${ARGN}) + ELSE() + SET(ASSIMP_EXPORTERS_DISABLED "${ASSIMP_EXPORTERS_DISABLED} ${name}") add_definitions(-DASSIMP_BUILD_NO_${name}_EXPORTER) ENDIF() ENDMACRO() SET(ASSIMP_LOADER_SRCS "") SET(ASSIMP_IMPORTERS_ENABLED "") # list of enabled importers -SET(ASSIMP_IMPORTERS_DISABLED "") # disabled list (used to print) +SET(ASSIMP_IMPORTERS_DISABLED "") # disabled importers list (used to print) + +SET(ASSIMP_EXPORTER_SRCS "") +SET(ASSIMP_EXPORTERS_ENABLED "") # list of enabled exporters +SET(ASSIMP_EXPORTERS_DISABLED "") # disabled exporters list (used to print) ADD_ASSIMP_IMPORTER( AMF - AMFImporter.hpp - AMFImporter_Macro.hpp - AMFImporter_Node.hpp - AMFImporter.cpp - AMFImporter_Geometry.cpp - AMFImporter_Material.cpp - AMFImporter_Postprocess.cpp + AMF/AMFImporter.hpp + AMF/AMFImporter_Macro.hpp + AMF/AMFImporter_Node.hpp + AMF/AMFImporter.cpp + AMF/AMFImporter_Geometry.cpp + AMF/AMFImporter_Material.cpp + AMF/AMFImporter_Postprocess.cpp ) ADD_ASSIMP_IMPORTER( 3DS - 3DSConverter.cpp - 3DSHelper.h - 3DSLoader.cpp - 3DSLoader.h - 3DSExporter.h - 3DSExporter.cpp + 3DS/3DSConverter.cpp + 3DS/3DSHelper.h + 3DS/3DSLoader.cpp + 3DS/3DSLoader.h +) + +ADD_ASSIMP_EXPORTER( 3DS + 3DS/3DSExporter.h + 3DS/3DSExporter.cpp ) ADD_ASSIMP_IMPORTER( AC - ACLoader.cpp - ACLoader.h + AC/ACLoader.cpp + AC/ACLoader.h ) ADD_ASSIMP_IMPORTER( ASE - ASELoader.cpp - ASELoader.h - ASEParser.cpp - ASEParser.h + ASE/ASELoader.cpp + ASE/ASELoader.h + ASE/ASEParser.cpp + ASE/ASEParser.h ) ADD_ASSIMP_IMPORTER( ASSBIN - AssbinExporter.h - AssbinExporter.cpp - AssbinLoader.h - AssbinLoader.cpp + Assbin/AssbinLoader.h + Assbin/AssbinLoader.cpp ) -ADD_ASSIMP_IMPORTER( ASSXML - AssxmlExporter.h - AssxmlExporter.cpp +ADD_ASSIMP_EXPORTER( ASSBIN + Assbin/AssbinExporter.h + Assbin/AssbinExporter.cpp +) + +ADD_ASSIMP_EXPORTER( ASSXML + Assxml/AssxmlExporter.h + Assxml/AssxmlExporter.cpp ) ADD_ASSIMP_IMPORTER( B3D - B3DImporter.cpp - B3DImporter.h + B3D/B3DImporter.cpp + B3D/B3DImporter.h ) ADD_ASSIMP_IMPORTER( BVH - BVHLoader.cpp - BVHLoader.h + BVH/BVHLoader.cpp + BVH/BVHLoader.h ) ADD_ASSIMP_IMPORTER( COLLADA - ColladaHelper.h - ColladaLoader.cpp - ColladaLoader.h - ColladaParser.cpp - ColladaParser.h - ColladaExporter.h - ColladaExporter.cpp + Collada/ColladaHelper.h + Collada/ColladaLoader.cpp + Collada/ColladaLoader.h + Collada/ColladaParser.cpp + Collada/ColladaParser.h +) + +ADD_ASSIMP_EXPORTER( COLLADA + Collada/ColladaExporter.h + Collada/ColladaExporter.cpp ) ADD_ASSIMP_IMPORTER( DXF - DXFLoader.cpp - DXFLoader.h - DXFHelper.h + DXF/DXFLoader.cpp + DXF/DXFLoader.h + DXF/DXFHelper.h ) ADD_ASSIMP_IMPORTER( CSM - CSMLoader.cpp - CSMLoader.h + CSM/CSMLoader.cpp + CSM/CSMLoader.h ) ADD_ASSIMP_IMPORTER( HMP - HMPFileData.h - HMPLoader.cpp - HMPLoader.h - HalfLifeFileData.h + HMP/HMPFileData.h + HMP/HMPLoader.cpp + HMP/HMPLoader.h + HMP/HalfLifeFileData.h ) ADD_ASSIMP_IMPORTER( IRRMESH - IRRMeshLoader.cpp - IRRMeshLoader.h - IRRShared.cpp - IRRShared.h + Irr/IRRMeshLoader.cpp + Irr/IRRMeshLoader.h + Irr/IRRShared.cpp + Irr/IRRShared.h ) ADD_ASSIMP_IMPORTER( IRR - IRRLoader.cpp - IRRLoader.h - IRRShared.cpp - IRRShared.h + Irr/IRRLoader.cpp + Irr/IRRLoader.h + Irr/IRRShared.cpp + Irr/IRRShared.h ) ADD_ASSIMP_IMPORTER( LWO - LWOAnimation.cpp - LWOAnimation.h - LWOBLoader.cpp - LWOFileData.h - LWOLoader.cpp - LWOLoader.h - LWOMaterial.cpp + LWO/LWOAnimation.cpp + LWO/LWOAnimation.h + LWO/LWOBLoader.cpp + LWO/LWOFileData.h + LWO/LWOLoader.cpp + LWO/LWOLoader.h + LWO/LWOMaterial.cpp ) ADD_ASSIMP_IMPORTER( LWS - LWSLoader.cpp - LWSLoader.h + LWS/LWSLoader.cpp + LWS/LWSLoader.h ) ADD_ASSIMP_IMPORTER( MD2 - MD2FileData.h - MD2Loader.cpp - MD2Loader.h - MD2NormalTable.h + MD2/MD2FileData.h + MD2/MD2Loader.cpp + MD2/MD2Loader.h + MD2/MD2NormalTable.h ) ADD_ASSIMP_IMPORTER( MD3 - MD3FileData.h - MD3Loader.cpp - MD3Loader.h + MD3/MD3FileData.h + MD3/MD3Loader.cpp + MD3/MD3Loader.h ) ADD_ASSIMP_IMPORTER( MD5 - MD5Loader.cpp - MD5Loader.h - MD5Parser.cpp - MD5Parser.h + MD5/MD5Loader.cpp + MD5/MD5Loader.h + MD5/MD5Parser.cpp + MD5/MD5Parser.h ) ADD_ASSIMP_IMPORTER( MDC - MDCFileData.h - MDCLoader.cpp - MDCLoader.h - MDCNormalTable.h + MDC/MDCFileData.h + MDC/MDCLoader.cpp + MDC/MDCLoader.h + MDC/MDCNormalTable.h ) ADD_ASSIMP_IMPORTER( MDL - MDLDefaultColorMap.h - MDLFileData.h - MDLLoader.cpp - MDLLoader.h - MDLMaterialLoader.cpp + MDL/MDLDefaultColorMap.h + MDL/MDLFileData.h + MDL/MDLLoader.cpp + MDL/MDLLoader.h + MDL/MDLMaterialLoader.cpp ) SET( MaterialSystem_SRCS - MaterialSystem.cpp - MaterialSystem.h + Material/MaterialSystem.cpp + Material/MaterialSystem.h ) SOURCE_GROUP( MaterialSystem FILES ${MaterialSystem_SRCS}) ADD_ASSIMP_IMPORTER( NFF - NFFLoader.cpp - NFFLoader.h + NFF/NFFLoader.cpp + NFF/NFFLoader.h ) ADD_ASSIMP_IMPORTER( NDO - NDOLoader.cpp - NDOLoader.h + NDO/NDOLoader.cpp + NDO/NDOLoader.h ) ADD_ASSIMP_IMPORTER( OFF - OFFLoader.cpp - OFFLoader.h + OFF/OFFLoader.cpp + OFF/OFFLoader.h ) ADD_ASSIMP_IMPORTER( OBJ - ObjFileData.h - ObjFileImporter.cpp - ObjFileImporter.h - ObjFileMtlImporter.cpp - ObjFileMtlImporter.h - ObjFileParser.cpp - ObjFileParser.h - ObjTools.h - ObjExporter.h - ObjExporter.cpp + Obj/ObjFileData.h + Obj/ObjFileImporter.cpp + Obj/ObjFileImporter.h + Obj/ObjFileMtlImporter.cpp + Obj/ObjFileMtlImporter.h + Obj/ObjFileParser.cpp + Obj/ObjFileParser.h + Obj/ObjTools.h +) + +ADD_ASSIMP_EXPORTER( OBJ + Obj/ObjExporter.h + Obj/ObjExporter.cpp ) ADD_ASSIMP_IMPORTER( OGRE - OgreImporter.h - OgreStructs.h - OgreParsingUtils.h - OgreBinarySerializer.h - OgreXmlSerializer.h - OgreImporter.cpp - OgreStructs.cpp - OgreBinarySerializer.cpp - OgreXmlSerializer.cpp - OgreMaterial.cpp + Ogre/OgreImporter.h + Ogre/OgreStructs.h + Ogre/OgreParsingUtils.h + Ogre/OgreBinarySerializer.h + Ogre/OgreXmlSerializer.h + Ogre/OgreImporter.cpp + Ogre/OgreStructs.cpp + Ogre/OgreBinarySerializer.cpp + Ogre/OgreXmlSerializer.cpp + Ogre/OgreMaterial.cpp ) ADD_ASSIMP_IMPORTER( OPENGEX - OpenGEXExporter.cpp - OpenGEXExporter.h - OpenGEXImporter.cpp - OpenGEXImporter.h - OpenGEXStructs.h + OpenGEX/OpenGEXImporter.cpp + OpenGEX/OpenGEXImporter.h + OpenGEX/OpenGEXStructs.h +) + +ADD_ASSIMP_EXPORTER( OPENGEX + OpenGEX/OpenGEXExporter.cpp + OpenGEX/OpenGEXExporter.h ) ADD_ASSIMP_IMPORTER( PLY - PlyLoader.cpp - PlyLoader.h - PlyParser.cpp - PlyParser.h - PlyExporter.cpp - PlyExporter.h + Ply/PlyLoader.cpp + Ply/PlyLoader.h + Ply/PlyParser.cpp + Ply/PlyParser.h +) + +ADD_ASSIMP_EXPORTER( PLY + Ply/PlyExporter.cpp + Ply/PlyExporter.h ) ADD_ASSIMP_IMPORTER( MS3D - MS3DLoader.cpp - MS3DLoader.h + MS3D/MS3DLoader.cpp + MS3D/MS3DLoader.h ) ADD_ASSIMP_IMPORTER( COB - COBLoader.cpp - COBLoader.h - COBScene.h + COB/COBLoader.cpp + COB/COBLoader.h + COB/COBScene.h ) ADD_ASSIMP_IMPORTER( BLEND - BlenderLoader.cpp - BlenderLoader.h - BlenderDNA.cpp - BlenderDNA.h - BlenderDNA.inl - BlenderScene.cpp - BlenderScene.h - BlenderSceneGen.h - BlenderIntermediate.h - BlenderModifier.h - BlenderModifier.cpp - BlenderBMesh.h - BlenderBMesh.cpp - BlenderTessellator.h - BlenderTessellator.cpp - BlenderCustomData.h - BlenderCustomData.cpp + Blender/BlenderLoader.cpp + Blender/BlenderLoader.h + Blender/BlenderDNA.cpp + Blender/BlenderDNA.h + Blender/BlenderDNA.inl + Blender/BlenderScene.cpp + Blender/BlenderScene.h + Blender/BlenderSceneGen.h + Blender/BlenderIntermediate.h + Blender/BlenderModifier.h + Blender/BlenderModifier.cpp + Blender/BlenderBMesh.h + Blender/BlenderBMesh.cpp + Blender/BlenderTessellator.h + Blender/BlenderTessellator.cpp + Blender/BlenderCustomData.h + Blender/BlenderCustomData.cpp ) ADD_ASSIMP_IMPORTER( IFC @@ -506,103 +571,107 @@ if (ASSIMP_BUILD_IFC_IMPORTER) endif (ASSIMP_BUILD_IFC_IMPORTER) ADD_ASSIMP_IMPORTER( XGL - XGLLoader.cpp - XGLLoader.h + XGL/XGLLoader.cpp + XGL/XGLLoader.h ) ADD_ASSIMP_IMPORTER( FBX - FBXImporter.cpp - FBXCompileConfig.h - FBXImporter.h - FBXParser.cpp - FBXParser.h - FBXTokenizer.cpp - FBXTokenizer.h - FBXImportSettings.h - FBXConverter.h - FBXConverter.cpp - FBXUtil.h - FBXUtil.cpp - FBXDocument.h - FBXDocument.cpp - FBXProperties.h - FBXProperties.cpp - FBXMeshGeometry.h - FBXMeshGeometry.cpp - FBXMaterial.cpp - FBXModel.cpp - FBXAnimation.cpp - FBXNodeAttribute.cpp - FBXDeformer.cpp - FBXBinaryTokenizer.cpp - FBXDocumentUtil.cpp - FBXExporter.h - FBXExporter.cpp - FBXExportNode.h - FBXExportNode.cpp - FBXExportProperty.h - FBXExportProperty.cpp - FBXCommon.h + FBX/FBXImporter.cpp + FBX/FBXCompileConfig.h + FBX/FBXImporter.h + FBX/FBXParser.cpp + FBX/FBXParser.h + FBX/FBXTokenizer.cpp + FBX/FBXTokenizer.h + FBX/FBXImportSettings.h + FBX/FBXConverter.h + FBX/FBXConverter.cpp + FBX/FBXUtil.h + FBX/FBXUtil.cpp + FBX/FBXDocument.h + FBX/FBXDocument.cpp + FBX/FBXProperties.h + FBX/FBXProperties.cpp + FBX/FBXMeshGeometry.h + FBX/FBXMeshGeometry.cpp + FBX/FBXMaterial.cpp + FBX/FBXModel.cpp + FBX/FBXAnimation.cpp + FBX/FBXNodeAttribute.cpp + FBX/FBXDeformer.cpp + FBX/FBXBinaryTokenizer.cpp + FBX/FBXDocumentUtil.cpp + FBX/FBXCommon.h +) + +ADD_ASSIMP_EXPORTER( FBX + FBX/FBXExporter.h + FBX/FBXExporter.cpp + FBX/FBXExportNode.h + FBX/FBXExportNode.cpp + FBX/FBXExportProperty.h + FBX/FBXExportProperty.cpp ) SET( PostProcessing_SRCS - CalcTangentsProcess.cpp - CalcTangentsProcess.h - ComputeUVMappingProcess.cpp - ComputeUVMappingProcess.h - ConvertToLHProcess.cpp - ConvertToLHProcess.h - EmbedTexturesProcess.cpp - EmbedTexturesProcess.h - FindDegenerates.cpp - FindDegenerates.h - FindInstancesProcess.cpp - FindInstancesProcess.h - FindInvalidDataProcess.cpp - FindInvalidDataProcess.h - FixNormalsStep.cpp - FixNormalsStep.h - DropFaceNormalsProcess.cpp - DropFaceNormalsProcess.h - GenFaceNormalsProcess.cpp - GenFaceNormalsProcess.h - GenVertexNormalsProcess.cpp - GenVertexNormalsProcess.h - PretransformVertices.cpp - PretransformVertices.h - ImproveCacheLocality.cpp - ImproveCacheLocality.h - JoinVerticesProcess.cpp - JoinVerticesProcess.h - LimitBoneWeightsProcess.cpp - LimitBoneWeightsProcess.h - RemoveRedundantMaterials.cpp - RemoveRedundantMaterials.h - RemoveVCProcess.cpp - RemoveVCProcess.h - SortByPTypeProcess.cpp - SortByPTypeProcess.h - SplitLargeMeshes.cpp - SplitLargeMeshes.h - TextureTransform.cpp - TextureTransform.h - TriangulateProcess.cpp - TriangulateProcess.h - ValidateDataStructure.cpp - ValidateDataStructure.h - OptimizeGraph.cpp - OptimizeGraph.h - OptimizeMeshes.cpp - OptimizeMeshes.h - DeboneProcess.cpp - DeboneProcess.h - ProcessHelper.h - ProcessHelper.cpp - PolyTools.h - MakeVerboseFormat.cpp - MakeVerboseFormat.h - ScaleProcess.cpp - ScaleProcess.h + PostProcessing/CalcTangentsProcess.cpp + PostProcessing/CalcTangentsProcess.h + PostProcessing/ComputeUVMappingProcess.cpp + PostProcessing/ComputeUVMappingProcess.h + PostProcessing/ConvertToLHProcess.cpp + PostProcessing/ConvertToLHProcess.h + PostProcessing/EmbedTexturesProcess.cpp + PostProcessing/EmbedTexturesProcess.h + PostProcessing/FindDegenerates.cpp + PostProcessing/FindDegenerates.h + PostProcessing/FindInstancesProcess.cpp + PostProcessing/FindInstancesProcess.h + PostProcessing/FindInvalidDataProcess.cpp + PostProcessing/FindInvalidDataProcess.h + PostProcessing/FixNormalsStep.cpp + PostProcessing/FixNormalsStep.h + PostProcessing/DropFaceNormalsProcess.cpp + PostProcessing/DropFaceNormalsProcess.h + PostProcessing/GenFaceNormalsProcess.cpp + PostProcessing/GenFaceNormalsProcess.h + PostProcessing/GenVertexNormalsProcess.cpp + PostProcessing/GenVertexNormalsProcess.h + PostProcessing/PretransformVertices.cpp + PostProcessing/PretransformVertices.h + PostProcessing/ImproveCacheLocality.cpp + PostProcessing/ImproveCacheLocality.h + PostProcessing/JoinVerticesProcess.cpp + PostProcessing/JoinVerticesProcess.h + PostProcessing/LimitBoneWeightsProcess.cpp + PostProcessing/LimitBoneWeightsProcess.h + PostProcessing/RemoveRedundantMaterials.cpp + PostProcessing/RemoveRedundantMaterials.h + PostProcessing/RemoveVCProcess.cpp + PostProcessing/RemoveVCProcess.h + PostProcessing/SortByPTypeProcess.cpp + PostProcessing/SortByPTypeProcess.h + PostProcessing/SplitLargeMeshes.cpp + PostProcessing/SplitLargeMeshes.h + PostProcessing/TextureTransform.cpp + PostProcessing/TextureTransform.h + PostProcessing/TriangulateProcess.cpp + PostProcessing/TriangulateProcess.h + PostProcessing/ValidateDataStructure.cpp + PostProcessing/ValidateDataStructure.h + PostProcessing/OptimizeGraph.cpp + PostProcessing/OptimizeGraph.h + PostProcessing/OptimizeMeshes.cpp + PostProcessing/OptimizeMeshes.h + PostProcessing/DeboneProcess.cpp + PostProcessing/DeboneProcess.h + PostProcessing/ProcessHelper.h + PostProcessing/ProcessHelper.cpp + PostProcessing/MakeVerboseFormat.cpp + PostProcessing/MakeVerboseFormat.h + PostProcessing/ScaleProcess.cpp + PostProcessing/ScaleProcess.h + PostProcessing/GenBoundingBoxesProcess.cpp + PostProcessing/GenBoundingBoxesProcess.h ) SOURCE_GROUP( PostProcessing FILES ${PostProcessing_SRCS}) @@ -610,252 +679,354 @@ SET( IrrXML_SRCS ${HEADER_PATH}/irrXMLWrapper.h ) SOURCE_GROUP( IrrXML FILES ${IrrXML_SRCS}) ADD_ASSIMP_IMPORTER( Q3D - Q3DLoader.cpp - Q3DLoader.h + Q3D/Q3DLoader.cpp + Q3D/Q3DLoader.h ) ADD_ASSIMP_IMPORTER( Q3BSP - Q3BSPFileData.h - Q3BSPFileParser.h - Q3BSPFileParser.cpp - Q3BSPFileImporter.h - Q3BSPFileImporter.cpp - Q3BSPZipArchive.h - Q3BSPZipArchive.cpp + Q3BSP/Q3BSPFileData.h + Q3BSP/Q3BSPFileParser.h + Q3BSP/Q3BSPFileParser.cpp + Q3BSP/Q3BSPFileImporter.h + Q3BSP/Q3BSPFileImporter.cpp ) ADD_ASSIMP_IMPORTER( RAW - RawLoader.cpp - RawLoader.h + Raw/RawLoader.cpp + Raw/RawLoader.h ) ADD_ASSIMP_IMPORTER( SIB - SIBImporter.cpp - SIBImporter.h + SIB/SIBImporter.cpp + SIB/SIBImporter.h ) ADD_ASSIMP_IMPORTER( SMD - SMDLoader.cpp - SMDLoader.h + SMD/SMDLoader.cpp + SMD/SMDLoader.h ) ADD_ASSIMP_IMPORTER( STL - STLLoader.cpp - STLLoader.h - STLExporter.h - STLExporter.cpp + STL/STLLoader.cpp + STL/STLLoader.h +) + +ADD_ASSIMP_EXPORTER( STL + STL/STLExporter.h + STL/STLExporter.cpp ) ADD_ASSIMP_IMPORTER( TERRAGEN - TerragenLoader.cpp - TerragenLoader.h + Terragen/TerragenLoader.cpp + Terragen/TerragenLoader.h ) ADD_ASSIMP_IMPORTER( 3D - UnrealLoader.cpp - UnrealLoader.h + Unreal/UnrealLoader.cpp + Unreal/UnrealLoader.h ) ADD_ASSIMP_IMPORTER( X - XFileHelper.h - XFileImporter.cpp - XFileImporter.h - XFileParser.cpp - XFileParser.h - XFileExporter.h - XFileExporter.cpp + X/XFileHelper.h + X/XFileImporter.cpp + X/XFileImporter.h + X/XFileParser.cpp + X/XFileParser.h +) + +ADD_ASSIMP_EXPORTER( X + X/XFileExporter.h + X/XFileExporter.cpp ) ADD_ASSIMP_IMPORTER( X3D - X3DExporter.cpp - X3DExporter.hpp - X3DImporter.cpp - X3DImporter.hpp - X3DImporter_Geometry2D.cpp - X3DImporter_Geometry3D.cpp - X3DImporter_Group.cpp - X3DImporter_Light.cpp - X3DImporter_Macro.hpp - X3DImporter_Metadata.cpp - X3DImporter_Networking.cpp - X3DImporter_Node.hpp - X3DImporter_Postprocess.cpp - X3DImporter_Rendering.cpp - X3DImporter_Shape.cpp - X3DImporter_Texturing.cpp - FIReader.hpp - FIReader.cpp - X3DVocabulary.cpp + X3D/X3DImporter.cpp + X3D/X3DImporter.hpp + X3D/X3DImporter_Geometry2D.cpp + X3D/X3DImporter_Geometry3D.cpp + X3D/X3DImporter_Group.cpp + X3D/X3DImporter_Light.cpp + X3D/X3DImporter_Macro.hpp + X3D/X3DImporter_Metadata.cpp + X3D/X3DImporter_Networking.cpp + X3D/X3DImporter_Node.hpp + X3D/X3DImporter_Postprocess.cpp + X3D/X3DImporter_Rendering.cpp + X3D/X3DImporter_Shape.cpp + X3D/X3DImporter_Texturing.cpp + X3D/FIReader.hpp + X3D/FIReader.cpp + X3D/X3DVocabulary.cpp +) + +ADD_ASSIMP_EXPORTER( X3D + X3D/X3DExporter.cpp + X3D/X3DExporter.hpp ) ADD_ASSIMP_IMPORTER( GLTF - glTFAsset.h - glTFAsset.inl - glTFAssetWriter.h - glTFAssetWriter.inl - glTFImporter.cpp - glTFImporter.h - glTFExporter.h - glTFExporter.cpp - glTF2Asset.h - glTF2Asset.inl - glTF2AssetWriter.h - glTF2AssetWriter.inl - glTF2Importer.cpp - glTF2Importer.h - glTF2Exporter.h - glTF2Exporter.cpp + glTF/glTFCommon.h + glTF/glTFCommon.cpp + glTF/glTFAsset.h + glTF/glTFAsset.inl + glTF/glTFAssetWriter.h + glTF/glTFAssetWriter.inl + glTF/glTFImporter.cpp + glTF/glTFImporter.h + glTF2/glTF2Asset.h + glTF2/glTF2Asset.inl + glTF2/glTF2AssetWriter.h + glTF2/glTF2AssetWriter.inl + glTF2/glTF2Importer.cpp + glTF2/glTF2Importer.h +) + +ADD_ASSIMP_EXPORTER( GLTF + glTF/glTFExporter.h + glTF/glTFExporter.cpp + glTF2/glTF2Exporter.h + glTF2/glTF2Exporter.cpp ) ADD_ASSIMP_IMPORTER( 3MF - D3MFImporter.h - D3MFImporter.cpp - D3MFExporter.h - D3MFExporter.cpp - D3MFOpcPackage.h - D3MFOpcPackage.cpp - 3MFXmlTags.h + 3MF/D3MFImporter.h + 3MF/D3MFImporter.cpp + 3MF/D3MFOpcPackage.h + 3MF/D3MFOpcPackage.cpp + 3MF/3MFXmlTags.h +) + +ADD_ASSIMP_EXPORTER( 3MF + 3MF/D3MFExporter.h + 3MF/D3MFExporter.cpp ) ADD_ASSIMP_IMPORTER( MMD - MMDCpp14.h - MMDImporter.cpp - MMDImporter.h - MMDPmdParser.h - MMDPmxParser.h - MMDPmxParser.cpp - MMDVmdParser.h + MMD/MMDCpp14.h + MMD/MMDImporter.cpp + MMD/MMDImporter.h + MMD/MMDPmdParser.h + MMD/MMDPmxParser.h + MMD/MMDPmxParser.cpp + MMD/MMDVmdParser.h ) -SET( Step_SRCS - STEPFile.h +ADD_ASSIMP_EXPORTER( ASSJSON + Assjson/cencode.c + Assjson/cencode.h + Assjson/json_exporter.cpp + Assjson/mesh_splitter.cpp + Assjson/mesh_splitter.h +) + +# Workaround for issue #2406 - force problematic large file to be optimized to prevent string table overflow error +# Used -Os instead of -O2 as previous issues had mentioned, since -Os is roughly speaking -O2, excluding any +# optimizations that take up extra space. Given that the issue is a string table overflowing, -Os seemed appropriate +# Also, I'm not positive if both link & compile flags are needed, but this hopefully ensures that the issue should not +# recur for edge cases such as static builds. +if ((CMAKE_COMPILER_IS_MINGW) AND (CMAKE_BUILD_TYPE MATCHES Debug)) + message("-- Applying MinGW StepFileGen1.cpp Debug Workaround") + SET_SOURCE_FILES_PROPERTIES(Importer/StepFile/StepFileGen1.cpp PROPERTIES COMPILE_FLAGS -Os ) + SET_SOURCE_FILES_PROPERTIES(Importer/StepFile/StepFileGen1.cpp PROPERTIES LINK_FLAGS -Os ) + SET_SOURCE_FILES_PROPERTIES(Importer/StepFile/StepFileGen1.cpp PROPERTIES STATIC_LIBRARY_FLAGS -Os ) +endif() + +ADD_ASSIMP_IMPORTER( STEP + Step/STEPFile.h Importer/StepFile/StepFileImporter.h Importer/StepFile/StepFileImporter.cpp Importer/StepFile/StepFileGen1.cpp Importer/StepFile/StepFileGen2.cpp Importer/StepFile/StepFileGen3.cpp Importer/StepFile/StepReaderGen.h - StepExporter.h - StepExporter.cpp ) -SOURCE_GROUP( Step FILES ${Step_SRCS}) -SET( Exporter_SRCS - Exporter.cpp - AssimpCExport.cpp - ${HEADER_PATH}/BlobIOSystem.h +ADD_ASSIMP_EXPORTER( STEP + Step/StepExporter.h + Step/StepExporter.cpp ) -SOURCE_GROUP( Exporter FILES ${Exporter_SRCS}) + +if ((NOT ASSIMP_NO_EXPORT) OR (NOT ASSIMP_EXPORTERS_ENABLED STREQUAL "")) + SET( Exporter_SRCS + Common/Exporter.cpp + CApi/AssimpCExport.cpp + ${HEADER_PATH}/BlobIOSystem.h + ) + SOURCE_GROUP( Exporter FILES ${Exporter_SRCS}) +endif() SET( Extra_SRCS MD4FileData.h ) SOURCE_GROUP( Extra FILES ${Extra_SRCS}) +# irrXML +IF(HUNTER_ENABLED) + hunter_add_package(irrXML) + find_package(irrXML CONFIG REQUIRED) +ELSE(HUNTER_ENABLED) + # irrXML already included in contrib directory by parent CMakeLists.txt. +ENDIF(HUNTER_ENABLED) -SET( Clipper_SRCS - ../contrib/clipper/clipper.hpp - ../contrib/clipper/clipper.cpp -) -SOURCE_GROUP( Clipper FILES ${Clipper_SRCS}) +# utf8 +IF(HUNTER_ENABLED) + hunter_add_package(utf8) + find_package(utf8 CONFIG REQUIRED) +ELSE(HUNTER_ENABLED) + # utf8 is header-only, so Assimp doesn't need to do anything. +ENDIF(HUNTER_ENABLED) -SET( Poly2Tri_SRCS - ../contrib/poly2tri/poly2tri/common/shapes.cc - ../contrib/poly2tri/poly2tri/common/shapes.h - ../contrib/poly2tri/poly2tri/common/utils.h - ../contrib/poly2tri/poly2tri/sweep/advancing_front.h - ../contrib/poly2tri/poly2tri/sweep/advancing_front.cc - ../contrib/poly2tri/poly2tri/sweep/cdt.cc - ../contrib/poly2tri/poly2tri/sweep/cdt.h - ../contrib/poly2tri/poly2tri/sweep/sweep.cc - ../contrib/poly2tri/poly2tri/sweep/sweep.h - ../contrib/poly2tri/poly2tri/sweep/sweep_context.cc - ../contrib/poly2tri/poly2tri/sweep/sweep_context.h -) -SOURCE_GROUP( Poly2Tri FILES ${Poly2Tri_SRCS}) +# polyclipping +IF(HUNTER_ENABLED) + hunter_add_package(polyclipping) + find_package(polyclipping CONFIG REQUIRED) +ELSE(HUNTER_ENABLED) + SET( Clipper_SRCS + ../contrib/clipper/clipper.hpp + ../contrib/clipper/clipper.cpp + ) + SOURCE_GROUP( Contrib\\Clipper FILES ${Clipper_SRCS}) +ENDIF(HUNTER_ENABLED) -SET( unzip_SRCS - ../contrib/unzip/crypt.h - ../contrib/unzip/ioapi.c - ../contrib/unzip/ioapi.h - ../contrib/unzip/unzip.c - ../contrib/unzip/unzip.h -) -SOURCE_GROUP( unzip FILES ${unzip_SRCS}) +# poly2tri +IF(HUNTER_ENABLED) + hunter_add_package(poly2tri) + find_package(poly2tri CONFIG REQUIRED) +ELSE(HUNTER_ENABLED) + SET( Poly2Tri_SRCS + ../contrib/poly2tri/poly2tri/common/shapes.cc + ../contrib/poly2tri/poly2tri/common/shapes.h + ../contrib/poly2tri/poly2tri/common/utils.h + ../contrib/poly2tri/poly2tri/sweep/advancing_front.h + ../contrib/poly2tri/poly2tri/sweep/advancing_front.cc + ../contrib/poly2tri/poly2tri/sweep/cdt.cc + ../contrib/poly2tri/poly2tri/sweep/cdt.h + ../contrib/poly2tri/poly2tri/sweep/sweep.cc + ../contrib/poly2tri/poly2tri/sweep/sweep.h + ../contrib/poly2tri/poly2tri/sweep/sweep_context.cc + ../contrib/poly2tri/poly2tri/sweep/sweep_context.h + ) + SOURCE_GROUP( Contrib\\Poly2Tri FILES ${Poly2Tri_SRCS}) +ENDIF(HUNTER_ENABLED) -SET( ziplib_SRCS - ../contrib/zip/src/miniz.h - ../contrib/zip/src/zip.c - ../contrib/zip/src/zip.h -) +# minizip/unzip +IF(HUNTER_ENABLED) + hunter_add_package(minizip) + find_package(minizip CONFIG REQUIRED) +ELSE(HUNTER_ENABLED) + SET( unzip_SRCS + ../contrib/unzip/crypt.h + ../contrib/unzip/ioapi.c + ../contrib/unzip/ioapi.h + ../contrib/unzip/unzip.c + ../contrib/unzip/unzip.h + ) + SOURCE_GROUP(Contrib\\unzip FILES ${unzip_SRCS}) +ENDIF(HUNTER_ENABLED) -SOURCE_GROUP( ziplib FILES ${ziplib_SRCS} ) +# zip (https://github.com/kuba--/zip) +IF(HUNTER_ENABLED) + hunter_add_package(zip) + find_package(zip CONFIG REQUIRED) +ELSE(HUNTER_ENABLED) + SET( ziplib_SRCS + ../contrib/zip/src/miniz.h + ../contrib/zip/src/zip.c + ../contrib/zip/src/zip.h + ) -SET ( openddl_parser_SRCS - ../contrib/openddlparser/code/OpenDDLParser.cpp - ../contrib/openddlparser/code/DDLNode.cpp - ../contrib/openddlparser/code/OpenDDLCommon.cpp - ../contrib/openddlparser/code/OpenDDLExport.cpp - ../contrib/openddlparser/code/Value.cpp - ../contrib/openddlparser/code/OpenDDLStream.cpp - ../contrib/openddlparser/include/openddlparser/OpenDDLParser.h - ../contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h - ../contrib/openddlparser/include/openddlparser/OpenDDLCommon.h - ../contrib/openddlparser/include/openddlparser/OpenDDLExport.h - ../contrib/openddlparser/include/openddlparser/OpenDDLStream.h - ../contrib/openddlparser/include/openddlparser/DDLNode.h - ../contrib/openddlparser/include/openddlparser/Value.h -) -SOURCE_GROUP( openddl_parser FILES ${openddl_parser_SRCS}) + # TODO if cmake required version has been updated to >3.12.0, collapse this to the second case only + if(${CMAKE_VERSION} VERSION_LESS "3.12.0") + add_definitions(-DMINIZ_USE_UNALIGNED_LOADS_AND_STORES=0) + else() + add_compile_definitions(MINIZ_USE_UNALIGNED_LOADS_AND_STORES=0) + endif() -SET ( open3dgc_SRCS - ../contrib/Open3DGC/o3dgcAdjacencyInfo.h - ../contrib/Open3DGC/o3dgcArithmeticCodec.cpp - ../contrib/Open3DGC/o3dgcArithmeticCodec.h - ../contrib/Open3DGC/o3dgcBinaryStream.h - ../contrib/Open3DGC/o3dgcCommon.h - ../contrib/Open3DGC/o3dgcDVEncodeParams.h - ../contrib/Open3DGC/o3dgcDynamicVectorDecoder.cpp - ../contrib/Open3DGC/o3dgcDynamicVectorDecoder.h - ../contrib/Open3DGC/o3dgcDynamicVectorEncoder.cpp - ../contrib/Open3DGC/o3dgcDynamicVectorEncoder.h - ../contrib/Open3DGC/o3dgcDynamicVector.h - ../contrib/Open3DGC/o3dgcFIFO.h - ../contrib/Open3DGC/o3dgcIndexedFaceSet.h - ../contrib/Open3DGC/o3dgcIndexedFaceSet.inl - ../contrib/Open3DGC/o3dgcSC3DMCDecoder.h - ../contrib/Open3DGC/o3dgcSC3DMCDecoder.inl - ../contrib/Open3DGC/o3dgcSC3DMCEncodeParams.h - ../contrib/Open3DGC/o3dgcSC3DMCEncoder.h - ../contrib/Open3DGC/o3dgcSC3DMCEncoder.inl - ../contrib/Open3DGC/o3dgcTimer.h - ../contrib/Open3DGC/o3dgcTools.cpp - ../contrib/Open3DGC/o3dgcTriangleFans.cpp - ../contrib/Open3DGC/o3dgcTriangleFans.h - ../contrib/Open3DGC/o3dgcTriangleListDecoder.h - ../contrib/Open3DGC/o3dgcTriangleListDecoder.inl - ../contrib/Open3DGC/o3dgcTriangleListEncoder.h - ../contrib/Open3DGC/o3dgcTriangleListEncoder.inl - ../contrib/Open3DGC/o3dgcVector.h - ../contrib/Open3DGC/o3dgcVector.inl -) -SOURCE_GROUP( open3dgc FILES ${open3dgc_SRCS}) + SOURCE_GROUP( ziplib FILES ${ziplib_SRCS} ) +ENDIF(HUNTER_ENABLED) + +# openddlparser +IF(HUNTER_ENABLED) + hunter_add_package(openddlparser) + find_package(openddlparser CONFIG REQUIRED) +ELSE(HUNTER_ENABLED) + SET ( openddl_parser_SRCS + ../contrib/openddlparser/code/OpenDDLParser.cpp + ../contrib/openddlparser/code/DDLNode.cpp + ../contrib/openddlparser/code/OpenDDLCommon.cpp + ../contrib/openddlparser/code/OpenDDLExport.cpp + ../contrib/openddlparser/code/Value.cpp + ../contrib/openddlparser/code/OpenDDLStream.cpp + ../contrib/openddlparser/include/openddlparser/OpenDDLParser.h + ../contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h + ../contrib/openddlparser/include/openddlparser/OpenDDLCommon.h + ../contrib/openddlparser/include/openddlparser/OpenDDLExport.h + ../contrib/openddlparser/include/openddlparser/OpenDDLStream.h + ../contrib/openddlparser/include/openddlparser/DDLNode.h + ../contrib/openddlparser/include/openddlparser/Value.h + ) + SOURCE_GROUP( Contrib\\openddl_parser FILES ${openddl_parser_SRCS}) +ENDIF(HUNTER_ENABLED) + +# Open3DGC +IF(HUNTER_ENABLED) + # Nothing to do, not available in Hunter yet. +ELSE(HUNTER_ENABLED) + SET ( open3dgc_SRCS + ../contrib/Open3DGC/o3dgcAdjacencyInfo.h + ../contrib/Open3DGC/o3dgcArithmeticCodec.cpp + ../contrib/Open3DGC/o3dgcArithmeticCodec.h + ../contrib/Open3DGC/o3dgcBinaryStream.h + ../contrib/Open3DGC/o3dgcCommon.h + ../contrib/Open3DGC/o3dgcDVEncodeParams.h + ../contrib/Open3DGC/o3dgcDynamicVectorDecoder.cpp + ../contrib/Open3DGC/o3dgcDynamicVectorDecoder.h + ../contrib/Open3DGC/o3dgcDynamicVectorEncoder.cpp + ../contrib/Open3DGC/o3dgcDynamicVectorEncoder.h + ../contrib/Open3DGC/o3dgcDynamicVector.h + ../contrib/Open3DGC/o3dgcFIFO.h + ../contrib/Open3DGC/o3dgcIndexedFaceSet.h + ../contrib/Open3DGC/o3dgcIndexedFaceSet.inl + ../contrib/Open3DGC/o3dgcSC3DMCDecoder.h + ../contrib/Open3DGC/o3dgcSC3DMCDecoder.inl + ../contrib/Open3DGC/o3dgcSC3DMCEncodeParams.h + ../contrib/Open3DGC/o3dgcSC3DMCEncoder.h + ../contrib/Open3DGC/o3dgcSC3DMCEncoder.inl + ../contrib/Open3DGC/o3dgcTimer.h + ../contrib/Open3DGC/o3dgcTools.cpp + ../contrib/Open3DGC/o3dgcTriangleFans.cpp + ../contrib/Open3DGC/o3dgcTriangleFans.h + ../contrib/Open3DGC/o3dgcTriangleListDecoder.h + ../contrib/Open3DGC/o3dgcTriangleListDecoder.inl + ../contrib/Open3DGC/o3dgcTriangleListEncoder.h + ../contrib/Open3DGC/o3dgcTriangleListEncoder.inl + ../contrib/Open3DGC/o3dgcVector.h + ../contrib/Open3DGC/o3dgcVector.inl + ) + SOURCE_GROUP( Contrib\\open3dgc FILES ${open3dgc_SRCS}) +ENDIF(HUNTER_ENABLED) # Check dependencies for glTF importer with Open3DGC-compression. # RT-extensions is used in "contrib/Open3DGC/o3dgcTimer.h" for collecting statistics. Pointed file # has implementation for different platforms: WIN32, __MACH__ and other ("else" block). FIND_PACKAGE(RT QUIET) -IF (RT_FOUND OR MSVC) +IF (NOT HUNTER_ENABLED AND (RT_FOUND OR MSVC)) SET( ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC 1 ) ADD_DEFINITIONS( -DASSIMP_IMPORTER_GLTF_USE_OPEN3DGC=1 ) ELSE () SET (open3dgc_SRCS "") - MESSAGE (INFO " RT-extension not found. glTF import/export will be built without Open3DGC-compression.") + MESSAGE (INFO " Hunter enabled or RT-extension not found. glTF import/export will be built without Open3DGC-compression.") #!TODO: off course is better to remove statistics timers from o3dgc codec. Or propose to choose what to use. ENDIF () -INCLUDE_DIRECTORIES( "../contrib/rapidjson/include" ) -INCLUDE_DIRECTORIES( "../contrib" ) +# RapidJSON +IF(HUNTER_ENABLED) + hunter_add_package(RapidJSON) + find_package(RapidJSON CONFIG REQUIRED) +ELSE(HUNTER_ENABLED) + INCLUDE_DIRECTORIES( "../contrib/rapidjson/include" ) + INCLUDE_DIRECTORIES( "../contrib" ) +ENDIF(HUNTER_ENABLED) # VC2010 fixes if(MSVC10) @@ -872,29 +1043,38 @@ if ( MSVC ) ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) endif ( MSVC ) -if (UNZIP_FOUND) - SET (unzip_compile_SRCS "") -else (UNZIP_FOUND) - SET (unzip_compile_SRCS ${unzip_SRCS}) - INCLUDE_DIRECTORIES( "../contrib/unzip/" ) -endif (UNZIP_FOUND) +IF(NOT HUNTER_ENABLED) + if (UNZIP_FOUND) + SET (unzip_compile_SRCS "") + else (UNZIP_FOUND) + SET (unzip_compile_SRCS ${unzip_SRCS}) + INCLUDE_DIRECTORIES( "../contrib/unzip/" ) + endif (UNZIP_FOUND) +ENDIF(NOT HUNTER_ENABLED) -MESSAGE(STATUS "Enabled formats:${ASSIMP_IMPORTERS_ENABLED}") -MESSAGE(STATUS "Disabled formats:${ASSIMP_IMPORTERS_DISABLED}") +MESSAGE(STATUS "Enabled importer formats:${ASSIMP_IMPORTERS_ENABLED}") +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} + ${CApi_SRCS} ${Common_SRCS} ${Logging_SRCS} ${Exporter_SRCS} ${PostProcessing_SRCS} ${MaterialSystem_SRCS} ${STEPParser_SRCS} - ${Step_SRCS} +# ${Step_SRCS} check if we need a different approach # Model Support ${ASSIMP_LOADER_SRCS} + ${ASSIMP_EXPORTER_SRCS} # Third-party libraries ${IrrXML_SRCS} @@ -908,14 +1088,15 @@ SET( assimp_src ${PUBLIC_HEADERS} ${COMPILER_HEADERS} - ) ADD_DEFINITIONS( -DOPENDDLPARSER_BUILD ) -INCLUDE_DIRECTORIES( - ${IRRXML_INCLUDE_DIR} - ../contrib/openddlparser/include -) +IF(NOT HUNTER_ENABLED) + INCLUDE_DIRECTORIES( + ${IRRXML_INCLUDE_DIR} + ../contrib/openddlparser/include + ) +ENDIF(NOT HUNTER_ENABLED) IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) SET( assimp_src ${assimp_src} ${C4D_SRCS}) @@ -928,16 +1109,31 @@ ADD_LIBRARY(assimp::assimp ALIAS assimp) TARGET_INCLUDE_DIRECTORIES ( assimp PUBLIC $ $ - $ + $ ) -TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES} ${OPENDDL_PARSER_LIBRARIES} ${IRRXML_LIBRARY} ) +IF(HUNTER_ENABLED) + TARGET_LINK_LIBRARIES(assimp + PUBLIC + polyclipping::polyclipping + irrXML::irrXML + openddlparser::openddl_parser + poly2tri::poly2tri + minizip::minizip + ZLIB::zlib + RapidJSON::rapidjson + utf8::utf8 + zip::zip + ) +ELSE(HUNTER_ENABLED) + TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES} ${OPENDDL_PARSER_LIBRARIES} ${IRRXML_LIBRARY} ) +ENDIF(HUNTER_ENABLED) -if(ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM) +if(ASSIMP_ANDROID_JNIIOSYSTEM) set(ASSIMP_ANDROID_JNIIOSYSTEM_PATH port/AndroidJNI) add_subdirectory(../${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/ ../${ASSIMP_ANDROID_JNIIOSYSTEM_PATH}/) target_link_libraries(assimp android_jniiosystem) -endif(ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM) +endif(ASSIMP_ANDROID_JNIIOSYSTEM) IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) TARGET_LINK_LIBRARIES(assimp optimized ${C4D_RELEASE_LIBRARIES}) @@ -947,26 +1143,41 @@ ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) if( MSVC ) # in order to prevent DLL hell, each of the DLLs have to be suffixed with the major version and msvc prefix - if( MSVC70 OR MSVC71 ) - set(MSVC_PREFIX "vc70") - elseif( MSVC80 ) - set(MSVC_PREFIX "vc80") - elseif( MSVC90 ) - set(MSVC_PREFIX "vc90") - elseif( MSVC10 ) - set(MSVC_PREFIX "vc100") - elseif( MSVC11 ) - set(MSVC_PREFIX "vc110") - elseif( MSVC12 ) - set(MSVC_PREFIX "vc120") - elseif( MSVC14 ) - set(MSVC_PREFIX "vc140") + # CMake 3.12 added a variable for this + if(MSVC_TOOLSET_VERSION) + set(MSVC_PREFIX "vc${MSVC_TOOLSET_VERSION}") else() - set(MSVC_PREFIX "vc150") + if( MSVC70 OR MSVC71 ) + set(MSVC_PREFIX "vc70") + elseif( MSVC80 ) + set(MSVC_PREFIX "vc80") + elseif( MSVC90 ) + set(MSVC_PREFIX "vc90") + elseif( MSVC10 ) + set(MSVC_PREFIX "vc100") + elseif( MSVC11 ) + set(MSVC_PREFIX "vc110") + elseif( MSVC12 ) + set(MSVC_PREFIX "vc120") + elseif( MSVC_VERSION LESS 1910) + set(MSVC_PREFIX "vc140") + elseif( MSVC_VERSION LESS 1920) + set(MSVC_PREFIX "vc141") + elseif( MSVC_VERSION LESS 1930) + set(MSVC_PREFIX "vc142") + else() + MESSAGE(WARNING "unknown msvc version ${MSVC_VERSION}") + set(MSVC_PREFIX "vc150") + endif() endif() set(LIBRARY_SUFFIX "${ASSIMP_LIBRARY_SUFFIX}-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library") endif() +if (${CMAKE_SYSTEM_NAME} MATCHES "WindowsStore") + target_compile_definitions(assimp PUBLIC WindowsStore) + TARGET_LINK_LIBRARIES(assimp advapi32) + #set(WindowsStore TRUE) +endif() SET_TARGET_PROPERTIES( assimp PROPERTIES VERSION ${ASSIMP_VERSION} SOVERSION ${ASSIMP_SOVERSION} # use full version @@ -998,24 +1209,37 @@ ENDIF(APPLE) # Build against external unzip, or add ../contrib/unzip so # assimp can #include "unzip.h" -if (UNZIP_FOUND) - INCLUDE_DIRECTORIES(${UNZIP_INCLUDE_DIRS}) - TARGET_LINK_LIBRARIES(assimp ${UNZIP_LIBRARIES}) -else (UNZIP_FOUND) - INCLUDE_DIRECTORIES("../") -endif (UNZIP_FOUND) +IF(NOT HUNTER_ENABLED) + if (UNZIP_FOUND) + INCLUDE_DIRECTORIES(${UNZIP_INCLUDE_DIRS}) + TARGET_LINK_LIBRARIES(assimp ${UNZIP_LIBRARIES}) + else (UNZIP_FOUND) + INCLUDE_DIRECTORIES("../") + endif (UNZIP_FOUND) +ENDIF(NOT HUNTER_ENABLED) # Add RT-extension library for glTF importer with Open3DGC-compression. IF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC) TARGET_LINK_LIBRARIES(assimp ${RT_LIBRARY}) ENDIF (RT_FOUND AND ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC) +IF(HUNTER_ENABLED) + INSTALL( TARGETS assimp + EXPORT "${TARGETS_EXPORT_NAME}" + LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} + FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + COMPONENT ${LIBASSIMP_COMPONENT} + INCLUDES DESTINATION "include") +ELSE(HUNTER_ENABLED) INSTALL( TARGETS assimp - LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} - ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} - RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} - FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} - COMPONENT ${LIBASSIMP_COMPONENT}) + LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} + FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + COMPONENT ${LIBASSIMP_COMPONENT}) +ENDIF(HUNTER_ENABLED) INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev) INSTALL( FILES ${COMPILER_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp/Compiler COMPONENT assimp-dev) @@ -1026,6 +1250,16 @@ if (ASSIMP_ANDROID_JNIIOSYSTEM) ENDIF(ASSIMP_ANDROID_JNIIOSYSTEM) if(MSVC AND ASSIMP_INSTALL_PDB) + # When only the static library is built, these properties must + # be set to ensure the static lib .pdb is staged for installation. + IF(NOT BUILD_SHARED_LIBS) + SET_TARGET_PROPERTIES( assimp PROPERTIES + COMPILE_PDB_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMPILE_PDB_NAME assimp${LIBRARY_SUFFIX} + COMPILE_PDB_NAME_DEBUG assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX} + ) + ENDIF() + IF(CMAKE_GENERATOR MATCHES "^Visual Studio") install(FILES ${Assimp_BINARY_DIR}/code/Debug/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb DESTINATION ${ASSIMP_LIB_INSTALL_DIR} diff --git a/code/COBLoader.cpp b/code/COB/COBLoader.cpp similarity index 98% rename from code/COBLoader.cpp rename to code/COB/COBLoader.cpp index a8e41dbbc..19e3cd59e 100644 --- a/code/COBLoader.cpp +++ b/code/COB/COBLoader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,20 +45,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_COB_IMPORTER -#include "COBLoader.h" -#include "COBScene.h" -#include "ConvertToLHProcess.h" +#include "COB/COBLoader.h" +#include "COB/COBScene.h" +#include "PostProcessing/ConvertToLHProcess.h" + #include #include #include #include #include -#include #include #include #include #include +#include + using namespace Assimp; using namespace Assimp::COB; using namespace Assimp::Formatter; @@ -144,7 +146,7 @@ void COBImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS // check header char head[32]; stream->CopyAndAdvance(head,32); - if (strncmp(head,"Caligari ",9)) { + if (strncmp(head,"Caligari ",9) != 0) { ThrowException("Could not found magic id: `Caligari`"); } @@ -656,14 +658,14 @@ void COBImporter::ReadLght_Ascii(Scene& out, LineSplitter& splitter, const Chunk ReadFloat3Tuple_Ascii(msh.color ,&rgb); SkipSpaces(&rgb); - if (strncmp(rgb,"cone angle",10)) { + if (strncmp(rgb,"cone angle",10) != 0) { ASSIMP_LOG_WARN_F( "Expected `cone angle` entity in `color` line in `Lght` chunk ", nfo.id ); } SkipSpaces(rgb+10,&rgb); msh.angle = fast_atof(&rgb); SkipSpaces(&rgb); - if (strncmp(rgb,"inner angle",11)) { + if (strncmp(rgb,"inner angle",11) != 0) { ASSIMP_LOG_WARN_F( "Expected `inner angle` entity in `color` line in `Lght` chunk ", nfo.id); } SkipSpaces(rgb+11,&rgb); @@ -896,6 +898,7 @@ public: : nfo(nfo) , reader(reader) , cur(reader.GetCurrentPos()) { + // empty } ~chunk_guard() { @@ -903,7 +906,7 @@ public: if(nfo.size != static_cast(-1)) { try { reader.IncPtr( static_cast< int >( nfo.size ) - reader.GetCurrentPos() + cur ); - } catch ( DeadlyImportError e ) { + } catch (const DeadlyImportError& ) { // out of limit so correct the value reader.IncPtr( reader.GetReadLimit() ); } @@ -911,15 +914,17 @@ public: } private: - const COB::ChunkInfo& nfo; StreamReaderLE& reader; long cur; }; // ------------------------------------------------------------------------------------------------ -void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) -{ +void COBImporter::ReadBinaryFile(Scene& out, StreamReaderLE* reader) { + if (nullptr == reader) { + return; + } + while(1) { std::string type; type += reader -> GetI1() @@ -1214,7 +1219,7 @@ void COBImporter::ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const const chunk_guard cn(nfo,reader); - out.nodes.push_back(std::shared_ptr(new Group())); + out.nodes.push_back(std::make_shared()); Group& msh = (Group&)(*out.nodes.back().get()); msh = nfo; diff --git a/code/COBLoader.h b/code/COB/COBLoader.h similarity index 99% rename from code/COBLoader.h rename to code/COB/COBLoader.h index 156c8d911..40fed324b 100644 --- a/code/COBLoader.h +++ b/code/COB/COBLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/COBScene.h b/code/COB/COBScene.h similarity index 99% rename from code/COBScene.h rename to code/COB/COBScene.h index 2473c42a5..90349be70 100644 --- a/code/COBScene.h +++ b/code/COB/COBScene.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/CSMLoader.cpp b/code/CSM/CSMLoader.cpp similarity index 99% rename from code/CSMLoader.cpp rename to code/CSM/CSMLoader.cpp index 777b6cf1b..9dbb38467 100644 --- a/code/CSMLoader.cpp +++ b/code/CSM/CSMLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/CSMLoader.h b/code/CSM/CSMLoader.h similarity index 98% rename from code/CSMLoader.h rename to code/CSM/CSMLoader.h index ea82bb87a..31a814b52 100644 --- a/code/CSMLoader.h +++ b/code/CSM/CSMLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/ColladaExporter.cpp b/code/Collada/ColladaExporter.cpp similarity index 95% rename from code/ColladaExporter.cpp rename to code/Collada/ColladaExporter.cpp index 0d5bdd46d..6fd31ed3b 100644 --- a/code/ColladaExporter.cpp +++ b/code/Collada/ColladaExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ColladaExporter.h" #include +#include #include #include #include @@ -64,13 +65,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; -namespace Assimp -{ +namespace Assimp { // ------------------------------------------------------------------------------------------------ // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp -void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) -{ +void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* /*pProperties*/) { std::string path = DefaultIOSystem::absolutePath(std::string(pFile)); std::string file = DefaultIOSystem::completeBaseName(std::string(pFile)); @@ -93,15 +92,15 @@ void ExportSceneCollada(const char* pFile, IOSystem* pIOSystem, const aiScene* p } // end of namespace Assimp - - // ------------------------------------------------------------------------------------------------ // Constructor for a specific scene to export -ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file) : mIOSystem(pIOSystem), mPath(path), mFile(file) -{ +ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file) +: mIOSystem(pIOSystem) +, mPath(path) +, mFile(file) { // make sure that all formatting happens using the standard, C locale and not the user's current locale mOutput.imbue( std::locale("C") ); - mOutput.precision(16); + mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION); mScene = pScene; mSceneOwned = false; @@ -115,17 +114,15 @@ ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, co // ------------------------------------------------------------------------------------------------ // Destructor -ColladaExporter::~ColladaExporter() -{ - if(mSceneOwned) { +ColladaExporter::~ColladaExporter() { + if ( mSceneOwned ) { delete mScene; } } // ------------------------------------------------------------------------------------------------ // Starts writing the contents -void ColladaExporter::WriteFile() -{ +void ColladaExporter::WriteFile() { // write the DTD mOutput << "" << endstr; // COLLADA element start @@ -158,9 +155,8 @@ void ColladaExporter::WriteFile() // ------------------------------------------------------------------------------------------------ // Writes the asset header -void ColladaExporter::WriteHeader() -{ - static const ai_real epsilon = ai_real( 0.00001 ); +void ColladaExporter::WriteHeader() { + static const ai_real epsilon = Math::getEpsilon(); static const aiQuaternion x_rot(aiMatrix3x3( 0, -1, 0, 1, 0, 0, @@ -238,25 +234,64 @@ void ColladaExporter::WriteHeader() mOutput << startstr << "" << endstr; PushTag(); - aiMetadata* meta = mScene->mRootNode->mMetaData; + // If no Scene metadata, use root node metadata + aiMetadata* meta = mScene->mMetaData; + if (nullptr == meta) { + meta = mScene->mRootNode->mMetaData; + } + aiString value; - if (!meta || !meta->Get("Author", value)) + if (!meta || !meta->Get("Author", value)) { mOutput << startstr << "" << "Assimp" << "" << endstr; - else + } else { mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; + } - if (!meta || !meta->Get("AuthoringTool", value)) + if (nullptr == meta || !meta->Get("AuthoringTool", value)) { mOutput << startstr << "" << "Assimp Exporter" << "" << endstr; - else + } else { mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; + } - //mOutput << startstr << "" << mScene->author.C_Str() << "" << endstr; - //mOutput << startstr << "" << mScene->authoringTool.C_Str() << "" << endstr; + if (meta) { + if (meta->Get("Comments", value)) { + mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; + } + if (meta->Get("Copyright", value)) { + mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; + } + if (meta->Get("SourceData", value)) { + mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; + } + } PopTag(); mOutput << startstr << "" << endstr; - mOutput << startstr << "" << date_str << "" << endstr; + + if (nullptr == meta || !meta->Get("Created", value)) { + mOutput << startstr << "" << date_str << "" << endstr; + } else { + mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; + } + + // Modified date is always the date saved mOutput << startstr << "" << date_str << "" << endstr; + + if (meta) { + if (meta->Get("Keywords", value)) { + mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; + } + if (meta->Get("Revision", value)) { + mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; + } + if (meta->Get("Subject", value)) { + mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; + } + if (meta->Get("Title", value)) { + mOutput << startstr << "" << XMLEscape(value.C_Str()) << "" << endstr; + } + } + mOutput << startstr << "" << endstr; mOutput << startstr << "" << up_axis << "" << endstr; PopTag(); @@ -269,18 +304,21 @@ void ColladaExporter::WriteTextures() { static const unsigned int buffer_size = 1024; char str[buffer_size]; - if(mScene->HasTextures()) { + if (mScene->HasTextures()) { for(unsigned int i = 0; i < mScene->mNumTextures; i++) { // It would be great to be able to create a directory in portable standard C++, but it's not the case, // so we just write the textures in the current directory. aiTexture* texture = mScene->mTextures[i]; + if ( nullptr == texture ) { + continue; + } ASSIMP_itoa10(str, buffer_size, i + 1); std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char*) texture->achFormatHint); - std::unique_ptr outfile(mIOSystem->Open(mPath + name, "wb")); + std::unique_ptr outfile(mIOSystem->Open(mPath + mIOSystem->getOsSeparator() + name, "wb")); if(outfile == NULL) { throw DeadlyExportError("could not open output texture file: " + mPath + name); } @@ -428,6 +466,7 @@ void ColladaExporter::WritePointLight(const aiLight *const light){ mOutput << startstr << "" << endstr; } + void ColladaExporter::WriteDirectionalLight(const aiLight *const light){ const aiColor3D &color= light->mColorDiffuse; mOutput << startstr << "" << endstr; @@ -440,6 +479,7 @@ void ColladaExporter::WriteDirectionalLight(const aiLight *const light){ mOutput << startstr << "" << endstr; } + void ColladaExporter::WriteSpotLight(const aiLight *const light){ const aiColor3D &color= light->mColorDiffuse; @@ -496,18 +536,16 @@ void ColladaExporter::WriteAmbienttLight(const aiLight *const light){ // ------------------------------------------------------------------------------------------------ // Reads a single surface entry from the given material keys -void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex) -{ - if( pSrcMat->GetTextureCount( pTexture) > 0 ) - { +void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, + aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex) { + if( pSrcMat->GetTextureCount( pTexture) > 0 ) { aiString texfile; unsigned int uvChannel = 0; pSrcMat->GetTexture( pTexture, 0, &texfile, NULL, &uvChannel); std::string index_str(texfile.C_Str()); - if(index_str.size() != 0 && index_str[0] == '*') - { + if(index_str.size() != 0 && index_str[0] == '*') { unsigned int index; index_str = index_str.substr(1, std::string::npos); @@ -525,15 +563,13 @@ void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* } else { throw DeadlyExportError("could not find embedded texture at index " + index_str); } - } else - { + } else { poSurface.texture = texfile.C_Str(); } poSurface.channel = uvChannel; poSurface.exist = true; - } else - { + } else { if( pKey ) poSurface.exist = pSrcMat->Get( pKey, static_cast(pType), static_cast(pIndex), poSurface.color) == aiReturn_SUCCESS; } @@ -541,15 +577,13 @@ void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* // ------------------------------------------------------------------------------------------------ // Reimplementation of isalnum(,C locale), because AppVeyor does not see standard version. -static bool isalnum_C(char c) -{ +static bool isalnum_C(char c) { return ( nullptr != strchr("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",c) ); } // ------------------------------------------------------------------------------------------------ // Writes an image entry for the given surface -void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd) -{ +void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd) { if( !pSurface.texture.empty() ) { mOutput << startstr << "" << endstr; @@ -803,8 +837,9 @@ void ColladaExporter::WriteControllerLibrary() mOutput << startstr << "" << endstr; PushTag(); - for( size_t a = 0; a < mScene->mNumMeshes; ++a) + for( size_t a = 0; a < mScene->mNumMeshes; ++a) { WriteController( a); + } PopTag(); mOutput << startstr << "" << endstr; @@ -1500,24 +1535,18 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode) // otherwise it is a normal node (NODE) const char * node_type; bool is_joint, is_skeleton_root = false; - if (NULL == findBone(pScene, pNode->mName.C_Str())) { + if (nullptr == findBone(pScene, pNode->mName.C_Str())) { node_type = "NODE"; is_joint = false; } else { node_type = "JOINT"; is_joint = true; - if(!pNode->mParent || NULL == findBone(pScene, pNode->mParent->mName.C_Str())) + if (!pNode->mParent || nullptr == findBone(pScene, pNode->mParent->mName.C_Str())) { is_skeleton_root = true; + } } const std::string node_name_escaped = XMLEscape(pNode->mName.data); - /* // customized, Note! the id field is crucial for inter-xml look up, it cannot be replaced with sid ?! - mOutput << startstr - << " textures; -protected: +public: /// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions /// Reads a single surface entry from the given material keys void ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex); diff --git a/code/ColladaHelper.h b/code/Collada/ColladaHelper.h similarity index 98% rename from code/ColladaHelper.h rename to code/Collada/ColladaHelper.h index fe6674b93..66cff2d20 100644 --- a/code/ColladaHelper.h +++ b/code/Collada/ColladaHelper.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -580,15 +580,11 @@ struct Image { std::string mFileName; - /** If image file name is zero, embedded image data - */ + /** Embedded image data */ std::vector mImageData; - /** If image file name is zero, file format of - * embedded image data. - */ + /** File format hint ofembedded image data */ std::string mEmbeddedFormat; - }; /** An animation channel. */ diff --git a/code/ColladaLoader.cpp b/code/Collada/ColladaLoader.cpp similarity index 58% rename from code/ColladaLoader.cpp rename to code/Collada/ColladaLoader.cpp index d86985a29..0fbc7d599 100644 --- a/code/ColladaLoader.cpp +++ b/code/Collada/ColladaLoader.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -43,7 +41,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Implementation of the Collada loader */ - #ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER #include "ColladaLoader.h" @@ -60,13 +57,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "time.h" #include "math.h" #include #include +#include -using namespace Assimp; +namespace Assimp { + using namespace Assimp::Formatter; static const aiImporterDesc desc = { @@ -74,78 +74,92 @@ static const aiImporterDesc desc = { "", "", "http://collada.org", - aiImporterFlags_SupportTextFlavour, + aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportCompressedFlavour, 1, 3, 1, 5, - "dae" + "dae zae" }; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer ColladaLoader::ColladaLoader() : mFileName() - , mMeshIndexByID() - , mMaterialIndexByName() - , mMeshes() - , newMats() - , mCameras() - , mLights() - , mTextures() - , mAnims() - , noSkeletonMesh( false ) + , mMeshIndexByID() + , mMaterialIndexByName() + , mMeshes() + , newMats() + , mCameras() + , mLights() + , mTextures() + , mAnims() + , noSkeletonMesh(false) , ignoreUpDirection(false) - , mNodeNameCounter( 0 ) -{} + , useColladaName(false) + , mNodeNameCounter(0) { + // empty +} // ------------------------------------------------------------------------------------------------ // Destructor, private as well -ColladaLoader::~ColladaLoader() -{} +ColladaLoader::~ColladaLoader() { + // empty +} // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const -{ +bool ColladaLoader::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { // check file extension - std::string extension = GetExtension(pFile); + const std::string extension = GetExtension(pFile); - if( extension == "dae") - return true; + bool readSig = checkSig && (pIOHandler != nullptr); + + if (!readSig) { + if (extension == "dae" || extension == "zae") { + return true; + } + } + + if (readSig) { + // Look for a DAE file inside, but don't extract it + ZipArchiveIOSystem zip_archive(pIOHandler, pFile); + if (zip_archive.isOpen()) + return !ColladaParser::ReadZaeManifest(zip_archive).empty(); + } // XML - too generic, we need to open the file and search for typical keywords - if( extension == "xml" || !extension.length() || checkSig) { + if (extension == "xml" || !extension.length() || checkSig) { /* If CanRead() is called in order to check whether we * support a specific file extension in general pIOHandler * might be NULL and it's our duty to return true here. */ - if (!pIOHandler)return true; - const char* tokens[] = {"GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; - ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION,0) != 0; - useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES,0) != 0; +void ColladaLoader::SetupProperties(const Importer* pImp) { + noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES, 0) != 0; + ignoreUpDirection = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION, 0) != 0; + useColladaName = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_USE_COLLADA_NAMES, 0) != 0; } // ------------------------------------------------------------------------------------------------ // Get file extension list -const aiImporterDesc* ColladaLoader::GetInfo () const -{ +const aiImporterDesc* ColladaLoader::GetInfo() const { return &desc; } // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. -void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) -{ +void ColladaLoader::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { mFileName = pFile; // clean all member arrays - just for safety, it should work even if we did not @@ -160,66 +174,82 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I mAnims.clear(); // parse the input file - ColladaParser parser( pIOHandler, pFile); + ColladaParser parser(pIOHandler, pFile); - if( !parser.mRootNode) + + if( !parser.mRootNode) { throw DeadlyImportError( "Collada: File came out empty. Something is wrong here."); + } // reserve some storage to avoid unnecessary reallocs - newMats.reserve(parser.mMaterialLibrary.size()*2); - mMeshes.reserve(parser.mMeshLibrary.size()*2); + newMats.reserve(parser.mMaterialLibrary.size()*2u); + mMeshes.reserve(parser.mMeshLibrary.size()*2u); mCameras.reserve(parser.mCameraLibrary.size()); mLights.reserve(parser.mLightLibrary.size()); // create the materials first, for the meshes to find - BuildMaterials( parser, pScene); + BuildMaterials(parser, pScene); // build the node hierarchy from it - pScene->mRootNode = BuildHierarchy( parser, parser.mRootNode); + pScene->mRootNode = BuildHierarchy(parser, parser.mRootNode); // ... then fill the materials with the now adjusted settings FillMaterials(parser, pScene); - // Apply unitsize scale calculation + // Apply unit-size scale calculation + pScene->mRootNode->mTransformation *= aiMatrix4x4(parser.mUnitSize, 0, 0, 0, 0, parser.mUnitSize, 0, 0, 0, 0, parser.mUnitSize, 0, 0, 0, 0, 1); if( !ignoreUpDirection ) { - // Convert to Y_UP, if different orientation - if( parser.mUpDirection == ColladaParser::UP_X) - pScene->mRootNode->mTransformation *= aiMatrix4x4( - 0, -1, 0, 0, - 1, 0, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1); - else if( parser.mUpDirection == ColladaParser::UP_Z) - pScene->mRootNode->mTransformation *= aiMatrix4x4( - 1, 0, 0, 0, - 0, 0, 1, 0, - 0, -1, 0, 0, - 0, 0, 0, 1); + // Convert to Y_UP, if different orientation + if( parser.mUpDirection == ColladaParser::UP_X) { + pScene->mRootNode->mTransformation *= aiMatrix4x4( + 0, -1, 0, 0, + 1, 0, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + } else if( parser.mUpDirection == ColladaParser::UP_Z) { + pScene->mRootNode->mTransformation *= aiMatrix4x4( + 1, 0, 0, 0, + 0, 0, 1, 0, + 0, -1, 0, 0, + 0, 0, 0, 1); + } + } + + // Store scene metadata + if (!parser.mAssetMetaData.empty()) { + const size_t numMeta(parser.mAssetMetaData.size()); + pScene->mMetaData = aiMetadata::Alloc(static_cast(numMeta)); + size_t i = 0; + for (auto it = parser.mAssetMetaData.cbegin(); it != parser.mAssetMetaData.cend(); ++it, ++i) { + pScene->mMetaData->Set(static_cast(i), (*it).first, (*it).second); + } } // store all meshes - StoreSceneMeshes( pScene); + StoreSceneMeshes(pScene); // store all materials - StoreSceneMaterials( pScene); + StoreSceneMaterials(pScene); + + // store all textures + StoreSceneTextures(pScene); // store all lights - StoreSceneLights( pScene); + StoreSceneLights(pScene); // store all cameras - StoreSceneCameras( pScene); + StoreSceneCameras(pScene); // store all animations - StoreAnimations( pScene, parser); - + StoreAnimations(pScene, parser); // If no meshes have been loaded, it's probably just an animated skeleton. - if (!pScene->mNumMeshes) { + if ( 0u == pScene->mNumMeshes) { if (!noSkeletonMesh) { SkeletonMeshBuilder hero(pScene); @@ -230,60 +260,56 @@ void ColladaLoader::InternReadFile( const std::string& pFile, aiScene* pScene, I // ------------------------------------------------------------------------------------------------ // Recursively constructs a scene node for the given parser node and returns it. -aiNode* ColladaLoader::BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode) -{ +aiNode* ColladaLoader::BuildHierarchy(const ColladaParser& pParser, const Collada::Node* pNode) { // create a node for it aiNode* node = new aiNode(); // find a name for the new node. It's more complicated than you might think - node->mName.Set( FindNameForNode( pNode)); + node->mName.Set(FindNameForNode(pNode)); // calculate the transformation matrix for it - node->mTransformation = pParser.CalculateResultTransform( pNode->mTransforms); + node->mTransformation = pParser.CalculateResultTransform(pNode->mTransforms); // now resolve node instances std::vector instances; - ResolveNodeInstances(pParser,pNode,instances); + ResolveNodeInstances(pParser, pNode, instances); // add children. first the *real* ones - node->mNumChildren = static_cast(pNode->mChildren.size()+instances.size()); + node->mNumChildren = static_cast(pNode->mChildren.size() + instances.size()); node->mChildren = new aiNode*[node->mNumChildren]; - for( size_t a = 0; a < pNode->mChildren.size(); a++) - { - node->mChildren[a] = BuildHierarchy( pParser, pNode->mChildren[a]); + for (size_t a = 0; a < pNode->mChildren.size(); ++a) { + node->mChildren[a] = BuildHierarchy(pParser, pNode->mChildren[a]); node->mChildren[a]->mParent = node; } // ... and finally the resolved node instances - for( size_t a = 0; a < instances.size(); a++) - { - node->mChildren[pNode->mChildren.size() + a] = BuildHierarchy( pParser, instances[a]); + for (size_t a = 0; a < instances.size(); ++a) { + node->mChildren[pNode->mChildren.size() + a] = BuildHierarchy(pParser, instances[a]); node->mChildren[pNode->mChildren.size() + a]->mParent = node; } // construct meshes - BuildMeshesForNode( pParser, pNode, node); + BuildMeshesForNode(pParser, pNode, node); // construct cameras BuildCamerasForNode(pParser, pNode, node); // construct lights BuildLightsForNode(pParser, pNode, node); + return node; } // ------------------------------------------------------------------------------------------------ // Resolve node instances -void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Collada::Node* pNode, - std::vector& resolved) -{ +void ColladaLoader::ResolveNodeInstances(const ColladaParser& pParser, const Collada::Node* pNode, + std::vector& resolved) { // reserve enough storage resolved.reserve(pNode->mNodeInstances.size()); // ... and iterate through all nodes to be instanced as children of pNode - for (const auto &nodeInst: pNode->mNodeInstances) - { + for (const auto &nodeInst : pNode->mNodeInstances) { // find the corresponding node in the library const ColladaParser::NodeLibrary::const_iterator itt = pParser.mNodeLibrary.find(nodeInst.mNode); const Collada::Node* nd = itt == pParser.mNodeLibrary.end() ? NULL : (*itt).second; @@ -291,13 +317,12 @@ void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Co // FIX for http://sourceforge.net/tracker/?func=detail&aid=3054873&group_id=226462&atid=1067632 // need to check for both name and ID to catch all. To avoid breaking valid files, // the workaround is only enabled when the first attempt to resolve the node has failed. - if (!nd) { + if (nullptr == nd) { nd = FindNode(pParser.mRootNode, nodeInst.mNode); } - if (!nd) + if (nullptr == nd) { ASSIMP_LOG_ERROR_F("Collada: Unable to resolve reference to instanced node ", nodeInst.mNode); - - else { + } else { // attach this node to the list of children resolved.push_back(nd); } @@ -307,12 +332,13 @@ void ColladaLoader::ResolveNodeInstances( const ColladaParser& pParser, const Co // ------------------------------------------------------------------------------------------------ // Resolve UV channels void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler, - const Collada::SemanticMappingTable& table) -{ + + const Collada::SemanticMappingTable& table) { std::map::const_iterator it = table.mMap.find(sampler.mUVChannel); if (it != table.mMap.end()) { - if (it->second.mType != Collada::IT_Texcoord) + if (it->second.mType != Collada::IT_Texcoord) { ASSIMP_LOG_ERROR("Collada: Unexpected effect input mapping"); + } sampler.mUVId = it->second.mSet; } @@ -320,15 +346,12 @@ void ColladaLoader::ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler // ------------------------------------------------------------------------------------------------ // Builds lights for the given node and references them -void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) -{ - for( const Collada::LightInstance& lid : pNode->mLights) - { +void ColladaLoader::BuildLightsForNode(const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) { + for (const Collada::LightInstance& lid : pNode->mLights) { // find the referred light - ColladaParser::LightLibrary::const_iterator srcLightIt = pParser.mLightLibrary.find( lid.mLight); - if( srcLightIt == pParser.mLightLibrary.end()) - { - ASSIMP_LOG_WARN_F("Collada: Unable to find light for ID \"" , lid.mLight , "\". Skipping."); + ColladaParser::LightLibrary::const_iterator srcLightIt = pParser.mLightLibrary.find(lid.mLight); + if (srcLightIt == pParser.mLightLibrary.end()) { + ASSIMP_LOG_WARN_F("Collada: Unable to find light for ID \"", lid.mLight, "\". Skipping."); continue; } const Collada::Light* srcLight = &srcLightIt->second; @@ -339,7 +362,7 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll out->mType = (aiLightSourceType)srcLight->mType; // collada lights point in -Z by default, rest is specified in node transform - out->mDirection = aiVector3D(0.f,0.f,-1.f); + out->mDirection = aiVector3D(0.f, 0.f, -1.f); out->mAttenuationConstant = srcLight->mAttConstant; out->mAttenuationLinear = srcLight->mAttLinear; @@ -358,27 +381,26 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll // convert falloff angle and falloff exponent in our representation, if given if (out->mType == aiLightSource_SPOT) { - - out->mAngleInnerCone = AI_DEG_TO_RAD( srcLight->mFalloffAngle ); + out->mAngleInnerCone = AI_DEG_TO_RAD(srcLight->mFalloffAngle); // ... some extension magic. - if (srcLight->mOuterAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET*(1-1e-6f)) - { + if (srcLight->mOuterAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - 1e-6f)) { // ... some deprecation magic. - if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET*(1-1e-6f)) - { + if (srcLight->mPenumbraAngle >= ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET * (1 - 1e-6f)) { // Need to rely on falloff_exponent. I don't know how to interpret it, so I need to guess .... // epsilon chosen to be 0.1 - out->mAngleOuterCone = std::acos(std::pow(0.1f,1.f/srcLight->mFalloffExponent))+ - out->mAngleInnerCone; + out->mAngleOuterCone = std::acos(std::pow(0.1f, 1.f / srcLight->mFalloffExponent)) + + out->mAngleInnerCone; } else { - out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD( srcLight->mPenumbraAngle ); + out->mAngleOuterCone = out->mAngleInnerCone + AI_DEG_TO_RAD(srcLight->mPenumbraAngle); if (out->mAngleOuterCone < out->mAngleInnerCone) - std::swap(out->mAngleInnerCone,out->mAngleOuterCone); + std::swap(out->mAngleInnerCone, out->mAngleOuterCone); } } - else out->mAngleOuterCone = AI_DEG_TO_RAD( srcLight->mOuterAngle ); + else { + out->mAngleOuterCone = AI_DEG_TO_RAD(srcLight->mOuterAngle); + } } // add to light list @@ -388,15 +410,12 @@ void ColladaLoader::BuildLightsForNode( const ColladaParser& pParser, const Coll // ------------------------------------------------------------------------------------------------ // Builds cameras for the given node and references them -void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) -{ - for( const Collada::CameraInstance& cid : pNode->mCameras) - { +void ColladaLoader::BuildCamerasForNode(const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) { + for (const Collada::CameraInstance& cid : pNode->mCameras) { // find the referred light - ColladaParser::CameraLibrary::const_iterator srcCameraIt = pParser.mCameraLibrary.find( cid.mCamera); - if( srcCameraIt == pParser.mCameraLibrary.end()) - { - ASSIMP_LOG_WARN_F("Collada: Unable to find camera for ID \"" , cid.mCamera , "\". Skipping."); + ColladaParser::CameraLibrary::const_iterator srcCameraIt = pParser.mCameraLibrary.find(cid.mCamera); + if (srcCameraIt == pParser.mCameraLibrary.end()) { + ASSIMP_LOG_WARN_F("Collada: Unable to find camera for ID \"", cid.mCamera, "\". Skipping."); continue; } const Collada::Camera* srcCamera = &srcCameraIt->second; @@ -411,7 +430,7 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col out->mName = pTarget->mName; // collada cameras point in -Z by default, rest is specified in node transform - out->mLookAt = aiVector3D(0.f,0.f,-1.f); + out->mLookAt = aiVector3D(0.f, 0.f, -1.f); // near/far z is already ok out->mClipPlaneFar = srcCamera->mZFar; @@ -419,8 +438,9 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col // ... but for the rest some values are optional // and we need to compute the others in any combination. - if (srcCamera->mAspect != 10e10f) + if (srcCamera->mAspect != 10e10f) { out->mAspect = srcCamera->mAspect; + } if (srcCamera->mHorFov != 10e10f) { out->mHorizontalFOV = srcCamera->mHorFov; @@ -429,8 +449,8 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col out->mAspect = std::tan(AI_DEG_TO_RAD(srcCamera->mHorFov)) / std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov)); } - } - else if (srcCamera->mAspect != 10e10f && srcCamera->mVerFov != 10e10f) { + + } else if (srcCamera->mAspect != 10e10f && srcCamera->mVerFov != 10e10f) { out->mHorizontalFOV = 2.0f * AI_RAD_TO_DEG(std::atan(srcCamera->mAspect * std::tan(AI_DEG_TO_RAD(srcCamera->mVerFov) * 0.5f))); } @@ -445,206 +465,194 @@ void ColladaLoader::BuildCamerasForNode( const ColladaParser& pParser, const Col // ------------------------------------------------------------------------------------------------ // Builds meshes for the given node and references them -void ColladaLoader::BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) -{ +void ColladaLoader::BuildMeshesForNode(const ColladaParser& pParser, const Collada::Node* pNode, aiNode* pTarget) { // accumulated mesh references by this node std::vector newMeshRefs; newMeshRefs.reserve(pNode->mMeshes.size()); // add a mesh for each subgroup in each collada mesh - for( const Collada::MeshInstance& mid : pNode->mMeshes) - { - const Collada::Mesh* srcMesh = NULL; - const Collada::Controller* srcController = NULL; + for (const Collada::MeshInstance& mid : pNode->mMeshes) { + const Collada::Mesh* srcMesh = nullptr; + const Collada::Controller* srcController = nullptr; // find the referred mesh - ColladaParser::MeshLibrary::const_iterator srcMeshIt = pParser.mMeshLibrary.find( mid.mMeshOrController); - if( srcMeshIt == pParser.mMeshLibrary.end()) - { + ColladaParser::MeshLibrary::const_iterator srcMeshIt = pParser.mMeshLibrary.find(mid.mMeshOrController); + if (srcMeshIt == pParser.mMeshLibrary.end()) { // if not found in the mesh-library, it might also be a controller referring to a mesh - ColladaParser::ControllerLibrary::const_iterator srcContrIt = pParser.mControllerLibrary.find( mid.mMeshOrController); - if( srcContrIt != pParser.mControllerLibrary.end()) - { + ColladaParser::ControllerLibrary::const_iterator srcContrIt = pParser.mControllerLibrary.find(mid.mMeshOrController); + if (srcContrIt != pParser.mControllerLibrary.end()) { srcController = &srcContrIt->second; - srcMeshIt = pParser.mMeshLibrary.find( srcController->mMeshId); - if( srcMeshIt != pParser.mMeshLibrary.end()) + srcMeshIt = pParser.mMeshLibrary.find(srcController->mMeshId); + if (srcMeshIt != pParser.mMeshLibrary.end()) { srcMesh = srcMeshIt->second; + } } - if( !srcMesh) - { + + if( nullptr == srcMesh) { ASSIMP_LOG_WARN_F( "Collada: Unable to find geometry for ID \"", mid.mMeshOrController, "\". Skipping." ); continue; } - } else - { + } + else { // ID found in the mesh library -> direct reference to an unskinned mesh srcMesh = srcMeshIt->second; } // build a mesh for each of its subgroups size_t vertexStart = 0, faceStart = 0; - for( size_t sm = 0; sm < srcMesh->mSubMeshes.size(); ++sm) - { + for (size_t sm = 0; sm < srcMesh->mSubMeshes.size(); ++sm) { const Collada::SubMesh& submesh = srcMesh->mSubMeshes[sm]; - if( submesh.mNumFaces == 0) + if (submesh.mNumFaces == 0) { continue; + } // find material assigned to this submesh std::string meshMaterial; - std::map::const_iterator meshMatIt = mid.mMaterials.find( submesh.mMaterial); + std::map::const_iterator meshMatIt = mid.mMaterials.find(submesh.mMaterial); - const Collada::SemanticMappingTable* table = NULL; - if( meshMatIt != mid.mMaterials.end()) - { + const Collada::SemanticMappingTable* table = nullptr; + if (meshMatIt != mid.mMaterials.end()) { table = &meshMatIt->second; meshMaterial = table->mMatName; } - else - { - ASSIMP_LOG_WARN_F( "Collada: No material specified for subgroup <", submesh.mMaterial, "> in geometry <", - mid.mMeshOrController, ">." ); - if( !mid.mMaterials.empty() ) + else { + ASSIMP_LOG_WARN_F("Collada: No material specified for subgroup <", submesh.mMaterial, "> in geometry <", + mid.mMeshOrController, ">."); + if (!mid.mMaterials.empty()) { meshMaterial = mid.mMaterials.begin()->second.mMatName; + } } // OK ... here the *real* fun starts ... we have the vertex-input-to-effect-semantic-table // given. The only mapping stuff which we do actually support is the UV channel. - std::map::const_iterator matIt = mMaterialIndexByName.find( meshMaterial); - unsigned int matIdx; - if( matIt != mMaterialIndexByName.end()) + std::map::const_iterator matIt = mMaterialIndexByName.find(meshMaterial); + unsigned int matIdx = 0; + if (matIt != mMaterialIndexByName.end()) { matIdx = static_cast(matIt->second); - else - matIdx = 0; + } - if (table && !table->mMap.empty() ) { + if (table && !table->mMap.empty()) { std::pair& mat = newMats[matIdx]; // Iterate through all texture channels assigned to the effect and // check whether we have mapping information for it. - ApplyVertexToEffectSemanticMapping(mat.first->mTexDiffuse, *table); - ApplyVertexToEffectSemanticMapping(mat.first->mTexAmbient, *table); - ApplyVertexToEffectSemanticMapping(mat.first->mTexSpecular, *table); - ApplyVertexToEffectSemanticMapping(mat.first->mTexEmissive, *table); - ApplyVertexToEffectSemanticMapping(mat.first->mTexTransparent,*table); - ApplyVertexToEffectSemanticMapping(mat.first->mTexBump, *table); + ApplyVertexToEffectSemanticMapping(mat.first->mTexDiffuse, *table); + ApplyVertexToEffectSemanticMapping(mat.first->mTexAmbient, *table); + ApplyVertexToEffectSemanticMapping(mat.first->mTexSpecular, *table); + ApplyVertexToEffectSemanticMapping(mat.first->mTexEmissive, *table); + ApplyVertexToEffectSemanticMapping(mat.first->mTexTransparent, *table); + ApplyVertexToEffectSemanticMapping(mat.first->mTexBump, *table); } // built lookup index of the Mesh-Submesh-Material combination - ColladaMeshIndex index( mid.mMeshOrController, sm, meshMaterial); + ColladaMeshIndex index(mid.mMeshOrController, sm, meshMaterial); // if we already have the mesh at the library, just add its index to the node's array - std::map::const_iterator dstMeshIt = mMeshIndexByID.find( index); - if( dstMeshIt != mMeshIndexByID.end()) { - newMeshRefs.push_back( dstMeshIt->second); + std::map::const_iterator dstMeshIt = mMeshIndexByID.find(index); + if (dstMeshIt != mMeshIndexByID.end()) { + newMeshRefs.push_back(dstMeshIt->second); } - else - { + else { // else we have to add the mesh to the collection and store its newly assigned index at the node - aiMesh* dstMesh = CreateMesh( pParser, srcMesh, submesh, srcController, vertexStart, faceStart); + aiMesh* dstMesh = CreateMesh(pParser, srcMesh, submesh, srcController, vertexStart, faceStart); // store the mesh, and store its new index in the node - newMeshRefs.push_back( mMeshes.size()); + newMeshRefs.push_back(mMeshes.size()); mMeshIndexByID[index] = mMeshes.size(); - mMeshes.push_back( dstMesh); + mMeshes.push_back(dstMesh); vertexStart += dstMesh->mNumVertices; faceStart += submesh.mNumFaces; // assign the material index dstMesh->mMaterialIndex = matIdx; - if(dstMesh->mName.length == 0) - { + if (dstMesh->mName.length == 0) { dstMesh->mName = mid.mMeshOrController; } - } + } } } // now place all mesh references we gathered in the target node pTarget->mNumMeshes = static_cast(newMeshRefs.size()); - if( newMeshRefs.size()) - { - struct UIntTypeConverter - { - unsigned int operator()(const size_t& v) const - { + if (newMeshRefs.size()) { + struct UIntTypeConverter { + unsigned int operator()(const size_t& v) const { return static_cast(v); } }; pTarget->mMeshes = new unsigned int[pTarget->mNumMeshes]; - std::transform( newMeshRefs.begin(), newMeshRefs.end(), pTarget->mMeshes, UIntTypeConverter()); + std::transform(newMeshRefs.begin(), newMeshRefs.end(), pTarget->mMeshes, UIntTypeConverter()); } } // ------------------------------------------------------------------------------------------------ // Find mesh from either meshes or morph target meshes -aiMesh *ColladaLoader::findMesh(std::string meshid) -{ - for (unsigned int i = 0; i < mMeshes.size(); i++) - if (std::string(mMeshes[i]->mName.data) == meshid) +aiMesh *ColladaLoader::findMesh(const std::string& meshid) { + for (unsigned int i = 0; i < mMeshes.size(); ++i) { + if (std::string(mMeshes[i]->mName.data) == meshid) { return mMeshes[i]; + } + } - for (unsigned int i = 0; i < mTargetMeshes.size(); i++) - if (std::string(mTargetMeshes[i]->mName.data) == meshid) + for (unsigned int i = 0; i < mTargetMeshes.size(); ++i) { + if (std::string(mTargetMeshes[i]->mName.data) == meshid) { return mTargetMeshes[i]; + } + } - return NULL; + return nullptr; } // ------------------------------------------------------------------------------------------------ // Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh -aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh, - const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace) -{ - aiMesh* dstMesh = new aiMesh; +aiMesh* ColladaLoader::CreateMesh(const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh, + const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace) { + std::unique_ptr dstMesh(new aiMesh); dstMesh->mName = pSrcMesh->mName; // count the vertices addressed by its faces - const size_t numVertices = std::accumulate( pSrcMesh->mFaceSize.begin() + pStartFace, + const size_t numVertices = std::accumulate(pSrcMesh->mFaceSize.begin() + pStartFace, pSrcMesh->mFaceSize.begin() + pStartFace + pSubMesh.mNumFaces, size_t(0)); // copy positions dstMesh->mNumVertices = static_cast(numVertices); dstMesh->mVertices = new aiVector3D[numVertices]; - std::copy( pSrcMesh->mPositions.begin() + pStartVertex, pSrcMesh->mPositions.begin() + + std::copy(pSrcMesh->mPositions.begin() + pStartVertex, pSrcMesh->mPositions.begin() + pStartVertex + numVertices, dstMesh->mVertices); // normals, if given. HACK: (thom) Due to the glorious Collada spec we never // know if we have the same number of normals as there are positions. So we // also ignore any vertex attribute if it has a different count - if( pSrcMesh->mNormals.size() >= pStartVertex + numVertices) - { + if (pSrcMesh->mNormals.size() >= pStartVertex + numVertices) { dstMesh->mNormals = new aiVector3D[numVertices]; - std::copy( pSrcMesh->mNormals.begin() + pStartVertex, pSrcMesh->mNormals.begin() + + std::copy(pSrcMesh->mNormals.begin() + pStartVertex, pSrcMesh->mNormals.begin() + pStartVertex + numVertices, dstMesh->mNormals); } // tangents, if given. - if( pSrcMesh->mTangents.size() >= pStartVertex + numVertices) - { + if (pSrcMesh->mTangents.size() >= pStartVertex + numVertices) { dstMesh->mTangents = new aiVector3D[numVertices]; - std::copy( pSrcMesh->mTangents.begin() + pStartVertex, pSrcMesh->mTangents.begin() + + std::copy(pSrcMesh->mTangents.begin() + pStartVertex, pSrcMesh->mTangents.begin() + pStartVertex + numVertices, dstMesh->mTangents); } // bitangents, if given. - if( pSrcMesh->mBitangents.size() >= pStartVertex + numVertices) - { + if (pSrcMesh->mBitangents.size() >= pStartVertex + numVertices) { dstMesh->mBitangents = new aiVector3D[numVertices]; - std::copy( pSrcMesh->mBitangents.begin() + pStartVertex, pSrcMesh->mBitangents.begin() + + std::copy(pSrcMesh->mBitangents.begin() + pStartVertex, pSrcMesh->mBitangents.begin() + pStartVertex + numVertices, dstMesh->mBitangents); } // same for texturecoords, as many as we have // empty slots are not allowed, need to pack and adjust UV indexes accordingly - for( size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) - { - if( pSrcMesh->mTexCoords[a].size() >= pStartVertex + numVertices) - { + for (size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { + if (pSrcMesh->mTexCoords[a].size() >= pStartVertex + numVertices) { dstMesh->mTextureCoords[real] = new aiVector3D[numVertices]; - for( size_t b = 0; b < numVertices; ++b) - dstMesh->mTextureCoords[real][b] = pSrcMesh->mTexCoords[a][pStartVertex+b]; + for (size_t b = 0; b < numVertices; ++b) { + dstMesh->mTextureCoords[real][b] = pSrcMesh->mTexCoords[a][pStartVertex + b]; + } dstMesh->mNumUVComponents[real] = pSrcMesh->mNumUVComponents[a]; ++real; @@ -652,12 +660,10 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: } // same for vertex colors, as many as we have. again the same packing to avoid empty slots - for( size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) - { - if( pSrcMesh->mColors[a].size() >= pStartVertex + numVertices) - { + for (size_t a = 0, real = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a) { + if (pSrcMesh->mColors[a].size() >= pStartVertex + numVertices) { dstMesh->mColors[real] = new aiColor4D[numVertices]; - std::copy( pSrcMesh->mColors[a].begin() + pStartVertex, pSrcMesh->mColors[a].begin() + pStartVertex + numVertices,dstMesh->mColors[real]); + std::copy(pSrcMesh->mColors[a].begin() + pStartVertex, pSrcMesh->mColors[a].begin() + pStartVertex + numVertices, dstMesh->mColors[real]); ++real; } } @@ -666,14 +672,14 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: size_t vertex = 0; dstMesh->mNumFaces = static_cast(pSubMesh.mNumFaces); dstMesh->mFaces = new aiFace[dstMesh->mNumFaces]; - for( size_t a = 0; a < dstMesh->mNumFaces; ++a) - { - size_t s = pSrcMesh->mFaceSize[ pStartFace + a]; + for (size_t a = 0; a < dstMesh->mNumFaces; ++a) { + size_t s = pSrcMesh->mFaceSize[pStartFace + a]; aiFace& face = dstMesh->mFaces[a]; face.mNumIndices = static_cast(s); face.mIndices = new unsigned int[s]; - for( size_t b = 0; b < s; ++b) + for (size_t b = 0; b < s; ++b) { face.mIndices[b] = static_cast(vertex++); + } } // create morph target meshes if any @@ -681,105 +687,104 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: std::vector targetWeights; Collada::MorphMethod method = Collada::Normalized; - for(std::map::const_iterator it = pParser.mControllerLibrary.begin(); - it != pParser.mControllerLibrary.end(); it++) - { + for (std::map::const_iterator it = pParser.mControllerLibrary.begin(); + it != pParser.mControllerLibrary.end(); ++it) { const Collada::Controller &c = it->second; - const Collada::Mesh* baseMesh = pParser.ResolveLibraryReference( pParser.mMeshLibrary, c.mMeshId); + const Collada::Mesh* baseMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, c.mMeshId); - if (c.mType == Collada::Morph && baseMesh->mName == pSrcMesh->mName) - { - const Collada::Accessor& targetAccessor = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, c.mMorphTarget); - const Collada::Accessor& weightAccessor = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, c.mMorphWeight); - const Collada::Data& targetData = pParser.ResolveLibraryReference( pParser.mDataLibrary, targetAccessor.mSource); - const Collada::Data& weightData = pParser.ResolveLibraryReference( pParser.mDataLibrary, weightAccessor.mSource); + if (c.mType == Collada::Morph && baseMesh->mName == pSrcMesh->mName) { + const Collada::Accessor& targetAccessor = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, c.mMorphTarget); + const Collada::Accessor& weightAccessor = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, c.mMorphWeight); + const Collada::Data& targetData = pParser.ResolveLibraryReference(pParser.mDataLibrary, targetAccessor.mSource); + const Collada::Data& weightData = pParser.ResolveLibraryReference(pParser.mDataLibrary, weightAccessor.mSource); // take method method = c.mMethod; - if (!targetData.mIsStringArray) - throw DeadlyImportError( "target data must contain id. "); - if (weightData.mIsStringArray) - throw DeadlyImportError( "target weight data must not be textual "); + if (!targetData.mIsStringArray) { + throw DeadlyImportError("target data must contain id. "); + } + if (weightData.mIsStringArray) { + throw DeadlyImportError("target weight data must not be textual "); + } - for (unsigned int i = 0; i < targetData.mStrings.size(); ++i) - { + for (unsigned int i = 0; i < targetData.mStrings.size(); ++i) { const Collada::Mesh* targetMesh = pParser.ResolveLibraryReference(pParser.mMeshLibrary, targetData.mStrings.at(i)); aiMesh *aimesh = findMesh(targetMesh->mName); - if (!aimesh) - { - if (targetMesh->mSubMeshes.size() > 1) - throw DeadlyImportError( "Morhing target mesh must be a single"); + if (!aimesh) { + if (targetMesh->mSubMeshes.size() > 1) { + throw DeadlyImportError("Morhing target mesh must be a single"); + } aimesh = CreateMesh(pParser, targetMesh, targetMesh->mSubMeshes.at(0), NULL, 0, 0); mTargetMeshes.push_back(aimesh); } targetMeshes.push_back(aimesh); } - for (unsigned int i = 0; i < weightData.mValues.size(); ++i) + for (unsigned int i = 0; i < weightData.mValues.size(); ++i) { targetWeights.push_back(weightData.mValues.at(i)); + } } } - if (targetMeshes.size() > 0 && targetWeights.size() == targetMeshes.size()) - { + if (targetMeshes.size() > 0 && targetWeights.size() == targetMeshes.size()) { std::vector animMeshes; - for (unsigned int i = 0; i < targetMeshes.size(); i++) - { - aiAnimMesh *animMesh = aiCreateAnimMesh(targetMeshes.at(i)); - animMesh->mWeight = targetWeights[i]; + for (unsigned int i = 0; i < targetMeshes.size(); ++i) { + aiMesh* targetMesh = targetMeshes.at(i); + aiAnimMesh *animMesh = aiCreateAnimMesh(targetMesh); + float weight = targetWeights[i]; + animMesh->mWeight = weight == 0 ? 1.0f : weight; + animMesh->mName = targetMesh->mName; animMeshes.push_back(animMesh); } dstMesh->mMethod = (method == Collada::Relative) - ? aiMorphingMethod_MORPH_RELATIVE - : aiMorphingMethod_MORPH_NORMALIZED; + ? aiMorphingMethod_MORPH_RELATIVE + : aiMorphingMethod_MORPH_NORMALIZED; dstMesh->mAnimMeshes = new aiAnimMesh*[animMeshes.size()]; dstMesh->mNumAnimMeshes = static_cast(animMeshes.size()); - for (unsigned int i = 0; i < animMeshes.size(); i++) + for (unsigned int i = 0; i < animMeshes.size(); ++i) { dstMesh->mAnimMeshes[i] = animMeshes.at(i); + } } // create bones if given - if( pSrcController && pSrcController->mType == Collada::Skin) - { + if (pSrcController && pSrcController->mType == Collada::Skin) { // resolve references - joint names - const Collada::Accessor& jointNamesAcc = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, pSrcController->mJointNameSource); - const Collada::Data& jointNames = pParser.ResolveLibraryReference( pParser.mDataLibrary, jointNamesAcc.mSource); + const Collada::Accessor& jointNamesAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mJointNameSource); + const Collada::Data& jointNames = pParser.ResolveLibraryReference(pParser.mDataLibrary, jointNamesAcc.mSource); // joint offset matrices - const Collada::Accessor& jointMatrixAcc = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, pSrcController->mJointOffsetMatrixSource); - const Collada::Data& jointMatrices = pParser.ResolveLibraryReference( pParser.mDataLibrary, jointMatrixAcc.mSource); + const Collada::Accessor& jointMatrixAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mJointOffsetMatrixSource); + const Collada::Data& jointMatrices = pParser.ResolveLibraryReference(pParser.mDataLibrary, jointMatrixAcc.mSource); // joint vertex_weight name list - should refer to the same list as the joint names above. If not, report and reconsider - const Collada::Accessor& weightNamesAcc = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, pSrcController->mWeightInputJoints.mAccessor); - if( &weightNamesAcc != &jointNamesAcc) - throw DeadlyImportError( "Temporary implementational laziness. If you read this, please report to the author."); + const Collada::Accessor& weightNamesAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mWeightInputJoints.mAccessor); + if (&weightNamesAcc != &jointNamesAcc) + throw DeadlyImportError("Temporary implementational laziness. If you read this, please report to the author."); // vertex weights - const Collada::Accessor& weightsAcc = pParser.ResolveLibraryReference( pParser.mAccessorLibrary, pSrcController->mWeightInputWeights.mAccessor); - const Collada::Data& weights = pParser.ResolveLibraryReference( pParser.mDataLibrary, weightsAcc.mSource); + const Collada::Accessor& weightsAcc = pParser.ResolveLibraryReference(pParser.mAccessorLibrary, pSrcController->mWeightInputWeights.mAccessor); + const Collada::Data& weights = pParser.ResolveLibraryReference(pParser.mDataLibrary, weightsAcc.mSource); - if( !jointNames.mIsStringArray || jointMatrices.mIsStringArray || weights.mIsStringArray) - throw DeadlyImportError( "Data type mismatch while resolving mesh joints"); + if (!jointNames.mIsStringArray || jointMatrices.mIsStringArray || weights.mIsStringArray) + throw DeadlyImportError("Data type mismatch while resolving mesh joints"); // sanity check: we rely on the vertex weights always coming as pairs of BoneIndex-WeightIndex - if( pSrcController->mWeightInputJoints.mOffset != 0 || pSrcController->mWeightInputWeights.mOffset != 1) - throw DeadlyImportError( "Unsupported vertex_weight addressing scheme. "); + if (pSrcController->mWeightInputJoints.mOffset != 0 || pSrcController->mWeightInputWeights.mOffset != 1) + throw DeadlyImportError("Unsupported vertex_weight addressing scheme. "); // create containers to collect the weights for each bone size_t numBones = jointNames.mStrings.size(); - std::vector > dstBones( numBones); + std::vector > dstBones(numBones); // build a temporary array of pointers to the start of each vertex's weights typedef std::vector< std::pair > IndexPairVector; std::vector weightStartPerVertex; - weightStartPerVertex.resize(pSrcController->mWeightCounts.size(),pSrcController->mWeights.end()); + weightStartPerVertex.resize(pSrcController->mWeightCounts.size(), pSrcController->mWeights.end()); IndexPairVector::const_iterator pit = pSrcController->mWeights.begin(); - for( size_t a = 0; a < pSrcController->mWeightCounts.size(); ++a) - { + for (size_t a = 0; a < pSrcController->mWeightCounts.size(); ++a) { weightStartPerVertex[a] = pit; pit += pSrcController->mWeightCounts[a]; } // now for each vertex put the corresponding vertex weights into each bone's weight collection - for( size_t a = pStartVertex; a < pStartVertex + numVertices; ++a) - { + for (size_t a = pStartVertex; a < pStartVertex + numVertices; ++a) { // which position index was responsible for this vertex? that's also the index by which // the controller assigns the vertex weights size_t orgIndex = pSrcMesh->mFacePosIndices[a]; @@ -787,58 +792,62 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: IndexPairVector::const_iterator iit = weightStartPerVertex[orgIndex]; size_t pairCount = pSrcController->mWeightCounts[orgIndex]; - for( size_t b = 0; b < pairCount; ++b, ++iit) - { - size_t jointIndex = iit->first; - size_t vertexIndex = iit->second; - ai_real weight = ReadFloat( weightsAcc, weights, vertexIndex, 0); + for( size_t b = 0; b < pairCount; ++b, ++iit) { + const size_t jointIndex = iit->first; + const size_t vertexIndex = iit->second; + ai_real weight = 1.0f; + if (!weights.mValues.empty()) { + weight = ReadFloat(weightsAcc, weights, vertexIndex, 0); + } // one day I gonna kill that XSI Collada exporter - if( weight > 0.0f) + if (weight > 0.0f) { aiVertexWeight w; w.mVertexId = static_cast(a - pStartVertex); w.mWeight = weight; - dstBones[jointIndex].push_back( w); + dstBones[jointIndex].push_back(w); } } } // count the number of bones which influence vertices of the current submesh size_t numRemainingBones = 0; - for( std::vector >::const_iterator it = dstBones.begin(); it != dstBones.end(); ++it) - if( it->size() > 0) - numRemainingBones++; + for( std::vector >::const_iterator it = dstBones.begin(); it != dstBones.end(); ++it) { + if( it->size() > 0) { + ++numRemainingBones; + } + } // create bone array and copy bone weights one by one dstMesh->mNumBones = static_cast(numRemainingBones); dstMesh->mBones = new aiBone*[numRemainingBones]; size_t boneCount = 0; - for( size_t a = 0; a < numBones; ++a) - { + for( size_t a = 0; a < numBones; ++a) { // omit bones without weights - if( dstBones[a].size() == 0) + if( dstBones[a].empty() ) { continue; + } // create bone with its weights aiBone* bone = new aiBone; - bone->mName = ReadString( jointNamesAcc, jointNames, a); - bone->mOffsetMatrix.a1 = ReadFloat( jointMatrixAcc, jointMatrices, a, 0); - bone->mOffsetMatrix.a2 = ReadFloat( jointMatrixAcc, jointMatrices, a, 1); - bone->mOffsetMatrix.a3 = ReadFloat( jointMatrixAcc, jointMatrices, a, 2); - bone->mOffsetMatrix.a4 = ReadFloat( jointMatrixAcc, jointMatrices, a, 3); - bone->mOffsetMatrix.b1 = ReadFloat( jointMatrixAcc, jointMatrices, a, 4); - bone->mOffsetMatrix.b2 = ReadFloat( jointMatrixAcc, jointMatrices, a, 5); - bone->mOffsetMatrix.b3 = ReadFloat( jointMatrixAcc, jointMatrices, a, 6); - bone->mOffsetMatrix.b4 = ReadFloat( jointMatrixAcc, jointMatrices, a, 7); - bone->mOffsetMatrix.c1 = ReadFloat( jointMatrixAcc, jointMatrices, a, 8); - bone->mOffsetMatrix.c2 = ReadFloat( jointMatrixAcc, jointMatrices, a, 9); - bone->mOffsetMatrix.c3 = ReadFloat( jointMatrixAcc, jointMatrices, a, 10); - bone->mOffsetMatrix.c4 = ReadFloat( jointMatrixAcc, jointMatrices, a, 11); + bone->mName = ReadString(jointNamesAcc, jointNames, a); + bone->mOffsetMatrix.a1 = ReadFloat(jointMatrixAcc, jointMatrices, a, 0); + bone->mOffsetMatrix.a2 = ReadFloat(jointMatrixAcc, jointMatrices, a, 1); + bone->mOffsetMatrix.a3 = ReadFloat(jointMatrixAcc, jointMatrices, a, 2); + bone->mOffsetMatrix.a4 = ReadFloat(jointMatrixAcc, jointMatrices, a, 3); + bone->mOffsetMatrix.b1 = ReadFloat(jointMatrixAcc, jointMatrices, a, 4); + bone->mOffsetMatrix.b2 = ReadFloat(jointMatrixAcc, jointMatrices, a, 5); + bone->mOffsetMatrix.b3 = ReadFloat(jointMatrixAcc, jointMatrices, a, 6); + bone->mOffsetMatrix.b4 = ReadFloat(jointMatrixAcc, jointMatrices, a, 7); + bone->mOffsetMatrix.c1 = ReadFloat(jointMatrixAcc, jointMatrices, a, 8); + bone->mOffsetMatrix.c2 = ReadFloat(jointMatrixAcc, jointMatrices, a, 9); + bone->mOffsetMatrix.c3 = ReadFloat(jointMatrixAcc, jointMatrices, a, 10); + bone->mOffsetMatrix.c4 = ReadFloat(jointMatrixAcc, jointMatrices, a, 11); bone->mNumWeights = static_cast(dstBones[a].size()); bone->mWeights = new aiVertexWeight[bone->mNumWeights]; - std::copy( dstBones[a].begin(), dstBones[a].end(), bone->mWeights); + std::copy(dstBones[a].begin(), dstBones[a].end(), bone->mWeights); // apply bind shape matrix to offset matrix aiMatrix4x4 bindShapeMatrix; @@ -865,119 +874,112 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: // and replace the bone's name by the node's name so that the user can use the standard // find-by-name method to associate nodes with bones. const Collada::Node* bnode = FindNode( pParser.mRootNode, bone->mName.data); - if( !bnode) + if( !bnode) { bnode = FindNodeBySID( pParser.mRootNode, bone->mName.data); + } // assign the name that we would have assigned for the source node - if( bnode) + if( bnode) { bone->mName.Set( FindNameForNode( bnode)); - else + } else { ASSIMP_LOG_WARN_F( "ColladaLoader::CreateMesh(): could not find corresponding node for joint \"", bone->mName.data, "\"." ); + } // and insert bone dstMesh->mBones[boneCount++] = bone; } } - return dstMesh; + return dstMesh.release(); } // ------------------------------------------------------------------------------------------------ // Stores all meshes in the given scene -void ColladaLoader::StoreSceneMeshes( aiScene* pScene) -{ +void ColladaLoader::StoreSceneMeshes( aiScene* pScene) { pScene->mNumMeshes = static_cast(mMeshes.size()); - if( mMeshes.size() > 0) - { - pScene->mMeshes = new aiMesh*[mMeshes.size()]; - std::copy( mMeshes.begin(), mMeshes.end(), pScene->mMeshes); - mMeshes.clear(); + if( mMeshes.empty() ) { + return; } + pScene->mMeshes = new aiMesh*[mMeshes.size()]; + std::copy( mMeshes.begin(), mMeshes.end(), pScene->mMeshes); + mMeshes.clear(); } // ------------------------------------------------------------------------------------------------ // Stores all cameras in the given scene -void ColladaLoader::StoreSceneCameras( aiScene* pScene) -{ +void ColladaLoader::StoreSceneCameras( aiScene* pScene) { pScene->mNumCameras = static_cast(mCameras.size()); - if( mCameras.size() > 0) - { - pScene->mCameras = new aiCamera*[mCameras.size()]; - std::copy( mCameras.begin(), mCameras.end(), pScene->mCameras); - mCameras.clear(); + if( mCameras.empty() ) { + return; } + pScene->mCameras = new aiCamera*[mCameras.size()]; + std::copy( mCameras.begin(), mCameras.end(), pScene->mCameras); + mCameras.clear(); } // ------------------------------------------------------------------------------------------------ // Stores all lights in the given scene -void ColladaLoader::StoreSceneLights( aiScene* pScene) -{ +void ColladaLoader::StoreSceneLights( aiScene* pScene) { pScene->mNumLights = static_cast(mLights.size()); - if( mLights.size() > 0) - { - pScene->mLights = new aiLight*[mLights.size()]; - std::copy( mLights.begin(), mLights.end(), pScene->mLights); - mLights.clear(); + if( mLights.empty() ) { + return; } + pScene->mLights = new aiLight*[mLights.size()]; + std::copy( mLights.begin(), mLights.end(), pScene->mLights); + mLights.clear(); } // ------------------------------------------------------------------------------------------------ // Stores all textures in the given scene -void ColladaLoader::StoreSceneTextures( aiScene* pScene) -{ +void ColladaLoader::StoreSceneTextures( aiScene* pScene) { pScene->mNumTextures = static_cast(mTextures.size()); - if( mTextures.size() > 0) - { - pScene->mTextures = new aiTexture*[mTextures.size()]; - std::copy( mTextures.begin(), mTextures.end(), pScene->mTextures); - mTextures.clear(); + if( mTextures.empty() ) { + return; } + pScene->mTextures = new aiTexture*[mTextures.size()]; + std::copy( mTextures.begin(), mTextures.end(), pScene->mTextures); + mTextures.clear(); } // ------------------------------------------------------------------------------------------------ // Stores all materials in the given scene -void ColladaLoader::StoreSceneMaterials( aiScene* pScene) -{ +void ColladaLoader::StoreSceneMaterials( aiScene* pScene) { pScene->mNumMaterials = static_cast(newMats.size()); - - if (newMats.size() > 0) { - pScene->mMaterials = new aiMaterial*[newMats.size()]; - for (unsigned int i = 0; i < newMats.size();++i) - pScene->mMaterials[i] = newMats[i].second; - - newMats.clear(); + if (newMats.empty() ) { + return; } + pScene->mMaterials = new aiMaterial*[newMats.size()]; + for (unsigned int i = 0; i < newMats.size();++i) { + pScene->mMaterials[i] = newMats[i].second; + } + newMats.clear(); } // ------------------------------------------------------------------------------------------------ // Stores all animations -void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pParser) -{ +void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pParser) { // recursively collect all animations from the collada scene - StoreAnimations( pScene, pParser, &pParser.mAnims, ""); + StoreAnimations(pScene, pParser, &pParser.mAnims, ""); // catch special case: many animations with the same length, each affecting only a single node. // we need to unite all those single-node-anims to a proper combined animation - for( size_t a = 0; a < mAnims.size(); ++a) - { + for( size_t a = 0; a < mAnims.size(); ++a) { aiAnimation* templateAnim = mAnims[a]; - if( templateAnim->mNumChannels == 1) - { + if( templateAnim->mNumChannels == 1) { // search for other single-channel-anims with the same duration std::vector collectedAnimIndices; - for( size_t b = a+1; b < mAnims.size(); ++b) - { + for( size_t b = a+1; b < mAnims.size(); ++b) { aiAnimation* other = mAnims[b]; - if( other->mNumChannels == 1 && other->mDuration == templateAnim->mDuration && - other->mTicksPerSecond == templateAnim->mTicksPerSecond ) - collectedAnimIndices.push_back( b); + if (other->mNumChannels == 1 && other->mDuration == templateAnim->mDuration && + other->mTicksPerSecond == templateAnim->mTicksPerSecond) + collectedAnimIndices.push_back(b); } // if there are other animations which fit the template anim, combine all channels into a single anim - if( !collectedAnimIndices.empty() ) + if (!collectedAnimIndices.empty()) { aiAnimation* combinedAnim = new aiAnimation(); - combinedAnim->mName = aiString( std::string( "combinedAnim_") + char( '0' + a)); + combinedAnim->mName = aiString(std::string("combinedAnim_") + char('0' + a)); combinedAnim->mDuration = templateAnim->mDuration; combinedAnim->mTicksPerSecond = templateAnim->mTicksPerSecond; combinedAnim->mNumChannels = static_cast(collectedAnimIndices.size() + 1); @@ -990,7 +992,7 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars mAnims[a] = combinedAnim; // move the memory of all other anims to the combined anim and erase them from the source anims - for( size_t b = 0; b < collectedAnimIndices.size(); ++b) + for (size_t b = 0; b < collectedAnimIndices.size(); ++b) { aiAnimation* srcAnimation = mAnims[collectedAnimIndices[b]]; combinedAnim->mChannels[1 + b] = srcAnimation->mChannels[0]; @@ -1000,9 +1002,9 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars // in a second go, delete all the single-channel-anims that we've stripped from their channels // back to front to preserve indices - you know, removing an element from a vector moves all elements behind the removed one - while( !collectedAnimIndices.empty() ) + while (!collectedAnimIndices.empty()) { - mAnims.erase( mAnims.begin() + collectedAnimIndices.back()); + mAnims.erase(mAnims.begin() + collectedAnimIndices.back()); collectedAnimIndices.pop_back(); } } @@ -1010,11 +1012,11 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars } // now store all anims in the scene - if( !mAnims.empty()) + if (!mAnims.empty()) { pScene->mNumAnimations = static_cast(mAnims.size()); pScene->mAnimations = new aiAnimation*[mAnims.size()]; - std::copy( mAnims.begin(), mAnims.end(), pScene->mAnimations); + std::copy(mAnims.begin(), mAnims.end(), pScene->mAnimations); } mAnims.clear(); @@ -1022,17 +1024,17 @@ void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pPars // ------------------------------------------------------------------------------------------------ // Constructs the animations for the given source anim -void ColladaLoader::StoreAnimations( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string &pPrefix) +void ColladaLoader::StoreAnimations(aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string &pPrefix) { std::string animName = pPrefix.empty() ? pSrcAnim->mName : pPrefix + "_" + pSrcAnim->mName; // create nested animations, if given - for( std::vector::const_iterator it = pSrcAnim->mSubAnims.begin(); it != pSrcAnim->mSubAnims.end(); ++it) - StoreAnimations( pScene, pParser, *it, animName); + for (std::vector::const_iterator it = pSrcAnim->mSubAnims.begin(); it != pSrcAnim->mSubAnims.end(); ++it) + StoreAnimations(pScene, pParser, *it, animName); // create animation channels, if any - if( !pSrcAnim->mChannels.empty()) - CreateAnimation( pScene, pParser, pSrcAnim, animName); + if (!pSrcAnim->mChannels.empty()) + CreateAnimation(pScene, pParser, pSrcAnim, animName); } struct MorphTimeValues @@ -1073,7 +1075,8 @@ void insertMorphTimeValue(std::vector &values, float time, floa { values[i].mKeys.push_back(k); return; - } else if (time > values[i].mTime && time < values[i+1].mTime) + } + else if (time > values[i].mTime && time < values[i + 1].mTime) { MorphTimeValues val; val.mTime = time; @@ -1099,30 +1102,30 @@ float getWeightAtKey(const std::vector &values, int key, unsign // ------------------------------------------------------------------------------------------------ // Constructs the animation for the given source anim -void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pName) +void ColladaLoader::CreateAnimation(aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pName) { // collect a list of animatable nodes std::vector nodes; - CollectNodes( pScene->mRootNode, nodes); + CollectNodes(pScene->mRootNode, nodes); std::vector anims; std::vector morphAnims; - for( std::vector::const_iterator nit = nodes.begin(); nit != nodes.end(); ++nit) + for (std::vector::const_iterator nit = nodes.begin(); nit != nodes.end(); ++nit) { // find all the collada anim channels which refer to the current node std::vector entries; std::string nodeName = (*nit)->mName.data; // find the collada node corresponding to the aiNode - const Collada::Node* srcNode = FindNode( pParser.mRootNode, nodeName); -// ai_assert( srcNode != NULL); - if( !srcNode) + const Collada::Node* srcNode = FindNode(pParser.mRootNode, nodeName); + // ai_assert( srcNode != NULL); + if (!srcNode) continue; // now check all channels if they affect the current node std::string targetID, subElement; - for( std::vector::const_iterator cit = pSrcAnim->mChannels.begin(); + for (std::vector::const_iterator cit = pSrcAnim->mChannels.begin(); cit != pSrcAnim->mChannels.end(); ++cit) { const Collada::AnimationChannel& srcChannel = *cit; @@ -1130,8 +1133,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars // we expect the animation target to be of type "nodeName/transformID.subElement". Ignore all others // find the slash that separates the node name - there should be only one - std::string::size_type slashPos = srcChannel.mTarget.find( '/'); - if( slashPos == std::string::npos) + std::string::size_type slashPos = srcChannel.mTarget.find('/'); + if (slashPos == std::string::npos) { std::string::size_type targetPos = srcChannel.mTarget.find(srcNode->mID); if (targetPos == std::string::npos) @@ -1140,44 +1143,45 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars // not node transform, but something else. store as unknown animation channel for now entry.mChannel = &(*cit); entry.mTargetId = srcChannel.mTarget.substr(targetPos + pSrcAnim->mName.length(), - srcChannel.mTarget.length() - targetPos - pSrcAnim->mName.length()); + srcChannel.mTarget.length() - targetPos - pSrcAnim->mName.length()); if (entry.mTargetId.front() == '-') entry.mTargetId = entry.mTargetId.substr(1); entries.push_back(entry); continue; } - if( srcChannel.mTarget.find( '/', slashPos+1) != std::string::npos) + if (srcChannel.mTarget.find('/', slashPos + 1) != std::string::npos) continue; targetID.clear(); - targetID = srcChannel.mTarget.substr( 0, slashPos); - if( targetID != srcNode->mID) + targetID = srcChannel.mTarget.substr(0, slashPos); + if (targetID != srcNode->mID) continue; // find the dot that separates the transformID - there should be only one or zero - std::string::size_type dotPos = srcChannel.mTarget.find( '.'); - if( dotPos != std::string::npos) + std::string::size_type dotPos = srcChannel.mTarget.find('.'); + if (dotPos != std::string::npos) { - if( srcChannel.mTarget.find( '.', dotPos+1) != std::string::npos) + if (srcChannel.mTarget.find('.', dotPos + 1) != std::string::npos) continue; - entry.mTransformId = srcChannel.mTarget.substr( slashPos+1, dotPos - slashPos - 1); + entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1, dotPos - slashPos - 1); subElement.clear(); - subElement = srcChannel.mTarget.substr( dotPos+1); - if( subElement == "ANGLE") + subElement = srcChannel.mTarget.substr(dotPos + 1); + if (subElement == "ANGLE") entry.mSubElement = 3; // last number in an Axis-Angle-Transform is the angle - else if( subElement == "X") + else if (subElement == "X") entry.mSubElement = 0; - else if( subElement == "Y") + else if (subElement == "Y") entry.mSubElement = 1; - else if( subElement == "Z") + else if (subElement == "Z") entry.mSubElement = 2; else - ASSIMP_LOG_WARN_F( "Unknown anim subelement <", subElement, ">. Ignoring" ); - } else { + ASSIMP_LOG_WARN_F("Unknown anim subelement <", subElement, ">. Ignoring"); + } + else { // no subelement following, transformId is remaining string - entry.mTransformId = srcChannel.mTarget.substr( slashPos+1); + entry.mTransformId = srcChannel.mTarget.substr(slashPos + 1); } std::string::size_type bracketPos = srcChannel.mTarget.find('('); @@ -1223,194 +1227,196 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars // determine which transform step is affected by this channel entry.mTransformIndex = SIZE_MAX; - for( size_t a = 0; a < srcNode->mTransforms.size(); ++a) - if( srcNode->mTransforms[a].mID == entry.mTransformId) + for (size_t a = 0; a < srcNode->mTransforms.size(); ++a) + if (srcNode->mTransforms[a].mID == entry.mTransformId) entry.mTransformIndex = a; - if( entry.mTransformIndex == SIZE_MAX) + if (entry.mTransformIndex == SIZE_MAX) { if (entry.mTransformId.find("morph-weights") != std::string::npos) { entry.mTargetId = entry.mTransformId; entry.mTransformId = ""; - } else + } + else continue; } entry.mChannel = &(*cit); - entries.push_back( entry); + entries.push_back(entry); } // if there's no channel affecting the current node, we skip it - if( entries.empty()) + if (entries.empty()) continue; // resolve the data pointers for all anim channels. Find the minimum time while we're at it - ai_real startTime = ai_real( 1e20 ), endTime = ai_real( -1e20 ); - for( std::vector::iterator it = entries.begin(); it != entries.end(); ++it) + ai_real startTime = ai_real(1e20), endTime = ai_real(-1e20); + for (std::vector::iterator it = entries.begin(); it != entries.end(); ++it) { Collada::ChannelEntry& e = *it; - e.mTimeAccessor = &pParser.ResolveLibraryReference( pParser.mAccessorLibrary, e.mChannel->mSourceTimes); - e.mTimeData = &pParser.ResolveLibraryReference( pParser.mDataLibrary, e.mTimeAccessor->mSource); - e.mValueAccessor = &pParser.ResolveLibraryReference( pParser.mAccessorLibrary, e.mChannel->mSourceValues); - e.mValueData = &pParser.ResolveLibraryReference( pParser.mDataLibrary, e.mValueAccessor->mSource); + e.mTimeAccessor = &pParser.ResolveLibraryReference(pParser.mAccessorLibrary, e.mChannel->mSourceTimes); + e.mTimeData = &pParser.ResolveLibraryReference(pParser.mDataLibrary, e.mTimeAccessor->mSource); + e.mValueAccessor = &pParser.ResolveLibraryReference(pParser.mAccessorLibrary, e.mChannel->mSourceValues); + e.mValueData = &pParser.ResolveLibraryReference(pParser.mDataLibrary, e.mValueAccessor->mSource); // time count and value count must match - if( e.mTimeAccessor->mCount != e.mValueAccessor->mCount) - throw DeadlyImportError( format() << "Time count / value count mismatch in animation channel \"" << e.mChannel->mTarget << "\"." ); + if (e.mTimeAccessor->mCount != e.mValueAccessor->mCount) + throw DeadlyImportError(format() << "Time count / value count mismatch in animation channel \"" << e.mChannel->mTarget << "\"."); - if( e.mTimeAccessor->mCount > 0 ) - { - // find bounding times - startTime = std::min( startTime, ReadFloat( *e.mTimeAccessor, *e.mTimeData, 0, 0)); - endTime = std::max( endTime, ReadFloat( *e.mTimeAccessor, *e.mTimeData, e.mTimeAccessor->mCount-1, 0)); - } + if (e.mTimeAccessor->mCount > 0) + { + // find bounding times + startTime = std::min(startTime, ReadFloat(*e.mTimeAccessor, *e.mTimeData, 0, 0)); + endTime = std::max(endTime, ReadFloat(*e.mTimeAccessor, *e.mTimeData, e.mTimeAccessor->mCount - 1, 0)); + } } - std::vector resultTrafos; - if( !entries.empty() && entries.front().mTimeAccessor->mCount > 0 ) - { - // create a local transformation chain of the node's transforms - std::vector transforms = srcNode->mTransforms; + std::vector resultTrafos; + if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) + { + // create a local transformation chain of the node's transforms + std::vector transforms = srcNode->mTransforms; - // now for every unique point in time, find or interpolate the key values for that time - // and apply them to the transform chain. Then the node's present transformation can be calculated. - ai_real time = startTime; - while( 1) - { - for( std::vector::iterator it = entries.begin(); it != entries.end(); ++it) - { - Collada::ChannelEntry& e = *it; + // now for every unique point in time, find or interpolate the key values for that time + // and apply them to the transform chain. Then the node's present transformation can be calculated. + ai_real time = startTime; + while (1) + { + for (std::vector::iterator it = entries.begin(); it != entries.end(); ++it) + { + Collada::ChannelEntry& e = *it; - // find the keyframe behind the current point in time - size_t pos = 0; - ai_real postTime = 0.0; - while( 1) - { - if( pos >= e.mTimeAccessor->mCount) - break; - postTime = ReadFloat( *e.mTimeAccessor, *e.mTimeData, pos, 0); - if( postTime >= time) - break; - ++pos; - } + // find the keyframe behind the current point in time + size_t pos = 0; + ai_real postTime = 0.0; + while (1) + { + if (pos >= e.mTimeAccessor->mCount) + break; + postTime = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos, 0); + if (postTime >= time) + break; + ++pos; + } - pos = std::min( pos, e.mTimeAccessor->mCount-1); + pos = std::min(pos, e.mTimeAccessor->mCount - 1); - // read values from there - ai_real temp[16]; - for( size_t c = 0; c < e.mValueAccessor->mSize; ++c) - temp[c] = ReadFloat( *e.mValueAccessor, *e.mValueData, pos, c); + // read values from there + ai_real temp[16]; + for (size_t c = 0; c < e.mValueAccessor->mSize; ++c) + temp[c] = ReadFloat(*e.mValueAccessor, *e.mValueData, pos, c); - // if not exactly at the key time, interpolate with previous value set - if( postTime > time && pos > 0) - { - ai_real preTime = ReadFloat( *e.mTimeAccessor, *e.mTimeData, pos-1, 0); - ai_real factor = (time - postTime) / (preTime - postTime); + // if not exactly at the key time, interpolate with previous value set + if (postTime > time && pos > 0) + { + ai_real preTime = ReadFloat(*e.mTimeAccessor, *e.mTimeData, pos - 1, 0); + ai_real factor = (time - postTime) / (preTime - postTime); - for( size_t c = 0; c < e.mValueAccessor->mSize; ++c) - { - ai_real v = ReadFloat( *e.mValueAccessor, *e.mValueData, pos-1, c); - temp[c] += (v - temp[c]) * factor; - } - } + for (size_t c = 0; c < e.mValueAccessor->mSize; ++c) + { + ai_real v = ReadFloat(*e.mValueAccessor, *e.mValueData, pos - 1, c); + temp[c] += (v - temp[c]) * factor; + } + } - // Apply values to current transformation - std::copy( temp, temp + e.mValueAccessor->mSize, transforms[e.mTransformIndex].f + e.mSubElement); - } + // Apply values to current transformation + std::copy(temp, temp + e.mValueAccessor->mSize, transforms[e.mTransformIndex].f + e.mSubElement); + } - // Calculate resulting transformation - aiMatrix4x4 mat = pParser.CalculateResultTransform( transforms); + // Calculate resulting transformation + aiMatrix4x4 mat = pParser.CalculateResultTransform(transforms); - // out of laziness: we store the time in matrix.d4 - mat.d4 = time; - resultTrafos.push_back( mat); + // out of laziness: we store the time in matrix.d4 + mat.d4 = time; + resultTrafos.push_back(mat); - // find next point in time to evaluate. That's the closest frame larger than the current in any channel - ai_real nextTime = ai_real( 1e20 ); - for( std::vector::iterator it = entries.begin(); it != entries.end(); ++it) - { - Collada::ChannelEntry& channelElement = *it; + // find next point in time to evaluate. That's the closest frame larger than the current in any channel + ai_real nextTime = ai_real(1e20); + for (std::vector::iterator it = entries.begin(); it != entries.end(); ++it) + { + Collada::ChannelEntry& channelElement = *it; - // find the next time value larger than the current - size_t pos = 0; - while( pos < channelElement.mTimeAccessor->mCount) - { - const ai_real t = ReadFloat( *channelElement.mTimeAccessor, *channelElement.mTimeData, pos, 0); - if( t > time) - { - nextTime = std::min( nextTime, t); - break; - } - ++pos; - } + // find the next time value larger than the current + size_t pos = 0; + while (pos < channelElement.mTimeAccessor->mCount) + { + const ai_real t = ReadFloat(*channelElement.mTimeAccessor, *channelElement.mTimeData, pos, 0); + if (t > time) + { + nextTime = std::min(nextTime, t); + break; + } + ++pos; + } - // https://github.com/assimp/assimp/issues/458 - // Sub-sample axis-angle channels if the delta between two consecutive - // key-frame angles is >= 180 degrees. - if (transforms[channelElement.mTransformIndex].mType == Collada::TF_ROTATE && channelElement.mSubElement == 3 && pos > 0 && pos < channelElement.mTimeAccessor->mCount) { - const ai_real cur_key_angle = ReadFloat(*channelElement.mValueAccessor, *channelElement.mValueData, pos, 0); - const ai_real last_key_angle = ReadFloat(*channelElement.mValueAccessor, *channelElement.mValueData, pos - 1, 0); - const ai_real cur_key_time = ReadFloat(*channelElement.mTimeAccessor, *channelElement.mTimeData, pos, 0); - const ai_real last_key_time = ReadFloat(*channelElement.mTimeAccessor, *channelElement.mTimeData, pos - 1, 0); - const ai_real last_eval_angle = last_key_angle + (cur_key_angle - last_key_angle) * (time - last_key_time) / (cur_key_time - last_key_time); - const ai_real delta = std::abs(cur_key_angle - last_eval_angle); - if (delta >= 180.0) { - const int subSampleCount = static_cast(std::floor(delta / 90.0)); - if (cur_key_time != time) { - const ai_real nextSampleTime = time + (cur_key_time - time) / subSampleCount; - nextTime = std::min(nextTime, nextSampleTime); - } - } - } - } + // https://github.com/assimp/assimp/issues/458 + // Sub-sample axis-angle channels if the delta between two consecutive + // key-frame angles is >= 180 degrees. + if (transforms[channelElement.mTransformIndex].mType == Collada::TF_ROTATE && channelElement.mSubElement == 3 && pos > 0 && pos < channelElement.mTimeAccessor->mCount) { + const ai_real cur_key_angle = ReadFloat(*channelElement.mValueAccessor, *channelElement.mValueData, pos, 0); + const ai_real last_key_angle = ReadFloat(*channelElement.mValueAccessor, *channelElement.mValueData, pos - 1, 0); + const ai_real cur_key_time = ReadFloat(*channelElement.mTimeAccessor, *channelElement.mTimeData, pos, 0); + const ai_real last_key_time = ReadFloat(*channelElement.mTimeAccessor, *channelElement.mTimeData, pos - 1, 0); + const ai_real last_eval_angle = last_key_angle + (cur_key_angle - last_key_angle) * (time - last_key_time) / (cur_key_time - last_key_time); + const ai_real delta = std::abs(cur_key_angle - last_eval_angle); + if (delta >= 180.0) { + const int subSampleCount = static_cast(std::floor(delta / 90.0)); + if (cur_key_time != time) { + const ai_real nextSampleTime = time + (cur_key_time - time) / subSampleCount; + nextTime = std::min(nextTime, nextSampleTime); + } + } + } + } - // no more keys on any channel after the current time -> we're done - if( nextTime > 1e19) - break; + // no more keys on any channel after the current time -> we're done + if (nextTime > 1e19) + break; - // else construct next keyframe at this following time point - time = nextTime; - } - } + // else construct next keyframe at this following time point + time = nextTime; + } + } // there should be some keyframes, but we aren't that fixated on valid input data // ai_assert( resultTrafos.size() > 0); // build an animation channel for the given node out of these trafo keys - if( !resultTrafos.empty() ) + if (!resultTrafos.empty()) { - aiNodeAnim* dstAnim = new aiNodeAnim; - dstAnim->mNodeName = nodeName; - dstAnim->mNumPositionKeys = static_cast(resultTrafos.size()); - dstAnim->mNumRotationKeys = static_cast(resultTrafos.size()); - dstAnim->mNumScalingKeys = static_cast(resultTrafos.size()); - dstAnim->mPositionKeys = new aiVectorKey[resultTrafos.size()]; - dstAnim->mRotationKeys = new aiQuatKey[resultTrafos.size()]; - dstAnim->mScalingKeys = new aiVectorKey[resultTrafos.size()]; + aiNodeAnim* dstAnim = new aiNodeAnim; + dstAnim->mNodeName = nodeName; + dstAnim->mNumPositionKeys = static_cast(resultTrafos.size()); + dstAnim->mNumRotationKeys = static_cast(resultTrafos.size()); + dstAnim->mNumScalingKeys = static_cast(resultTrafos.size()); + dstAnim->mPositionKeys = new aiVectorKey[resultTrafos.size()]; + dstAnim->mRotationKeys = new aiQuatKey[resultTrafos.size()]; + dstAnim->mScalingKeys = new aiVectorKey[resultTrafos.size()]; - for( size_t a = 0; a < resultTrafos.size(); ++a) - { - aiMatrix4x4 mat = resultTrafos[a]; - double time = double( mat.d4); // remember? time is stored in mat.d4 - mat.d4 = 1.0f; + for (size_t a = 0; a < resultTrafos.size(); ++a) + { + aiMatrix4x4 mat = resultTrafos[a]; + double time = double(mat.d4); // remember? time is stored in mat.d4 + mat.d4 = 1.0f; - dstAnim->mPositionKeys[a].mTime = time; - dstAnim->mRotationKeys[a].mTime = time; - dstAnim->mScalingKeys[a].mTime = time; - mat.Decompose( dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue); - } + dstAnim->mPositionKeys[a].mTime = time; + dstAnim->mRotationKeys[a].mTime = time; + dstAnim->mScalingKeys[a].mTime = time; + mat.Decompose(dstAnim->mScalingKeys[a].mValue, dstAnim->mRotationKeys[a].mValue, dstAnim->mPositionKeys[a].mValue); + } - anims.push_back( dstAnim); - } else + anims.push_back(dstAnim); + } + else { - ASSIMP_LOG_WARN( "Collada loader: found empty animation channel, ignored. Please check your exporter."); + ASSIMP_LOG_WARN("Collada loader: found empty animation channel, ignored. Please check your exporter."); } - if( !entries.empty() && entries.front().mTimeAccessor->mCount > 0 ) + if (!entries.empty() && entries.front().mTimeAccessor->mCount > 0) { std::vector morphChannels; - for( std::vector::iterator it = entries.begin(); it != entries.end(); ++it) + for (std::vector::iterator it = entries.begin(); it != entries.end(); ++it) { Collada::ChannelEntry& e = *it; @@ -1433,7 +1439,7 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars std::vector morphTimeValues; int morphAnimChannelIndex = 0; - for( std::vector::iterator it = morphChannels.begin(); it != morphChannels.end(); ++it) + for (std::vector::iterator it = morphChannels.begin(); it != morphChannels.end(); ++it) { Collada::ChannelEntry& e = *it; std::string::size_type apos = e.mTargetId.find('('); @@ -1455,8 +1461,8 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars for (unsigned int key = 0; key < morphAnim->mNumKeys; key++) { morphAnim->mKeys[key].mNumValuesAndWeights = static_cast(morphChannels.size()); - morphAnim->mKeys[key].mValues = new unsigned int [morphChannels.size()]; - morphAnim->mKeys[key].mWeights = new double [morphChannels.size()]; + morphAnim->mKeys[key].mValues = new unsigned int[morphChannels.size()]; + morphAnim->mKeys[key].mWeights = new double[morphChannels.size()]; morphAnim->mKeys[key].mTime = morphTimeValues[key].mTime; for (unsigned int valueIndex = 0; valueIndex < morphChannels.size(); valueIndex++) @@ -1471,48 +1477,48 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars } } - if( !anims.empty() || !morphAnims.empty()) + if (!anims.empty() || !morphAnims.empty()) { aiAnimation* anim = new aiAnimation; - anim->mName.Set( pName); + anim->mName.Set(pName); anim->mNumChannels = static_cast(anims.size()); if (anim->mNumChannels > 0) { anim->mChannels = new aiNodeAnim*[anims.size()]; - std::copy( anims.begin(), anims.end(), anim->mChannels); + std::copy(anims.begin(), anims.end(), anim->mChannels); } anim->mNumMorphMeshChannels = static_cast(morphAnims.size()); if (anim->mNumMorphMeshChannels > 0) { anim->mMorphMeshChannels = new aiMeshMorphAnim*[anim->mNumMorphMeshChannels]; - std::copy( morphAnims.begin(), morphAnims.end(), anim->mMorphMeshChannels); + std::copy(morphAnims.begin(), morphAnims.end(), anim->mMorphMeshChannels); } anim->mDuration = 0.0f; - for( size_t a = 0; a < anims.size(); ++a) + for (size_t a = 0; a < anims.size(); ++a) { - anim->mDuration = std::max( anim->mDuration, anims[a]->mPositionKeys[anims[a]->mNumPositionKeys-1].mTime); - anim->mDuration = std::max( anim->mDuration, anims[a]->mRotationKeys[anims[a]->mNumRotationKeys-1].mTime); - anim->mDuration = std::max( anim->mDuration, anims[a]->mScalingKeys[anims[a]->mNumScalingKeys-1].mTime); + anim->mDuration = std::max(anim->mDuration, anims[a]->mPositionKeys[anims[a]->mNumPositionKeys - 1].mTime); + anim->mDuration = std::max(anim->mDuration, anims[a]->mRotationKeys[anims[a]->mNumRotationKeys - 1].mTime); + anim->mDuration = std::max(anim->mDuration, anims[a]->mScalingKeys[anims[a]->mNumScalingKeys - 1].mTime); } for (size_t a = 0; a < morphAnims.size(); ++a) { - anim->mDuration = std::max(anim->mDuration, morphAnims[a]->mKeys[morphAnims[a]->mNumKeys-1].mTime); + anim->mDuration = std::max(anim->mDuration, morphAnims[a]->mKeys[morphAnims[a]->mNumKeys - 1].mTime); } anim->mTicksPerSecond = 1; - mAnims.push_back( anim); + mAnims.push_back(anim); } } // ------------------------------------------------------------------------------------------------ // Add a texture to a material structure -void ColladaLoader::AddTexture ( aiMaterial& mat, const ColladaParser& pParser, +void ColladaLoader::AddTexture(aiMaterial& mat, const ColladaParser& pParser, const Collada::Effect& effect, const Collada::Sampler& sampler, aiTextureType type, unsigned int idx) { // first of all, basic file name - const aiString name = FindFilenameForEffectTexture( pParser, effect, sampler.mName ); - mat.AddProperty( &name, _AI_MATKEY_TEXTURE_BASE, type, idx ); + const aiString name = FindFilenameForEffectTexture(pParser, effect, sampler.mName); + mat.AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, type, idx); // mapping mode int map = aiTextureMapMode_Clamp; @@ -1521,7 +1527,7 @@ void ColladaLoader::AddTexture ( aiMaterial& mat, const ColladaParser& pParser, if (sampler.mWrapU && sampler.mMirrorU) map = aiTextureMapMode_Mirror; - mat.AddProperty( &map, 1, _AI_MATKEY_MAPPINGMODE_U_BASE, type, idx); + mat.AddProperty(&map, 1, _AI_MATKEY_MAPPINGMODE_U_BASE, type, idx); map = aiTextureMapMode_Clamp; if (sampler.mWrapV) @@ -1529,18 +1535,18 @@ void ColladaLoader::AddTexture ( aiMaterial& mat, const ColladaParser& pParser, if (sampler.mWrapV && sampler.mMirrorV) map = aiTextureMapMode_Mirror; - mat.AddProperty( &map, 1, _AI_MATKEY_MAPPINGMODE_V_BASE, type, idx); + mat.AddProperty(&map, 1, _AI_MATKEY_MAPPINGMODE_V_BASE, type, idx); // UV transformation mat.AddProperty(&sampler.mTransform, 1, _AI_MATKEY_UVTRANSFORM_BASE, type, idx); // Blend mode - mat.AddProperty((int*)&sampler.mOp , 1, + mat.AddProperty((int*)&sampler.mOp, 1, _AI_MATKEY_TEXBLEND_BASE, type, idx); // Blend factor - mat.AddProperty((ai_real*)&sampler.mWeighting , 1, + mat.AddProperty((ai_real*)&sampler.mWeighting, 1, _AI_MATKEY_TEXBLEND_BASE, type, idx); // UV source index ... if we didn't resolve the mapping, it is actually just @@ -1552,7 +1558,7 @@ void ColladaLoader::AddTexture ( aiMaterial& mat, const ColladaParser& pParser, map = sampler.mUVId; else { map = -1; - for (std::string::const_iterator it = sampler.mUVChannel.begin();it != sampler.mUVChannel.end(); ++it){ + for (std::string::const_iterator it = sampler.mUVChannel.begin(); it != sampler.mUVChannel.end(); ++it) { if (IsNumeric(*it)) { map = strtoul10(&(*it)); break; @@ -1563,12 +1569,12 @@ void ColladaLoader::AddTexture ( aiMaterial& mat, const ColladaParser& pParser, map = 0; } } - mat.AddProperty(&map,1,_AI_MATKEY_UVWSRC_BASE,type,idx); + mat.AddProperty(&map, 1, _AI_MATKEY_UVWSRC_BASE, type, idx); } // ------------------------------------------------------------------------------------------------ // Fills materials from the collada material definitions -void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pScene*/) +void ColladaLoader::FillMaterials(const ColladaParser& pParser, aiScene* /*pScene*/) { for (auto &elem : newMats) { @@ -1580,7 +1586,7 @@ void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pSce if (effect.mFaceted) /* fixme */ shadeMode = aiShadingMode_Flat; else { - switch( effect.mShadeType) + switch (effect.mShadeType) { case Collada::Shade_Constant: shadeMode = aiShadingMode_NoShading; @@ -1601,56 +1607,57 @@ void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pSce break; } } - mat.AddProperty( &shadeMode, 1, AI_MATKEY_SHADING_MODEL); + mat.AddProperty(&shadeMode, 1, AI_MATKEY_SHADING_MODEL); // double-sided? shadeMode = effect.mDoubleSided; - mat.AddProperty( &shadeMode, 1, AI_MATKEY_TWOSIDED); + mat.AddProperty(&shadeMode, 1, AI_MATKEY_TWOSIDED); // wireframe? shadeMode = effect.mWireframe; - mat.AddProperty( &shadeMode, 1, AI_MATKEY_ENABLE_WIREFRAME); + mat.AddProperty(&shadeMode, 1, AI_MATKEY_ENABLE_WIREFRAME); // add material colors - mat.AddProperty( &effect.mAmbient, 1,AI_MATKEY_COLOR_AMBIENT); - mat.AddProperty( &effect.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); - mat.AddProperty( &effect.mSpecular, 1,AI_MATKEY_COLOR_SPECULAR); - mat.AddProperty( &effect.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); - mat.AddProperty( &effect.mReflective, 1, AI_MATKEY_COLOR_REFLECTIVE); + mat.AddProperty(&effect.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT); + mat.AddProperty(&effect.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); + mat.AddProperty(&effect.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR); + mat.AddProperty(&effect.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); + mat.AddProperty(&effect.mReflective, 1, AI_MATKEY_COLOR_REFLECTIVE); // scalar properties - mat.AddProperty( &effect.mShininess, 1, AI_MATKEY_SHININESS); - mat.AddProperty( &effect.mReflectivity, 1, AI_MATKEY_REFLECTIVITY); - mat.AddProperty( &effect.mRefractIndex, 1, AI_MATKEY_REFRACTI); + mat.AddProperty(&effect.mShininess, 1, AI_MATKEY_SHININESS); + mat.AddProperty(&effect.mReflectivity, 1, AI_MATKEY_REFLECTIVITY); + mat.AddProperty(&effect.mRefractIndex, 1, AI_MATKEY_REFRACTI); // transparency, a very hard one. seemingly not all files are following the // specification here (1.0 transparency => completely opaque)... // therefore, we let the opportunity for the user to manually invert // the transparency if necessary and we add preliminary support for RGB_ZERO mode - if(effect.mTransparency >= 0.f && effect.mTransparency <= 1.f) { + if (effect.mTransparency >= 0.f && effect.mTransparency <= 1.f) { // handle RGB transparency completely, cf Collada specs 1.5.0 pages 249 and 304 - if(effect.mRGBTransparency) { - // use luminance as defined by ISO/CIE color standards (see ITU-R Recommendation BT.709-4) + if (effect.mRGBTransparency) { + // use luminance as defined by ISO/CIE color standards (see ITU-R Recommendation BT.709-4) effect.mTransparency *= ( 0.212671f * effect.mTransparent.r + 0.715160f * effect.mTransparent.g + 0.072169f * effect.mTransparent.b - ); + ); effect.mTransparent.a = 1.f; - mat.AddProperty( &effect.mTransparent, 1, AI_MATKEY_COLOR_TRANSPARENT ); - } else { - effect.mTransparency *= effect.mTransparent.a; + mat.AddProperty(&effect.mTransparent, 1, AI_MATKEY_COLOR_TRANSPARENT); + } + else { + effect.mTransparency *= effect.mTransparent.a; } - if(effect.mInvertTransparency) { + if (effect.mInvertTransparency) { effect.mTransparency = 1.f - effect.mTransparency; } // Is the material finally transparent ? if (effect.mHasTransparency || effect.mTransparency < 1.f) { - mat.AddProperty( &effect.mTransparency, 1, AI_MATKEY_OPACITY ); + mat.AddProperty(&effect.mTransparency, 1, AI_MATKEY_OPACITY); } } @@ -1660,87 +1667,87 @@ void ColladaLoader::FillMaterials( const ColladaParser& pParser, aiScene* /*pSce AddTexture(mat, pParser, effect, effect.mTexAmbient, aiTextureType_LIGHTMAP); } - if( !effect.mTexEmissive.mName.empty()) - AddTexture( mat, pParser, effect, effect.mTexEmissive, aiTextureType_EMISSIVE); + if (!effect.mTexEmissive.mName.empty()) + AddTexture(mat, pParser, effect, effect.mTexEmissive, aiTextureType_EMISSIVE); - if( !effect.mTexSpecular.mName.empty()) - AddTexture( mat, pParser, effect, effect.mTexSpecular, aiTextureType_SPECULAR); + if (!effect.mTexSpecular.mName.empty()) + AddTexture(mat, pParser, effect, effect.mTexSpecular, aiTextureType_SPECULAR); - if( !effect.mTexDiffuse.mName.empty()) - AddTexture( mat, pParser, effect, effect.mTexDiffuse, aiTextureType_DIFFUSE); + if (!effect.mTexDiffuse.mName.empty()) + AddTexture(mat, pParser, effect, effect.mTexDiffuse, aiTextureType_DIFFUSE); - if( !effect.mTexBump.mName.empty()) - AddTexture( mat, pParser, effect, effect.mTexBump, aiTextureType_NORMALS); + if (!effect.mTexBump.mName.empty()) + AddTexture(mat, pParser, effect, effect.mTexBump, aiTextureType_NORMALS); - if( !effect.mTexTransparent.mName.empty()) - AddTexture( mat, pParser, effect, effect.mTexTransparent, aiTextureType_OPACITY); + if (!effect.mTexTransparent.mName.empty()) + AddTexture(mat, pParser, effect, effect.mTexTransparent, aiTextureType_OPACITY); - if( !effect.mTexReflective.mName.empty()) - AddTexture( mat, pParser, effect, effect.mTexReflective, aiTextureType_REFLECTION); + if (!effect.mTexReflective.mName.empty()) + AddTexture(mat, pParser, effect, effect.mTexReflective, aiTextureType_REFLECTION); } } // ------------------------------------------------------------------------------------------------ // Constructs materials from the collada material definitions -void ColladaLoader::BuildMaterials( ColladaParser& pParser, aiScene* /*pScene*/) +void ColladaLoader::BuildMaterials(ColladaParser& pParser, aiScene* /*pScene*/) { newMats.reserve(pParser.mMaterialLibrary.size()); - for( ColladaParser::MaterialLibrary::const_iterator matIt = pParser.mMaterialLibrary.begin(); + for (ColladaParser::MaterialLibrary::const_iterator matIt = pParser.mMaterialLibrary.begin(); matIt != pParser.mMaterialLibrary.end(); ++matIt) { const Collada::Material& material = matIt->second; // a material is only a reference to an effect - ColladaParser::EffectLibrary::iterator effIt = pParser.mEffectLibrary.find( material.mEffect); - if( effIt == pParser.mEffectLibrary.end()) + ColladaParser::EffectLibrary::iterator effIt = pParser.mEffectLibrary.find(material.mEffect); + if (effIt == pParser.mEffectLibrary.end()) continue; Collada::Effect& effect = effIt->second; // create material aiMaterial* mat = new aiMaterial; - aiString name( material.mName.empty() ? matIt->first : material.mName ); - mat->AddProperty(&name,AI_MATKEY_NAME); + aiString name(material.mName.empty() ? matIt->first : material.mName); + mat->AddProperty(&name, AI_MATKEY_NAME); // store the material mMaterialIndexByName[matIt->first] = newMats.size(); - newMats.push_back( std::pair( &effect,mat) ); + newMats.push_back(std::pair(&effect, mat)); } // ScenePreprocessor generates a default material automatically if none is there. // All further code here in this loader works well without a valid material so // we can safely let it to ScenePreprocessor. #if 0 - if( newMats.size() == 0) + if (newMats.size() == 0) { aiMaterial* mat = new aiMaterial; - aiString name( AI_DEFAULT_MATERIAL_NAME ); - mat->AddProperty( &name, AI_MATKEY_NAME); + aiString name(AI_DEFAULT_MATERIAL_NAME); + mat->AddProperty(&name, AI_MATKEY_NAME); const int shadeMode = aiShadingMode_Phong; - mat->AddProperty( &shadeMode, 1, AI_MATKEY_SHADING_MODEL); - aiColor4D colAmbient( 0.2, 0.2, 0.2, 1.0), colDiffuse( 0.8, 0.8, 0.8, 1.0), colSpecular( 0.5, 0.5, 0.5, 0.5); - mat->AddProperty( &colAmbient, 1, AI_MATKEY_COLOR_AMBIENT); - mat->AddProperty( &colDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); - mat->AddProperty( &colSpecular, 1, AI_MATKEY_COLOR_SPECULAR); + mat->AddProperty(&shadeMode, 1, AI_MATKEY_SHADING_MODEL); + aiColor4D colAmbient(0.2, 0.2, 0.2, 1.0), colDiffuse(0.8, 0.8, 0.8, 1.0), colSpecular(0.5, 0.5, 0.5, 0.5); + mat->AddProperty(&colAmbient, 1, AI_MATKEY_COLOR_AMBIENT); + mat->AddProperty(&colDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); + mat->AddProperty(&colSpecular, 1, AI_MATKEY_COLOR_SPECULAR); const ai_real specExp = 5.0; - mat->AddProperty( &specExp, 1, AI_MATKEY_SHININESS); - } + mat->AddProperty(&specExp, 1, AI_MATKEY_SHININESS); +} #endif } // ------------------------------------------------------------------------------------------------ // Resolves the texture name for the given effect texture entry -aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pParser, +aiString ColladaLoader::FindFilenameForEffectTexture(const ColladaParser& pParser, const Collada::Effect& pEffect, const std::string& pName) { aiString result; // recurse through the param references until we end up at an image std::string name = pName; - while( 1) + while (1) { // the given string is a param entry. Find it - Collada::Effect::ParamLibrary::const_iterator it = pEffect.mParams.find( name); + Collada::Effect::ParamLibrary::const_iterator it = pEffect.mParams.find(name); // if not found, we're at the end of the recursion. The resulting string should be the image ID - if( it == pEffect.mParams.end()) + if (it == pEffect.mParams.end()) break; // else recurse on @@ -1748,8 +1755,8 @@ aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pPars } // find the image referred by this name in the image library of the scene - ColladaParser::ImageLibrary::const_iterator imIt = pParser.mImageLibrary.find( name); - if( imIt == pParser.mImageLibrary.end()) + ColladaParser::ImageLibrary::const_iterator imIt = pParser.mImageLibrary.find(name); + if (imIt == pParser.mImageLibrary.end()) { ASSIMP_LOG_WARN_F("Collada: Unable to resolve effect texture entry \"", pName, "\", ended up at ID \"", name, "\"."); @@ -1760,41 +1767,41 @@ aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pPars } // if this is an embedded texture image setup an aiTexture for it - if (imIt->second.mFileName.empty()) + if (!imIt->second.mImageData.empty()) { - if (imIt->second.mImageData.empty()) { - throw DeadlyImportError("Collada: Invalid texture, no data or file reference given"); - } - aiTexture* tex = new aiTexture(); + // Store embedded texture name reference + tex->mFilename.Set(imIt->second.mFileName.c_str()); + result.Set(imIt->second.mFileName); + + // TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING" +// result.data[0] = '*'; +// result.length = 1 + ASSIMP_itoa10(result.data + 1, static_cast(MAXLEN - 1), static_cast(mTextures.size())); + + // setup format hint if (imIt->second.mEmbeddedFormat.length() > 3) { ASSIMP_LOG_WARN("Collada: texture format hint is too long, truncating to 3 characters"); } - strncpy(tex->achFormatHint,imIt->second.mEmbeddedFormat.c_str(),3); + strncpy(tex->achFormatHint, imIt->second.mEmbeddedFormat.c_str(), 3); // and copy texture data tex->mHeight = 0; tex->mWidth = static_cast(imIt->second.mImageData.size()); tex->pcData = (aiTexel*)new char[tex->mWidth]; - memcpy(tex->pcData,&imIt->second.mImageData[0],tex->mWidth); - - // TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING" - // In FBX files textures are now stored internally by Assimp with their filename included - // Now Assimp can lookup through the loaded textures after all data is processed - // We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it - // This may occur on this case too, it has to be studied - // setup texture reference string - result.data[0] = '*'; - result.length = 1 + ASSIMP_itoa10(result.data+1,static_cast(MAXLEN-1),static_cast(mTextures.size())); + memcpy(tex->pcData, &imIt->second.mImageData[0], tex->mWidth); // and add this texture to the list mTextures.push_back(tex); } else { - result.Set( imIt->second.mFileName ); + if (imIt->second.mFileName.empty()) { + throw DeadlyImportError("Collada: Invalid texture, no data or file reference given"); + } + + result.Set(imIt->second.mFileName); ConvertPath(result); } return result; @@ -1802,77 +1809,78 @@ aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pPars // ------------------------------------------------------------------------------------------------ // Convert a path read from a collada file to the usual representation -void ColladaLoader::ConvertPath (aiString& ss) +void ColladaLoader::ConvertPath(aiString& ss) { // TODO: collada spec, p 22. Handle URI correctly. // For the moment we're just stripping the file:// away to make it work. // Windows doesn't seem to be able to find stuff like // 'file://..\LWO\LWO2\MappingModes\earthSpherical.jpg' - if (0 == strncmp(ss.data,"file://",7)) + if (0 == strncmp(ss.data, "file://", 7)) { ss.length -= 7; - memmove(ss.data,ss.data+7,ss.length); + memmove(ss.data, ss.data + 7, ss.length); ss.data[ss.length] = '\0'; } - // Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes... - // I need to filter it without destroying linux paths starting with "/somewhere" + // Maxon Cinema Collada Export writes "file:///C:\andsoon" with three slashes... + // I need to filter it without destroying linux paths starting with "/somewhere" #if defined( _MSC_VER ) - if( ss.data[0] == '/' && isalpha( (unsigned char) ss.data[1]) && ss.data[2] == ':' ) { + if (ss.data[0] == '/' && isalpha((unsigned char)ss.data[1]) && ss.data[2] == ':') { #else - if (ss.data[ 0 ] == '/' && isalpha( ss.data[ 1 ] ) && ss.data[ 2 ] == ':') { + if (ss.data[0] == '/' && isalpha(ss.data[1]) && ss.data[2] == ':') { #endif - --ss.length; - ::memmove( ss.data, ss.data+1, ss.length); - ss.data[ss.length] = 0; - } - - // find and convert all %xy special chars - char* out = ss.data; - for( const char* it = ss.data; it != ss.data + ss.length; /**/ ) - { - if( *it == '%' && (it + 3) < ss.data + ss.length ) - { - // separate the number to avoid dragging in chars from behind into the parsing - char mychar[3] = { it[1], it[2], 0 }; - size_t nbr = strtoul16( mychar); - it += 3; - *out++ = (char)(nbr & 0xFF); - } else - { - *out++ = *it++; + --ss.length; + ::memmove(ss.data, ss.data + 1, ss.length); + ss.data[ss.length] = 0; } - } - // adjust length and terminator of the shortened string - *out = 0; - ss.length = (ptrdiff_t) (out - ss.data); + // find and convert all %xy special chars + char* out = ss.data; + for (const char* it = ss.data; it != ss.data + ss.length; /**/) + { + if (*it == '%' && (it + 3) < ss.data + ss.length) + { + // separate the number to avoid dragging in chars from behind into the parsing + char mychar[3] = { it[1], it[2], 0 }; + size_t nbr = strtoul16(mychar); + it += 3; + *out++ = (char)(nbr & 0xFF); + } + else + { + *out++ = *it++; + } + } + + // adjust length and terminator of the shortened string + *out = 0; + ss.length = (ptrdiff_t)(out - ss.data); } // ------------------------------------------------------------------------------------------------ // Reads a float value from an accessor and its data array. -ai_real ColladaLoader::ReadFloat( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex, size_t pOffset) const +ai_real ColladaLoader::ReadFloat(const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex, size_t pOffset) const { // FIXME: (thom) Test for data type here in every access? For the moment, I leave this to the caller size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset + pOffset; - ai_assert( pos < pData.mValues.size()); + ai_assert(pos < pData.mValues.size()); return pData.mValues[pos]; } // ------------------------------------------------------------------------------------------------ // Reads a string value from an accessor and its data array. -const std::string& ColladaLoader::ReadString( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex) const +const std::string& ColladaLoader::ReadString(const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex) const { size_t pos = pAccessor.mStride * pIndex + pAccessor.mOffset; - ai_assert( pos < pData.mStrings.size()); + ai_assert(pos < pData.mStrings.size()); return pData.mStrings[pos]; } // ------------------------------------------------------------------------------------------------ // Collects all nodes into the given array -void ColladaLoader::CollectNodes( const aiNode* pNode, std::vector& poNodes) const +void ColladaLoader::CollectNodes(const aiNode* pNode, std::vector& poNodes) const { - poNodes.push_back( pNode); + poNodes.push_back(pNode); for (size_t a = 0; a < pNode->mNumChildren; ++a) { CollectNodes(pNode->mChildren[a], poNodes); } @@ -1880,15 +1888,15 @@ void ColladaLoader::CollectNodes( const aiNode* pNode, std::vectormName == pName || pNode->mID == pName) + if (pNode->mName == pName || pNode->mID == pName) return pNode; - for( size_t a = 0; a < pNode->mChildren.size(); ++a) + for (size_t a = 0; a < pNode->mChildren.size(); ++a) { - const Collada::Node* node = FindNode( pNode->mChildren[a], pName); - if( node) + const Collada::Node* node = FindNode(pNode->mChildren[a], pName); + if (node) return node; } @@ -1897,43 +1905,57 @@ const Collada::Node* ColladaLoader::FindNode( const Collada::Node* pNode, const // ------------------------------------------------------------------------------------------------ // Finds a node in the collada scene by the given SID -const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const -{ - if( pNode->mSID == pSID) - return pNode; +const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const { + if (nullptr == pNode) { + return nullptr; + } - for( size_t a = 0; a < pNode->mChildren.size(); ++a) - { - const Collada::Node* node = FindNodeBySID( pNode->mChildren[a], pSID); - if( node) - return node; - } + if (pNode->mSID == pSID) { + return pNode; + } - return NULL; + for( size_t a = 0; a < pNode->mChildren.size(); ++a) { + const Collada::Node* node = FindNodeBySID( pNode->mChildren[a], pSID); + if (node) { + return node; + } + } + + return nullptr; } // ------------------------------------------------------------------------------------------------ // Finds a proper unique name for a node derived from the collada-node's properties. // The name must be unique for proper node-bone association. -std::string ColladaLoader::FindNameForNode( const Collada::Node* pNode) +std::string ColladaLoader::FindNameForNode(const Collada::Node* pNode) { // If explicitly requested, just use the collada name. - if (useColladaName) { - return pNode->mName; - } - - // Now setup the name of the assimp node. The collada name might not be - // unique, so we use the collada ID. - if (!pNode->mID.empty()) - return pNode->mID; - else if (!pNode->mSID.empty()) - return pNode->mSID; - else + if (useColladaName) { - // No need to worry. Unnamed nodes are no problem at all, except - // if cameras or lights need to be assigned to them. - return format() << "$ColladaAutoName$_" << mNodeNameCounter++; + if (!pNode->mName.empty()) { + return pNode->mName; + } + else { + return format() << "$ColladaAutoName$_" << mNodeNameCounter++; + } + } + else + { + // Now setup the name of the assimp node. The collada name might not be + // unique, so we use the collada ID. + if (!pNode->mID.empty()) + return pNode->mID; + else if (!pNode->mSID.empty()) + return pNode->mSID; + else + { + // No need to worry. Unnamed nodes are no problem at all, except + // if cameras or lights need to be assigned to them. + return format() << "$ColladaAutoName$_" << mNodeNameCounter++; + } } } +} // Namespace Assimp + #endif // !! ASSIMP_BUILD_NO_DAE_IMPORTER diff --git a/code/ColladaLoader.h b/code/Collada/ColladaLoader.h similarity index 97% rename from code/ColladaLoader.h rename to code/Collada/ColladaLoader.h index d61845b24..dce46e06f 100644 --- a/code/ColladaLoader.h +++ b/code/Collada/ColladaLoader.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -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, diff --git a/code/ColladaParser.cpp b/code/Collada/ColladaParser.cpp similarity index 50% rename from code/ColladaParser.cpp rename to code/Collada/ColladaParser.cpp index 052cd51c4..646ec473d 100644 --- a/code/ColladaParser.cpp +++ b/code/Collada/ColladaParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -57,6 +57,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include @@ -66,9 +67,9 @@ using namespace Assimp::Formatter; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile) - : mFileName( pFile ) - , mReader( nullptr ) +ColladaParser::ColladaParser(IOSystem* pIOHandler, const std::string& pFile) + : mFileName(pFile) + , mReader(nullptr) , mDataLibrary() , mAccessorLibrary() , mMeshLibrary() @@ -79,32 +80,60 @@ ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile) , mLightLibrary() , mCameraLibrary() , mControllerLibrary() - , mRootNode( nullptr ) + , mRootNode(nullptr) , mAnims() - , mUnitSize( 1.0f ) - , mUpDirection( UP_Y ) - , mFormat(FV_1_5_n ) // We assume the newest file format by default + , mUnitSize(1.0f) + , mUpDirection(UP_Y) + , mFormat(FV_1_5_n) // We assume the newest file format by default { // validate io-handler instance - if (nullptr == pIOHandler ) { - throw DeadlyImportError("IOSystem is NULL." ); + if (nullptr == pIOHandler) { + throw DeadlyImportError("IOSystem is NULL."); } - // open the file - std::unique_ptr file( pIOHandler->Open(pFile ) ); - if (file.get() == nullptr) { - throw DeadlyImportError( "Failed to open file " + pFile + "." ); + std::unique_ptr daefile; + std::unique_ptr zip_archive; + + // Determine type + std::string extension = BaseImporter::GetExtension(pFile); + if (extension != "dae") { + zip_archive.reset(new ZipArchiveIOSystem(pIOHandler, pFile)); + } + + if (zip_archive && zip_archive->isOpen()) { + std::string dae_filename = ReadZaeManifest(*zip_archive); + + if (dae_filename.empty()) { + ThrowException(std::string("Invalid ZAE")); + } + + daefile.reset(zip_archive->Open(dae_filename.c_str())); + if (daefile == nullptr) { + ThrowException(std::string("Invalid ZAE manifest: '") + std::string(dae_filename) + std::string("' is missing")); + } + } + else { + // attempt to open the file directly + daefile.reset(pIOHandler->Open(pFile)); + if (daefile.get() == nullptr) { + throw DeadlyImportError("Failed to open file '" + pFile + "'."); + } } // generate a XML reader for it - std::unique_ptr mIOWrapper(new CIrrXML_IOStreamReader(file.get())); - mReader = irr::io::createIrrXMLReader( mIOWrapper.get()); + std::unique_ptr mIOWrapper(new CIrrXML_IOStreamReader(daefile.get())); + mReader = irr::io::createIrrXMLReader(mIOWrapper.get()); if (!mReader) { - ThrowException("Collada: Unable to open file."); + ThrowException("Unable to read file, malformed XML"); } // start reading ReadContents(); + + // read embedded textures + if (zip_archive && zip_archive->isOpen()) { + ReadEmbeddedTextures(*zip_archive); + } } // ------------------------------------------------------------------------------------------------ @@ -112,18 +141,61 @@ ColladaParser::ColladaParser( IOSystem* pIOHandler, const std::string& pFile) ColladaParser::~ColladaParser() { delete mReader; - for( NodeLibrary::iterator it = mNodeLibrary.begin(); it != mNodeLibrary.end(); ++it) + for (NodeLibrary::iterator it = mNodeLibrary.begin(); it != mNodeLibrary.end(); ++it) delete it->second; - for( MeshLibrary::iterator it = mMeshLibrary.begin(); it != mMeshLibrary.end(); ++it) + for (MeshLibrary::iterator it = mMeshLibrary.begin(); it != mMeshLibrary.end(); ++it) delete it->second; } +// ------------------------------------------------------------------------------------------------ +// Read a ZAE manifest and return the filename to attempt to open +std::string ColladaParser::ReadZaeManifest(ZipArchiveIOSystem &zip_archive) { + // Open the manifest + std::unique_ptr manifestfile(zip_archive.Open("manifest.xml")); + if (manifestfile == nullptr) + { + // No manifest, hope there is only one .DAE inside + std::vector file_list; + zip_archive.getFileListExtension(file_list, "dae"); + + if (file_list.empty()) + return std::string(); + + return file_list.front(); + } + + std::unique_ptr mIOWrapper(new CIrrXML_IOStreamReader(manifestfile.get())); + std::unique_ptr manifest_reader(irr::io::createIrrXMLReader(mIOWrapper.get())); + + while (manifest_reader->read()) + { + // find the manifest "dae_root" element + if (manifest_reader->getNodeType() == irr::io::EXN_ELEMENT) + { + if (::strcmp(manifest_reader->getNodeName(), "dae_root") == 0) + { + if (!manifest_reader->read()) + return std::string(); + if (manifest_reader->getNodeType() != irr::io::EXN_TEXT && manifest_reader->getNodeType() != irr::io::EXN_CDATA) + return std::string(); + + const char* filepath = manifest_reader->getNodeData(); + if (filepath == nullptr) + return std::string(); + + return std::string(filepath); + } + } + } + return std::string(); +} + // ------------------------------------------------------------------------------------------------ // Read bool from text contents of current element bool ColladaParser::ReadBoolFromTextContent() { const char* cur = GetTextContent(); - return (!ASSIMP_strincmp(cur,"true",4) || '0' != *cur); + return (!ASSIMP_strincmp(cur, "true", 4) || '0' != *cur); } // ------------------------------------------------------------------------------------------------ @@ -138,39 +210,41 @@ ai_real ColladaParser::ReadFloatFromTextContent() // Reads the contents of the file void ColladaParser::ReadContents() { - while( mReader->read()) + while (mReader->read()) { // handle the root element "COLLADA" - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "COLLADA")) + if (IsElement("COLLADA")) { // check for 'version' attribute const int attrib = TestAttribute("version"); if (attrib != -1) { const char* version = mReader->getAttributeValue(attrib); - if (!::strncmp(version,"1.5",3)) { - mFormat = FV_1_5_n; + if (!::strncmp(version, "1.5", 3)) { + mFormat = FV_1_5_n; ASSIMP_LOG_DEBUG("Collada schema version is 1.5.n"); } - else if (!::strncmp(version,"1.4",3)) { - mFormat = FV_1_4_n; + else if (!::strncmp(version, "1.4", 3)) { + mFormat = FV_1_4_n; ASSIMP_LOG_DEBUG("Collada schema version is 1.4.n"); } - else if (!::strncmp(version,"1.3",3)) { - mFormat = FV_1_3_n; + else if (!::strncmp(version, "1.3", 3)) { + mFormat = FV_1_3_n; ASSIMP_LOG_DEBUG("Collada schema version is 1.3.n"); } } ReadStructure(); - } else + } + else { - ASSIMP_LOG_DEBUG_F( "Ignoring global element <", mReader->getNodeName(), ">." ); + ASSIMP_LOG_DEBUG_F("Ignoring global element <", mReader->getNodeName(), ">."); SkipElement(); } - } else + } + else { // skip everything else silently } @@ -181,47 +255,47 @@ void ColladaParser::ReadContents() // Reads the structure of the file void ColladaParser::ReadStructure() { - while( mReader->read()) + while (mReader->read()) { // beginning of elements - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "asset")) + if (IsElement("asset")) ReadAssetInfo(); - else if( IsElement( "library_animations")) + else if (IsElement("library_animations")) ReadAnimationLibrary(); - else if (IsElement("library_animation_clips")) - ReadAnimationClipLibrary(); - else if( IsElement( "library_controllers")) + else if (IsElement("library_animation_clips")) + ReadAnimationClipLibrary(); + else if (IsElement("library_controllers")) ReadControllerLibrary(); - else if( IsElement( "library_images")) + else if (IsElement("library_images")) ReadImageLibrary(); - else if( IsElement( "library_materials")) + else if (IsElement("library_materials")) ReadMaterialLibrary(); - else if( IsElement( "library_effects")) + else if (IsElement("library_effects")) ReadEffectLibrary(); - else if( IsElement( "library_geometries")) + else if (IsElement("library_geometries")) ReadGeometryLibrary(); - else if( IsElement( "library_visual_scenes")) + else if (IsElement("library_visual_scenes")) ReadSceneLibrary(); - else if( IsElement( "library_lights")) + else if (IsElement("library_lights")) ReadLightLibrary(); - else if( IsElement( "library_cameras")) + else if (IsElement("library_cameras")) ReadCameraLibrary(); - else if( IsElement( "library_nodes")) + else if (IsElement("library_nodes")) ReadSceneNode(NULL); /* some hacking to reuse this piece of code */ - else if( IsElement( "scene")) + else if (IsElement("scene")) ReadScene(); else SkipElement(); } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { break; } } - PostProcessRootAnimations(); + PostProcessRootAnimations(); PostProcessControllers(); } @@ -229,136 +303,208 @@ void ColladaParser::ReadStructure() // Reads asset information such as coordinate system information and legal blah void ColladaParser::ReadAssetInfo() { - if( mReader->isEmptyElement()) + if (mReader->isEmptyElement()) return; - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "unit")) + if (IsElement("unit")) { // read unit data from the element's attributes - const int attrIndex = TestAttribute( "meter"); + const int attrIndex = TestAttribute("meter"); if (attrIndex == -1) { mUnitSize = 1.f; } else { - mUnitSize = mReader->getAttributeValueAsFloat( attrIndex); + mUnitSize = mReader->getAttributeValueAsFloat(attrIndex); } // consume the trailing stuff - if( !mReader->isEmptyElement()) + if (!mReader->isEmptyElement()) SkipElement(); } - else if( IsElement( "up_axis")) + else if (IsElement("up_axis")) { // read content, strip whitespace, compare const char* content = GetTextContent(); - if( strncmp( content, "X_UP", 4) == 0) + if (strncmp(content, "X_UP", 4) == 0) mUpDirection = UP_X; - else if( strncmp( content, "Z_UP", 4) == 0) + else if (strncmp(content, "Z_UP", 4) == 0) mUpDirection = UP_Z; else mUpDirection = UP_Y; // check element end - TestClosing( "up_axis"); - } else + TestClosing("up_axis"); + } + else if (IsElement("contributor")) { - SkipElement(); + ReadContributorInfo(); + } + else + { + ReadMetaDataItem(mAssetMetaData); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "asset") != 0) - ThrowException( "Expected end of element."); + if (strcmp(mReader->getNodeName(), "asset") != 0) + ThrowException("Expected end of element."); break; } } } +// ------------------------------------------------------------------------------------------------ +// Reads the contributor info +void ColladaParser::ReadContributorInfo() +{ + if (mReader->isEmptyElement()) + return; + + while (mReader->read()) + { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) + { + ReadMetaDataItem(mAssetMetaData); + } + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + { + if (strcmp(mReader->getNodeName(), "contributor") != 0) + ThrowException("Expected end of element."); + break; + } + } +} + +// ------------------------------------------------------------------------------------------------ +// Reads a single string metadata item +void ColladaParser::ReadMetaDataItem(StringMetaData &metadata) +{ + // Metadata such as created, keywords, subject etc + const char* key_char = mReader->getNodeName(); + if (key_char != nullptr) + { + const std::string key_str(key_char); + const char* value_char = TestTextContent(); + if (value_char != nullptr) + { + std::string camel_key_str = key_str; + ToCamelCase(camel_key_str); + aiString aistr; + aistr.Set(value_char); + metadata.emplace(camel_key_str, aistr); + } + TestClosing(key_str.c_str()); + } + else + SkipElement(); +} + +// ------------------------------------------------------------------------------------------------ +// Convert underscore_seperated to CamelCase: "authoring_tool" becomes "AuthoringTool" +void ColladaParser::ToCamelCase(std::string &text) +{ + if (text.empty()) + return; + // Capitalise first character + text[0] = ToUpper(text[0]); + for (auto it = text.begin(); it != text.end(); /*iterated below*/) + { + if ((*it) == '_') + { + it = text.erase(it); + if (it != text.end()) + (*it) = ToUpper(*it); + } + else + ++it; + } +} + // ------------------------------------------------------------------------------------------------ // Reads the animation clips void ColladaParser::ReadAnimationClipLibrary() { - if (mReader->isEmptyElement()) - return; + if (mReader->isEmptyElement()) + return; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("animation_clip")) - { - // optional name given as an attribute - std::string animName; - int indexName = TestAttribute("name"); - int indexID = TestAttribute("id"); - if (indexName >= 0) - animName = mReader->getAttributeValue(indexName); - else if (indexID >= 0) - animName = mReader->getAttributeValue(indexID); - else - animName = std::string("animation_") + to_string(mAnimationClipLibrary.size()); + while (mReader->read()) + { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) + { + if (IsElement("animation_clip")) + { + // optional name given as an attribute + std::string animName; + int indexName = TestAttribute("name"); + int indexID = TestAttribute("id"); + if (indexName >= 0) + animName = mReader->getAttributeValue(indexName); + else if (indexID >= 0) + animName = mReader->getAttributeValue(indexID); + else + animName = std::string("animation_") + to_string(mAnimationClipLibrary.size()); - std::pair > clip; + std::pair > clip; - clip.first = animName; + clip.first = animName; - while (mReader->read()) - { - if (mReader->getNodeType() == irr::io::EXN_ELEMENT) - { - if (IsElement("instance_animation")) - { - int indexUrl = TestAttribute("url"); - if (indexUrl >= 0) - { - const char* url = mReader->getAttributeValue(indexUrl); - if (url[0] != '#') - ThrowException("Unknown reference format"); + while (mReader->read()) + { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) + { + if (IsElement("instance_animation")) + { + int indexUrl = TestAttribute("url"); + if (indexUrl >= 0) + { + const char* url = mReader->getAttributeValue(indexUrl); + if (url[0] != '#') + ThrowException("Unknown reference format"); - url++; + url++; - clip.second.push_back(url); - } - } - else - { - // ignore the rest - SkipElement(); - } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { - if (strcmp(mReader->getNodeName(), "animation_clip") != 0) - ThrowException("Expected end of element."); + clip.second.push_back(url); + } + } + else + { + // ignore the rest + SkipElement(); + } + } + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + { + if (strcmp(mReader->getNodeName(), "animation_clip") != 0) + ThrowException("Expected end of element."); - break; - } - } + break; + } + } - if (clip.second.size() > 0) - { - mAnimationClipLibrary.push_back(clip); - } - } - else - { - // ignore the rest - SkipElement(); - } - } - else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - { - if (strcmp(mReader->getNodeName(), "library_animation_clips") != 0) - ThrowException("Expected end of element."); + if (clip.second.size() > 0) + { + mAnimationClipLibrary.push_back(clip); + } + } + else + { + // ignore the rest + SkipElement(); + } + } + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + { + if (strcmp(mReader->getNodeName(), "library_animation_clips") != 0) + ThrowException("Expected end of element."); - break; - } - } + break; + } + } } void ColladaParser::PostProcessControllers() @@ -367,11 +513,11 @@ void ColladaParser::PostProcessControllers() for (ControllerLibrary::iterator it = mControllerLibrary.begin(); it != mControllerLibrary.end(); ++it) { meshId = it->second.mMeshId; ControllerLibrary::iterator findItr = mControllerLibrary.find(meshId); - while(findItr != mControllerLibrary.end()) { + while (findItr != mControllerLibrary.end()) { meshId = findItr->second.mMeshId; findItr = mControllerLibrary.find(meshId); } - + it->second.mMeshId = meshId; } } @@ -380,43 +526,43 @@ void ColladaParser::PostProcessControllers() // Re-build animations from animation clip library, if present, otherwise combine single-channel animations void ColladaParser::PostProcessRootAnimations() { - if (mAnimationClipLibrary.size() > 0) - { - Animation temp; + if (mAnimationClipLibrary.size() > 0) + { + Animation temp; - for (AnimationClipLibrary::iterator it = mAnimationClipLibrary.begin(); it != mAnimationClipLibrary.end(); ++it) - { - std::string clipName = it->first; + for (AnimationClipLibrary::iterator it = mAnimationClipLibrary.begin(); it != mAnimationClipLibrary.end(); ++it) + { + std::string clipName = it->first; - Animation *clip = new Animation(); - clip->mName = clipName; + Animation *clip = new Animation(); + clip->mName = clipName; - temp.mSubAnims.push_back(clip); + temp.mSubAnims.push_back(clip); - for (std::vector::iterator a = it->second.begin(); a != it->second.end(); ++a) - { - std::string animationID = *a; + for (std::vector::iterator a = it->second.begin(); a != it->second.end(); ++a) + { + std::string animationID = *a; - AnimationLibrary::iterator animation = mAnimationLibrary.find(animationID); + AnimationLibrary::iterator animation = mAnimationLibrary.find(animationID); - if (animation != mAnimationLibrary.end()) - { - Animation *pSourceAnimation = animation->second; + if (animation != mAnimationLibrary.end()) + { + Animation *pSourceAnimation = animation->second; - pSourceAnimation->CollectChannelsRecursively(clip->mChannels); - } - } - } + pSourceAnimation->CollectChannelsRecursively(clip->mChannels); + } + } + } - mAnims = temp; + mAnims = temp; - // Ensure no double deletes. - temp.mSubAnims.clear(); - } - else - { - mAnims.CombineSingleChannelAnimations(); - } + // Ensure no double deletes. + temp.mSubAnims.clear(); + } + else + { + mAnims.CombineSingleChannelAnimations(); + } } // ------------------------------------------------------------------------------------------------ @@ -426,24 +572,25 @@ void ColladaParser::ReadAnimationLibrary() if (mReader->isEmptyElement()) return; - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "animation")) + if (IsElement("animation")) { // delegate the reading. Depending on the inner elements it will be a container or a anim channel - ReadAnimation( &mAnims); - } else + ReadAnimation(&mAnims); + } + else { // ignore the rest SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "library_animations") != 0) - ThrowException( "Expected end of element."); + if (strcmp(mReader->getNodeName(), "library_animations") != 0) + ThrowException("Expected end of element."); break; } @@ -452,9 +599,9 @@ void ColladaParser::ReadAnimationLibrary() // ------------------------------------------------------------------------------------------------ // Reads an animation into the given parent structure -void ColladaParser::ReadAnimation( Collada::Animation* pParent) +void ColladaParser::ReadAnimation(Collada::Animation* pParent) { - if( mReader->isEmptyElement()) + if (mReader->isEmptyElement()) return; // an element may be a container for grouping sub-elements or an animation channel @@ -466,68 +613,68 @@ void ColladaParser::ReadAnimation( Collada::Animation* pParent) // optional name given as an attribute std::string animName; - std::string animID; - int indexName = TestAttribute( "name"); - int indexID = TestAttribute( "id"); + std::string animID; + int indexName = TestAttribute("name"); + int indexID = TestAttribute("id"); - if (indexID >= 0) - animID = mReader->getAttributeValue(indexID); + if (indexID >= 0) + animID = mReader->getAttributeValue(indexID); - if( indexName >= 0) - animName = mReader->getAttributeValue( indexName); - else if( indexID >= 0) + if (indexName >= 0) + animName = mReader->getAttributeValue(indexName); + else if (indexID >= 0) animName = animID; else animName = "animation"; - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { // we have subanimations - if( IsElement( "animation")) + if (IsElement("animation")) { // create container from our element - if( !anim) + if (!anim) { anim = new Animation; anim->mName = animName; - pParent->mSubAnims.push_back( anim); + pParent->mSubAnims.push_back(anim); } // recurse into the subelement - ReadAnimation( anim); + ReadAnimation(anim); } - else if( IsElement( "source")) + else if (IsElement("source")) { // possible animation data - we'll never know. Better store it ReadSource(); } - else if( IsElement( "sampler")) + else if (IsElement("sampler")) { // read the ID to assign the corresponding collada channel afterwards. - int indexID = GetAttribute( "id"); - std::string id = mReader->getAttributeValue( indexID); - ChannelMap::iterator newChannel = channels.insert( std::make_pair( id, AnimationChannel())).first; + int indexID = GetAttribute("id"); + std::string id = mReader->getAttributeValue(indexID); + ChannelMap::iterator newChannel = channels.insert(std::make_pair(id, AnimationChannel())).first; // have it read into a channel - ReadAnimationSampler( newChannel->second); + ReadAnimationSampler(newChannel->second); } - else if( IsElement( "channel")) + else if (IsElement("channel")) { // the binding element whose whole purpose is to provide the target to animate // Thanks, Collada! A directly posted information would have been too simple, I guess. // Better add another indirection to that! Can't have enough of those. - int indexTarget = GetAttribute( "target"); - int indexSource = GetAttribute( "source"); - const char* sourceId = mReader->getAttributeValue( indexSource); - if( sourceId[0] == '#') + int indexTarget = GetAttribute("target"); + int indexSource = GetAttribute("source"); + const char* sourceId = mReader->getAttributeValue(indexSource); + if (sourceId[0] == '#') sourceId++; - ChannelMap::iterator cit = channels.find( sourceId); - if( cit != channels.end()) - cit->second.mTarget = mReader->getAttributeValue( indexTarget); + ChannelMap::iterator cit = channels.find(sourceId); + if (cit != channels.end()) + cit->second.mTarget = mReader->getAttributeValue(indexTarget); - if( !mReader->isEmptyElement()) + if (!mReader->isEmptyElement()) SkipElement(); } else @@ -536,24 +683,24 @@ void ColladaParser::ReadAnimation( Collada::Animation* pParent) SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "animation") != 0) - ThrowException( "Expected end of element."); + if (strcmp(mReader->getNodeName(), "animation") != 0) + ThrowException("Expected end of element."); break; } } // it turned out to have channels - add them - if( !channels.empty()) + if (!channels.empty()) { - // FIXME: Is this essentially doing the same as "single-anim-node" codepath in - // ColladaLoader::StoreAnimations? For now, this has been deferred to after - // all animations and all clips have been read. Due to handling of - // this cannot be done here, as the channel owner - // is lost, and some exporters make up animations by referring to multiple - // single-channel animations from an . + // FIXME: Is this essentially doing the same as "single-anim-node" codepath in + // ColladaLoader::StoreAnimations? For now, this has been deferred to after + // all animations and all clips have been read. Due to handling of + // this cannot be done here, as the channel owner + // is lost, and some exporters make up animations by referring to multiple + // single-channel animations from an . /* // special filtering for stupid exporters packing each channel into a separate animation if( channels.size() == 1) @@ -563,53 +710,53 @@ void ColladaParser::ReadAnimation( Collada::Animation* pParent) */ { // else create the animation, if not done yet, and store the channels - if( !anim) + if (!anim) { anim = new Animation; anim->mName = animName; - pParent->mSubAnims.push_back( anim); + pParent->mSubAnims.push_back(anim); } - for( ChannelMap::const_iterator it = channels.begin(); it != channels.end(); ++it) - anim->mChannels.push_back( it->second); + for (ChannelMap::const_iterator it = channels.begin(); it != channels.end(); ++it) + anim->mChannels.push_back(it->second); - if (indexID >= 0) - { - mAnimationLibrary[animID] = anim; - } + if (indexID >= 0) + { + mAnimationLibrary[animID] = anim; + } } } } // ------------------------------------------------------------------------------------------------ // Reads an animation sampler into the given anim channel -void ColladaParser::ReadAnimationSampler( Collada::AnimationChannel& pChannel) +void ColladaParser::ReadAnimationSampler(Collada::AnimationChannel& pChannel) { - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "input")) + if (IsElement("input")) { - int indexSemantic = GetAttribute( "semantic"); - const char* semantic = mReader->getAttributeValue( indexSemantic); - int indexSource = GetAttribute( "source"); - const char* source = mReader->getAttributeValue( indexSource); - if( source[0] != '#') - ThrowException( "Unsupported URL format"); + int indexSemantic = GetAttribute("semantic"); + const char* semantic = mReader->getAttributeValue(indexSemantic); + int indexSource = GetAttribute("source"); + const char* source = mReader->getAttributeValue(indexSource); + if (source[0] != '#') + ThrowException("Unsupported URL format"); source++; - if( strcmp( semantic, "INPUT") == 0) + if (strcmp(semantic, "INPUT") == 0) pChannel.mSourceTimes = source; - else if( strcmp( semantic, "OUTPUT") == 0) + else if (strcmp(semantic, "OUTPUT") == 0) pChannel.mSourceValues = source; - else if( strcmp( semantic, "IN_TANGENT") == 0) + else if (strcmp(semantic, "IN_TANGENT") == 0) pChannel.mInTanValues = source; - else if( strcmp( semantic, "OUT_TANGENT") == 0) + else if (strcmp(semantic, "OUT_TANGENT") == 0) pChannel.mOutTanValues = source; - else if( strcmp( semantic, "INTERPOLATION") == 0) + else if (strcmp(semantic, "INTERPOLATION") == 0) pChannel.mInterpolationValues = source; - if( !mReader->isEmptyElement()) + if (!mReader->isEmptyElement()) SkipElement(); } else @@ -618,10 +765,10 @@ void ColladaParser::ReadAnimationSampler( Collada::AnimationChannel& pChannel) SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "sampler") != 0) - ThrowException( "Expected end of element."); + if (strcmp(mReader->getNodeName(), "sampler") != 0) + ThrowException("Expected end of element."); break; } @@ -635,31 +782,32 @@ void ColladaParser::ReadControllerLibrary() if (mReader->isEmptyElement()) return; - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "controller")) + if (IsElement("controller")) { // read ID. Ask the spec if it's necessary or optional... you might be surprised. - int attrID = GetAttribute( "id"); - std::string id = mReader->getAttributeValue( attrID); + int attrID = GetAttribute("id"); + std::string id = mReader->getAttributeValue(attrID); // create an entry and store it in the library under its ID mControllerLibrary[id] = Controller(); // read on from there - ReadController( mControllerLibrary[id]); - } else + ReadController(mControllerLibrary[id]); + } + else { // ignore the rest SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "library_controllers") != 0) - ThrowException( "Expected end of element."); + if (strcmp(mReader->getNodeName(), "library_controllers") != 0) + ThrowException("Expected end of element."); break; } @@ -668,17 +816,17 @@ void ColladaParser::ReadControllerLibrary() // ------------------------------------------------------------------------------------------------ // Reads a controller into the given mesh structure -void ColladaParser::ReadController( Collada::Controller& pController) +void ColladaParser::ReadController(Collada::Controller& pController) { // initial values pController.mType = Skin; pController.mMethod = Normalized; - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { // two types of controllers: "skin" and "morph". Only the first one is relevant, we skip the other - if( IsElement( "morph")) + if (IsElement("morph")) { pController.mType = Morph; int baseIndex = GetAttribute("source"); @@ -690,47 +838,47 @@ void ColladaParser::ReadController( Collada::Controller& pController) pController.mMethod = Relative; } } - else if( IsElement( "skin")) + else if (IsElement("skin")) { // read the mesh it refers to. According to the spec this could also be another // controller, but I refuse to implement every single idea they've come up with - int sourceIndex = GetAttribute( "source"); - pController.mMeshId = mReader->getAttributeValue( sourceIndex) + 1; + int sourceIndex = GetAttribute("source"); + pController.mMeshId = mReader->getAttributeValue(sourceIndex) + 1; } - else if( IsElement( "bind_shape_matrix")) + else if (IsElement("bind_shape_matrix")) { // content is 16 floats to define a matrix... it seems to be important for some models const char* content = GetTextContent(); // read the 16 floats - for( unsigned int a = 0; a < 16; a++) + for (unsigned int a = 0; a < 16; a++) { // read a number - content = fast_atoreal_move( content, pController.mBindShapeMatrix[a]); + content = fast_atoreal_move(content, pController.mBindShapeMatrix[a]); // skip whitespace after it - SkipSpacesAndLineEnd( &content); + SkipSpacesAndLineEnd(&content); } - TestClosing( "bind_shape_matrix"); + TestClosing("bind_shape_matrix"); } - else if( IsElement( "source")) + else if (IsElement("source")) { // data array - we have specialists to handle this ReadSource(); } - else if( IsElement( "joints")) + else if (IsElement("joints")) { - ReadControllerJoints( pController); + ReadControllerJoints(pController); } - else if( IsElement( "vertex_weights")) + else if (IsElement("vertex_weights")) { - ReadControllerWeights( pController); + ReadControllerWeights(pController); } - else if ( IsElement( "targets" )) + else if (IsElement("targets")) { while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if ( IsElement( "input")) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("input")) { int semanticsIndex = GetAttribute("semantic"); int sourceIndex = GetAttribute("source"); @@ -744,11 +892,12 @@ void ColladaParser::ReadController( Collada::Controller& pController) pController.mMorphWeight = source + 1; } } - } else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "targets") == 0) + } + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "targets") == 0) break; else - ThrowException( "Expected end of element."); + ThrowException("Expected end of element."); } } } @@ -758,47 +907,47 @@ void ColladaParser::ReadController( Collada::Controller& pController) SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "controller") == 0) + if (strcmp(mReader->getNodeName(), "controller") == 0) break; - else if( strcmp( mReader->getNodeName(), "skin") != 0 && strcmp( mReader->getNodeName(), "morph") != 0) - ThrowException( "Expected end of element."); + else if (strcmp(mReader->getNodeName(), "skin") != 0 && strcmp(mReader->getNodeName(), "morph") != 0) + ThrowException("Expected end of element."); } } } // ------------------------------------------------------------------------------------------------ // Reads the joint definitions for the given controller -void ColladaParser::ReadControllerJoints( Collada::Controller& pController) +void ColladaParser::ReadControllerJoints(Collada::Controller& pController) { - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { // Input channels for joint data. Two possible semantics: "JOINT" and "INV_BIND_MATRIX" - if( IsElement( "input")) + if (IsElement("input")) { - int indexSemantic = GetAttribute( "semantic"); - const char* attrSemantic = mReader->getAttributeValue( indexSemantic); - int indexSource = GetAttribute( "source"); - const char* attrSource = mReader->getAttributeValue( indexSource); + int indexSemantic = GetAttribute("semantic"); + const char* attrSemantic = mReader->getAttributeValue(indexSemantic); + int indexSource = GetAttribute("source"); + const char* attrSource = mReader->getAttributeValue(indexSource); // local URLS always start with a '#'. We don't support global URLs - if( attrSource[0] != '#') - ThrowException( format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of data element" ); + if (attrSource[0] != '#') + ThrowException(format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of data element"); attrSource++; // parse source URL to corresponding source - if( strcmp( attrSemantic, "JOINT") == 0) + if (strcmp(attrSemantic, "JOINT") == 0) pController.mJointNameSource = attrSource; - else if( strcmp( attrSemantic, "INV_BIND_MATRIX") == 0) + else if (strcmp(attrSemantic, "INV_BIND_MATRIX") == 0) pController.mJointOffsetMatrixSource = attrSource; else - ThrowException( format() << "Unknown semantic \"" << attrSemantic << "\" in data element" ); + ThrowException(format() << "Unknown semantic \"" << attrSemantic << "\" in data element"); // skip inner data, if present - if( !mReader->isEmptyElement()) + if (!mReader->isEmptyElement()) SkipElement(); } else @@ -807,10 +956,10 @@ void ColladaParser::ReadControllerJoints( Collada::Controller& pController) SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "joints") != 0) - ThrowException( "Expected end of element."); + if (strcmp(mReader->getNodeName(), "joints") != 0) + ThrowException("Expected end of element."); break; } @@ -819,85 +968,85 @@ void ColladaParser::ReadControllerJoints( Collada::Controller& pController) // ------------------------------------------------------------------------------------------------ // Reads the joint weights for the given controller -void ColladaParser::ReadControllerWeights( Collada::Controller& pController) +void ColladaParser::ReadControllerWeights(Collada::Controller& pController) { // read vertex count from attributes and resize the array accordingly - int indexCount = GetAttribute( "count"); - size_t vertexCount = (size_t) mReader->getAttributeValueAsInt( indexCount); - pController.mWeightCounts.resize( vertexCount); + int indexCount = GetAttribute("count"); + size_t vertexCount = (size_t)mReader->getAttributeValueAsInt(indexCount); + pController.mWeightCounts.resize(vertexCount); - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { // Input channels for weight data. Two possible semantics: "JOINT" and "WEIGHT" - if( IsElement( "input") && vertexCount > 0 ) + if (IsElement("input") && vertexCount > 0) { InputChannel channel; - int indexSemantic = GetAttribute( "semantic"); - const char* attrSemantic = mReader->getAttributeValue( indexSemantic); - int indexSource = GetAttribute( "source"); - const char* attrSource = mReader->getAttributeValue( indexSource); - int indexOffset = TestAttribute( "offset"); - if( indexOffset >= 0) - channel.mOffset = mReader->getAttributeValueAsInt( indexOffset); + int indexSemantic = GetAttribute("semantic"); + const char* attrSemantic = mReader->getAttributeValue(indexSemantic); + int indexSource = GetAttribute("source"); + const char* attrSource = mReader->getAttributeValue(indexSource); + int indexOffset = TestAttribute("offset"); + if (indexOffset >= 0) + channel.mOffset = mReader->getAttributeValueAsInt(indexOffset); // local URLS always start with a '#'. We don't support global URLs - if( attrSource[0] != '#') - ThrowException( format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of data element" ); + if (attrSource[0] != '#') + ThrowException(format() << "Unsupported URL format in \"" << attrSource << "\" in source attribute of data element"); channel.mAccessor = attrSource + 1; // parse source URL to corresponding source - if( strcmp( attrSemantic, "JOINT") == 0) + if (strcmp(attrSemantic, "JOINT") == 0) pController.mWeightInputJoints = channel; - else if( strcmp( attrSemantic, "WEIGHT") == 0) + else if (strcmp(attrSemantic, "WEIGHT") == 0) pController.mWeightInputWeights = channel; else - ThrowException( format() << "Unknown semantic \"" << attrSemantic << "\" in data element" ); + ThrowException(format() << "Unknown semantic \"" << attrSemantic << "\" in data element"); // skip inner data, if present - if( !mReader->isEmptyElement()) + if (!mReader->isEmptyElement()) SkipElement(); } - else if( IsElement( "vcount") && vertexCount > 0 ) + else if (IsElement("vcount") && vertexCount > 0) { // read weight count per vertex const char* text = GetTextContent(); size_t numWeights = 0; - for( std::vector::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) + for (std::vector::iterator it = pController.mWeightCounts.begin(); it != pController.mWeightCounts.end(); ++it) { - if( *text == 0) - ThrowException( "Out of data while reading "); + if (*text == 0) + ThrowException("Out of data while reading "); - *it = strtoul10( text, &text); + *it = strtoul10(text, &text); numWeights += *it; - SkipSpacesAndLineEnd( &text); + SkipSpacesAndLineEnd(&text); } - TestClosing( "vcount"); + TestClosing("vcount"); // reserve weight count - pController.mWeights.resize( numWeights); + pController.mWeights.resize(numWeights); } - else if( IsElement( "v") && vertexCount > 0 ) + else if (IsElement("v") && vertexCount > 0) { // read JointIndex - WeightIndex pairs const char* text = GetTextContent(); - for( std::vector< std::pair >::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) + for (std::vector< std::pair >::iterator it = pController.mWeights.begin(); it != pController.mWeights.end(); ++it) { - if( *text == 0) - ThrowException( "Out of data while reading "); - it->first = strtoul10( text, &text); - SkipSpacesAndLineEnd( &text); - if( *text == 0) - ThrowException( "Out of data while reading "); - it->second = strtoul10( text, &text); - SkipSpacesAndLineEnd( &text); + if (*text == 0) + ThrowException("Out of data while reading "); + it->first = strtoul10(text, &text); + SkipSpacesAndLineEnd(&text); + if (*text == 0) + ThrowException("Out of data while reading "); + it->second = strtoul10(text, &text); + SkipSpacesAndLineEnd(&text); } - TestClosing( "v"); + TestClosing("v"); } else { @@ -905,10 +1054,10 @@ void ColladaParser::ReadControllerWeights( Collada::Controller& pController) SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "vertex_weights") != 0) - ThrowException( "Expected end of element."); + if (strcmp(mReader->getNodeName(), "vertex_weights") != 0) + ThrowException("Expected end of element."); break; } @@ -919,32 +1068,33 @@ void ColladaParser::ReadControllerWeights( Collada::Controller& pController) // Reads the image library contents void ColladaParser::ReadImageLibrary() { - if( mReader->isEmptyElement()) + if (mReader->isEmptyElement()) return; - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "image")) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("image")) { // read ID. Another entry which is "optional" by design but obligatory in reality - int attrID = GetAttribute( "id"); - std::string id = mReader->getAttributeValue( attrID); + int attrID = GetAttribute("id"); + std::string id = mReader->getAttributeValue(attrID); // create an entry and store it in the library under its ID mImageLibrary[id] = Image(); // read on from there - ReadImage( mImageLibrary[id]); - } else + ReadImage(mImageLibrary[id]); + } + else { // ignore the rest SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "library_images") != 0) - ThrowException( "Expected end of element."); + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "library_images") != 0) + ThrowException("Expected end of element."); break; } @@ -953,16 +1103,16 @@ void ColladaParser::ReadImageLibrary() // ------------------------------------------------------------------------------------------------ // Reads an image entry into the given image -void ColladaParser::ReadImage( Collada::Image& pImage) +void ColladaParser::ReadImage(Collada::Image& pImage) { - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT){ + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { // Need to run different code paths here, depending on the Collada XSD version if (IsElement("image")) { SkipElement(); } - else if( IsElement( "init_from")) + else if (IsElement("init_from")) { if (mFormat == FV_1_4_n) { @@ -971,7 +1121,7 @@ void ColladaParser::ReadImage( Collada::Image& pImage) // element content is filename - hopefully const char* sz = TestTextContent(); if (sz)pImage.mFileName = sz; - TestClosing( "init_from"); + TestClosing("init_from"); } if (!pImage.mFileName.length()) { pImage.mFileName = "unknown_texture"; @@ -999,14 +1149,14 @@ void ColladaParser::ReadImage( Collada::Image& pImage) } else if (mFormat == FV_1_5_n) { - if( IsElement( "ref")) + if (IsElement("ref")) { // element content is filename - hopefully const char* sz = TestTextContent(); if (sz)pImage.mFileName = sz; - TestClosing( "ref"); + TestClosing("ref"); } - else if( IsElement( "hex") && !pImage.mFileName.length()) + else if (IsElement("hex") && !pImage.mFileName.length()) { // embedded image. get format const int attrib = TestAttribute("format"); @@ -1021,12 +1171,12 @@ void ColladaParser::ReadImage( Collada::Image& pImage) const char* cur = data; while (!IsSpaceOrNewLine(*cur)) cur++; - const unsigned int size = (unsigned int)(cur-data) * 2; + const unsigned int size = (unsigned int)(cur - data) * 2; pImage.mImageData.resize(size); - for (unsigned int i = 0; i < size;++i) - pImage.mImageData[i] = HexOctetToDecimal(data+(i<<1)); + for (unsigned int i = 0; i < size; ++i) + pImage.mImageData[i] = HexOctetToDecimal(data + (i << 1)); - TestClosing( "hex"); + TestClosing("hex"); } } else @@ -1035,8 +1185,8 @@ void ColladaParser::ReadImage( Collada::Image& pImage) SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "image") == 0) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "image") == 0) break; } } @@ -1046,36 +1196,36 @@ void ColladaParser::ReadImage( Collada::Image& pImage) // Reads the material library void ColladaParser::ReadMaterialLibrary() { - if( mReader->isEmptyElement()) + if (mReader->isEmptyElement()) return; std::map names; - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "material")) + if (IsElement("material")) { // read ID. By now you probably know my opinion about this "specification" - int attrID = GetAttribute( "id"); - std::string id = mReader->getAttributeValue( attrID); + int attrID = GetAttribute("id"); + std::string id = mReader->getAttributeValue(attrID); std::string name; int attrName = TestAttribute("name"); if (attrName >= 0) - name = mReader->getAttributeValue( attrName); + name = mReader->getAttributeValue(attrName); // create an entry and store it in the library under its ID mMaterialLibrary[id] = Material(); - if( !name.empty()) + if (!name.empty()) { - std::map::iterator it = names.find( name); - if( it != names.end()) + std::map::iterator it = names.find(name); + if (it != names.end()) { std::ostringstream strStream; strStream << ++it->second; - name.append( " " + strStream.str()); + name.append(" " + strStream.str()); } else { @@ -1085,17 +1235,18 @@ void ColladaParser::ReadMaterialLibrary() mMaterialLibrary[id].mName = name; } - ReadMaterial( mMaterialLibrary[id]); - } else + ReadMaterial(mMaterialLibrary[id]); + } + else { // ignore the rest SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "library_materials") != 0) - ThrowException( "Expected end of element."); + if (strcmp(mReader->getNodeName(), "library_materials") != 0) + ThrowException("Expected end of element."); break; } @@ -1106,30 +1257,31 @@ void ColladaParser::ReadMaterialLibrary() // Reads the light library void ColladaParser::ReadLightLibrary() { - if( mReader->isEmptyElement()) + if (mReader->isEmptyElement()) return; - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "light")) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("light")) { // read ID. By now you probably know my opinion about this "specification" - int attrID = GetAttribute( "id"); - std::string id = mReader->getAttributeValue( attrID); + int attrID = GetAttribute("id"); + std::string id = mReader->getAttributeValue(attrID); // create an entry and store it in the library under its ID ReadLight(mLightLibrary[id] = Light()); - } else + } + else { // ignore the rest SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "library_lights") != 0) - ThrowException( "Expected end of element."); + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "library_lights") != 0) + ThrowException("Expected end of element."); break; } @@ -1140,35 +1292,36 @@ void ColladaParser::ReadLightLibrary() // Reads the camera library void ColladaParser::ReadCameraLibrary() { - if( mReader->isEmptyElement()) + if (mReader->isEmptyElement()) return; - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "camera")) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("camera")) { // read ID. By now you probably know my opinion about this "specification" - int attrID = GetAttribute( "id"); - std::string id = mReader->getAttributeValue( attrID); + int attrID = GetAttribute("id"); + std::string id = mReader->getAttributeValue(attrID); // create an entry and store it in the library under its ID Camera& cam = mCameraLibrary[id]; - attrID = TestAttribute( "name"); + attrID = TestAttribute("name"); if (attrID != -1) - cam.mName = mReader->getAttributeValue( attrID); + cam.mName = mReader->getAttributeValue(attrID); ReadCamera(cam); - } else + } + else { // ignore the rest SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "library_cameras") != 0) - ThrowException( "Expected end of element."); + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "library_cameras") != 0) + ThrowException("Expected end of element."); break; } @@ -1177,34 +1330,35 @@ void ColladaParser::ReadCameraLibrary() // ------------------------------------------------------------------------------------------------ // Reads a material entry into the given material -void ColladaParser::ReadMaterial( Collada::Material& pMaterial) +void ColladaParser::ReadMaterial(Collada::Material& pMaterial) { - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (IsElement("material")) { SkipElement(); } - else if( IsElement( "instance_effect")) + else if (IsElement("instance_effect")) { // referred effect by URL - int attrUrl = GetAttribute( "url"); - const char* url = mReader->getAttributeValue( attrUrl); - if( url[0] != '#') - ThrowException( "Unknown reference format"); + int attrUrl = GetAttribute("url"); + const char* url = mReader->getAttributeValue(attrUrl); + if (url[0] != '#') + ThrowException("Unknown reference format"); - pMaterial.mEffect = url+1; + pMaterial.mEffect = url + 1; SkipElement(); - } else + } + else { // ignore the rest SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "material") != 0) - ThrowException( "Expected end of element."); + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "material") != 0) + ThrowException("Expected end of element."); break; } @@ -1213,11 +1367,11 @@ void ColladaParser::ReadMaterial( Collada::Material& pMaterial) // ------------------------------------------------------------------------------------------------ // Reads a light entry into the given light -void ColladaParser::ReadLight( Collada::Light& pLight) +void ColladaParser::ReadLight(Collada::Light& pLight) { - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (IsElement("light")) { SkipElement(); } @@ -1237,16 +1391,16 @@ void ColladaParser::ReadLight( Collada::Light& pLight) // text content contains 3 floats const char* content = GetTextContent(); - content = fast_atoreal_move( content, (ai_real&)pLight.mColor.r); - SkipSpacesAndLineEnd( &content); + content = fast_atoreal_move(content, (ai_real&)pLight.mColor.r); + SkipSpacesAndLineEnd(&content); - content = fast_atoreal_move( content, (ai_real&)pLight.mColor.g); - SkipSpacesAndLineEnd( &content); + content = fast_atoreal_move(content, (ai_real&)pLight.mColor.g); + SkipSpacesAndLineEnd(&content); - content = fast_atoreal_move( content, (ai_real&)pLight.mColor.b); - SkipSpacesAndLineEnd( &content); + content = fast_atoreal_move(content, (ai_real&)pLight.mColor.b); + SkipSpacesAndLineEnd(&content); - TestClosing( "color"); + TestClosing("color"); } else if (IsElement("constant_attenuation")) { pLight.mAttConstant = ReadFloatFromTextContent(); @@ -1298,8 +1452,8 @@ void ColladaParser::ReadLight( Collada::Light& pLight) TestClosing("decay_falloff"); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "light") == 0) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "light") == 0) break; } } @@ -1307,11 +1461,11 @@ void ColladaParser::ReadLight( Collada::Light& pLight) // ------------------------------------------------------------------------------------------------ // Reads a camera entry into the given light -void ColladaParser::ReadCamera( Collada::Camera& pCamera) +void ColladaParser::ReadCamera(Collada::Camera& pCamera) { - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { if (IsElement("camera")) { SkipElement(); } @@ -1339,8 +1493,8 @@ void ColladaParser::ReadCamera( Collada::Camera& pCamera) TestClosing("zfar"); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "camera") == 0) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "camera") == 0) break; } } @@ -1354,28 +1508,29 @@ void ColladaParser::ReadEffectLibrary() return; } - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "effect")) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("effect")) { // read ID. Do I have to repeat my ranting about "optional" attributes? - int attrID = GetAttribute( "id"); - std::string id = mReader->getAttributeValue( attrID); + int attrID = GetAttribute("id"); + std::string id = mReader->getAttributeValue(attrID); // create an entry and store it in the library under its ID mEffectLibrary[id] = Effect(); // read on from there - ReadEffect( mEffectLibrary[id]); - } else + ReadEffect(mEffectLibrary[id]); + } + else { // ignore the rest SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "library_effects") != 0) - ThrowException( "Expected end of element."); + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "library_effects") != 0) + ThrowException("Expected end of element."); break; } @@ -1384,22 +1539,22 @@ void ColladaParser::ReadEffectLibrary() // ------------------------------------------------------------------------------------------------ // Reads an effect entry into the given effect -void ColladaParser::ReadEffect( Collada::Effect& pEffect) +void ColladaParser::ReadEffect(Collada::Effect& pEffect) { // for the moment we don't support any other type of effect. - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "profile_COMMON")) - ReadEffectProfileCommon( pEffect); + if (IsElement("profile_COMMON")) + ReadEffectProfileCommon(pEffect); else SkipElement(); } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "effect") != 0) - ThrowException( "Expected end of element."); + if (strcmp(mReader->getNodeName(), "effect") != 0) + ThrowException("Expected end of element."); break; } @@ -1408,107 +1563,107 @@ void ColladaParser::ReadEffect( Collada::Effect& pEffect) // ------------------------------------------------------------------------------------------------ // Reads an COMMON effect profile -void ColladaParser::ReadEffectProfileCommon( Collada::Effect& pEffect) +void ColladaParser::ReadEffectProfileCommon(Collada::Effect& pEffect) { - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "newparam")) { + if (IsElement("newparam")) { // save ID - int attrSID = GetAttribute( "sid"); - std::string sid = mReader->getAttributeValue( attrSID); + int attrSID = GetAttribute("sid"); + std::string sid = mReader->getAttributeValue(attrSID); pEffect.mParams[sid] = EffectParam(); - ReadEffectParam( pEffect.mParams[sid]); + ReadEffectParam(pEffect.mParams[sid]); } - else if( IsElement( "technique") || IsElement( "extra")) + else if (IsElement("technique") || IsElement("extra")) { // just syntactic sugar } - else if( mFormat == FV_1_4_n && IsElement( "image")) + else if (mFormat == FV_1_4_n && IsElement("image")) { // read ID. Another entry which is "optional" by design but obligatory in reality - int attrID = GetAttribute( "id"); - std::string id = mReader->getAttributeValue( attrID); + int attrID = GetAttribute("id"); + std::string id = mReader->getAttributeValue(attrID); // create an entry and store it in the library under its ID mImageLibrary[id] = Image(); // read on from there - ReadImage( mImageLibrary[id]); + ReadImage(mImageLibrary[id]); } /* Shading modes */ - else if( IsElement( "phong")) + else if (IsElement("phong")) pEffect.mShadeType = Shade_Phong; - else if( IsElement( "constant")) + else if (IsElement("constant")) pEffect.mShadeType = Shade_Constant; - else if( IsElement( "lambert")) + else if (IsElement("lambert")) pEffect.mShadeType = Shade_Lambert; - else if( IsElement( "blinn")) + else if (IsElement("blinn")) pEffect.mShadeType = Shade_Blinn; /* Color + texture properties */ - else if( IsElement( "emission")) - ReadEffectColor( pEffect.mEmissive, pEffect.mTexEmissive); - else if( IsElement( "ambient")) - ReadEffectColor( pEffect.mAmbient, pEffect.mTexAmbient); - else if( IsElement( "diffuse")) - ReadEffectColor( pEffect.mDiffuse, pEffect.mTexDiffuse); - else if( IsElement( "specular")) - ReadEffectColor( pEffect.mSpecular, pEffect.mTexSpecular); - else if( IsElement( "reflective")) { - ReadEffectColor( pEffect.mReflective, pEffect.mTexReflective); + else if (IsElement("emission")) + ReadEffectColor(pEffect.mEmissive, pEffect.mTexEmissive); + else if (IsElement("ambient")) + ReadEffectColor(pEffect.mAmbient, pEffect.mTexAmbient); + else if (IsElement("diffuse")) + ReadEffectColor(pEffect.mDiffuse, pEffect.mTexDiffuse); + else if (IsElement("specular")) + ReadEffectColor(pEffect.mSpecular, pEffect.mTexSpecular); + else if (IsElement("reflective")) { + ReadEffectColor(pEffect.mReflective, pEffect.mTexReflective); } - else if( IsElement( "transparent")) { + else if (IsElement("transparent")) { pEffect.mHasTransparency = true; const char* opaque = mReader->getAttributeValueSafe("opaque"); - if(::strcmp(opaque, "RGB_ZERO") == 0 || ::strcmp(opaque, "RGB_ONE") == 0) { + if (::strcmp(opaque, "RGB_ZERO") == 0 || ::strcmp(opaque, "RGB_ONE") == 0) { pEffect.mRGBTransparency = true; } // In RGB_ZERO mode, the transparency is interpreted in reverse, go figure... - if(::strcmp(opaque, "RGB_ZERO") == 0 || ::strcmp(opaque, "A_ZERO") == 0) { - pEffect.mInvertTransparency = true; - } + if (::strcmp(opaque, "RGB_ZERO") == 0 || ::strcmp(opaque, "A_ZERO") == 0) { + pEffect.mInvertTransparency = true; + } - ReadEffectColor( pEffect.mTransparent,pEffect.mTexTransparent); + ReadEffectColor(pEffect.mTransparent, pEffect.mTexTransparent); } - else if( IsElement( "shininess")) - ReadEffectFloat( pEffect.mShininess); - else if( IsElement( "reflectivity")) - ReadEffectFloat( pEffect.mReflectivity); + else if (IsElement("shininess")) + ReadEffectFloat(pEffect.mShininess); + else if (IsElement("reflectivity")) + ReadEffectFloat(pEffect.mReflectivity); /* Single scalar properties */ - else if( IsElement( "transparency")) - ReadEffectFloat( pEffect.mTransparency); - else if( IsElement( "index_of_refraction")) - ReadEffectFloat( pEffect.mRefractIndex); + else if (IsElement("transparency")) + ReadEffectFloat(pEffect.mTransparency); + else if (IsElement("index_of_refraction")) + ReadEffectFloat(pEffect.mRefractIndex); // GOOGLEEARTH/OKINO extensions // ------------------------------------------------------- - else if( IsElement( "double_sided")) + else if (IsElement("double_sided")) pEffect.mDoubleSided = ReadBoolFromTextContent(); // FCOLLADA extensions // ------------------------------------------------------- - else if( IsElement( "bump")) { + else if (IsElement("bump")) { aiColor4D dummy; - ReadEffectColor( dummy,pEffect.mTexBump); + ReadEffectColor(dummy, pEffect.mTexBump); } // MAX3D extensions // ------------------------------------------------------- - else if( IsElement( "wireframe")) { + else if (IsElement("wireframe")) { pEffect.mWireframe = ReadBoolFromTextContent(); - TestClosing( "wireframe"); + TestClosing("wireframe"); } - else if( IsElement( "faceted")) { + else if (IsElement("faceted")) { pEffect.mFaceted = ReadBoolFromTextContent(); - TestClosing( "faceted"); + TestClosing("faceted"); } else { @@ -1516,8 +1671,8 @@ void ColladaParser::ReadEffectProfileCommon( Collada::Effect& pEffect) SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "profile_COMMON") == 0) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "profile_COMMON") == 0) { break; } @@ -1527,92 +1682,92 @@ void ColladaParser::ReadEffectProfileCommon( Collada::Effect& pEffect) // ------------------------------------------------------------------------------------------------ // Read texture wrapping + UV transform settings from a profile==Maya chunk -void ColladaParser::ReadSamplerProperties( Sampler& out ) +void ColladaParser::ReadSamplerProperties(Sampler& out) { if (mReader->isEmptyElement()) { return; } - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { // MAYA extensions // ------------------------------------------------------- - if( IsElement( "wrapU")) { + if (IsElement("wrapU")) { out.mWrapU = ReadBoolFromTextContent(); - TestClosing( "wrapU"); + TestClosing("wrapU"); } - else if( IsElement( "wrapV")) { + else if (IsElement("wrapV")) { out.mWrapV = ReadBoolFromTextContent(); - TestClosing( "wrapV"); + TestClosing("wrapV"); } - else if( IsElement( "mirrorU")) { + else if (IsElement("mirrorU")) { out.mMirrorU = ReadBoolFromTextContent(); - TestClosing( "mirrorU"); + TestClosing("mirrorU"); } - else if( IsElement( "mirrorV")) { + else if (IsElement("mirrorV")) { out.mMirrorV = ReadBoolFromTextContent(); - TestClosing( "mirrorV"); + TestClosing("mirrorV"); } - else if( IsElement( "repeatU")) { + else if (IsElement("repeatU")) { out.mTransform.mScaling.x = ReadFloatFromTextContent(); - TestClosing( "repeatU"); + TestClosing("repeatU"); } - else if( IsElement( "repeatV")) { + else if (IsElement("repeatV")) { out.mTransform.mScaling.y = ReadFloatFromTextContent(); - TestClosing( "repeatV"); + TestClosing("repeatV"); } - else if( IsElement( "offsetU")) { + else if (IsElement("offsetU")) { out.mTransform.mTranslation.x = ReadFloatFromTextContent(); - TestClosing( "offsetU"); + TestClosing("offsetU"); } - else if( IsElement( "offsetV")) { + else if (IsElement("offsetV")) { out.mTransform.mTranslation.y = ReadFloatFromTextContent(); - TestClosing( "offsetV"); + TestClosing("offsetV"); } - else if( IsElement( "rotateUV")) { + else if (IsElement("rotateUV")) { out.mTransform.mRotation = ReadFloatFromTextContent(); - TestClosing( "rotateUV"); + TestClosing("rotateUV"); } - else if( IsElement( "blend_mode")) { + else if (IsElement("blend_mode")) { const char* sz = GetTextContent(); // http://www.feelingsoftware.com/content/view/55/72/lang,en/ // NONE, OVER, IN, OUT, ADD, SUBTRACT, MULTIPLY, DIFFERENCE, LIGHTEN, DARKEN, SATURATE, DESATURATE and ILLUMINATE - if (0 == ASSIMP_strincmp(sz,"ADD",3)) + if (0 == ASSIMP_strincmp(sz, "ADD", 3)) out.mOp = aiTextureOp_Add; - else if (0 == ASSIMP_strincmp(sz,"SUBTRACT",8)) + else if (0 == ASSIMP_strincmp(sz, "SUBTRACT", 8)) out.mOp = aiTextureOp_Subtract; - else if (0 == ASSIMP_strincmp(sz,"MULTIPLY",8)) + else if (0 == ASSIMP_strincmp(sz, "MULTIPLY", 8)) out.mOp = aiTextureOp_Multiply; - else { + else { ASSIMP_LOG_WARN("Collada: Unsupported MAYA texture blend mode"); } - TestClosing( "blend_mode"); + TestClosing("blend_mode"); } // OKINO extensions // ------------------------------------------------------- - else if( IsElement( "weighting")) { + else if (IsElement("weighting")) { out.mWeighting = ReadFloatFromTextContent(); - TestClosing( "weighting"); + TestClosing("weighting"); } - else if( IsElement( "mix_with_previous_layer")) { + else if (IsElement("mix_with_previous_layer")) { out.mMixWithPrevious = ReadFloatFromTextContent(); - TestClosing( "mix_with_previous_layer"); + TestClosing("mix_with_previous_layer"); } // MAX3D extensions // ------------------------------------------------------- - else if( IsElement( "amount")) { + else if (IsElement("amount")) { out.mWeighting = ReadFloatFromTextContent(); - TestClosing( "amount"); + TestClosing("amount"); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "technique") == 0) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "technique") == 0) break; } } @@ -1620,7 +1775,7 @@ void ColladaParser::ReadSamplerProperties( Sampler& out ) // ------------------------------------------------------------------------------------------------ // Reads an effect entry containing a color or a texture defining that color -void ColladaParser::ReadEffectColor( aiColor4D& pColor, Sampler& pSampler) +void ColladaParser::ReadEffectColor(aiColor4D& pColor, Sampler& pSampler) { if (mReader->isEmptyElement()) return; @@ -1628,64 +1783,64 @@ void ColladaParser::ReadEffectColor( aiColor4D& pColor, Sampler& pSampler) // Save current element name const std::string curElem = mReader->getNodeName(); - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "color")) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("color")) { // text content contains 4 floats const char* content = GetTextContent(); - content = fast_atoreal_move( content, (ai_real&)pColor.r); - SkipSpacesAndLineEnd( &content); + content = fast_atoreal_move(content, (ai_real&)pColor.r); + SkipSpacesAndLineEnd(&content); - content = fast_atoreal_move( content, (ai_real&)pColor.g); - SkipSpacesAndLineEnd( &content); + content = fast_atoreal_move(content, (ai_real&)pColor.g); + SkipSpacesAndLineEnd(&content); - content = fast_atoreal_move( content, (ai_real&)pColor.b); - SkipSpacesAndLineEnd( &content); + content = fast_atoreal_move(content, (ai_real&)pColor.b); + SkipSpacesAndLineEnd(&content); - content = fast_atoreal_move( content, (ai_real&)pColor.a); - SkipSpacesAndLineEnd( &content); - TestClosing( "color"); + content = fast_atoreal_move(content, (ai_real&)pColor.a); + SkipSpacesAndLineEnd(&content); + TestClosing("color"); } - else if( IsElement( "texture")) + else if (IsElement("texture")) { // get name of source texture/sampler - int attrTex = GetAttribute( "texture"); - pSampler.mName = mReader->getAttributeValue( attrTex); + int attrTex = GetAttribute("texture"); + pSampler.mName = mReader->getAttributeValue(attrTex); // get name of UV source channel. Specification demands it to be there, but some exporters // don't write it. It will be the default UV channel in case it's missing. - attrTex = TestAttribute( "texcoord"); - if( attrTex >= 0 ) - pSampler.mUVChannel = mReader->getAttributeValue( attrTex); + attrTex = TestAttribute("texcoord"); + if (attrTex >= 0) + pSampler.mUVChannel = mReader->getAttributeValue(attrTex); //SkipElement(); // as we've read texture, the color needs to be 1,1,1,1 pColor = aiColor4D(1.f, 1.f, 1.f, 1.f); } - else if( IsElement( "technique")) + else if (IsElement("technique")) { - const int _profile = GetAttribute( "profile"); - const char* profile = mReader->getAttributeValue( _profile ); + const int _profile = GetAttribute("profile"); + const char* profile = mReader->getAttributeValue(_profile); // Some extensions are quite useful ... ReadSamplerProperties processes // several extensions in MAYA, OKINO and MAX3D profiles. - if (!::strcmp(profile,"MAYA") || !::strcmp(profile,"MAX3D") || !::strcmp(profile,"OKINO")) + if (!::strcmp(profile, "MAYA") || !::strcmp(profile, "MAX3D") || !::strcmp(profile, "OKINO")) { // get more information on this sampler ReadSamplerProperties(pSampler); } else SkipElement(); } - else if( !IsElement( "extra")) + else if (!IsElement("extra")) { // ignore the rest SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END){ + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { if (mReader->getNodeName() == curElem) break; } @@ -1694,26 +1849,27 @@ void ColladaParser::ReadEffectColor( aiColor4D& pColor, Sampler& pSampler) // ------------------------------------------------------------------------------------------------ // Reads an effect entry containing a float -void ColladaParser::ReadEffectFloat( ai_real& pFloat) +void ColladaParser::ReadEffectFloat(ai_real& pFloat) { - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT){ - if( IsElement( "float")) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("float")) { // text content contains a single floats const char* content = GetTextContent(); - content = fast_atoreal_move( content, pFloat); - SkipSpacesAndLineEnd( &content); + content = fast_atoreal_move(content, pFloat); + SkipSpacesAndLineEnd(&content); - TestClosing( "float"); - } else + TestClosing("float"); + } + else { // ignore the rest SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END){ + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { break; } } @@ -1721,54 +1877,55 @@ void ColladaParser::ReadEffectFloat( ai_real& pFloat) // ------------------------------------------------------------------------------------------------ // Reads an effect parameter specification of any kind -void ColladaParser::ReadEffectParam( Collada::EffectParam& pParam) +void ColladaParser::ReadEffectParam(Collada::EffectParam& pParam) { - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "surface")) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("surface")) { // image ID given inside tags - TestOpening( "init_from"); + TestOpening("init_from"); const char* content = GetTextContent(); pParam.mType = Param_Surface; pParam.mReference = content; - TestClosing( "init_from"); + TestClosing("init_from"); // don't care for remaining stuff - SkipElement( "surface"); + SkipElement("surface"); } - else if( IsElement( "sampler2D") && (FV_1_4_n == mFormat || FV_1_3_n == mFormat)) + else if (IsElement("sampler2D") && (FV_1_4_n == mFormat || FV_1_3_n == mFormat)) { // surface ID is given inside tags - TestOpening( "source"); + TestOpening("source"); const char* content = GetTextContent(); pParam.mType = Param_Sampler; pParam.mReference = content; - TestClosing( "source"); + TestClosing("source"); // don't care for remaining stuff - SkipElement( "sampler2D"); + SkipElement("sampler2D"); } - else if( IsElement( "sampler2D")) + else if (IsElement("sampler2D")) { // surface ID is given inside tags - TestOpening( "instance_image"); + TestOpening("instance_image"); int attrURL = GetAttribute("url"); - const char* url = mReader->getAttributeValue( attrURL); - if( url[0] != '#') - ThrowException( "Unsupported URL format in instance_image"); + const char* url = mReader->getAttributeValue(attrURL); + if (url[0] != '#') + ThrowException("Unsupported URL format in instance_image"); url++; pParam.mType = Param_Sampler; pParam.mReference = url; - SkipElement( "sampler2D"); - } else + SkipElement("sampler2D"); + } + else { // ignore unknown element SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { break; } } @@ -1778,18 +1935,18 @@ void ColladaParser::ReadEffectParam( Collada::EffectParam& pParam) // Reads the geometry library contents void ColladaParser::ReadGeometryLibrary() { - if( mReader->isEmptyElement()) + if (mReader->isEmptyElement()) return; - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "geometry")) + if (IsElement("geometry")) { // read ID. Another entry which is "optional" by design but obligatory in reality - int indexID = GetAttribute( "id"); - std::string id = mReader->getAttributeValue( indexID); + int indexID = GetAttribute("id"); + std::string id = mReader->getAttributeValue(indexID); // TODO: (thom) support SIDs // ai_assert( TestAttribute( "sid") == -1); @@ -1800,23 +1957,24 @@ void ColladaParser::ReadGeometryLibrary() // read the mesh name if it exists const int nameIndex = TestAttribute("name"); - if(nameIndex != -1) + if (nameIndex != -1) { mesh->mName = mReader->getAttributeValue(nameIndex); } // read on from there - ReadGeometry( mesh); - } else + ReadGeometry(mesh); + } + else { // ignore the rest SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "library_geometries") != 0) - ThrowException( "Expected end of element."); + if (strcmp(mReader->getNodeName(), "library_geometries") != 0) + ThrowException("Expected end of element."); break; } @@ -1825,29 +1983,30 @@ void ColladaParser::ReadGeometryLibrary() // ------------------------------------------------------------------------------------------------ // Reads a geometry from the geometry library. -void ColladaParser::ReadGeometry( Collada::Mesh* pMesh) +void ColladaParser::ReadGeometry(Collada::Mesh* pMesh) { - if( mReader->isEmptyElement()) + if (mReader->isEmptyElement()) return; - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "mesh")) + if (IsElement("mesh")) { // read on from there - ReadMesh( pMesh); - } else + ReadMesh(pMesh); + } + else { // ignore the rest SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "geometry") != 0) - ThrowException( "Expected end of element."); + if (strcmp(mReader->getNodeName(), "geometry") != 0) + ThrowException("Expected end of element."); break; } @@ -1856,50 +2015,52 @@ void ColladaParser::ReadGeometry( Collada::Mesh* pMesh) // ------------------------------------------------------------------------------------------------ // Reads a mesh from the geometry library -void ColladaParser::ReadMesh( Mesh* pMesh) +void ColladaParser::ReadMesh(Mesh* pMesh) { - if( mReader->isEmptyElement()) + if (mReader->isEmptyElement()) return; - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "source")) + if (IsElement("source")) { // we have professionals dealing with this ReadSource(); } - else if( IsElement( "vertices")) + else if (IsElement("vertices")) { // read per-vertex mesh data - ReadVertexData( pMesh); + ReadVertexData(pMesh); } - else if( IsElement( "triangles") || IsElement( "lines") || IsElement( "linestrips") - || IsElement( "polygons") || IsElement( "polylist") || IsElement( "trifans") || IsElement( "tristrips")) + else if (IsElement("triangles") || IsElement("lines") || IsElement("linestrips") + || IsElement("polygons") || IsElement("polylist") || IsElement("trifans") || IsElement("tristrips")) { // read per-index mesh data and faces setup - ReadIndexData( pMesh); - } else + ReadIndexData(pMesh); + } + else { // ignore the restf SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "technique_common") == 0) + if (strcmp(mReader->getNodeName(), "technique_common") == 0) { // end of another meaningless element - read over it } - else if( strcmp( mReader->getNodeName(), "mesh") == 0) + else if (strcmp(mReader->getNodeName(), "mesh") == 0) { // end of element - we're done here break; - } else + } + else { // everything else should be punished - ThrowException( "Expected end of element."); + ThrowException("Expected end of element."); } } } @@ -1909,44 +2070,46 @@ void ColladaParser::ReadMesh( Mesh* pMesh) // Reads a source element void ColladaParser::ReadSource() { - int indexID = GetAttribute( "id"); - std::string sourceID = mReader->getAttributeValue( indexID); + int indexID = GetAttribute("id"); + std::string sourceID = mReader->getAttributeValue(indexID); - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "float_array") || IsElement( "IDREF_array") || IsElement( "Name_array")) + if (IsElement("float_array") || IsElement("IDREF_array") || IsElement("Name_array")) { ReadDataArray(); } - else if( IsElement( "technique_common")) + else if (IsElement("technique_common")) { // I don't care for your profiles } - else if( IsElement( "accessor")) + else if (IsElement("accessor")) { - ReadAccessor( sourceID); - } else + ReadAccessor(sourceID); + } + else { // ignore the rest SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "source") == 0) + if (strcmp(mReader->getNodeName(), "source") == 0) { // end of - we're done break; } - else if( strcmp( mReader->getNodeName(), "technique_common") == 0) + else if (strcmp(mReader->getNodeName(), "technique_common") == 0) { // end of another meaningless element - read over it - } else + } + else { // everything else should be punished - ThrowException( "Expected end of element."); + ThrowException("Expected end of element."); } } } @@ -1958,83 +2121,84 @@ void ColladaParser::ReadDataArray() { std::string elmName = mReader->getNodeName(); bool isStringArray = (elmName == "IDREF_array" || elmName == "Name_array"); - bool isEmptyElement = mReader->isEmptyElement(); + bool isEmptyElement = mReader->isEmptyElement(); // read attributes - int indexID = GetAttribute( "id"); - std::string id = mReader->getAttributeValue( indexID); - int indexCount = GetAttribute( "count"); - unsigned int count = (unsigned int) mReader->getAttributeValueAsInt( indexCount); + int indexID = GetAttribute("id"); + std::string id = mReader->getAttributeValue(indexID); + int indexCount = GetAttribute("count"); + unsigned int count = (unsigned int)mReader->getAttributeValueAsInt(indexCount); const char* content = TestTextContent(); - // read values and store inside an array in the data library - mDataLibrary[id] = Data(); - Data& data = mDataLibrary[id]; - data.mIsStringArray = isStringArray; + // read values and store inside an array in the data library + mDataLibrary[id] = Data(); + Data& data = mDataLibrary[id]; + data.mIsStringArray = isStringArray; - // some exporters write empty data arrays, but we need to conserve them anyways because others might reference them - if (content) - { - if( isStringArray) + // some exporters write empty data arrays, but we need to conserve them anyways because others might reference them + if (content) + { + if (isStringArray) { - data.mStrings.reserve( count); + data.mStrings.reserve(count); std::string s; - for( unsigned int a = 0; a < count; a++) + for (unsigned int a = 0; a < count; a++) { - if( *content == 0) - ThrowException( "Expected more values while reading IDREF_array contents."); + if (*content == 0) + ThrowException("Expected more values while reading IDREF_array contents."); s.clear(); - while( !IsSpaceOrNewLine( *content)) + while (!IsSpaceOrNewLine(*content)) s += *content++; - data.mStrings.push_back( s); + data.mStrings.push_back(s); - SkipSpacesAndLineEnd( &content); + SkipSpacesAndLineEnd(&content); } - } else + } + else { - data.mValues.reserve( count); + data.mValues.reserve(count); - for( unsigned int a = 0; a < count; a++) + for (unsigned int a = 0; a < count; a++) { - if( *content == 0) - ThrowException( "Expected more values while reading float_array contents."); + if (*content == 0) + ThrowException("Expected more values while reading float_array contents."); ai_real value; // read a number - content = fast_atoreal_move( content, value); - data.mValues.push_back( value); + content = fast_atoreal_move(content, value); + data.mValues.push_back(value); // skip whitespace after it - SkipSpacesAndLineEnd( &content); + SkipSpacesAndLineEnd(&content); } } } - // test for closing tag - if( !isEmptyElement ) - TestClosing( elmName.c_str()); + // test for closing tag + if (!isEmptyElement) + TestClosing(elmName.c_str()); } // ------------------------------------------------------------------------------------------------ // Reads an accessor and stores it in the global library -void ColladaParser::ReadAccessor( const std::string& pID) +void ColladaParser::ReadAccessor(const std::string& pID) { // read accessor attributes - int attrSource = GetAttribute( "source"); - const char* source = mReader->getAttributeValue( attrSource); - if( source[0] != '#') - ThrowException( format() << "Unknown reference format in url \"" << source << "\" in source attribute of element." ); - int attrCount = GetAttribute( "count"); - unsigned int count = (unsigned int) mReader->getAttributeValueAsInt( attrCount); - int attrOffset = TestAttribute( "offset"); + int attrSource = GetAttribute("source"); + const char* source = mReader->getAttributeValue(attrSource); + if (source[0] != '#') + ThrowException(format() << "Unknown reference format in url \"" << source << "\" in source attribute of element."); + int attrCount = GetAttribute("count"); + unsigned int count = (unsigned int)mReader->getAttributeValueAsInt(attrCount); + int attrOffset = TestAttribute("offset"); unsigned int offset = 0; - if( attrOffset > -1) - offset = (unsigned int) mReader->getAttributeValueAsInt( attrOffset); - int attrStride = TestAttribute( "stride"); + if (attrOffset > -1) + offset = (unsigned int)mReader->getAttributeValueAsInt(attrOffset); + int attrStride = TestAttribute("stride"); unsigned int stride = 1; - if( attrStride > -1) - stride = (unsigned int) mReader->getAttributeValueAsInt( attrStride); + if (attrStride > -1) + stride = (unsigned int)mReader->getAttributeValueAsInt(attrStride); // store in the library under the given ID mAccessorLibrary[pID] = Accessor(); @@ -2042,77 +2206,78 @@ void ColladaParser::ReadAccessor( const std::string& pID) acc.mCount = count; acc.mOffset = offset; acc.mStride = stride; - acc.mSource = source+1; // ignore the leading '#' + acc.mSource = source + 1; // ignore the leading '#' acc.mSize = 0; // gets incremented with every param // and read the components - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "param")) + if (IsElement("param")) { // read data param - int attrName = TestAttribute( "name"); + int attrName = TestAttribute("name"); std::string name; - if( attrName > -1) + if (attrName > -1) { - name = mReader->getAttributeValue( attrName); + name = mReader->getAttributeValue(attrName); // analyse for common type components and store it's sub-offset in the corresponding field /* Cartesian coordinates */ - if( name == "X") acc.mSubOffset[0] = acc.mParams.size(); - else if( name == "Y") acc.mSubOffset[1] = acc.mParams.size(); - else if( name == "Z") acc.mSubOffset[2] = acc.mParams.size(); + if (name == "X") acc.mSubOffset[0] = acc.mParams.size(); + else if (name == "Y") acc.mSubOffset[1] = acc.mParams.size(); + else if (name == "Z") acc.mSubOffset[2] = acc.mParams.size(); /* RGBA colors */ - else if( name == "R") acc.mSubOffset[0] = acc.mParams.size(); - else if( name == "G") acc.mSubOffset[1] = acc.mParams.size(); - else if( name == "B") acc.mSubOffset[2] = acc.mParams.size(); - else if( name == "A") acc.mSubOffset[3] = acc.mParams.size(); + else if (name == "R") acc.mSubOffset[0] = acc.mParams.size(); + else if (name == "G") acc.mSubOffset[1] = acc.mParams.size(); + else if (name == "B") acc.mSubOffset[2] = acc.mParams.size(); + else if (name == "A") acc.mSubOffset[3] = acc.mParams.size(); /* UVWQ (STPQ) texture coordinates */ - else if( name == "S") acc.mSubOffset[0] = acc.mParams.size(); - else if( name == "T") acc.mSubOffset[1] = acc.mParams.size(); - else if( name == "P") acc.mSubOffset[2] = acc.mParams.size(); - // else if( name == "Q") acc.mSubOffset[3] = acc.mParams.size(); - /* 4D uv coordinates are not supported in Assimp */ + else if (name == "S") acc.mSubOffset[0] = acc.mParams.size(); + else if (name == "T") acc.mSubOffset[1] = acc.mParams.size(); + else if (name == "P") acc.mSubOffset[2] = acc.mParams.size(); + // else if( name == "Q") acc.mSubOffset[3] = acc.mParams.size(); + /* 4D uv coordinates are not supported in Assimp */ - /* Generic extra data, interpreted as UV data, too*/ - else if( name == "U") acc.mSubOffset[0] = acc.mParams.size(); - else if( name == "V") acc.mSubOffset[1] = acc.mParams.size(); + /* Generic extra data, interpreted as UV data, too*/ + else if (name == "U") acc.mSubOffset[0] = acc.mParams.size(); + else if (name == "V") acc.mSubOffset[1] = acc.mParams.size(); //else // DefaultLogger::get()->warn( format() << "Unknown accessor parameter \"" << name << "\". Ignoring data channel." ); } // read data type - int attrType = TestAttribute( "type"); - if( attrType > -1) + int attrType = TestAttribute("type"); + if (attrType > -1) { // for the moment we only distinguish between a 4x4 matrix and anything else. // TODO: (thom) I don't have a spec here at work. Check if there are other multi-value types // which should be tested for here. - std::string type = mReader->getAttributeValue( attrType); - if( type == "float4x4") + std::string type = mReader->getAttributeValue(attrType); + if (type == "float4x4") acc.mSize += 16; else acc.mSize += 1; } - acc.mParams.push_back( name); + acc.mParams.push_back(name); // skip remaining stuff of this element, if any SkipElement(); - } else + } + else { - ThrowException( format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag " ); + ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag "); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "accessor") != 0) - ThrowException( "Expected end of element."); + if (strcmp(mReader->getNodeName(), "accessor") != 0) + ThrowException("Expected end of element."); break; } } @@ -2120,29 +2285,30 @@ void ColladaParser::ReadAccessor( const std::string& pID) // ------------------------------------------------------------------------------------------------ // Reads input declarations of per-vertex mesh data into the given mesh -void ColladaParser::ReadVertexData( Mesh* pMesh) +void ColladaParser::ReadVertexData(Mesh* pMesh) { // extract the ID of the element. Not that we care, but to catch strange referencing schemes we should warn about - int attrID= GetAttribute( "id"); - pMesh->mVertexID = mReader->getAttributeValue( attrID); + int attrID = GetAttribute("id"); + pMesh->mVertexID = mReader->getAttributeValue(attrID); // a number of elements - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "input")) + if (IsElement("input")) { - ReadInputChannel( pMesh->mPerVertexData); - } else + ReadInputChannel(pMesh->mPerVertexData); + } + else { - ThrowException( format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag " ); + ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag "); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "vertices") != 0) - ThrowException( "Expected end of element."); + if (strcmp(mReader->getNodeName(), "vertices") != 0) + ThrowException("Expected end of element."); break; } @@ -2151,79 +2317,79 @@ void ColladaParser::ReadVertexData( Mesh* pMesh) // ------------------------------------------------------------------------------------------------ // Reads input declarations of per-index mesh data into the given mesh -void ColladaParser::ReadIndexData( Mesh* pMesh) +void ColladaParser::ReadIndexData(Mesh* pMesh) { std::vector vcount; std::vector perIndexData; // read primitive count from the attribute - int attrCount = GetAttribute( "count"); - size_t numPrimitives = (size_t) mReader->getAttributeValueAsInt( attrCount); + int attrCount = GetAttribute("count"); + size_t numPrimitives = (size_t)mReader->getAttributeValueAsInt(attrCount); // some mesh types (e.g. tristrips) don't specify primitive count upfront, // so we need to sum up the actual number of primitives while we read the

-tags size_t actualPrimitives = 0; // material subgroup - int attrMaterial = TestAttribute( "material"); + int attrMaterial = TestAttribute("material"); SubMesh subgroup; - if( attrMaterial > -1) - subgroup.mMaterial = mReader->getAttributeValue( attrMaterial); + if (attrMaterial > -1) + subgroup.mMaterial = mReader->getAttributeValue(attrMaterial); // distinguish between polys and triangles std::string elementName = mReader->getNodeName(); PrimitiveType primType = Prim_Invalid; - if( IsElement( "lines")) + if (IsElement("lines")) primType = Prim_Lines; - else if( IsElement( "linestrips")) + else if (IsElement("linestrips")) primType = Prim_LineStrip; - else if( IsElement( "polygons")) + else if (IsElement("polygons")) primType = Prim_Polygon; - else if( IsElement( "polylist")) + else if (IsElement("polylist")) primType = Prim_Polylist; - else if( IsElement( "triangles")) + else if (IsElement("triangles")) primType = Prim_Triangles; - else if( IsElement( "trifans")) + else if (IsElement("trifans")) primType = Prim_TriFans; - else if( IsElement( "tristrips")) + else if (IsElement("tristrips")) primType = Prim_TriStrips; - ai_assert( primType != Prim_Invalid); + ai_assert(primType != Prim_Invalid); // also a number of elements, but in addition a

primitive collection and probably index counts for all primitives - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "input")) + if (IsElement("input")) { - ReadInputChannel( perIndexData); + ReadInputChannel(perIndexData); } - else if( IsElement( "vcount")) + else if (IsElement("vcount")) { - if( !mReader->isEmptyElement()) + if (!mReader->isEmptyElement()) { if (numPrimitives) // It is possible to define a mesh without any primitives { // case - specifies the number of indices for each polygon const char* content = GetTextContent(); - vcount.reserve( numPrimitives); - for( unsigned int a = 0; a < numPrimitives; a++) + vcount.reserve(numPrimitives); + for (unsigned int a = 0; a < numPrimitives; a++) { - if( *content == 0) - ThrowException( "Expected more values while reading contents."); + if (*content == 0) + ThrowException("Expected more values while reading contents."); // read a number - vcount.push_back( (size_t) strtoul10( content, &content)); + vcount.push_back((size_t)strtoul10(content, &content)); // skip whitespace after it - SkipSpacesAndLineEnd( &content); + SkipSpacesAndLineEnd(&content); } } - TestClosing( "vcount"); + TestClosing("vcount"); } } - else if( IsElement( "p")) + else if (IsElement("p")) { - if( !mReader->isEmptyElement()) + if (!mReader->isEmptyElement()) { // now here the actual fun starts - these are the indices to construct the mesh data from actualPrimitives += ReadPrimitives(pMesh, perIndexData, numPrimitives, vcount, primType); @@ -2232,23 +2398,25 @@ void ColladaParser::ReadIndexData( Mesh* pMesh) else if (IsElement("extra")) { SkipElement("extra"); - } else if ( IsElement("ph")) { + } + else if (IsElement("ph")) { SkipElement("ph"); - } else { - ThrowException( format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <" << elementName << ">" ); + } + else { + ThrowException(format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <" << elementName << ">"); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( mReader->getNodeName() != elementName) - ThrowException( format() << "Expected end of <" << elementName << "> element." ); + if (mReader->getNodeName() != elementName) + ThrowException(format() << "Expected end of <" << elementName << "> element."); break; } } #ifdef ASSIMP_BUILD_DEBUG - if (primType != Prim_TriFans && primType != Prim_TriStrips && primType != Prim_LineStrip && + if (primType != Prim_TriFans && primType != Prim_TriStrips && primType != Prim_LineStrip && primType != Prim_Lines) { // this is ONLY to workaround a bug in SketchUp 15.3.331 where it writes the wrong 'count' when it writes out the 'lines'. ai_assert(actualPrimitives == numPrimitives); } @@ -2261,42 +2429,42 @@ void ColladaParser::ReadIndexData( Mesh* pMesh) // ------------------------------------------------------------------------------------------------ // Reads a single input channel element and stores it in the given array, if valid -void ColladaParser::ReadInputChannel( std::vector& poChannels) +void ColladaParser::ReadInputChannel(std::vector& poChannels) { InputChannel channel; // read semantic - int attrSemantic = GetAttribute( "semantic"); - std::string semantic = mReader->getAttributeValue( attrSemantic); - channel.mType = GetTypeForSemantic( semantic); + int attrSemantic = GetAttribute("semantic"); + std::string semantic = mReader->getAttributeValue(attrSemantic); + channel.mType = GetTypeForSemantic(semantic); // read source - int attrSource = GetAttribute( "source"); - const char* source = mReader->getAttributeValue( attrSource); - if( source[0] != '#') - ThrowException( format() << "Unknown reference format in url \"" << source << "\" in source attribute of element." ); - channel.mAccessor = source+1; // skipping the leading #, hopefully the remaining text is the accessor ID only + int attrSource = GetAttribute("source"); + const char* source = mReader->getAttributeValue(attrSource); + if (source[0] != '#') + ThrowException(format() << "Unknown reference format in url \"" << source << "\" in source attribute of element."); + channel.mAccessor = source + 1; // skipping the leading #, hopefully the remaining text is the accessor ID only // read index offset, if per-index - int attrOffset = TestAttribute( "offset"); - if( attrOffset > -1) - channel.mOffset = mReader->getAttributeValueAsInt( attrOffset); + int attrOffset = TestAttribute("offset"); + if (attrOffset > -1) + channel.mOffset = mReader->getAttributeValueAsInt(attrOffset); // read set if texture coordinates - if(channel.mType == IT_Texcoord || channel.mType == IT_Color){ + if (channel.mType == IT_Texcoord || channel.mType == IT_Color) { int attrSet = TestAttribute("set"); - if(attrSet > -1){ - attrSet = mReader->getAttributeValueAsInt( attrSet); - if(attrSet < 0) - ThrowException( format() << "Invalid index \"" << (attrSet) << "\" in set attribute of element" ); + if (attrSet > -1) { + attrSet = mReader->getAttributeValueAsInt(attrSet); + if (attrSet < 0) + ThrowException(format() << "Invalid index \"" << (attrSet) << "\" in set attribute of element"); channel.mIndex = attrSet; } } // store, if valid type - if( channel.mType != IT_Invalid) - poChannels.push_back( channel); + if (channel.mType != IT_Invalid) + poChannels.push_back(channel); // skip remaining stuff of this element, if any SkipElement(); @@ -2304,116 +2472,118 @@ void ColladaParser::ReadInputChannel( std::vector& poChannels) // ------------------------------------------------------------------------------------------------ // Reads a

primitive index list and assembles the mesh data into the given mesh -size_t ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector& pPerIndexChannels, +size_t ColladaParser::ReadPrimitives(Mesh* pMesh, std::vector& pPerIndexChannels, size_t pNumPrimitives, const std::vector& pVCount, PrimitiveType pPrimType) { // determine number of indices coming per vertex // find the offset index for all per-vertex channels size_t numOffsets = 1; size_t perVertexOffset = SIZE_MAX; // invalid value - for( const InputChannel& channel : pPerIndexChannels) + for (const InputChannel& channel : pPerIndexChannels) { - numOffsets = std::max( numOffsets, channel.mOffset+1); - if( channel.mType == IT_Vertex) + numOffsets = std::max(numOffsets, channel.mOffset + 1); + if (channel.mType == IT_Vertex) perVertexOffset = channel.mOffset; } // determine the expected number of indices size_t expectedPointCount = 0; - switch( pPrimType) + switch (pPrimType) { - case Prim_Polylist: - { - for( size_t i : pVCount) - expectedPointCount += i; - break; - } - case Prim_Lines: - expectedPointCount = 2 * pNumPrimitives; - break; - case Prim_Triangles: - expectedPointCount = 3 * pNumPrimitives; - break; - default: - // other primitive types don't state the index count upfront... we need to guess - break; + case Prim_Polylist: + { + for (size_t i : pVCount) + expectedPointCount += i; + break; + } + case Prim_Lines: + expectedPointCount = 2 * pNumPrimitives; + break; + case Prim_Triangles: + expectedPointCount = 3 * pNumPrimitives; + break; + default: + // other primitive types don't state the index count upfront... we need to guess + break; } // and read all indices into a temporary array std::vector indices; - if( expectedPointCount > 0) - indices.reserve( expectedPointCount * numOffsets); + if (expectedPointCount > 0) + indices.reserve(expectedPointCount * numOffsets); if (pNumPrimitives > 0) // It is possible to not contain any indices { const char* content = GetTextContent(); - while( *content != 0) + while (*content != 0) { // read a value. // Hack: (thom) Some exporters put negative indices sometimes. We just try to carry on anyways. - int value = std::max( 0, strtol10( content, &content)); - indices.push_back( size_t( value)); + int value = std::max(0, strtol10(content, &content)); + indices.push_back(size_t(value)); // skip whitespace after it - SkipSpacesAndLineEnd( &content); + SkipSpacesAndLineEnd(&content); } } - // complain if the index count doesn't fit - if( expectedPointCount > 0 && indices.size() != expectedPointCount * numOffsets) { + // complain if the index count doesn't fit + if (expectedPointCount > 0 && indices.size() != expectedPointCount * numOffsets) { if (pPrimType == Prim_Lines) { // HACK: We just fix this number since SketchUp 15.3.331 writes the wrong 'count' for 'lines' - ReportWarning( "Expected different index count in

element, %d instead of %d.", indices.size(), expectedPointCount * numOffsets); + ReportWarning("Expected different index count in

element, %zu instead of %zu.", indices.size(), expectedPointCount * numOffsets); pNumPrimitives = (indices.size() / numOffsets) / 2; - } else - ThrowException( "Expected different index count in

element."); + } + else + ThrowException("Expected different index count in

element."); - } else if( expectedPointCount == 0 && (indices.size() % numOffsets) != 0) - ThrowException( "Expected different index count in

element."); + } + else if (expectedPointCount == 0 && (indices.size() % numOffsets) != 0) + ThrowException("Expected different index count in

element."); - // find the data for all sources - for( std::vector::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it) + // find the data for all sources + for (std::vector::iterator it = pMesh->mPerVertexData.begin(); it != pMesh->mPerVertexData.end(); ++it) { InputChannel& input = *it; - if( input.mResolved) + if (input.mResolved) continue; // find accessor - input.mResolved = &ResolveLibraryReference( mAccessorLibrary, input.mAccessor); + input.mResolved = &ResolveLibraryReference(mAccessorLibrary, input.mAccessor); // resolve accessor's data pointer as well, if necessary const Accessor* acc = input.mResolved; - if( !acc->mData) - acc->mData = &ResolveLibraryReference( mDataLibrary, acc->mSource); + if (!acc->mData) + acc->mData = &ResolveLibraryReference(mDataLibrary, acc->mSource); } // and the same for the per-index channels - for( std::vector::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it) + for (std::vector::iterator it = pPerIndexChannels.begin(); it != pPerIndexChannels.end(); ++it) { InputChannel& input = *it; - if( input.mResolved) + if (input.mResolved) continue; // ignore vertex pointer, it doesn't refer to an accessor - if( input.mType == IT_Vertex) + if (input.mType == IT_Vertex) { // warn if the vertex channel does not refer to the element in the same mesh - if( input.mAccessor != pMesh->mVertexID) - ThrowException( "Unsupported vertex referencing scheme."); + if (input.mAccessor != pMesh->mVertexID) + ThrowException("Unsupported vertex referencing scheme."); continue; } // find accessor - input.mResolved = &ResolveLibraryReference( mAccessorLibrary, input.mAccessor); + input.mResolved = &ResolveLibraryReference(mAccessorLibrary, input.mAccessor); // resolve accessor's data pointer as well, if necessary const Accessor* acc = input.mResolved; - if( !acc->mData) - acc->mData = &ResolveLibraryReference( mDataLibrary, acc->mSource); + if (!acc->mData) + acc->mData = &ResolveLibraryReference(mDataLibrary, acc->mSource); } // For continued primitives, the given count does not come all in one

, but only one primitive per

size_t numPrimitives = pNumPrimitives; - if( pPrimType == Prim_TriFans || pPrimType == Prim_Polygon) + if (pPrimType == Prim_TriFans || pPrimType == Prim_Polygon) numPrimitives = 1; // For continued primitives, the given count is actually the number of

's inside the parent tag - if ( pPrimType == Prim_TriStrips){ + if (pPrimType == Prim_TriStrips) { size_t numberOfVertices = indices.size() / numOffsets; numPrimitives = numberOfVertices - 2; } @@ -2422,66 +2592,66 @@ size_t ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector& pP numPrimitives = numberOfVertices - 1; } - pMesh->mFaceSize.reserve( numPrimitives); - pMesh->mFacePosIndices.reserve( indices.size() / numOffsets); + pMesh->mFaceSize.reserve(numPrimitives); + pMesh->mFacePosIndices.reserve(indices.size() / numOffsets); size_t polylistStartVertex = 0; for (size_t currentPrimitive = 0; currentPrimitive < numPrimitives; currentPrimitive++) { // determine number of points for this primitive size_t numPoints = 0; - switch( pPrimType) + switch (pPrimType) { - case Prim_Lines: - numPoints = 2; - for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++) - CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); - break; - case Prim_LineStrip: - numPoints = 2; - for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++) - CopyVertex(currentVertex, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); - break; - case Prim_Triangles: - numPoints = 3; - for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++) - CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); - break; - case Prim_TriStrips: - numPoints = 3; - ReadPrimTriStrips(numOffsets, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); - break; - case Prim_Polylist: - numPoints = pVCount[currentPrimitive]; - for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++) - CopyVertex(polylistStartVertex + currentVertex, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, 0, indices); - polylistStartVertex += numPoints; - break; - case Prim_TriFans: - case Prim_Polygon: - numPoints = indices.size() / numOffsets; - for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++) - CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); - break; - default: - // LineStrip is not supported due to expected index unmangling - ThrowException( "Unsupported primitive type."); - break; + case Prim_Lines: + numPoints = 2; + for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++) + CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); + break; + case Prim_LineStrip: + numPoints = 2; + for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++) + CopyVertex(currentVertex, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); + break; + case Prim_Triangles: + numPoints = 3; + for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++) + CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); + break; + case Prim_TriStrips: + numPoints = 3; + ReadPrimTriStrips(numOffsets, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); + break; + case Prim_Polylist: + numPoints = pVCount[currentPrimitive]; + for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++) + CopyVertex(polylistStartVertex + currentVertex, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, 0, indices); + polylistStartVertex += numPoints; + break; + case Prim_TriFans: + case Prim_Polygon: + numPoints = indices.size() / numOffsets; + for (size_t currentVertex = 0; currentVertex < numPoints; currentVertex++) + CopyVertex(currentVertex, numOffsets, numPoints, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); + break; + default: + // LineStrip is not supported due to expected index unmangling + ThrowException("Unsupported primitive type."); + break; } // store the face size to later reconstruct the face from - pMesh->mFaceSize.push_back( numPoints); + pMesh->mFaceSize.push_back(numPoints); } // if I ever get my hands on that guy who invented this steaming pile of indirection... - TestClosing( "p"); + TestClosing("p"); return numPrimitives; } ///@note This function willn't work correctly if both PerIndex and PerVertex channels have same channels. ///For example if TEXCOORD present in both and tags this function will create wrong uv coordinates. ///It's not clear from COLLADA documentation is this allowed or not. For now only exporter fixed to avoid such behavior -void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset, Mesh* pMesh, std::vector& pPerIndexChannels, size_t currentPrimitive, const std::vector& indices){ +void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t numPoints, size_t perVertexOffset, Mesh* pMesh, std::vector& pPerIndexChannels, size_t currentPrimitive, const std::vector& indices) { // calculate the base offset of the vertex whose attributes we ant to copy size_t baseOffset = currentPrimitive * numOffsets * numPoints + currentVertex * numOffsets; @@ -2499,8 +2669,8 @@ void ColladaParser::CopyVertex(size_t currentVertex, size_t numOffsets, size_t n pMesh->mFacePosIndices.push_back(indices[baseOffset + perVertexOffset]); } -void ColladaParser::ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Mesh* pMesh, std::vector& pPerIndexChannels, size_t currentPrimitive, const std::vector& indices){ - if (currentPrimitive % 2 != 0){ +void ColladaParser::ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, Mesh* pMesh, std::vector& pPerIndexChannels, size_t currentPrimitive, const std::vector& indices) { + if (currentPrimitive % 2 != 0) { //odd tristrip triangles need their indices mangled, to preserve winding direction CopyVertex(1, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); CopyVertex(0, numOffsets, 1, perVertexOffset, pMesh, pPerIndexChannels, currentPrimitive, indices); @@ -2515,108 +2685,110 @@ void ColladaParser::ReadPrimTriStrips(size_t numOffsets, size_t perVertexOffset, // ------------------------------------------------------------------------------------------------ // Extracts a single object from an input channel and stores it in the appropriate mesh data array -void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, size_t pLocalIndex, Mesh* pMesh) +void ColladaParser::ExtractDataObjectFromChannel(const InputChannel& pInput, size_t pLocalIndex, Mesh* pMesh) { // ignore vertex referrer - we handle them that separate - if( pInput.mType == IT_Vertex) + if (pInput.mType == IT_Vertex) return; const Accessor& acc = *pInput.mResolved; - if( pLocalIndex >= acc.mCount) - ThrowException( format() << "Invalid data index (" << pLocalIndex << "/" << acc.mCount << ") in primitive specification" ); + if (pLocalIndex >= acc.mCount) + ThrowException(format() << "Invalid data index (" << pLocalIndex << "/" << acc.mCount << ") in primitive specification"); // get a pointer to the start of the data object referred to by the accessor and the local index - const ai_real* dataObject = &(acc.mData->mValues[0]) + acc.mOffset + pLocalIndex* acc.mStride; + const ai_real* dataObject = &(acc.mData->mValues[0]) + acc.mOffset + pLocalIndex * acc.mStride; // assemble according to the accessors component sub-offset list. We don't care, yet, // what kind of object exactly we're extracting here ai_real obj[4]; - for( size_t c = 0; c < 4; ++c) + for (size_t c = 0; c < 4; ++c) obj[c] = dataObject[acc.mSubOffset[c]]; // now we reinterpret it according to the type we're reading here - switch( pInput.mType) + switch (pInput.mType) { - case IT_Position: // ignore all position streams except 0 - there can be only one position - if( pInput.mIndex == 0) - pMesh->mPositions.push_back( aiVector3D( obj[0], obj[1], obj[2])); - else - ASSIMP_LOG_ERROR("Collada: just one vertex position stream supported"); - break; - case IT_Normal: - // pad to current vertex count if necessary - if( pMesh->mNormals.size() < pMesh->mPositions.size()-1) - pMesh->mNormals.insert( pMesh->mNormals.end(), pMesh->mPositions.size() - pMesh->mNormals.size() - 1, aiVector3D( 0, 1, 0)); + case IT_Position: // ignore all position streams except 0 - there can be only one position + if (pInput.mIndex == 0) + pMesh->mPositions.push_back(aiVector3D(obj[0], obj[1], obj[2])); + else + ASSIMP_LOG_ERROR("Collada: just one vertex position stream supported"); + break; + case IT_Normal: + // pad to current vertex count if necessary + if (pMesh->mNormals.size() < pMesh->mPositions.size() - 1) + pMesh->mNormals.insert(pMesh->mNormals.end(), pMesh->mPositions.size() - pMesh->mNormals.size() - 1, aiVector3D(0, 1, 0)); - // ignore all normal streams except 0 - there can be only one normal - if( pInput.mIndex == 0) - pMesh->mNormals.push_back( aiVector3D( obj[0], obj[1], obj[2])); - else - ASSIMP_LOG_ERROR("Collada: just one vertex normal stream supported"); - break; - case IT_Tangent: - // pad to current vertex count if necessary - if( pMesh->mTangents.size() < pMesh->mPositions.size()-1) - pMesh->mTangents.insert( pMesh->mTangents.end(), pMesh->mPositions.size() - pMesh->mTangents.size() - 1, aiVector3D( 1, 0, 0)); + // ignore all normal streams except 0 - there can be only one normal + if (pInput.mIndex == 0) + pMesh->mNormals.push_back(aiVector3D(obj[0], obj[1], obj[2])); + else + ASSIMP_LOG_ERROR("Collada: just one vertex normal stream supported"); + break; + case IT_Tangent: + // pad to current vertex count if necessary + if (pMesh->mTangents.size() < pMesh->mPositions.size() - 1) + pMesh->mTangents.insert(pMesh->mTangents.end(), pMesh->mPositions.size() - pMesh->mTangents.size() - 1, aiVector3D(1, 0, 0)); - // ignore all tangent streams except 0 - there can be only one tangent - if( pInput.mIndex == 0) - pMesh->mTangents.push_back( aiVector3D( obj[0], obj[1], obj[2])); - else - ASSIMP_LOG_ERROR("Collada: just one vertex tangent stream supported"); - break; - case IT_Bitangent: - // pad to current vertex count if necessary - if( pMesh->mBitangents.size() < pMesh->mPositions.size()-1) - pMesh->mBitangents.insert( pMesh->mBitangents.end(), pMesh->mPositions.size() - pMesh->mBitangents.size() - 1, aiVector3D( 0, 0, 1)); + // ignore all tangent streams except 0 - there can be only one tangent + if (pInput.mIndex == 0) + pMesh->mTangents.push_back(aiVector3D(obj[0], obj[1], obj[2])); + else + ASSIMP_LOG_ERROR("Collada: just one vertex tangent stream supported"); + break; + case IT_Bitangent: + // pad to current vertex count if necessary + if (pMesh->mBitangents.size() < pMesh->mPositions.size() - 1) + pMesh->mBitangents.insert(pMesh->mBitangents.end(), pMesh->mPositions.size() - pMesh->mBitangents.size() - 1, aiVector3D(0, 0, 1)); - // ignore all bitangent streams except 0 - there can be only one bitangent - if( pInput.mIndex == 0) - pMesh->mBitangents.push_back( aiVector3D( obj[0], obj[1], obj[2])); - else - ASSIMP_LOG_ERROR("Collada: just one vertex bitangent stream supported"); - break; - case IT_Texcoord: - // up to 4 texture coord sets are fine, ignore the others - if( pInput.mIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS) + // ignore all bitangent streams except 0 - there can be only one bitangent + if (pInput.mIndex == 0) + pMesh->mBitangents.push_back(aiVector3D(obj[0], obj[1], obj[2])); + else + ASSIMP_LOG_ERROR("Collada: just one vertex bitangent stream supported"); + break; + case IT_Texcoord: + // up to 4 texture coord sets are fine, ignore the others + if (pInput.mIndex < AI_MAX_NUMBER_OF_TEXTURECOORDS) + { + // pad to current vertex count if necessary + if (pMesh->mTexCoords[pInput.mIndex].size() < pMesh->mPositions.size() - 1) + pMesh->mTexCoords[pInput.mIndex].insert(pMesh->mTexCoords[pInput.mIndex].end(), + pMesh->mPositions.size() - pMesh->mTexCoords[pInput.mIndex].size() - 1, aiVector3D(0, 0, 0)); + + pMesh->mTexCoords[pInput.mIndex].push_back(aiVector3D(obj[0], obj[1], obj[2])); + if (0 != acc.mSubOffset[2] || 0 != acc.mSubOffset[3]) /* hack ... consider cleaner solution */ + pMesh->mNumUVComponents[pInput.mIndex] = 3; + } + else + { + ASSIMP_LOG_ERROR("Collada: too many texture coordinate sets. Skipping."); + } + break; + case IT_Color: + // up to 4 color sets are fine, ignore the others + if (pInput.mIndex < AI_MAX_NUMBER_OF_COLOR_SETS) + { + // pad to current vertex count if necessary + if (pMesh->mColors[pInput.mIndex].size() < pMesh->mPositions.size() - 1) + pMesh->mColors[pInput.mIndex].insert(pMesh->mColors[pInput.mIndex].end(), + pMesh->mPositions.size() - pMesh->mColors[pInput.mIndex].size() - 1, aiColor4D(0, 0, 0, 1)); + + aiColor4D result(0, 0, 0, 1); + for (size_t i = 0; i < pInput.mResolved->mSize; ++i) { - // pad to current vertex count if necessary - if( pMesh->mTexCoords[pInput.mIndex].size() < pMesh->mPositions.size()-1) - pMesh->mTexCoords[pInput.mIndex].insert( pMesh->mTexCoords[pInput.mIndex].end(), - pMesh->mPositions.size() - pMesh->mTexCoords[pInput.mIndex].size() - 1, aiVector3D( 0, 0, 0)); - - pMesh->mTexCoords[pInput.mIndex].push_back( aiVector3D( obj[0], obj[1], obj[2])); - if (0 != acc.mSubOffset[2] || 0 != acc.mSubOffset[3]) /* hack ... consider cleaner solution */ - pMesh->mNumUVComponents[pInput.mIndex]=3; - } else - { - ASSIMP_LOG_ERROR("Collada: too many texture coordinate sets. Skipping."); + result[static_cast(i)] = obj[pInput.mResolved->mSubOffset[i]]; } - break; - case IT_Color: - // up to 4 color sets are fine, ignore the others - if( pInput.mIndex < AI_MAX_NUMBER_OF_COLOR_SETS) - { - // pad to current vertex count if necessary - if( pMesh->mColors[pInput.mIndex].size() < pMesh->mPositions.size()-1) - pMesh->mColors[pInput.mIndex].insert( pMesh->mColors[pInput.mIndex].end(), - pMesh->mPositions.size() - pMesh->mColors[pInput.mIndex].size() - 1, aiColor4D( 0, 0, 0, 1)); + pMesh->mColors[pInput.mIndex].push_back(result); + } + else + { + ASSIMP_LOG_ERROR("Collada: too many vertex color sets. Skipping."); + } - aiColor4D result(0, 0, 0, 1); - for (size_t i = 0; i < pInput.mResolved->mSize; ++i) - { - result[static_cast(i)] = obj[pInput.mResolved->mSubOffset[i]]; - } - pMesh->mColors[pInput.mIndex].push_back(result); - } else - { - ASSIMP_LOG_ERROR("Collada: too many vertex color sets. Skipping."); - } - - break; - default: - // IT_Invalid and IT_Vertex - ai_assert(false && "shouldn't ever get here"); + break; + default: + // IT_Invalid and IT_Vertex + ai_assert(false && "shouldn't ever get here"); } } @@ -2624,25 +2796,25 @@ void ColladaParser::ExtractDataObjectFromChannel( const InputChannel& pInput, si // Reads the library of node hierarchies and scene parts void ColladaParser::ReadSceneLibrary() { - if( mReader->isEmptyElement()) + if (mReader->isEmptyElement()) return; - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { // a visual scene - generate root node under its ID and let ReadNode() do the recursive work - if( IsElement( "visual_scene")) + if (IsElement("visual_scene")) { // read ID. Is optional according to the spec, but how on earth should a scene_instance refer to it then? - int indexID = GetAttribute( "id"); - const char* attrID = mReader->getAttributeValue( indexID); + int indexID = GetAttribute("id"); + const char* attrID = mReader->getAttributeValue(indexID); // read name if given. - int indexName = TestAttribute( "name"); + int indexName = TestAttribute("name"); const char* attrName = "unnamed"; - if( indexName > -1) - attrName = mReader->getAttributeValue( indexName); + if (indexName > -1) + attrName = mReader->getAttributeValue(indexName); // create a node and store it in the library under its ID Node* node = new Node; @@ -2650,55 +2822,56 @@ void ColladaParser::ReadSceneLibrary() node->mName = attrName; mNodeLibrary[node->mID] = node; - ReadSceneNode( node); - } else + ReadSceneNode(node); + } + else { // ignore the rest SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "library_visual_scenes") == 0) + if (strcmp(mReader->getNodeName(), "library_visual_scenes") == 0) //ThrowException( "Expected end of \"library_visual_scenes\" element."); - break; + break; } } } // ------------------------------------------------------------------------------------------------ // Reads a scene node's contents including children and stores it in the given node -void ColladaParser::ReadSceneNode( Node* pNode) +void ColladaParser::ReadSceneNode(Node* pNode) { // quit immediately on elements - if( mReader->isEmptyElement()) + if (mReader->isEmptyElement()) return; - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "node")) + if (IsElement("node")) { Node* child = new Node; - int attrID = TestAttribute( "id"); - if( attrID > -1) - child->mID = mReader->getAttributeValue( attrID); - int attrSID = TestAttribute( "sid"); - if( attrSID > -1) - child->mSID = mReader->getAttributeValue( attrSID); + int attrID = TestAttribute("id"); + if (attrID > -1) + child->mID = mReader->getAttributeValue(attrID); + int attrSID = TestAttribute("sid"); + if (attrSID > -1) + child->mSID = mReader->getAttributeValue(attrSID); - int attrName = TestAttribute( "name"); - if( attrName > -1) - child->mName = mReader->getAttributeValue( attrName); + int attrName = TestAttribute("name"); + if (attrName > -1) + child->mName = mReader->getAttributeValue(attrName); // TODO: (thom) support SIDs // ai_assert( TestAttribute( "sid") == -1); if (pNode) { - pNode->mChildren.push_back( child); + pNode->mChildren.push_back(child); child->mParent = pNode; } else @@ -2709,26 +2882,26 @@ void ColladaParser::ReadSceneNode( Node* pNode) } // read on recursively from there - ReadSceneNode( child); + ReadSceneNode(child); continue; } // For any further stuff we need a valid node to work on else if (!pNode) continue; - if( IsElement( "lookat")) - ReadNodeTransformation( pNode, TF_LOOKAT); - else if( IsElement( "matrix")) - ReadNodeTransformation( pNode, TF_MATRIX); - else if( IsElement( "rotate")) - ReadNodeTransformation( pNode, TF_ROTATE); - else if( IsElement( "scale")) - ReadNodeTransformation( pNode, TF_SCALE); - else if( IsElement( "skew")) - ReadNodeTransformation( pNode, TF_SKEW); - else if( IsElement( "translate")) - ReadNodeTransformation( pNode, TF_TRANSLATE); - else if( IsElement( "render") && pNode->mParent == NULL && 0 == pNode->mPrimaryCamera.length()) + if (IsElement("lookat")) + ReadNodeTransformation(pNode, TF_LOOKAT); + else if (IsElement("matrix")) + ReadNodeTransformation(pNode, TF_MATRIX); + else if (IsElement("rotate")) + ReadNodeTransformation(pNode, TF_ROTATE); + else if (IsElement("scale")) + ReadNodeTransformation(pNode, TF_SCALE); + else if (IsElement("skew")) + ReadNodeTransformation(pNode, TF_SKEW); + else if (IsElement("translate")) + ReadNodeTransformation(pNode, TF_TRANSLATE); + else if (IsElement("render") && pNode->mParent == NULL && 0 == pNode->mPrimaryCamera.length()) { // ... scene evaluation or, in other words, postprocessing pipeline, // or, again in other words, a turing-complete description how to @@ -2741,14 +2914,14 @@ void ColladaParser::ReadSceneNode( Node* pNode) if (s[0] != '#') ASSIMP_LOG_ERROR("Collada: Unresolved reference format of camera"); else - pNode->mPrimaryCamera = s+1; + pNode->mPrimaryCamera = s + 1; } } - else if( IsElement( "instance_node")) + else if (IsElement("instance_node")) { // find the node in the library - int attrID = TestAttribute( "url"); - if( attrID != -1) + int attrID = TestAttribute("url"); + if (attrID != -1) { const char* s = mReader->getAttributeValue(attrID); if (s[0] != '#') @@ -2756,16 +2929,16 @@ void ColladaParser::ReadSceneNode( Node* pNode) else { pNode->mNodeInstances.push_back(NodeInstance()); - pNode->mNodeInstances.back().mNode = s+1; + pNode->mNodeInstances.back().mNode = s + 1; } } } - else if( IsElement( "instance_geometry") || IsElement( "instance_controller")) + else if (IsElement("instance_geometry") || IsElement("instance_controller")) { // Reference to a mesh or controller, with possible material associations - ReadNodeGeometry( pNode); + ReadNodeGeometry(pNode); } - else if( IsElement( "instance_light")) + else if (IsElement("instance_light")) { // Reference to a light, name given in 'url' attribute int attrID = TestAttribute("url"); @@ -2773,15 +2946,15 @@ void ColladaParser::ReadSceneNode( Node* pNode) ASSIMP_LOG_WARN("Collada: Expected url attribute in element"); else { - const char* url = mReader->getAttributeValue( attrID); - if( url[0] != '#') - ThrowException( "Unknown reference format in element"); + const char* url = mReader->getAttributeValue(attrID); + if (url[0] != '#') + ThrowException("Unknown reference format in element"); pNode->mLights.push_back(LightInstance()); - pNode->mLights.back().mLight = url+1; + pNode->mLights.back().mLight = url + 1; } } - else if( IsElement( "instance_camera")) + else if (IsElement("instance_camera")) { // Reference to a camera, name given in 'url' attribute int attrID = TestAttribute("url"); @@ -2789,12 +2962,12 @@ void ColladaParser::ReadSceneNode( Node* pNode) ASSIMP_LOG_WARN("Collada: Expected url attribute in element"); else { - const char* url = mReader->getAttributeValue( attrID); - if( url[0] != '#') - ThrowException( "Unknown reference format in element"); + const char* url = mReader->getAttributeValue(attrID); + if (url[0] != '#') + ThrowException("Unknown reference format in element"); pNode->mCameras.push_back(CameraInstance()); - pNode->mCameras.back().mCamera = url+1; + pNode->mCameras.back().mCamera = url + 1; } } else @@ -2803,7 +2976,7 @@ void ColladaParser::ReadSceneNode( Node* pNode) SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { break; } } @@ -2811,9 +2984,9 @@ void ColladaParser::ReadSceneNode( Node* pNode) // ------------------------------------------------------------------------------------------------ // Reads a node transformation entry of the given type and adds it to the given node's transformation list. -void ColladaParser::ReadNodeTransformation( Node* pNode, TransformType pType) +void ColladaParser::ReadNodeTransformation(Node* pNode, TransformType pType) { - if( mReader->isEmptyElement()) + if (mReader->isEmptyElement()) return; std::string tagName = mReader->getNodeName(); @@ -2822,38 +2995,38 @@ void ColladaParser::ReadNodeTransformation( Node* pNode, TransformType pType) tf.mType = pType; // read SID - int indexSID = TestAttribute( "sid"); - if( indexSID >= 0) - tf.mID = mReader->getAttributeValue( indexSID); + int indexSID = TestAttribute("sid"); + if (indexSID >= 0) + tf.mID = mReader->getAttributeValue(indexSID); // how many parameters to read per transformation type static const unsigned int sNumParameters[] = { 9, 4, 3, 3, 7, 16 }; const char* content = GetTextContent(); // read as many parameters and store in the transformation - for( unsigned int a = 0; a < sNumParameters[pType]; a++) + for (unsigned int a = 0; a < sNumParameters[pType]; a++) { // read a number - content = fast_atoreal_move( content, tf.f[a]); + content = fast_atoreal_move(content, tf.f[a]); // skip whitespace after it - SkipSpacesAndLineEnd( &content); + SkipSpacesAndLineEnd(&content); } // place the transformation at the queue of the node - pNode->mTransforms.push_back( tf); + pNode->mTransforms.push_back(tf); // and consume the closing tag - TestClosing( tagName.c_str()); + TestClosing(tagName.c_str()); } // ------------------------------------------------------------------------------------------------ // Processes bind_vertex_input and bind elements -void ColladaParser::ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl) +void ColladaParser::ReadMaterialVertexInputBinding(Collada::SemanticMappingTable& tbl) { - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "bind_vertex_input")) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("bind_vertex_input")) { Collada::InputSemanticMapEntry vn; @@ -2863,7 +3036,7 @@ void ColladaParser::ReadMaterialVertexInputBinding( Collada::SemanticMappingTabl // input semantic n = GetAttribute("input_semantic"); - vn.mType = GetTypeForSemantic( mReader->getAttributeValue(n) ); + vn.mType = GetTypeForSemantic(mReader->getAttributeValue(n)); // index of input set n = TestAttribute("input_set"); @@ -2872,103 +3045,124 @@ void ColladaParser::ReadMaterialVertexInputBinding( Collada::SemanticMappingTabl tbl.mMap[s] = vn; } - else if( IsElement( "bind")) { + else if (IsElement("bind")) { ASSIMP_LOG_WARN("Collada: Found unsupported element"); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "instance_material") == 0) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { + if (strcmp(mReader->getNodeName(), "instance_material") == 0) break; } } } +void Assimp::ColladaParser::ReadEmbeddedTextures(ZipArchiveIOSystem& zip_archive) +{ + // Attempt to load any undefined Collada::Image in ImageLibrary + for (ImageLibrary::iterator it = mImageLibrary.begin(); it != mImageLibrary.end(); ++it) { + Collada::Image &image = (*it).second; + + if (image.mImageData.empty()) { + std::unique_ptr image_file(zip_archive.Open(image.mFileName.c_str())); + if (image_file) { + image.mImageData.resize(image_file->FileSize()); + image_file->Read(image.mImageData.data(), image_file->FileSize(), 1); + image.mEmbeddedFormat = BaseImporter::GetExtension(image.mFileName); + if (image.mEmbeddedFormat == "jpeg") { + image.mEmbeddedFormat = "jpg"; + } + } + } + } +} + // ------------------------------------------------------------------------------------------------ // Reads a mesh reference in a node and adds it to the node's mesh list -void ColladaParser::ReadNodeGeometry( Node* pNode) +void ColladaParser::ReadNodeGeometry(Node* pNode) { // referred mesh is given as an attribute of the element - int attrUrl = GetAttribute( "url"); - const char* url = mReader->getAttributeValue( attrUrl); - if( url[0] != '#') - ThrowException( "Unknown reference format"); + int attrUrl = GetAttribute("url"); + const char* url = mReader->getAttributeValue(attrUrl); + if (url[0] != '#') + ThrowException("Unknown reference format"); Collada::MeshInstance instance; - instance.mMeshOrController = url+1; // skipping the leading # + instance.mMeshOrController = url + 1; // skipping the leading # - if( !mReader->isEmptyElement()) + if (!mReader->isEmptyElement()) { // read material associations. Ignore additional elements in between - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "instance_material")) + if (IsElement("instance_material")) { // read ID of the geometry subgroup and the target material - int attrGroup = GetAttribute( "symbol"); - std::string group = mReader->getAttributeValue( attrGroup); - int attrMaterial = GetAttribute( "target"); - const char* urlMat = mReader->getAttributeValue( attrMaterial); + int attrGroup = GetAttribute("symbol"); + std::string group = mReader->getAttributeValue(attrGroup); + int attrMaterial = GetAttribute("target"); + const char* urlMat = mReader->getAttributeValue(attrMaterial); Collada::SemanticMappingTable s; - if( urlMat[0] == '#') + if (urlMat[0] == '#') urlMat++; s.mMatName = urlMat; // resolve further material details + THIS UGLY AND NASTY semantic mapping stuff - if( !mReader->isEmptyElement()) + if (!mReader->isEmptyElement()) ReadMaterialVertexInputBinding(s); // store the association instance.mMaterials[group] = s; } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { - if( strcmp( mReader->getNodeName(), "instance_geometry") == 0 - || strcmp( mReader->getNodeName(), "instance_controller") == 0) + if (strcmp(mReader->getNodeName(), "instance_geometry") == 0 + || strcmp(mReader->getNodeName(), "instance_controller") == 0) break; } } } // store it - pNode->mMeshes.push_back( instance); + pNode->mMeshes.push_back(instance); } // ------------------------------------------------------------------------------------------------ // Reads the collada scene void ColladaParser::ReadScene() { - if( mReader->isEmptyElement()) + if (mReader->isEmptyElement()) return; - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT) { - if( IsElement( "instance_visual_scene")) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) { + if (IsElement("instance_visual_scene")) { // should be the first and only occurrence - if( mRootNode) - ThrowException( "Invalid scene containing multiple root nodes in element"); + if (mRootNode) + ThrowException("Invalid scene containing multiple root nodes in element"); // read the url of the scene to instance. Should be of format "#some_name" - int urlIndex = GetAttribute( "url"); - const char* url = mReader->getAttributeValue( urlIndex); - if( url[0] != '#') - ThrowException( "Unknown reference format in element"); + int urlIndex = GetAttribute("url"); + const char* url = mReader->getAttributeValue(urlIndex); + if (url[0] != '#') + ThrowException("Unknown reference format in element"); // find the referred scene, skip the leading # - NodeLibrary::const_iterator sit = mNodeLibrary.find( url+1); - if( sit == mNodeLibrary.end()) - ThrowException( "Unable to resolve visual_scene reference \"" + std::string(url) + "\" in element."); + NodeLibrary::const_iterator sit = mNodeLibrary.find(url + 1); + if (sit == mNodeLibrary.end()) + ThrowException("Unable to resolve visual_scene reference \"" + std::string(url) + "\" in element."); mRootNode = sit->second; - } else { + } + else { SkipElement(); } } - else if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END){ + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) { break; } } @@ -2976,23 +3170,23 @@ void ColladaParser::ReadScene() // ------------------------------------------------------------------------------------------------ // Aborts the file reading with an exception -AI_WONT_RETURN void ColladaParser::ThrowException( const std::string& pError) const +AI_WONT_RETURN void ColladaParser::ThrowException(const std::string& pError) const { - throw DeadlyImportError( format() << "Collada: " << mFileName << " - " << pError ); + throw DeadlyImportError(format() << "Collada: " << mFileName << " - " << pError); } -void ColladaParser::ReportWarning(const char* msg,...) +void ColladaParser::ReportWarning(const char* msg, ...) { ai_assert(NULL != msg); va_list args; - va_start(args,msg); + va_start(args, msg); char szBuffer[3000]; - const int iLen = vsprintf(szBuffer,msg,args); + const int iLen = vsprintf(szBuffer, msg, args); ai_assert(iLen > 0); va_end(args); - ASSIMP_LOG_WARN_F("Validation warning: ", std::string(szBuffer,iLen)); + ASSIMP_LOG_WARN_F("Validation warning: ", std::string(szBuffer, iLen)); } // ------------------------------------------------------------------------------------------------ @@ -3000,84 +3194,84 @@ void ColladaParser::ReportWarning(const char* msg,...) void ColladaParser::SkipElement() { // nothing to skip if it's an - if( mReader->isEmptyElement()) + if (mReader->isEmptyElement()) return; // reroute - SkipElement( mReader->getNodeName()); + SkipElement(mReader->getNodeName()); } // ------------------------------------------------------------------------------------------------ // Skips all data until the end node of the given element -void ColladaParser::SkipElement( const char* pElement) +void ColladaParser::SkipElement(const char* pElement) { // copy the current node's name because it'a pointer to the reader's internal buffer, // which is going to change with the upcoming parsing std::string element = pElement; - while( mReader->read()) + while (mReader->read()) { - if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END) - if( mReader->getNodeName() == element) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + if (mReader->getNodeName() == element) break; } } // ------------------------------------------------------------------------------------------------ // Tests for an opening element of the given name, throws an exception if not found -void ColladaParser::TestOpening( const char* pName) +void ColladaParser::TestOpening(const char* pName) { // read element start - if( !mReader->read()) - ThrowException( format() << "Unexpected end of file while beginning of <" << pName << "> element." ); + if (!mReader->read()) + ThrowException(format() << "Unexpected end of file while beginning of <" << pName << "> element."); // whitespace in front is ok, just read again if found - if( mReader->getNodeType() == irr::io::EXN_TEXT) - if( !mReader->read()) - ThrowException( format() << "Unexpected end of file while reading beginning of <" << pName << "> element." ); + if (mReader->getNodeType() == irr::io::EXN_TEXT) + if (!mReader->read()) + ThrowException(format() << "Unexpected end of file while reading beginning of <" << pName << "> element."); - if( mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp( mReader->getNodeName(), pName) != 0) - ThrowException( format() << "Expected start of <" << pName << "> element." ); + if (mReader->getNodeType() != irr::io::EXN_ELEMENT || strcmp(mReader->getNodeName(), pName) != 0) + ThrowException(format() << "Expected start of <" << pName << "> element."); } // ------------------------------------------------------------------------------------------------ // Tests for the closing tag of the given element, throws an exception if not found -void ColladaParser::TestClosing( const char* pName) +void ColladaParser::TestClosing(const char* pName) { // check if we're already on the closing tag and return right away - if( mReader->getNodeType() == irr::io::EXN_ELEMENT_END && strcmp( mReader->getNodeName(), pName) == 0) + if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END && strcmp(mReader->getNodeName(), pName) == 0) return; // if not, read some more - if( !mReader->read()) - ThrowException( format() << "Unexpected end of file while reading end of <" << pName << "> element." ); + if (!mReader->read()) + ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element."); // whitespace in front is ok, just read again if found - if( mReader->getNodeType() == irr::io::EXN_TEXT) - if( !mReader->read()) - ThrowException( format() << "Unexpected end of file while reading end of <" << pName << "> element." ); + if (mReader->getNodeType() == irr::io::EXN_TEXT) + if (!mReader->read()) + ThrowException(format() << "Unexpected end of file while reading end of <" << pName << "> element."); // but this has the be the closing tag, or we're lost - if( mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp( mReader->getNodeName(), pName) != 0) - ThrowException( format() << "Expected end of <" << pName << "> element." ); + if (mReader->getNodeType() != irr::io::EXN_ELEMENT_END || strcmp(mReader->getNodeName(), pName) != 0) + ThrowException(format() << "Expected end of <" << pName << "> element."); } // ------------------------------------------------------------------------------------------------ // Returns the index of the named attribute or -1 if not found. Does not throw, therefore useful for optional attributes -int ColladaParser::GetAttribute( const char* pAttr) const +int ColladaParser::GetAttribute(const char* pAttr) const { - int index = TestAttribute( pAttr); - if( index != -1) + int index = TestAttribute(pAttr); + if (index != -1) return index; // attribute not found -> throw an exception - ThrowException( format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">." ); + ThrowException(format() << "Expected attribute \"" << pAttr << "\" for element <" << mReader->getNodeName() << ">."); return -1; } // ------------------------------------------------------------------------------------------------ // Tests the present element for the presence of one attribute, returns its index or throws an exception if not found -int ColladaParser::TestAttribute( const char* pAttr) const +int ColladaParser::TestAttribute(const char* pAttr) const { - for( int a = 0; a < mReader->getAttributeCount(); a++) - if( strcmp( mReader->getAttributeName( a), pAttr) == 0) + for (int a = 0; a < mReader->getAttributeCount(); a++) + if (strcmp(mReader->getAttributeName(a), pAttr) == 0) return a; return -1; @@ -3088,8 +3282,8 @@ int ColladaParser::TestAttribute( const char* pAttr) const const char* ColladaParser::GetTextContent() { const char* sz = TestTextContent(); - if(!sz) { - ThrowException( "Invalid contents in element \"n\"."); + if (!sz) { + ThrowException("Invalid contents in element \"n\"."); } return sz; } @@ -3099,85 +3293,85 @@ const char* ColladaParser::GetTextContent() const char* ColladaParser::TestTextContent() { // present node should be the beginning of an element - if( mReader->getNodeType() != irr::io::EXN_ELEMENT || mReader->isEmptyElement()) + if (mReader->getNodeType() != irr::io::EXN_ELEMENT || mReader->isEmptyElement()) return NULL; // read contents of the element - if( !mReader->read() ) + if (!mReader->read()) return NULL; - if( mReader->getNodeType() != irr::io::EXN_TEXT && mReader->getNodeType() != irr::io::EXN_CDATA) + if (mReader->getNodeType() != irr::io::EXN_TEXT && mReader->getNodeType() != irr::io::EXN_CDATA) return NULL; // skip leading whitespace const char* text = mReader->getNodeData(); - SkipSpacesAndLineEnd( &text); + SkipSpacesAndLineEnd(&text); return text; } // ------------------------------------------------------------------------------------------------ // Calculates the resulting transformation fromm all the given transform steps -aiMatrix4x4 ColladaParser::CalculateResultTransform( const std::vector& pTransforms) const +aiMatrix4x4 ColladaParser::CalculateResultTransform(const std::vector& pTransforms) const { aiMatrix4x4 res; - for( std::vector::const_iterator it = pTransforms.begin(); it != pTransforms.end(); ++it) + for (std::vector::const_iterator it = pTransforms.begin(); it != pTransforms.end(); ++it) { const Transform& tf = *it; - switch( tf.mType) + switch (tf.mType) { - case TF_LOOKAT: - { - aiVector3D pos( tf.f[0], tf.f[1], tf.f[2]); - aiVector3D dstPos( tf.f[3], tf.f[4], tf.f[5]); - aiVector3D up = aiVector3D( tf.f[6], tf.f[7], tf.f[8]).Normalize(); - aiVector3D dir = aiVector3D( dstPos - pos).Normalize(); - aiVector3D right = (dir ^ up).Normalize(); + case TF_LOOKAT: + { + aiVector3D pos(tf.f[0], tf.f[1], tf.f[2]); + aiVector3D dstPos(tf.f[3], tf.f[4], tf.f[5]); + aiVector3D up = aiVector3D(tf.f[6], tf.f[7], tf.f[8]).Normalize(); + aiVector3D dir = aiVector3D(dstPos - pos).Normalize(); + aiVector3D right = (dir ^ up).Normalize(); - res *= aiMatrix4x4( - right.x, up.x, -dir.x, pos.x, - right.y, up.y, -dir.y, pos.y, - right.z, up.z, -dir.z, pos.z, - 0, 0, 0, 1); - break; - } - case TF_ROTATE: - { - aiMatrix4x4 rot; - ai_real angle = tf.f[3] * ai_real( AI_MATH_PI) / ai_real( 180.0 ); - aiVector3D axis( tf.f[0], tf.f[1], tf.f[2]); - aiMatrix4x4::Rotation( angle, axis, rot); - res *= rot; - break; - } - case TF_TRANSLATE: - { - aiMatrix4x4 trans; - aiMatrix4x4::Translation( aiVector3D( tf.f[0], tf.f[1], tf.f[2]), trans); - res *= trans; - break; - } - case TF_SCALE: - { - aiMatrix4x4 scale( tf.f[0], 0.0f, 0.0f, 0.0f, 0.0f, tf.f[1], 0.0f, 0.0f, 0.0f, 0.0f, tf.f[2], 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f); - res *= scale; - break; - } - case TF_SKEW: - // TODO: (thom) - ai_assert( false); - break; - case TF_MATRIX: - { - aiMatrix4x4 mat( tf.f[0], tf.f[1], tf.f[2], tf.f[3], tf.f[4], tf.f[5], tf.f[6], tf.f[7], - tf.f[8], tf.f[9], tf.f[10], tf.f[11], tf.f[12], tf.f[13], tf.f[14], tf.f[15]); - res *= mat; - break; - } - default: - ai_assert( false); - break; + res *= aiMatrix4x4( + right.x, up.x, -dir.x, pos.x, + right.y, up.y, -dir.y, pos.y, + right.z, up.z, -dir.z, pos.z, + 0, 0, 0, 1); + break; + } + case TF_ROTATE: + { + aiMatrix4x4 rot; + ai_real angle = tf.f[3] * ai_real(AI_MATH_PI) / ai_real(180.0); + aiVector3D axis(tf.f[0], tf.f[1], tf.f[2]); + aiMatrix4x4::Rotation(angle, axis, rot); + res *= rot; + break; + } + case TF_TRANSLATE: + { + aiMatrix4x4 trans; + aiMatrix4x4::Translation(aiVector3D(tf.f[0], tf.f[1], tf.f[2]), trans); + res *= trans; + break; + } + case TF_SCALE: + { + aiMatrix4x4 scale(tf.f[0], 0.0f, 0.0f, 0.0f, 0.0f, tf.f[1], 0.0f, 0.0f, 0.0f, 0.0f, tf.f[2], 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + res *= scale; + break; + } + case TF_SKEW: + // TODO: (thom) + ai_assert(false); + break; + case TF_MATRIX: + { + aiMatrix4x4 mat(tf.f[0], tf.f[1], tf.f[2], tf.f[3], tf.f[4], tf.f[5], tf.f[6], tf.f[7], + tf.f[8], tf.f[9], tf.f[10], tf.f[11], tf.f[12], tf.f[13], tf.f[14], tf.f[15]); + res *= mat; + break; + } + default: + ai_assert(false); + break; } } @@ -3186,29 +3380,29 @@ aiMatrix4x4 ColladaParser::CalculateResultTransform( const std::vector StringMetaData; + /** Constructor from XML file */ 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(); @@ -81,6 +88,15 @@ namespace Assimp /** Reads asset information such as coordinate system information and legal blah */ void ReadAssetInfo(); + /** Reads contributor information such as author and legal blah */ + void ReadContributorInfo(); + + /** Reads generic metadata into provided map */ + 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(); @@ -223,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; @@ -343,6 +362,9 @@ namespace Assimp /** Which is the up vector */ enum { UP_X, UP_Y, UP_Z } mUpDirection; + /** Asset metadata (global for scene) */ + StringMetaData mAssetMetaData; + /** Collada file format version */ Collada::FormatVersion mFormat; }; diff --git a/code/Assimp.cpp b/code/Common/Assimp.cpp similarity index 99% rename from code/Assimp.cpp rename to code/Common/Assimp.cpp index 87f436602..178b2c01d 100644 --- a/code/Assimp.cpp +++ b/code/Common/Assimp.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -54,7 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "CInterfaceIOWrapper.h" +#include "CApi/CInterfaceIOWrapper.h" #include "Importer.h" #include "ScenePrivate.h" diff --git a/code/BaseImporter.cpp b/code/Common/BaseImporter.cpp similarity index 95% rename from code/BaseImporter.cpp rename to code/Common/BaseImporter.cpp index f03db189f..b77bbfe23 100644 --- a/code/BaseImporter.cpp +++ b/code/Common/BaseImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -76,9 +76,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( 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 +116,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 +133,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 } @@ -320,7 +341,11 @@ std::string BaseImporter::GetExtension( const std::string& file ) { return false; } -#include "../contrib/utf8cpp/source/utf8.h" +#ifdef ASSIMP_USE_HUNTER +# include +#else +# include "../contrib/utf8cpp/source/utf8.h" +#endif // ------------------------------------------------------------------------------------------------ // Convert to UTF8 data @@ -584,6 +609,8 @@ aiScene* BatchLoader::GetImport( unsigned int which ) return nullptr; } + + // ------------------------------------------------------------------------------------------------ void BatchLoader::LoadAll() { diff --git a/code/BaseProcess.cpp b/code/Common/BaseProcess.cpp similarity index 97% rename from code/BaseProcess.cpp rename to code/Common/BaseProcess.cpp index 154b586d2..e247be418 100644 --- a/code/BaseProcess.cpp +++ b/code/Common/BaseProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -89,7 +89,7 @@ void BaseProcess::ExecuteOnScene( Importer* pImp) // and kill the partially imported data delete pImp->Pimpl()->mScene; - pImp->Pimpl()->mScene = NULL; + pImp->Pimpl()->mScene = nullptr; } } diff --git a/code/BaseProcess.h b/code/Common/BaseProcess.h similarity index 99% rename from code/BaseProcess.h rename to code/Common/BaseProcess.h index b09fc732e..4d5c7a76b 100644 --- a/code/BaseProcess.h +++ b/code/Common/BaseProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/Bitmap.cpp b/code/Common/Bitmap.cpp similarity index 99% rename from code/Bitmap.cpp rename to code/Common/Bitmap.cpp index 903a13fb1..b22b71ea9 100644 --- a/code/Bitmap.cpp +++ b/code/Common/Bitmap.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/CreateAnimMesh.cpp b/code/Common/CreateAnimMesh.cpp similarity index 96% rename from code/CreateAnimMesh.cpp rename to code/Common/CreateAnimMesh.cpp index 1a052849b..98b60e531 100644 --- a/code/CreateAnimMesh.cpp +++ b/code/Common/CreateAnimMesh.cpp @@ -47,10 +47,6 @@ namespace Assimp { aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh) { aiAnimMesh *animesh = new aiAnimMesh; - animesh->mVertices = NULL; - animesh->mNormals = NULL; - animesh->mTangents = NULL; - animesh->mBitangents = NULL; animesh->mNumVertices = mesh->mNumVertices; if (mesh->mVertices) { animesh->mVertices = new aiVector3D[animesh->mNumVertices]; diff --git a/code/DefaultIOStream.cpp b/code/Common/DefaultIOStream.cpp similarity index 99% rename from code/DefaultIOStream.cpp rename to code/Common/DefaultIOStream.cpp index 3b0a672a7..1c100b618 100644 --- a/code/DefaultIOStream.cpp +++ b/code/Common/DefaultIOStream.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/DefaultIOSystem.cpp b/code/Common/DefaultIOSystem.cpp similarity index 58% rename from code/DefaultIOSystem.cpp rename to code/Common/DefaultIOSystem.cpp index 58afe475c..6fdc24dd8 100644 --- a/code/DefaultIOSystem.cpp +++ b/code/Common/DefaultIOSystem.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -61,75 +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) - 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) - 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]; - - bool isUnicode = IsTextUnicode(pFile, static_cast(strlen(pFile)), NULL) != 0; - if (isUnicode) { - - MultiByteToWideChar(CP_UTF8, MB_PRECOMPOSED, pFile, -1, fileName16, PATHLIMIT); - struct __stat64 filestat; - if (0 != _wstat64(fileName16, &filestat)) { - return false; - } - } else { - FILE* file = ::fopen(pFile, "rb"); - if (!file) - return false; - - ::fclose(file); + struct __stat64 filestat; + if (_wstat64(Utf8ToWide(pFile).c_str(), &filestat) != 0) { + return false; } #else - FILE* file = ::fopen( pFile, "rb"); - if( !file) + FILE* file = ::fopen(pFile, "rb"); + if (!file) return false; - ::fclose( file); + ::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]; - bool isUnicode = IsTextUnicode(strFile, static_cast(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 { - file = ::fopen(strFile, strMode); - } + 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; } @@ -147,74 +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__ ) - bool isUnicode = IsTextUnicode(in, static_cast(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); - if (ret) { - WideCharToMultiByte(CP_UTF8, MB_PRECOMPOSED, out16, -1, _out, PATHLIMIT, nullptr, nullptr); - } - 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 { - 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); - } + ai_assert(in); + std::string out; +#ifdef _WIN32 + wchar_t* ret = ::_wfullpath(nullptr, Utf8ToWide(in).c_str(), 0); + if (ret) { + out = WideToUtf8(ret); + free(ret); } #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("\\/"); @@ -223,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("\\/"); @@ -241,5 +214,3 @@ std::string DefaultIOSystem::absolutePath( const std::string &path ) } // ------------------------------------------------------------------------------------------------ - -#undef PATHLIMIT diff --git a/code/DefaultLogger.cpp b/code/Common/DefaultLogger.cpp similarity index 99% rename from code/DefaultLogger.cpp rename to code/Common/DefaultLogger.cpp index 2871a4131..de3528d2b 100644 --- a/code/DefaultLogger.cpp +++ b/code/Common/DefaultLogger.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/DefaultProgressHandler.h b/code/Common/DefaultProgressHandler.h similarity index 98% rename from code/DefaultProgressHandler.h rename to code/Common/DefaultProgressHandler.h index 851c17be6..bd2cce00b 100644 --- a/code/DefaultProgressHandler.h +++ b/code/Common/DefaultProgressHandler.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/Exporter.cpp b/code/Common/Exporter.cpp similarity index 94% rename from code/Exporter.cpp rename to code/Common/Exporter.cpp index 0acde75bf..34d49c472 100644 --- a/code/Exporter.cpp +++ b/code/Common/Exporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -61,15 +61,16 @@ Here we implement only the C++ interface (Assimp::Exporter). #include #include #include - -#include "DefaultProgressHandler.h" -#include "BaseProcess.h" -#include "JoinVerticesProcess.h" -#include "MakeVerboseFormat.h" -#include "ConvertToLHProcess.h" -#include "PretransformVertices.h" #include -#include "ScenePrivate.h" + +#include "Common/DefaultProgressHandler.h" +#include "Common/BaseProcess.h" +#include "Common/ScenePrivate.h" +#include "PostProcessing/CalcTangentsProcess.h" +#include "PostProcessing/MakeVerboseFormat.h" +#include "PostProcessing/JoinVerticesProcess.h" +#include "PostProcessing/ConvertToLHProcess.h" +#include "PostProcessing/PretransformVertices.h" #include @@ -101,6 +102,7 @@ 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 ExportAssimp2Json(const char* , IOSystem*, const aiScene* , const Assimp::ExportProperties*); // ------------------------------------------------------------------------------------------------ // global array of all export formats which Assimp supports in its current build @@ -161,11 +163,11 @@ Exporter::ExportFormatEntry gExporters[] = #endif #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER - Exporter::ExportFormatEntry( "assbin", "Assimp Binary", "assbin" , &ExportSceneAssbin, 0 ), + Exporter::ExportFormatEntry( "assbin", "Assimp Binary File", "assbin" , &ExportSceneAssbin, 0 ), #endif #ifndef ASSIMP_BUILD_NO_ASSXML_EXPORTER - Exporter::ExportFormatEntry( "assxml", "Assxml Document", "assxml" , &ExportSceneAssxml, 0 ), + Exporter::ExportFormatEntry( "assxml", "Assimp XML Document", "assxml" , &ExportSceneAssxml, 0 ), #endif #ifndef ASSIMP_BUILD_NO_X3D_EXPORTER @@ -178,7 +180,11 @@ Exporter::ExportFormatEntry gExporters[] = #endif #ifndef ASSIMP_BUILD_NO_3MF_EXPORTER - Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 ) + Exporter::ExportFormatEntry( "3mf", "The 3MF-File-Format", "3mf", &ExportScene3MF, 0 ), +#endif + +#ifndef ASSIMP_BUILD_NO_ASSJSON_EXPORTER + Exporter::ExportFormatEntry( "assjson", "Assimp JSON Document", "json", &ExportAssimp2Json, 0) #endif }; @@ -288,7 +294,7 @@ void Exporter::SetProgressHandler(ProgressHandler* pHandler) { // ------------------------------------------------------------------------------------------------ const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const char* pFormatId, - unsigned int, const ExportProperties* /*pProperties*/ ) { + unsigned int pPreprocessing, const ExportProperties* pProperties) { if (pimpl->blob) { delete pimpl->blob; pimpl->blob = nullptr; @@ -298,7 +304,7 @@ const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const cha BlobIOSystem* blobio = new BlobIOSystem(); pimpl->mIOSystem = std::shared_ptr( blobio ); - if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName())) { + if (AI_SUCCESS != Export(pScene,pFormatId,blobio->GetMagicFileName(), pPreprocessing, pProperties)) { pimpl->mIOSystem = old; return nullptr; } @@ -309,34 +315,6 @@ const aiExportDataBlob* Exporter::ExportToBlob( const aiScene* pScene, const cha return pimpl->blob; } -// ------------------------------------------------------------------------------------------------ -bool IsVerboseFormat(const aiMesh* mesh) { - // avoid slow vector specialization - std::vector 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) { @@ -346,7 +324,7 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c // 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); @@ -466,7 +444,10 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c } ExportProperties emptyProperties; // Never pass NULL ExportProperties so Exporters don't have to worry. - exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProperties ? pProperties : &emptyProperties); + ExportProperties* pProp = pProperties ? (ExportProperties*)pProperties : &emptyProperties; + pProp->SetPropertyBool("bJoinIdenticalVertices", must_join_again); + exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp); + exp.mExportFunction(pPath,pimpl->mIOSystem.get(),scenecopy.get(), pProp); pimpl->mProgressHandler->UpdateFileWrite(4, 4); } catch (DeadlyExportError& err) { diff --git a/code/FileLogStream.h b/code/Common/FileLogStream.h similarity index 98% rename from code/FileLogStream.h rename to code/Common/FileLogStream.h index 9966091d2..740c50319 100644 --- a/code/FileLogStream.h +++ b/code/Common/FileLogStream.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/FileSystemFilter.h b/code/Common/FileSystemFilter.h similarity index 100% rename from code/FileSystemFilter.h rename to code/Common/FileSystemFilter.h diff --git a/code/IFF.h b/code/Common/IFF.h similarity index 100% rename from code/IFF.h rename to code/Common/IFF.h diff --git a/code/Importer.cpp b/code/Common/Importer.cpp similarity index 98% rename from code/Importer.cpp rename to code/Common/Importer.cpp index fe6df187c..91b50859a 100644 --- a/code/Importer.cpp +++ b/code/Common/Importer.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -64,15 +64,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ------------------------------------------------------------------------------------------------ // Internal headers // ------------------------------------------------------------------------------------------------ -#include "Importer.h" -#include -#include "BaseProcess.h" +#include "Common/Importer.h" +#include "Common/BaseProcess.h" +#include "Common/DefaultProgressHandler.h" +#include "PostProcessing/ProcessHelper.h" +#include "Common/ScenePreprocessor.h" +#include "Common/ScenePrivate.h" -#include "DefaultProgressHandler.h" +#include #include -#include "ProcessHelper.h" -#include "ScenePreprocessor.h" -#include "ScenePrivate.h" #include #include #include @@ -86,7 +86,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #ifndef ASSIMP_BUILD_NO_VALIDATEDS_PROCESS -# include "ValidateDataStructure.h" +# include "PostProcessing/ValidateDataStructure.h" #endif using namespace Assimp::Profiling; @@ -483,7 +483,7 @@ const aiScene* Importer::ReadFileFromMemory( const void* pBuffer, IOSystem* io = pimpl->mIOHandler; pimpl->mIOHandler = NULL; - SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength)); + SetIOHandler(new MemoryIOSystem((const uint8_t*)pBuffer,pLength,io)); // read the file and recover the previous IOSystem static const size_t BufSize(Importer::MaxLenHint + 28); @@ -590,10 +590,12 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) // Find an worker class which can handle the file BaseImporter* imp = NULL; + SetPropertyInteger("importerIndex", -1); for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, false)) { imp = pimpl->mImporter[a]; + SetPropertyInteger("importerIndex", a); break; } } @@ -606,6 +608,7 @@ const aiScene* Importer::ReadFile( const char* _pFile, unsigned int pFlags) for( unsigned int a = 0; a < pimpl->mImporter.size(); a++) { if( pimpl->mImporter[a]->CanRead( pFile, pimpl->mIOHandler, true)) { imp = pimpl->mImporter[a]; + SetPropertyInteger("importerIndex", a); break; } } diff --git a/code/Importer.h b/code/Common/Importer.h similarity index 99% rename from code/Importer.h rename to code/Common/Importer.h index c6628c428..a439d99c2 100644 --- a/code/Importer.h +++ b/code/Common/Importer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/ImporterRegistry.cpp b/code/Common/ImporterRegistry.cpp similarity index 85% rename from code/ImporterRegistry.cpp rename to code/Common/ImporterRegistry.cpp index d3ae53c7d..32ac3b416 100644 --- a/code/ImporterRegistry.cpp +++ b/code/Common/ImporterRegistry.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -56,148 +56,148 @@ corresponding preprocessor flag to selectively disable formats. // (include_new_importers_here) // ------------------------------------------------------------------------------------------------ #ifndef ASSIMP_BUILD_NO_X_IMPORTER -# include "XFileImporter.h" +# include "X/XFileImporter.h" #endif #ifndef ASSIMP_BUILD_NO_AMF_IMPORTER -# include "AMFImporter.hpp" +# include "AMF/AMFImporter.hpp" #endif #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER -# include "3DSLoader.h" +# include "3DS/3DSLoader.h" #endif #ifndef ASSIMP_BUILD_NO_MD3_IMPORTER -# include "MD3Loader.h" +# include "MD3/MD3Loader.h" #endif #ifndef ASSIMP_BUILD_NO_MDL_IMPORTER -# include "MDLLoader.h" +# include "MDL/MDLLoader.h" #endif #ifndef ASSIMP_BUILD_NO_MD2_IMPORTER -# include "MD2Loader.h" +# include "MD2/MD2Loader.h" #endif #ifndef ASSIMP_BUILD_NO_PLY_IMPORTER -# include "PlyLoader.h" +# include "Ply/PlyLoader.h" #endif #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER -# include "ASELoader.h" +# include "ASE/ASELoader.h" #endif #ifndef ASSIMP_BUILD_NO_OBJ_IMPORTER -# include "ObjFileImporter.h" +# include "Obj/ObjFileImporter.h" #endif #ifndef ASSIMP_BUILD_NO_HMP_IMPORTER -# include "HMPLoader.h" +# include "HMP/HMPLoader.h" #endif #ifndef ASSIMP_BUILD_NO_SMD_IMPORTER -# include "SMDLoader.h" +# include "SMD/SMDLoader.h" #endif #ifndef ASSIMP_BUILD_NO_MDC_IMPORTER -# include "MDCLoader.h" +# include "MDC/MDCLoader.h" #endif #ifndef ASSIMP_BUILD_NO_MD5_IMPORTER -# include "MD5Loader.h" +# include "MD5/MD5Loader.h" #endif #ifndef ASSIMP_BUILD_NO_STL_IMPORTER -# include "STLLoader.h" +# include "STL/STLLoader.h" #endif #ifndef ASSIMP_BUILD_NO_LWO_IMPORTER -# include "LWOLoader.h" +# include "LWO/LWOLoader.h" #endif #ifndef ASSIMP_BUILD_NO_DXF_IMPORTER -# include "DXFLoader.h" +# include "DXF/DXFLoader.h" #endif #ifndef ASSIMP_BUILD_NO_NFF_IMPORTER -# include "NFFLoader.h" +# include "NFF/NFFLoader.h" #endif #ifndef ASSIMP_BUILD_NO_RAW_IMPORTER -# include "RawLoader.h" +# include "Raw/RawLoader.h" #endif #ifndef ASSIMP_BUILD_NO_SIB_IMPORTER -# include "SIBImporter.h" +# include "SIB/SIBImporter.h" #endif #ifndef ASSIMP_BUILD_NO_OFF_IMPORTER -# include "OFFLoader.h" +# include "OFF/OFFLoader.h" #endif #ifndef ASSIMP_BUILD_NO_AC_IMPORTER -# include "ACLoader.h" +# include "AC/ACLoader.h" #endif #ifndef ASSIMP_BUILD_NO_BVH_IMPORTER -# include "BVHLoader.h" +# include "BVH/BVHLoader.h" #endif #ifndef ASSIMP_BUILD_NO_IRRMESH_IMPORTER -# include "IRRMeshLoader.h" +# include "Irr/IRRMeshLoader.h" #endif #ifndef ASSIMP_BUILD_NO_IRR_IMPORTER -# include "IRRLoader.h" +# include "Irr/IRRLoader.h" #endif #ifndef ASSIMP_BUILD_NO_Q3D_IMPORTER -# include "Q3DLoader.h" +# include "Q3D/Q3DLoader.h" #endif #ifndef ASSIMP_BUILD_NO_B3D_IMPORTER -# include "B3DImporter.h" +# include "B3D/B3DImporter.h" #endif #ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER -# include "ColladaLoader.h" +# include "Collada/ColladaLoader.h" #endif #ifndef ASSIMP_BUILD_NO_TERRAGEN_IMPORTER -# include "TerragenLoader.h" +# include "Terragen/TerragenLoader.h" #endif #ifndef ASSIMP_BUILD_NO_CSM_IMPORTER -# include "CSMLoader.h" +# include "CSM/CSMLoader.h" #endif #ifndef ASSIMP_BUILD_NO_3D_IMPORTER -# include "UnrealLoader.h" +# include "Unreal/UnrealLoader.h" #endif #ifndef ASSIMP_BUILD_NO_LWS_IMPORTER -# include "LWSLoader.h" +# include "LWS/LWSLoader.h" #endif #ifndef ASSIMP_BUILD_NO_OGRE_IMPORTER -# include "OgreImporter.h" +# include "Ogre/OgreImporter.h" #endif #ifndef ASSIMP_BUILD_NO_OPENGEX_IMPORTER -# include "OpenGEXImporter.h" +# include "OpenGEX/OpenGEXImporter.h" #endif #ifndef ASSIMP_BUILD_NO_MS3D_IMPORTER -# include "MS3DLoader.h" +# include "MS3D/MS3DLoader.h" #endif #ifndef ASSIMP_BUILD_NO_COB_IMPORTER -# include "COBLoader.h" +# include "COB/COBLoader.h" #endif #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER -# include "BlenderLoader.h" +# include "Blender/BlenderLoader.h" #endif #ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER -# include "Q3BSPFileImporter.h" +# include "Q3BSP/Q3BSPFileImporter.h" #endif #ifndef ASSIMP_BUILD_NO_NDO_IMPORTER -# include "NDOLoader.h" +# include "NDO/NDOLoader.h" #endif #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER # include "Importer/IFC/IFCLoader.h" #endif #ifndef ASSIMP_BUILD_NO_XGL_IMPORTER -# include "XGLLoader.h" +# include "XGL/XGLLoader.h" #endif #ifndef ASSIMP_BUILD_NO_FBX_IMPORTER -# include "FBXImporter.h" +# include "FBX/FBXImporter.h" #endif #ifndef ASSIMP_BUILD_NO_ASSBIN_IMPORTER -# include "AssbinLoader.h" +# include "Assbin/AssbinLoader.h" #endif #ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER -# include "glTFImporter.h" -# include "glTF2Importer.h" +# include "glTF/glTFImporter.h" +# include "glTF2/glTF2Importer.h" #endif #ifndef ASSIMP_BUILD_NO_C4D_IMPORTER -# include "C4DImporter.h" +# include "C4D/C4DImporter.h" #endif #ifndef ASSIMP_BUILD_NO_3MF_IMPORTER -# include "D3MFImporter.h" +# include "3MF/D3MFImporter.h" #endif #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER -# include "X3DImporter.hpp" +# include "X3D/X3DImporter.hpp" #endif #ifndef ASSIMP_BUILD_NO_MMD_IMPORTER -# include "MMDImporter.h" +# include "MMD/MMDImporter.h" #endif -#ifndef ASSIMP_BUILD_NO_STEPFILE_IMPORTER +#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER # include "Importer/StepFile/StepFileImporter.h" #endif @@ -355,7 +355,7 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out) #ifndef ASSIMP_BUILD_NO_MMD_IMPORTER out.push_back( new MMDImporter() ); #endif -#ifndef ASSIMP_BUILD_NO_STEPFILE_IMPORTER +#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER out.push_back(new StepFile::StepFileImporter()); #endif } @@ -364,7 +364,7 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out) void DeleteImporterInstanceList(std::vector< BaseImporter* >& deleteList){ for(size_t i= 0; i& out) #ifndef ASSIMP_BUILD_NO_TRANSFORMTEXCOORDS_PROCESS out.push_back( new TextureTransformStep()); #endif +#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS) + out.push_back( new ScaleProcess()); +#endif #if (!defined ASSIMP_BUILD_NO_PRETRANSFORMVERTICES_PROCESS) out.push_back( new PretransformVertices()); #endif @@ -208,9 +215,6 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out) #endif #if (!defined ASSIMP_BUILD_NO_GENFACENORMALS_PROCESS) out.push_back( new GenFaceNormalsProcess()); -#endif -#if (!defined ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS) - out.push_back( new ScaleProcess()); #endif // ......................................................................... // DON'T change the order of these five .. @@ -246,6 +250,9 @@ void GetPostProcessingStepInstanceList(std::vector< BaseProcess* >& out) #if (!defined ASSIMP_BUILD_NO_IMPROVECACHELOCALITY_PROCESS) out.push_back( new ImproveCacheLocalityProcess()); #endif +#if (!defined ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS) + out.push_back(new GenBoundingBoxesProcess); +#endif } } diff --git a/code/RemoveComments.cpp b/code/Common/RemoveComments.cpp similarity index 99% rename from code/RemoveComments.cpp rename to code/Common/RemoveComments.cpp index 3ba3c60be..91700a769 100644 --- a/code/RemoveComments.cpp +++ b/code/Common/RemoveComments.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/SGSpatialSort.cpp b/code/Common/SGSpatialSort.cpp similarity index 99% rename from code/SGSpatialSort.cpp rename to code/Common/SGSpatialSort.cpp index d74c57ed5..120070b0a 100644 --- a/code/SGSpatialSort.cpp +++ b/code/Common/SGSpatialSort.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/SceneCombiner.cpp b/code/Common/SceneCombiner.cpp similarity index 95% rename from code/SceneCombiner.cpp rename to code/Common/SceneCombiner.cpp index 883447372..f7b13cc95 100644 --- a/code/SceneCombiner.cpp +++ b/code/Common/SceneCombiner.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -738,7 +738,11 @@ void SceneCombiner::MergeBones(aiMesh* out,std::vector::const_iterator // And copy the final weights - adjust the vertex IDs by the // face index offset of the corresponding mesh. - for (std::vector< BoneSrcIndex >::const_iterator wmit = (*boneIt).pSrcBones.begin(); wmit != wend; ++wmit) { + for (std::vector< BoneSrcIndex >::const_iterator wmit = (*boneIt).pSrcBones.begin(); wmit != (*boneIt).pSrcBones.end(); ++wmit) { + if (wmit == wend) { + break; + } + aiBone* pip = (*wmit).first; for (unsigned int mp = 0; mp < pip->mNumWeights;++mp,++avw) { const aiVertexWeight& vfi = pip->mWeights[mp]; @@ -1087,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); } // ------------------------------------------------------------------------------------------------ @@ -1163,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 ); } // ------------------------------------------------------------------------------------------------ @@ -1182,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 ) { diff --git a/code/ScenePreprocessor.cpp b/code/Common/ScenePreprocessor.cpp similarity index 99% rename from code/ScenePreprocessor.cpp rename to code/Common/ScenePreprocessor.cpp index 1228ab2c2..432a3d766 100644 --- a/code/ScenePreprocessor.cpp +++ b/code/Common/ScenePreprocessor.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/ScenePreprocessor.h b/code/Common/ScenePreprocessor.h similarity index 99% rename from code/ScenePreprocessor.h rename to code/Common/ScenePreprocessor.h index 3900a237b..3f4c8d7c3 100644 --- a/code/ScenePreprocessor.h +++ b/code/Common/ScenePreprocessor.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/ScenePrivate.h b/code/Common/ScenePrivate.h similarity index 98% rename from code/ScenePrivate.h rename to code/Common/ScenePrivate.h index 775b9cb52..f336aafc9 100644 --- a/code/ScenePrivate.h +++ b/code/Common/ScenePrivate.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/SkeletonMeshBuilder.cpp b/code/Common/SkeletonMeshBuilder.cpp similarity index 99% rename from code/SkeletonMeshBuilder.cpp rename to code/Common/SkeletonMeshBuilder.cpp index ecfe8586f..06cfe034e 100644 --- a/code/SkeletonMeshBuilder.cpp +++ b/code/Common/SkeletonMeshBuilder.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/SpatialSort.cpp b/code/Common/SpatialSort.cpp similarity index 99% rename from code/SpatialSort.cpp rename to code/Common/SpatialSort.cpp index b0ab6e412..a4f3a4e4b 100644 --- a/code/SpatialSort.cpp +++ b/code/Common/SpatialSort.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/SplitByBoneCountProcess.cpp b/code/Common/SplitByBoneCountProcess.cpp similarity index 99% rename from code/SplitByBoneCountProcess.cpp rename to code/Common/SplitByBoneCountProcess.cpp index 6faf11086..2ef66a9af 100644 --- a/code/SplitByBoneCountProcess.cpp +++ b/code/Common/SplitByBoneCountProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/SplitByBoneCountProcess.h b/code/Common/SplitByBoneCountProcess.h similarity index 99% rename from code/SplitByBoneCountProcess.h rename to code/Common/SplitByBoneCountProcess.h index b46dd6b0f..6c904a9df 100644 --- a/code/SplitByBoneCountProcess.h +++ b/code/Common/SplitByBoneCountProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/StandardShapes.cpp b/code/Common/StandardShapes.cpp similarity index 95% rename from code/StandardShapes.cpp rename to code/Common/StandardShapes.cpp index 7d2319401..2e5100130 100644 --- a/code/StandardShapes.cpp +++ b/code/Common/StandardShapes.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -127,35 +127,35 @@ aiMesh* StandardShapes::MakeMesh(const std::vector& positions, // Determine which kinds of primitives the mesh consists of aiMesh* out = new aiMesh(); - switch (numIndices) - { - case 1: - out->mPrimitiveTypes = aiPrimitiveType_POINT; - break; - case 2: - out->mPrimitiveTypes = aiPrimitiveType_LINE; - break; - case 3: - out->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - break; - default: - out->mPrimitiveTypes = aiPrimitiveType_POLYGON; - break; + switch (numIndices) { + case 1: + out->mPrimitiveTypes = aiPrimitiveType_POINT; + break; + case 2: + out->mPrimitiveTypes = aiPrimitiveType_LINE; + break; + case 3: + out->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; + break; + default: + out->mPrimitiveTypes = aiPrimitiveType_POLYGON; + break; }; out->mNumFaces = (unsigned int)positions.size() / numIndices; out->mFaces = new aiFace[out->mNumFaces]; - for (unsigned int i = 0, a = 0; i < out->mNumFaces;++i) - { + for (unsigned int i = 0, a = 0; i < out->mNumFaces;++i) { aiFace& f = out->mFaces[i]; f.mNumIndices = numIndices; f.mIndices = new unsigned int[numIndices]; - for (unsigned int i = 0; i < numIndices;++i,++a) - f.mIndices[i] = a; + for (unsigned int j = 0; i < numIndices; ++i, ++a) { + f.mIndices[j] = a; + } } out->mNumVertices = (unsigned int)positions.size(); out->mVertices = new aiVector3D[out->mNumVertices]; ::memcpy(out->mVertices,&positions[0],out->mNumVertices*sizeof(aiVector3D)); + return out; } @@ -466,8 +466,8 @@ void StandardShapes::MakeCone(ai_real height,ai_real radius1, // Need to flip face order? if ( SIZE_MAX != old ) { - for (size_t s = old; s < positions.size();s += 3) { - std::swap(positions[s],positions[s+1]); + for (size_t p = old; p < positions.size();p += 3) { + std::swap(positions[p],positions[p+1]); } } } diff --git a/code/StdOStreamLogStream.h b/code/Common/StdOStreamLogStream.h similarity index 98% rename from code/StdOStreamLogStream.h rename to code/Common/StdOStreamLogStream.h index 43b8d7de2..893e261a2 100644 --- a/code/StdOStreamLogStream.h +++ b/code/Common/StdOStreamLogStream.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/Subdivision.cpp b/code/Common/Subdivision.cpp similarity index 99% rename from code/Subdivision.cpp rename to code/Common/Subdivision.cpp index 2f2f09596..60c54939f 100644 --- a/code/Subdivision.cpp +++ b/code/Common/Subdivision.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -43,9 +43,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include "ProcessHelper.h" #include #include + +#include "PostProcessing/ProcessHelper.h" + #include using namespace Assimp; @@ -56,8 +58,7 @@ void mydummy() {} * implementation is basing on recursive refinement. Directly evaluating the result is also * possible and much quicker, but it depends on lengthy matrix lookup tables. */ // ------------------------------------------------------------------------------------------------ -class CatmullClarkSubdivider : public Subdivider -{ +class CatmullClarkSubdivider : public Subdivider { public: void Subdivide (aiMesh* mesh, aiMesh*& out, unsigned int num, bool discard_input); void Subdivide (aiMesh** smesh, size_t nmesh, diff --git a/code/TargetAnimation.cpp b/code/Common/TargetAnimation.cpp similarity index 99% rename from code/TargetAnimation.cpp rename to code/Common/TargetAnimation.cpp index 2834b1f10..b8062499f 100644 --- a/code/TargetAnimation.cpp +++ b/code/Common/TargetAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/TargetAnimation.h b/code/Common/TargetAnimation.h similarity index 99% rename from code/TargetAnimation.h rename to code/Common/TargetAnimation.h index bb37e6008..91634ab5a 100644 --- a/code/TargetAnimation.h +++ b/code/Common/TargetAnimation.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/Version.cpp b/code/Common/Version.cpp similarity index 97% rename from code/Version.cpp rename to code/Common/Version.cpp index b823abd68..868cfb06a 100644 --- a/code/Version.cpp +++ b/code/Common/Version.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -46,8 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "ScenePrivate.h" -static const unsigned int MajorVersion = 4; -static const unsigned int MinorVersion = 1; +static const unsigned int MajorVersion = 5; +static const unsigned int MinorVersion = 0; // -------------------------------------------------------------------------------- // Legal information string - don't remove this. diff --git a/code/VertexTriangleAdjacency.cpp b/code/Common/VertexTriangleAdjacency.cpp similarity index 99% rename from code/VertexTriangleAdjacency.cpp rename to code/Common/VertexTriangleAdjacency.cpp index b41fd029d..7cfd1a350 100644 --- a/code/VertexTriangleAdjacency.cpp +++ b/code/Common/VertexTriangleAdjacency.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/VertexTriangleAdjacency.h b/code/Common/VertexTriangleAdjacency.h similarity index 99% rename from code/VertexTriangleAdjacency.h rename to code/Common/VertexTriangleAdjacency.h index 23624a5be..f3be47612 100644 --- a/code/VertexTriangleAdjacency.h +++ b/code/Common/VertexTriangleAdjacency.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/Win32DebugLogStream.h b/code/Common/Win32DebugLogStream.h similarity index 98% rename from code/Win32DebugLogStream.h rename to code/Common/Win32DebugLogStream.h index 7bbe8002a..a6063a261 100644 --- a/code/Win32DebugLogStream.h +++ b/code/Common/Win32DebugLogStream.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/Common/ZipArchiveIOSystem.cpp b/code/Common/ZipArchiveIOSystem.cpp new file mode 100644 index 000000000..7c37a05f9 --- /dev/null +++ b/code/Common/ZipArchiveIOSystem.cpp @@ -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 +#include + +#include + +#include +#include + +#ifdef ASSIMP_USE_HUNTER +# include +#else +# include +#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(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(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(io_stream->Write(buf, 1, size)); + } + + long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) { + IOStream* io_stream = (IOStream*)stream; + + return static_cast(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(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 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(&(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(m_Size)) != static_cast(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(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& rFileList); + void getFileListExtension(std::vector& 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 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& rFileList) { + MapArchive(); + rFileList.clear(); + + for (const auto &file : m_ArchiveMap) { + rFileList.push_back(file.first); + } + } + + void ZipArchiveIOSystem::Implement::getFileListExtension(std::vector& 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& rFileList) const { + return pImpl->getFileList(rFileList); + } + + void ZipArchiveIOSystem::getFileListExtension(std::vector& 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()); + } + +} diff --git a/code/assbin_chunks.h b/code/Common/assbin_chunks.h similarity index 100% rename from code/assbin_chunks.h rename to code/Common/assbin_chunks.h diff --git a/code/scene.cpp b/code/Common/scene.cpp similarity index 99% rename from code/scene.cpp rename to code/Common/scene.cpp index 676051163..2acb348d8 100644 --- a/code/scene.cpp +++ b/code/Common/scene.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/simd.cpp b/code/Common/simd.cpp similarity index 98% rename from code/simd.cpp rename to code/Common/simd.cpp index 9e2a83a60..04615f408 100644 --- a/code/simd.cpp +++ b/code/Common/simd.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/simd.h b/code/Common/simd.h similarity index 98% rename from code/simd.h rename to code/Common/simd.h index 19117569d..3eecdd458 100644 --- a/code/simd.h +++ b/code/Common/simd.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/D3MFOpcPackage.cpp b/code/D3MFOpcPackage.cpp deleted file mode 100644 index 8161a31e4..000000000 --- a/code/D3MFOpcPackage.cpp +++ /dev/null @@ -1,531 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2018, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -#ifndef ASSIMP_BUILD_NO_3MF_IMPORTER - -#include "D3MFOpcPackage.h" -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#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(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(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(io_stream->Write(buf, 1, size)); -} - -long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) { - IOStream* io_stream = (IOStream*) stream; - - return static_cast(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; - - 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; - mapping.opaque = reinterpret_cast(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 &rFileList); - -private: - bool mapArchive(); - -private: - unzFile m_ZipFileHandle; - std::map 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::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::iterator it = m_ArchiveMap.find(pFile); - - if(it != m_ArchiveMap.end()) { - result = static_cast(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 &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::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 OpcPackageRelationshipPtr; - -class OpcPackageRelationshipReader { -public: - OpcPackageRelationshipReader(XmlReader* xmlReader) { - while(xmlReader->read()) { - if(xmlReader->getNodeType() == irr::io::EXN_ELEMENT && - xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_CONTAINER) - { - ParseRootNode(xmlReader); - } - } - } - - void ParseRootNode(XmlReader* xmlReader) - { - ParseAttributes(xmlReader); - - while(xmlReader->read()) - { - if(xmlReader->getNodeType() == irr::io::EXN_ELEMENT && - xmlReader->getNodeName() == XmlTag::RELS_RELATIONSHIP_NODE) - { - ParseChildNode(xmlReader); - } - } - } - - void ParseAttributes(XmlReader*) { - // empty - } - - bool validateRels( OpcPackageRelationshipPtr &relPtr ) { - if ( relPtr->id.empty() || relPtr->type.empty() || relPtr->target.empty() ) { - return false; - } - return true; - } - - void ParseChildNode(XmlReader* xmlReader) { - OpcPackageRelationshipPtr relPtr(new OpcPackageRelationship()); - - relPtr->id = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_ID.c_str()); - relPtr->type = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TYPE.c_str()); - relPtr->target = xmlReader->getAttributeValueSafe(XmlTag::RELS_ATTRIB_TARGET.c_str()); - if ( validateRels( relPtr ) ) { - m_relationShips.push_back( relPtr ); - } - } - - std::vector m_relationShips; -}; - -// ------------------------------------------------------------------------------------------------ -D3MFOpcPackage::D3MFOpcPackage(IOSystem* pIOHandler, const std::string& rFile) -: mRootStream(nullptr) -, mZipArchive() { - mZipArchive.reset( new D3MF::D3MFZipArchive( pIOHandler, rFile ) ); - if(!mZipArchive->isOpen()) { - throw DeadlyImportError("Failed to open file " + rFile+ "."); - } - - std::vector fileList; - mZipArchive->getFileList(fileList); - - for (auto& file: fileList) { - if(file == D3MF::XmlTag::ROOT_RELATIONSHIPS_ARCHIVE) { - //PkgRelationshipReader pkgRelReader(file, archive); - ai_assert(mZipArchive->Exists(file.c_str())); - - IOStream *fileStream = mZipArchive->Open(file.c_str()); - - ai_assert(fileStream != nullptr); - - std::string rootFile = ReadPackageRootRelationship(fileStream); - if ( rootFile.size() > 0 && rootFile[ 0 ] == '/' ) { - rootFile = rootFile.substr( 1 ); - if ( rootFile[ 0 ] == '/' ) { - // deal with zip-bug - rootFile = rootFile.substr( 1 ); - } - } - - ASSIMP_LOG_DEBUG(rootFile); - - 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) { - - } - } -} - -D3MFOpcPackage::~D3MFOpcPackage() { - // empty -} - -IOStream* D3MFOpcPackage::RootStream() const { - return mRootStream; -} - -static const std::string ModelRef = "3D/3dmodel.model"; - -bool D3MFOpcPackage::validate() { - if ( nullptr == mRootStream || nullptr == mZipArchive ) { - return false; - } - - return mZipArchive->Exists( ModelRef.c_str() ); -} - -bool D3MFOpcPackage::isZipArchive( IOSystem* pIOHandler, const std::string& rFile ) { - D3MF::D3MFZipArchive ar( pIOHandler, rFile ); - if ( !ar.isOpen() ) { - return false; - } - - return true; -} - -std::string D3MFOpcPackage::ReadPackageRootRelationship(IOStream* stream) { - std::unique_ptr xmlStream(new CIrrXML_IOStreamReader(stream)); - std::unique_ptr xml(irr::io::createIrrXMLReader(xmlStream.get())); - - OpcPackageRelationshipReader reader(xml.get()); - - auto itr = std::find_if(reader.m_relationShips.begin(), reader.m_relationShips.end(), [](const OpcPackageRelationshipPtr& rel){ - return rel->type == XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE; - }); - - if ( itr == reader.m_relationShips.end() ) { - throw DeadlyImportError( "Cannot find " + XmlTag::PACKAGE_START_PART_RELATIONSHIP_TYPE ); - } - - return (*itr)->target; -} - -} // Namespace D3MF -} // Namespace Assimp - -#endif //ASSIMP_BUILD_NO_3MF_IMPORTER diff --git a/code/DXFHelper.h b/code/DXF/DXFHelper.h similarity index 99% rename from code/DXFHelper.h rename to code/DXF/DXFHelper.h index daf2f97e2..0ec8e130b 100644 --- a/code/DXFHelper.h +++ b/code/DXF/DXFHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/DXFLoader.cpp b/code/DXF/DXFLoader.cpp similarity index 99% rename from code/DXFLoader.cpp rename to code/DXF/DXFLoader.cpp index 6710597df..baf315485 100644 --- a/code/DXFLoader.cpp +++ b/code/DXF/DXFLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,12 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_DXF_IMPORTER -#include "DXFLoader.h" -#include -#include "ConvertToLHProcess.h" -#include +#include "DXF/DXFLoader.h" +#include "DXF/DXFHelper.h" +#include "PostProcessing/ConvertToLHProcess.h" -#include "DXFHelper.h" +#include +#include #include #include #include diff --git a/code/DXFLoader.h b/code/DXF/DXFLoader.h similarity index 99% rename from code/DXFLoader.h rename to code/DXF/DXFLoader.h index e7f534e98..044cf6bcb 100644 --- a/code/DXFLoader.h +++ b/code/DXF/DXFLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/FBXAnimation.cpp b/code/FBX/FBXAnimation.cpp similarity index 98% rename from code/FBXAnimation.cpp rename to code/FBX/FBXAnimation.cpp index 24ab9b14b..874914431 100644 --- a/code/FBXAnimation.cpp +++ b/code/FBX/FBXAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -105,8 +105,8 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, cons const Scope& sc = GetRequiredScope(element); // find target node - const char* whitelist[] = {"Model","NodeAttribute"}; - const std::vector& conns = doc.GetConnectionsBySourceSequenced(ID(),whitelist,2); + const char* whitelist[] = {"Model","NodeAttribute","Deformer"}; + const std::vector& conns = doc.GetConnectionsBySourceSequenced(ID(),whitelist,3); for(const Connection* con : conns) { diff --git a/code/FBXBinaryTokenizer.cpp b/code/FBX/FBXBinaryTokenizer.cpp similarity index 96% rename from code/FBXBinaryTokenizer.cpp rename to code/FBX/FBXBinaryTokenizer.cpp index b81a9f945..a4a2bc8e7 100644 --- a/code/FBXBinaryTokenizer.cpp +++ b/code/FBX/FBXBinaryTokenizer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -83,7 +83,7 @@ namespace FBX { // e_unknown_21 = 1 << 21, // e_unknown_22 = 1 << 22, // e_unknown_23 = 1 << 23, -// e_flag_field_size_64_bit = 1 << 24, // Not sure what is +// e_flag_field_size_64_bit = 1 << 24, // Not sure what is // e_unknown_25 = 1 << 25, // e_unknown_26 = 1 << 26, // e_unknown_27 = 1 << 27, @@ -98,7 +98,7 @@ namespace FBX { // return (flags & to_check) != 0; //} // ------------------------------------------------------------------------------------------------ -Token::Token(const char* sbegin, const char* send, TokenType type, unsigned int offset) +Token::Token(const char* sbegin, const char* send, TokenType type, size_t offset) : #ifdef DEBUG contents(sbegin, static_cast(send-sbegin)), @@ -122,18 +122,18 @@ namespace { // ------------------------------------------------------------------------------------------------ // signal tokenization error, this is always unrecoverable. Throws DeadlyImportError. -AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int offset) AI_WONT_RETURN_SUFFIX; -AI_WONT_RETURN void TokenizeError(const std::string& message, unsigned int offset) +AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) AI_WONT_RETURN_SUFFIX; +AI_WONT_RETURN void TokenizeError(const std::string& message, size_t offset) { throw DeadlyImportError(Util::AddOffset("FBX-Tokenize",message,offset)); } // ------------------------------------------------------------------------------------------------ -uint32_t Offset(const char* begin, const char* cursor) { +size_t Offset(const char* begin, const char* cursor) { ai_assert(begin <= cursor); - return static_cast(cursor - begin); + return cursor - begin; } // ------------------------------------------------------------------------------------------------ @@ -276,8 +276,8 @@ void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, case 'f': case 'd': case 'l': - case 'i': { - + case 'i': + case 'c': { const uint32_t length = ReadWord(input, cursor, end); const uint32_t encoding = ReadWord(input, cursor, end); @@ -298,6 +298,10 @@ void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, stride = 8; break; + case 'c': + stride = 1; + break; + default: ai_assert(false); }; @@ -420,7 +424,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, // ------------------------------------------------------------------------------------------------ // TODO: Test FBX Binary files newer than the 7500 version to check if the 64 bits address behaviour is consistent -void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int length) +void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length) { ai_assert(input); diff --git a/code/FBXCommon.h b/code/FBX/FBXCommon.h similarity index 98% rename from code/FBXCommon.h rename to code/FBX/FBXCommon.h index 60b040552..e51644913 100644 --- a/code/FBXCommon.h +++ b/code/FBX/FBXCommon.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -47,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - +namespace Assimp { namespace FBX { const std::string NULL_RECORD = { // 13 null bytes @@ -80,7 +80,7 @@ namespace FBX TransformInheritance_MAX // end-of-enum sentinel }; } - +} #endif // ASSIMP_BUILD_NO_FBX_EXPORTER #endif // AI_FBXCOMMON_H_INC diff --git a/code/FBXCompileConfig.h b/code/FBX/FBXCompileConfig.h similarity index 98% rename from code/FBXCompileConfig.h rename to code/FBX/FBXCompileConfig.h index 2e7336e85..3a3841fa5 100644 --- a/code/FBXCompileConfig.h +++ b/code/FBX/FBXCompileConfig.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/FBX/FBXConverter.cpp b/code/FBX/FBXConverter.cpp new file mode 100644 index 000000000..152be3277 --- /dev/null +++ b/code/FBX/FBXConverter.cpp @@ -0,0 +1,3615 @@ +/* +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 FBXConverter.cpp + * @brief Implementation of the FBX DOM -> aiScene converter + */ + +#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER + +#include "FBXConverter.h" +#include "FBXParser.h" +#include "FBXMeshGeometry.h" +#include "FBXDocument.h" +#include "FBXUtil.h" +#include "FBXProperties.h" +#include "FBXImporter.h" + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + + +namespace Assimp { + namespace FBX { + + using namespace Util; + +#define MAGIC_NODE_TAG "_$AssimpFbx$" + +#define CONVERT_FBX_TIME(time) static_cast(time) / 46186158000L + + FBXConverter::FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones ) + : defaultMaterialIndex() + , lights() + , cameras() + , textures() + , materials_converted() + , textures_converted() + , meshes_converted() + , node_anim_chain_bits() + , mNodeNames() + , anim_fps() + , out(out) + , 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(); + ConvertRootNode(); + + if (doc.Settings().readAllMaterials) { + // unfortunately this means we have to evaluate all objects + for (const ObjectMap::value_type& v : doc.Objects()) { + + const Object* ob = v.second->Get(); + if (!ob) { + continue; + } + + const Material* mat = dynamic_cast(ob); + if (mat) { + + if (materials_converted.find(mat) == materials_converted.end()) { + ConvertMaterial(*mat, 0); + } + } + } + } + + ConvertGlobalSettings(); + TransferDataToScene(); + + // if we didn't read any meshes set the AI_SCENE_FLAGS_INCOMPLETE + // to make sure the scene passes assimp's validation. FBX files + // need not contain geometry (i.e. camera animations, raw armatures). + if (out->mNumMeshes == 0) { + out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; + } + } + + + FBXConverter::~FBXConverter() { + std::for_each(meshes.begin(), meshes.end(), Util::delete_fun()); + std::for_each(materials.begin(), materials.end(), Util::delete_fun()); + std::for_each(animations.begin(), animations.end(), Util::delete_fun()); + std::for_each(lights.begin(), lights.end(), Util::delete_fun()); + std::for_each(cameras.begin(), cameras.end(), Util::delete_fun()); + std::for_each(textures.begin(), textures.end(), Util::delete_fun()); + } + + void FBXConverter::ConvertRootNode() { + out->mRootNode = new aiNode(); + std::string unique_name; + GetUniqueName("RootNode", unique_name); + out->mRootNode->mName.Set(unique_name); + + // root has ID 0 + ConvertNodes(0L, *out->mRootNode); + } + + static std::string getAncestorBaseName(const aiNode* node) + { + const char* nodeName = nullptr; + size_t length = 0; + while (node && (!nodeName || length == 0)) + { + nodeName = node->mName.C_Str(); + length = node->mName.length; + node = node->mParent; + } + + if (!nodeName || length == 0) + { + return {}; + } + // could be std::string_view if c++17 available + return std::string(nodeName, length); + } + + // Make unique name + std::string FBXConverter::MakeUniqueNodeName(const Model* const model, const aiNode& parent) + { + std::string original_name = FixNodeName(model->Name()); + if (original_name.empty()) + { + original_name = getAncestorBaseName(&parent); + } + std::string unique_name; + GetUniqueName(original_name, unique_name); + return unique_name; + } + + void FBXConverter::ConvertNodes(uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform) { + const std::vector& conns = doc.GetConnectionsByDestinationSequenced(id, "Model"); + + std::vector nodes; + nodes.reserve(conns.size()); + + std::vector nodes_chain; + std::vector post_nodes_chain; + + try { + for (const Connection* con : conns) { + + // ignore object-property links + if (con->PropertyName().length()) { + continue; + } + + const Object* const object = con->SourceObject(); + if (nullptr == object) { + FBXImporter::LogWarn("failed to convert source object for Model link"); + continue; + } + + const Model* const model = dynamic_cast(object); + + if (nullptr != model) { + nodes_chain.clear(); + post_nodes_chain.clear(); + + aiMatrix4x4 new_abs_transform = parent_transform; + + std::string unique_name = MakeUniqueNodeName(model, parent); + + // 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); + + ai_assert(nodes_chain.size()); + + if (need_additional_node) { + nodes_chain.push_back(new aiNode(unique_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); + + if (last_parent != &parent) { + last_parent->mNumChildren = 1; + last_parent->mChildren = new aiNode*[1]; + last_parent->mChildren[0] = prenode; + } + + prenode->mParent = last_parent; + last_parent = prenode; + + new_abs_transform *= prenode->mTransformation; + } + + // attach geometry + ConvertModel(*model, *nodes_chain.back(), new_abs_transform); + + // check if there will be any child nodes + const std::vector& child_conns + = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model"); + + // if so, link the geometric transform inverse nodes + // before we attach any child nodes + if (child_conns.size()) { + for (aiNode* postnode : post_nodes_chain) { + ai_assert(postnode); + + if (last_parent != &parent) { + last_parent->mNumChildren = 1; + last_parent->mChildren = new aiNode*[1]; + last_parent->mChildren[0] = postnode; + } + + postnode->mParent = last_parent; + last_parent = postnode; + + new_abs_transform *= postnode->mTransformation; + } + } + else { + // free the nodes we allocated as we don't need them + Util::delete_fun deleter; + std::for_each( + post_nodes_chain.begin(), + post_nodes_chain.end(), + deleter + ); + } + + // attach sub-nodes (if any) + ConvertNodes(model->ID(), *last_parent, new_abs_transform); + + if (doc.Settings().readLights) { + ConvertLights(*model, unique_name); + } + + if (doc.Settings().readCameras) { + ConvertCameras(*model, unique_name); + } + + nodes.push_back(nodes_chain.front()); + nodes_chain.clear(); + } + } + + if (nodes.size()) { + parent.mChildren = new aiNode*[nodes.size()](); + parent.mNumChildren = static_cast(nodes.size()); + + std::swap_ranges(nodes.begin(), nodes.end(), parent.mChildren); + } + } + catch (std::exception&) { + Util::delete_fun deleter; + std::for_each(nodes.begin(), nodes.end(), deleter); + std::for_each(nodes_chain.begin(), nodes_chain.end(), deleter); + std::for_each(post_nodes_chain.begin(), post_nodes_chain.end(), deleter); + } + } + + + void FBXConverter::ConvertLights(const Model& model, const std::string &orig_name) { + const std::vector& node_attrs = model.GetAttributes(); + for (const NodeAttribute* attr : node_attrs) { + const Light* const light = dynamic_cast(attr); + if (light) { + ConvertLight(*light, orig_name); + } + } + } + + void FBXConverter::ConvertCameras(const Model& model, const std::string &orig_name) { + const std::vector& node_attrs = model.GetAttributes(); + for (const NodeAttribute* attr : node_attrs) { + const Camera* const cam = dynamic_cast(attr); + if (cam) { + ConvertCamera(*cam, orig_name); + } + } + } + + void FBXConverter::ConvertLight(const Light& light, const std::string &orig_name) { + lights.push_back(new aiLight()); + aiLight* const out_light = lights.back(); + + out_light->mName.Set(orig_name); + + const float intensity = light.Intensity() / 100.0f; + const aiVector3D& col = light.Color(); + + out_light->mColorDiffuse = aiColor3D(col.x, col.y, col.z); + out_light->mColorDiffuse.r *= intensity; + out_light->mColorDiffuse.g *= intensity; + out_light->mColorDiffuse.b *= intensity; + + out_light->mColorSpecular = out_light->mColorDiffuse; + + //lights are defined along negative y direction + out_light->mPosition = aiVector3D(0.0f); + out_light->mDirection = aiVector3D(0.0f, -1.0f, 0.0f); + out_light->mUp = aiVector3D(0.0f, 0.0f, -1.0f); + + switch (light.LightType()) + { + case Light::Type_Point: + out_light->mType = aiLightSource_POINT; + break; + + case Light::Type_Directional: + out_light->mType = aiLightSource_DIRECTIONAL; + break; + + case Light::Type_Spot: + out_light->mType = aiLightSource_SPOT; + out_light->mAngleOuterCone = AI_DEG_TO_RAD(light.OuterAngle()); + out_light->mAngleInnerCone = AI_DEG_TO_RAD(light.InnerAngle()); + break; + + case Light::Type_Area: + FBXImporter::LogWarn("cannot represent area light, set to UNDEFINED"); + out_light->mType = aiLightSource_UNDEFINED; + break; + + case Light::Type_Volume: + FBXImporter::LogWarn("cannot represent volume light, set to UNDEFINED"); + out_light->mType = aiLightSource_UNDEFINED; + break; + default: + ai_assert(false); + } + + float decay = light.DecayStart(); + switch (light.DecayType()) + { + case Light::Decay_None: + out_light->mAttenuationConstant = decay; + out_light->mAttenuationLinear = 0.0f; + out_light->mAttenuationQuadratic = 0.0f; + break; + case Light::Decay_Linear: + out_light->mAttenuationConstant = 0.0f; + out_light->mAttenuationLinear = 2.0f / decay; + out_light->mAttenuationQuadratic = 0.0f; + break; + case Light::Decay_Quadratic: + out_light->mAttenuationConstant = 0.0f; + out_light->mAttenuationLinear = 0.0f; + out_light->mAttenuationQuadratic = 2.0f / (decay * decay); + break; + case Light::Decay_Cubic: + FBXImporter::LogWarn("cannot represent cubic attenuation, set to Quadratic"); + out_light->mAttenuationQuadratic = 1.0f; + break; + default: + ai_assert(false); + break; + } + } + + void FBXConverter::ConvertCamera(const Camera& cam, const std::string &orig_name) + { + cameras.push_back(new aiCamera()); + aiCamera* const out_camera = cameras.back(); + + out_camera->mName.Set(orig_name); + + out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight(); + + out_camera->mPosition = aiVector3D(0.0f); + out_camera->mLookAt = aiVector3D(1.0f, 0.0f, 0.0f); + out_camera->mUp = aiVector3D(0.0f, 1.0f, 0.0f); + + out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView()); + + out_camera->mClipPlaneNear = cam.NearPlane(); + out_camera->mClipPlaneFar = cam.FarPlane(); + + out_camera->mHorizontalFOV = AI_DEG_TO_RAD(cam.FieldOfView()); + out_camera->mClipPlaneNear = cam.NearPlane(); + out_camera->mClipPlaneFar = cam.FarPlane(); + } + + void FBXConverter::GetUniqueName(const std::string &name, std::string &uniqueName) + { + uniqueName = name; + auto it_pair = mNodeNames.insert({ name, 0 }); // duplicate node name instance count + unsigned int& i = it_pair.first->second; + while (!it_pair.second) + { + i++; + std::ostringstream ext; + ext << name << std::setfill('0') << std::setw(3) << i; + uniqueName = ext.str(); + it_pair = mNodeNames.insert({ uniqueName, 0 }); + } + } + + const char* FBXConverter::NameTransformationComp(TransformationComp comp) { + switch (comp) { + case TransformationComp_Translation: + return "Translation"; + case TransformationComp_RotationOffset: + return "RotationOffset"; + case TransformationComp_RotationPivot: + return "RotationPivot"; + case TransformationComp_PreRotation: + return "PreRotation"; + case TransformationComp_Rotation: + return "Rotation"; + case TransformationComp_PostRotation: + return "PostRotation"; + case TransformationComp_RotationPivotInverse: + return "RotationPivotInverse"; + case TransformationComp_ScalingOffset: + return "ScalingOffset"; + case TransformationComp_ScalingPivot: + return "ScalingPivot"; + case TransformationComp_Scaling: + return "Scaling"; + case TransformationComp_ScalingPivotInverse: + return "ScalingPivotInverse"; + case TransformationComp_GeometricScaling: + return "GeometricScaling"; + case TransformationComp_GeometricRotation: + return "GeometricRotation"; + case TransformationComp_GeometricTranslation: + return "GeometricTranslation"; + case TransformationComp_GeometricScalingInverse: + return "GeometricScalingInverse"; + case TransformationComp_GeometricRotationInverse: + return "GeometricRotationInverse"; + case TransformationComp_GeometricTranslationInverse: + return "GeometricTranslationInverse"; + case TransformationComp_MAXIMUM: // this is to silence compiler warnings + default: + break; + } + + ai_assert(false); + + return nullptr; + } + + const char* FBXConverter::NameTransformationCompProperty(TransformationComp comp) { + switch (comp) { + case TransformationComp_Translation: + return "Lcl Translation"; + case TransformationComp_RotationOffset: + return "RotationOffset"; + case TransformationComp_RotationPivot: + return "RotationPivot"; + case TransformationComp_PreRotation: + return "PreRotation"; + case TransformationComp_Rotation: + return "Lcl Rotation"; + case TransformationComp_PostRotation: + return "PostRotation"; + case TransformationComp_RotationPivotInverse: + return "RotationPivotInverse"; + case TransformationComp_ScalingOffset: + return "ScalingOffset"; + case TransformationComp_ScalingPivot: + return "ScalingPivot"; + case TransformationComp_Scaling: + return "Lcl Scaling"; + case TransformationComp_ScalingPivotInverse: + return "ScalingPivotInverse"; + case TransformationComp_GeometricScaling: + return "GeometricScaling"; + case TransformationComp_GeometricRotation: + return "GeometricRotation"; + case TransformationComp_GeometricTranslation: + return "GeometricTranslation"; + case TransformationComp_GeometricScalingInverse: + return "GeometricScalingInverse"; + case TransformationComp_GeometricRotationInverse: + return "GeometricRotationInverse"; + case TransformationComp_GeometricTranslationInverse: + return "GeometricTranslationInverse"; + case TransformationComp_MAXIMUM: // this is to silence compiler warnings + break; + } + + ai_assert(false); + + return nullptr; + } + + aiVector3D FBXConverter::TransformationCompDefaultValue(TransformationComp comp) + { + // XXX a neat way to solve the never-ending special cases for scaling + // would be to do everything in log space! + return comp == TransformationComp_Scaling ? aiVector3D(1.f, 1.f, 1.f) : aiVector3D(); + } + + void FBXConverter::GetRotationMatrix(Model::RotOrder mode, const aiVector3D& rotation, aiMatrix4x4& out) + { + if (mode == Model::RotOrder_SphericXYZ) { + FBXImporter::LogError("Unsupported RotationMode: SphericXYZ"); + out = aiMatrix4x4(); + return; + } + + const float angle_epsilon = Math::getEpsilon(); + + out = aiMatrix4x4(); + + bool is_id[3] = { true, true, true }; + + aiMatrix4x4 temp[3]; + if (std::fabs(rotation.z) > angle_epsilon) { + aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(rotation.z), temp[2]); + is_id[2] = false; + } + if (std::fabs(rotation.y) > angle_epsilon) { + aiMatrix4x4::RotationY(AI_DEG_TO_RAD(rotation.y), temp[1]); + is_id[1] = false; + } + if (std::fabs(rotation.x) > angle_epsilon) { + aiMatrix4x4::RotationX(AI_DEG_TO_RAD(rotation.x), temp[0]); + is_id[0] = false; + } + + int order[3] = { -1, -1, -1 }; + + // note: rotation order is inverted since we're left multiplying as is usual in assimp + switch (mode) + { + case Model::RotOrder_EulerXYZ: + order[0] = 2; + order[1] = 1; + order[2] = 0; + break; + + case Model::RotOrder_EulerXZY: + order[0] = 1; + order[1] = 2; + order[2] = 0; + break; + + case Model::RotOrder_EulerYZX: + order[0] = 0; + order[1] = 2; + order[2] = 1; + break; + + case Model::RotOrder_EulerYXZ: + order[0] = 2; + order[1] = 0; + order[2] = 1; + break; + + case Model::RotOrder_EulerZXY: + order[0] = 1; + order[1] = 0; + order[2] = 2; + break; + + case Model::RotOrder_EulerZYX: + order[0] = 0; + order[1] = 1; + order[2] = 2; + break; + + default: + ai_assert(false); + break; + } + + ai_assert(order[0] >= 0); + ai_assert(order[0] <= 2); + ai_assert(order[1] >= 0); + ai_assert(order[1] <= 2); + ai_assert(order[2] >= 0); + ai_assert(order[2] <= 2); + + if (!is_id[order[0]]) { + out = temp[order[0]]; + } + + if (!is_id[order[1]]) { + out = out * temp[order[1]]; + } + + if (!is_id[order[2]]) { + out = out * temp[order[2]]; + } + } + + bool FBXConverter::NeedsComplexTransformationChain(const Model& model) + { + const PropertyTable& props = model.Props(); + bool ok; + + const float zero_epsilon = 1e-6f; + const aiVector3D all_ones(1.0f, 1.0f, 1.0f); + for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) { + const TransformationComp comp = static_cast(i); + + if (comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation) { + continue; + } + + bool scale_compare = (comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling); + + const aiVector3D& v = PropertyGet(props, NameTransformationCompProperty(comp), ok); + if (ok && scale_compare) { + if ((v - all_ones).SquareLength() > zero_epsilon) { + return true; + } + } else if (ok) { + if (v.SquareLength() > zero_epsilon) { + return true; + } + } + } + + return false; + } + + std::string FBXConverter::NameTransformationChainNode(const std::string& name, TransformationComp comp) + { + return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp); + } + + bool FBXConverter::GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector& output_nodes, + std::vector& post_output_nodes) { + const PropertyTable& props = model.Props(); + const Model::RotOrder rot = model.RotationOrder(); + + 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(TransformationComp_MAXIMUM), aiMatrix4x4()); + + // generate transformation matrices for all the different transformation components + const float zero_epsilon = Math::getEpsilon(); + const aiVector3D all_ones(1.0f, 1.0f, 1.0f); + + const aiVector3D& PreRotation = PropertyGet(props, "PreRotation", ok); + if (ok && PreRotation.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_PreRotation); + + GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PreRotation, chain[TransformationComp_PreRotation]); + } + + const aiVector3D& PostRotation = PropertyGet(props, "PostRotation", ok); + if (ok && PostRotation.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_PostRotation); + + GetRotationMatrix(Model::RotOrder::RotOrder_EulerXYZ, PostRotation, chain[TransformationComp_PostRotation]); + } + + const aiVector3D& RotationPivot = PropertyGet(props, "RotationPivot", ok); + if (ok && RotationPivot.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_RotationPivot) | (1 << TransformationComp_RotationPivotInverse); + + aiMatrix4x4::Translation(RotationPivot, chain[TransformationComp_RotationPivot]); + aiMatrix4x4::Translation(-RotationPivot, chain[TransformationComp_RotationPivotInverse]); + } + + const aiVector3D& RotationOffset = PropertyGet(props, "RotationOffset", ok); + if (ok && RotationOffset.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_RotationOffset); + + aiMatrix4x4::Translation(RotationOffset, chain[TransformationComp_RotationOffset]); + } + + const aiVector3D& ScalingOffset = PropertyGet(props, "ScalingOffset", ok); + if (ok && ScalingOffset.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_ScalingOffset); + + aiMatrix4x4::Translation(ScalingOffset, chain[TransformationComp_ScalingOffset]); + } + + const aiVector3D& ScalingPivot = PropertyGet(props, "ScalingPivot", ok); + if (ok && ScalingPivot.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_ScalingPivot) | (1 << TransformationComp_ScalingPivotInverse); + + aiMatrix4x4::Translation(ScalingPivot, chain[TransformationComp_ScalingPivot]); + aiMatrix4x4::Translation(-ScalingPivot, chain[TransformationComp_ScalingPivotInverse]); + } + + const aiVector3D& Translation = PropertyGet(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(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(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(props, "GeometricScaling", ok); + if (ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_GeometricScaling); + aiMatrix4x4::Scaling(GeometricScaling, chain[TransformationComp_GeometricScaling]); + aiVector3D GeometricScalingInverse = GeometricScaling; + bool canscale = true; + for (unsigned int i = 0; i < 3; ++i) { + if (std::fabs(GeometricScalingInverse[i]) > zero_epsilon) { + GeometricScalingInverse[i] = 1.0f / GeometricScaling[i]; + } + else { + FBXImporter::LogError("cannot invert geometric scaling matrix with a 0.0 scale component"); + canscale = false; + break; + } + } + if (canscale) { + chainBits = chainBits | (1 << TransformationComp_GeometricScalingInverse); + aiMatrix4x4::Scaling(GeometricScalingInverse, chain[TransformationComp_GeometricScalingInverse]); + } + } + + const aiVector3D& GeometricRotation = PropertyGet(props, "GeometricRotation", ok); + if (ok && GeometricRotation.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_GeometricRotation) | (1 << TransformationComp_GeometricRotationInverse); + GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotation]); + GetRotationMatrix(rot, GeometricRotation, chain[TransformationComp_GeometricRotationInverse]); + chain[TransformationComp_GeometricRotationInverse].Inverse(); + } + + const aiVector3D& GeometricTranslation = PropertyGet(props, "GeometricTranslation", ok); + if (ok && GeometricTranslation.SquareLength() > zero_epsilon) { + chainBits = chainBits | (1 << TransformationComp_GeometricTranslation) | (1 << TransformationComp_GeometricTranslationInverse); + aiMatrix4x4::Translation(GeometricTranslation, chain[TransformationComp_GeometricTranslation]); + aiMatrix4x4::Translation(-GeometricTranslation, chain[TransformationComp_GeometricTranslationInverse]); + } + + // 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) == ((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 ((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 + // have associated node animation channels. These can not be dropped + // even if they have identity transform in bind pose. + NodeAnimBitMap::const_iterator it = node_anim_chain_bits.find(name); + const unsigned int anim_chain_bitmask = (it == node_anim_chain_bits.end() ? 0 : (*it).second); + + unsigned int bit = 0x1; + for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) { + const TransformationComp comp = static_cast(i); + + if ((chainBits & bit) == 0 && (anim_chain_bitmask & bit) == 0) { + continue; + } + + if (comp == TransformationComp_PostRotation) { + chain[i] = chain[i].Inverse(); + } + + aiNode* nd = new aiNode(); + nd->mName.Set(NameTransformationChainNode(name, comp)); + nd->mTransformation = chain[i]; + + // geometric inverses go in a post-node chain + if (comp == TransformationComp_GeometricScalingInverse || + comp == TransformationComp_GeometricRotationInverse || + comp == TransformationComp_GeometricTranslationInverse + ) { + post_output_nodes.push_back(nd); + } + else { + output_nodes.push_back(nd); + } + } + + ai_assert(output_nodes.size()); + return true; + } + + // else, we can just multiply the matrices together + aiNode* nd = new aiNode(); + output_nodes.push_back(nd); + + // name passed to the method is already unique + nd->mName.Set(name); + + for (const auto &transform : chain) { + nd->mTransformation = nd->mTransformation * transform; + } + return false; + } + + void FBXConverter::SetupNodeMetadata(const Model& model, aiNode& nd) + { + const PropertyTable& props = model.Props(); + DirectPropertyMap unparsedProperties = props.GetUnparsedProperties(); + + // create metadata on node + const std::size_t numStaticMetaData = 2; + aiMetadata* data = aiMetadata::Alloc(static_cast(unparsedProperties.size() + numStaticMetaData)); + nd.mMetaData = data; + int index = 0; + + // find user defined properties (3ds Max) + data->Set(index++, "UserProperties", aiString(PropertyGet(props, "UDP3DSMAX", ""))); + // preserve the info that a node was marked as Null node in the original file. + data->Set(index++, "IsNull", model.IsNull() ? true : false); + + // add unparsed properties to the node's metadata + for (const DirectPropertyMap::value_type& prop : unparsedProperties) { + // Interpret the property as a concrete type + if (const TypedProperty* interpreted = prop.second->As >()) { + data->Set(index++, prop.first, interpreted->Value()); + } + else if (const TypedProperty* interpreted = prop.second->As >()) { + data->Set(index++, prop.first, interpreted->Value()); + } + else if (const TypedProperty* interpreted = prop.second->As >()) { + data->Set(index++, prop.first, interpreted->Value()); + } + else if (const TypedProperty* interpreted = prop.second->As >()) { + data->Set(index++, prop.first, interpreted->Value()); + } + else if (const TypedProperty* interpreted = prop.second->As >()) { + data->Set(index++, prop.first, aiString(interpreted->Value())); + } + else if (const TypedProperty* interpreted = prop.second->As >()) { + data->Set(index++, prop.first, interpreted->Value()); + } + else { + ai_assert(false); + } + } + } + + void FBXConverter::ConvertModel(const Model& model, aiNode& nd, const aiMatrix4x4& node_global_transform) + { + const std::vector& geos = model.GetGeometry(); + + std::vector meshes; + meshes.reserve(geos.size()); + + for (const Geometry* geo : geos) { + + const MeshGeometry* const mesh = dynamic_cast(geo); + const LineGeometry* const line = dynamic_cast(geo); + if (mesh) { + const std::vector& indices = ConvertMesh(*mesh, model, node_global_transform, nd); + std::copy(indices.begin(), indices.end(), std::back_inserter(meshes)); + } + else if (line) { + const std::vector& indices = ConvertLine(*line, model, node_global_transform, nd); + std::copy(indices.begin(), indices.end(), std::back_inserter(meshes)); + } + else { + FBXImporter::LogWarn("ignoring unrecognized geometry: " + geo->Name()); + } + } + + if (meshes.size()) { + nd.mMeshes = new unsigned int[meshes.size()](); + nd.mNumMeshes = static_cast(meshes.size()); + + std::swap_ranges(meshes.begin(), meshes.end(), nd.mMeshes); + } + } + + std::vector FBXConverter::ConvertMesh(const MeshGeometry& mesh, const Model& model, + const aiMatrix4x4& node_global_transform, aiNode& nd) + { + std::vector temp; + + MeshMap::const_iterator it = meshes_converted.find(&mesh); + if (it != meshes_converted.end()) { + std::copy((*it).second.begin(), (*it).second.end(), std::back_inserter(temp)); + return temp; + } + + const std::vector& vertices = mesh.GetVertices(); + const std::vector& faces = mesh.GetFaceIndexCounts(); + if (vertices.empty() || faces.empty()) { + FBXImporter::LogWarn("ignoring empty geometry: " + mesh.Name()); + return temp; + } + + // one material per mesh maps easily to aiMesh. Multiple material + // meshes need to be split. + const MatIndexArray& mindices = mesh.GetMaterialIndices(); + if (doc.Settings().readMaterials && !mindices.empty()) { + const MatIndexArray::value_type base = mindices[0]; + for (MatIndexArray::value_type index : mindices) { + if (index != base) { + return ConvertMeshMultiMaterial(mesh, model, node_global_transform, nd); + } + } + } + + // faster code-path, just copy the data + temp.push_back(ConvertMeshSingleMaterial(mesh, model, node_global_transform, nd)); + return temp; + } + + std::vector FBXConverter::ConvertLine(const LineGeometry& line, const Model& model, + const aiMatrix4x4& node_global_transform, aiNode& nd) + { + std::vector temp; + + const std::vector& vertices = line.GetVertices(); + const std::vector& indices = line.GetIndices(); + if (vertices.empty() || indices.empty()) { + FBXImporter::LogWarn("ignoring empty line: " + line.Name()); + return temp; + } + + aiMesh* const out_mesh = SetupEmptyMesh(line, nd); + out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; + + // copy vertices + out_mesh->mNumVertices = static_cast(vertices.size()); + out_mesh->mVertices = new aiVector3D[out_mesh->mNumVertices]; + std::copy(vertices.begin(), vertices.end(), out_mesh->mVertices); + + //Number of line segments (faces) is "Number of Points - Number of Endpoints" + //N.B.: Endpoints in FbxLine are denoted by negative indices. + //If such an Index is encountered, add 1 and multiply by -1 to get the real index. + unsigned int epcount = 0; + for (unsigned i = 0; i < indices.size(); i++) + { + if (indices[i] < 0) { + epcount++; + } + } + unsigned int pcount = static_cast( indices.size() ); + unsigned int scount = out_mesh->mNumFaces = pcount - epcount; + + aiFace* fac = out_mesh->mFaces = new aiFace[scount](); + for (unsigned int i = 0; i < pcount; ++i) { + if (indices[i] < 0) continue; + aiFace& f = *fac++; + f.mNumIndices = 2; //2 == aiPrimitiveType_LINE + f.mIndices = new unsigned int[2]; + f.mIndices[0] = indices[i]; + int segid = indices[(i + 1 == pcount ? 0 : i + 1)]; //If we have reached he last point, wrap around + f.mIndices[1] = (segid < 0 ? (segid + 1)*-1 : segid); //Convert EndPoint Index to normal Index + } + temp.push_back(static_cast(meshes.size() - 1)); + return temp; + } + + aiMesh* FBXConverter::SetupEmptyMesh(const Geometry& mesh, aiNode& nd) + { + aiMesh* const out_mesh = new aiMesh(); + meshes.push_back(out_mesh); + meshes_converted[&mesh].push_back(static_cast(meshes.size() - 1)); + + // set name + std::string name = mesh.Name(); + if (name.substr(0, 10) == "Geometry::") { + name = name.substr(10); + } + + if (name.length()) { + out_mesh->mName.Set(name); + } + else + { + out_mesh->mName = nd.mName; + } + + return out_mesh; + } + + unsigned int FBXConverter::ConvertMeshSingleMaterial(const MeshGeometry& mesh, const Model& model, + const aiMatrix4x4& node_global_transform, aiNode& nd) + { + const MatIndexArray& mindices = mesh.GetMaterialIndices(); + aiMesh* const out_mesh = SetupEmptyMesh(mesh, nd); + + const std::vector& vertices = mesh.GetVertices(); + const std::vector& faces = mesh.GetFaceIndexCounts(); + + // copy vertices + out_mesh->mNumVertices = static_cast(vertices.size()); + out_mesh->mVertices = new aiVector3D[vertices.size()]; + + std::copy(vertices.begin(), vertices.end(), out_mesh->mVertices); + + // generate dummy faces + out_mesh->mNumFaces = static_cast(faces.size()); + aiFace* fac = out_mesh->mFaces = new aiFace[faces.size()](); + + unsigned int cursor = 0; + for (unsigned int pcount : faces) { + aiFace& f = *fac++; + f.mNumIndices = pcount; + f.mIndices = new unsigned int[pcount]; + switch (pcount) + { + case 1: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; + break; + case 2: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; + break; + case 3: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; + break; + default: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; + break; + } + for (unsigned int i = 0; i < pcount; ++i) { + f.mIndices[i] = cursor++; + } + } + + // copy normals + const std::vector& normals = mesh.GetNormals(); + if (normals.size()) { + ai_assert(normals.size() == vertices.size()); + + out_mesh->mNormals = new aiVector3D[vertices.size()]; + std::copy(normals.begin(), normals.end(), out_mesh->mNormals); + } + + // copy tangents - assimp requires both tangents and bitangents (binormals) + // to be present, or neither of them. Compute binormals from normals + // and tangents if needed. + const std::vector& tangents = mesh.GetTangents(); + const std::vector* binormals = &mesh.GetBinormals(); + + if (tangents.size()) { + std::vector tempBinormals; + if (!binormals->size()) { + if (normals.size()) { + tempBinormals.resize(normals.size()); + for (unsigned int i = 0; i < tangents.size(); ++i) { + tempBinormals[i] = normals[i] ^ tangents[i]; + } + + binormals = &tempBinormals; + } + else { + binormals = NULL; + } + } + + if (binormals) { + ai_assert(tangents.size() == vertices.size()); + ai_assert(binormals->size() == vertices.size()); + + out_mesh->mTangents = new aiVector3D[vertices.size()]; + std::copy(tangents.begin(), tangents.end(), out_mesh->mTangents); + + out_mesh->mBitangents = new aiVector3D[vertices.size()]; + std::copy(binormals->begin(), binormals->end(), out_mesh->mBitangents); + } + } + + // copy texture coords + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + const std::vector& uvs = mesh.GetTextureCoords(i); + if (uvs.empty()) { + break; + } + + aiVector3D* out_uv = out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()]; + for (const aiVector2D& v : uvs) { + *out_uv++ = aiVector3D(v.x, v.y, 0.0f); + } + + out_mesh->mNumUVComponents[i] = 2; + } + + // copy vertex colors + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i) { + const std::vector& colors = mesh.GetVertexColors(i); + if (colors.empty()) { + break; + } + + out_mesh->mColors[i] = new aiColor4D[vertices.size()]; + std::copy(colors.begin(), colors.end(), out_mesh->mColors[i]); + } + + if (!doc.Settings().readMaterials || mindices.empty()) { + FBXImporter::LogError("no material assigned to mesh, setting default material"); + out_mesh->mMaterialIndex = GetDefaultMaterial(); + } + else { + 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); + } + + std::vector animMeshes; + for (const BlendShape* blendShape : mesh.GetBlendShapes()) { + for (const BlendShapeChannel* blendShapeChannel : blendShape->BlendShapeChannels()) { + const std::vector& shapeGeometries = blendShapeChannel->GetShapeGeometries(); + for (size_t i = 0; i < shapeGeometries.size(); i++) { + aiAnimMesh *animMesh = aiCreateAnimMesh(out_mesh); + const ShapeGeometry* shapeGeometry = shapeGeometries.at(i); + const std::vector& vertices = shapeGeometry->GetVertices(); + const std::vector& normals = shapeGeometry->GetNormals(); + const std::vector& indices = shapeGeometry->GetIndices(); + animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name())); + for (size_t j = 0; j < indices.size(); j++) { + unsigned int index = indices.at(j); + aiVector3D vertex = vertices.at(j); + aiVector3D normal = normals.at(j); + unsigned int count = 0; + const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count); + for (unsigned int k = 0; k < count; k++) { + unsigned int index = outIndices[k]; + animMesh->mVertices[index] += vertex; + if (animMesh->mNormals != nullptr) { + animMesh->mNormals[index] += normal; + animMesh->mNormals[index].NormalizeSafe(); + } + } + } + animMesh->mWeight = shapeGeometries.size() > 1 ? blendShapeChannel->DeformPercent() / 100.0f : 1.0f; + animMeshes.push_back(animMesh); + } + } + } + const size_t numAnimMeshes = animMeshes.size(); + if (numAnimMeshes > 0) { + out_mesh->mNumAnimMeshes = static_cast(numAnimMeshes); + out_mesh->mAnimMeshes = new aiAnimMesh*[numAnimMeshes]; + for (size_t i = 0; i < numAnimMeshes; i++) { + out_mesh->mAnimMeshes[i] = animMeshes.at(i); + } + } + return static_cast(meshes.size() - 1); + } + + std::vector FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model, + const aiMatrix4x4& node_global_transform, aiNode& nd) + { + const MatIndexArray& mindices = mesh.GetMaterialIndices(); + ai_assert(mindices.size()); + + std::set had; + std::vector indices; + + for (MatIndexArray::value_type index : mindices) { + if (had.find(index) == had.end()) { + + indices.push_back(ConvertMeshMultiMaterial(mesh, model, index, node_global_transform, nd)); + had.insert(index); + } + } + + return indices; + } + + unsigned int FBXConverter::ConvertMeshMultiMaterial(const MeshGeometry& mesh, const Model& model, + MatIndexArray::value_type index, + const aiMatrix4x4& node_global_transform, + aiNode& nd) + { + aiMesh* const out_mesh = SetupEmptyMesh(mesh, nd); + + const MatIndexArray& mindices = mesh.GetMaterialIndices(); + const std::vector& vertices = mesh.GetVertices(); + const std::vector& faces = mesh.GetFaceIndexCounts(); + + const bool process_weights = doc.Settings().readWeights && mesh.DeformerSkin() != NULL; + + unsigned int count_faces = 0; + unsigned int count_vertices = 0; + + // count faces + std::vector::const_iterator itf = faces.begin(); + for (MatIndexArray::const_iterator it = mindices.begin(), + end = mindices.end(); it != end; ++it, ++itf) + { + if ((*it) != index) { + continue; + } + ++count_faces; + count_vertices += *itf; + } + + ai_assert(count_faces); + ai_assert(count_vertices); + + // mapping from output indices to DOM indexing, needed to resolve weights or blendshapes + std::vector reverseMapping; + std::map translateIndexMap; + if (process_weights || mesh.GetBlendShapes().size() > 0) { + reverseMapping.resize(count_vertices); + } + + // allocate output data arrays, but don't fill them yet + out_mesh->mNumVertices = count_vertices; + out_mesh->mVertices = new aiVector3D[count_vertices]; + + out_mesh->mNumFaces = count_faces; + aiFace* fac = out_mesh->mFaces = new aiFace[count_faces](); + + + // allocate normals + const std::vector& normals = mesh.GetNormals(); + if (normals.size()) { + ai_assert(normals.size() == vertices.size()); + out_mesh->mNormals = new aiVector3D[vertices.size()]; + } + + // allocate tangents, binormals. + const std::vector& tangents = mesh.GetTangents(); + const std::vector* binormals = &mesh.GetBinormals(); + std::vector tempBinormals; + + if (tangents.size()) { + if (!binormals->size()) { + if (normals.size()) { + // XXX this computes the binormals for the entire mesh, not only + // the part for which we need them. + tempBinormals.resize(normals.size()); + for (unsigned int i = 0; i < tangents.size(); ++i) { + tempBinormals[i] = normals[i] ^ tangents[i]; + } + + binormals = &tempBinormals; + } + else { + binormals = NULL; + } + } + + if (binormals) { + ai_assert(tangents.size() == vertices.size() && binormals->size() == vertices.size()); + + out_mesh->mTangents = new aiVector3D[vertices.size()]; + out_mesh->mBitangents = new aiVector3D[vertices.size()]; + } + } + + // allocate texture coords + unsigned int num_uvs = 0; + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i, ++num_uvs) { + const std::vector& uvs = mesh.GetTextureCoords(i); + if (uvs.empty()) { + break; + } + + out_mesh->mTextureCoords[i] = new aiVector3D[vertices.size()]; + out_mesh->mNumUVComponents[i] = 2; + } + + // allocate vertex colors + unsigned int num_vcs = 0; + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i, ++num_vcs) { + const std::vector& colors = mesh.GetVertexColors(i); + if (colors.empty()) { + break; + } + + out_mesh->mColors[i] = new aiColor4D[vertices.size()]; + } + + unsigned int cursor = 0, in_cursor = 0; + + itf = faces.begin(); + for (MatIndexArray::const_iterator it = mindices.begin(), end = mindices.end(); it != end; ++it, ++itf) + { + const unsigned int pcount = *itf; + if ((*it) != index) { + in_cursor += pcount; + continue; + } + + aiFace& f = *fac++; + + f.mNumIndices = pcount; + f.mIndices = new unsigned int[pcount]; + switch (pcount) + { + case 1: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; + break; + case 2: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; + break; + case 3: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; + break; + default: + out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; + break; + } + for (unsigned int i = 0; i < pcount; ++i, ++cursor, ++in_cursor) { + f.mIndices[i] = cursor; + + if (reverseMapping.size()) { + reverseMapping[cursor] = in_cursor; + translateIndexMap[in_cursor] = cursor; + } + + out_mesh->mVertices[cursor] = vertices[in_cursor]; + + if (out_mesh->mNormals) { + out_mesh->mNormals[cursor] = normals[in_cursor]; + } + + if (out_mesh->mTangents) { + out_mesh->mTangents[cursor] = tangents[in_cursor]; + out_mesh->mBitangents[cursor] = (*binormals)[in_cursor]; + } + + for (unsigned int j = 0; j < num_uvs; ++j) { + const std::vector& uvs = mesh.GetTextureCoords(j); + out_mesh->mTextureCoords[j][cursor] = aiVector3D(uvs[in_cursor].x, uvs[in_cursor].y, 0.0f); + } + + for (unsigned int j = 0; j < num_vcs; ++j) { + const std::vector& cols = mesh.GetVertexColors(j); + out_mesh->mColors[j][cursor] = cols[in_cursor]; + } + } + } + + ConvertMaterialForMesh(out_mesh, model, mesh, index); + + if (process_weights) { + ConvertWeights(out_mesh, model, mesh, node_global_transform, index, &reverseMapping); + } + + std::vector animMeshes; + for (const BlendShape* blendShape : mesh.GetBlendShapes()) { + for (const BlendShapeChannel* blendShapeChannel : blendShape->BlendShapeChannels()) { + const std::vector& shapeGeometries = blendShapeChannel->GetShapeGeometries(); + for (size_t i = 0; i < shapeGeometries.size(); i++) { + aiAnimMesh* animMesh = aiCreateAnimMesh(out_mesh); + const ShapeGeometry* shapeGeometry = shapeGeometries.at(i); + const std::vector& vertices = shapeGeometry->GetVertices(); + const std::vector& normals = shapeGeometry->GetNormals(); + const std::vector& indices = shapeGeometry->GetIndices(); + animMesh->mName.Set(FixAnimMeshName(shapeGeometry->Name())); + for (size_t j = 0; j < indices.size(); j++) { + unsigned int index = indices.at(j); + aiVector3D vertex = vertices.at(j); + aiVector3D normal = normals.at(j); + unsigned int count = 0; + const unsigned int* outIndices = mesh.ToOutputVertexIndex(index, count); + for (unsigned int k = 0; k < count; k++) { + unsigned int outIndex = outIndices[k]; + if (translateIndexMap.find(outIndex) == translateIndexMap.end()) + continue; + unsigned int index = translateIndexMap[outIndex]; + animMesh->mVertices[index] += vertex; + if (animMesh->mNormals != nullptr) { + animMesh->mNormals[index] += normal; + animMesh->mNormals[index].NormalizeSafe(); + } + } + } + animMesh->mWeight = shapeGeometries.size() > 1 ? blendShapeChannel->DeformPercent() / 100.0f : 1.0f; + animMeshes.push_back(animMesh); + } + } + } + + const size_t numAnimMeshes = animMeshes.size(); + if (numAnimMeshes > 0) { + out_mesh->mNumAnimMeshes = static_cast(numAnimMeshes); + out_mesh->mAnimMeshes = new aiAnimMesh*[numAnimMeshes]; + for (size_t i = 0; i < numAnimMeshes; i++) { + out_mesh->mAnimMeshes[i] = animMeshes.at(i); + } + } + + return static_cast(meshes.size() - 1); + } + + void FBXConverter::ConvertWeights(aiMesh* out, const Model& model, const MeshGeometry& geo, + const aiMatrix4x4& node_global_transform, + unsigned int materialIndex, + std::vector* outputVertStartIndices) + { + ai_assert(geo.DeformerSkin()); + + std::vector out_indices; + std::vector index_out_indices; + std::vector count_out_indices; + + const Skin& sk = *geo.DeformerSkin(); + + std::vector bones; + bones.reserve(sk.Clusters().size()); + + const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION; + ai_assert(no_mat_check || outputVertStartIndices); + + try { + + for (const Cluster* cluster : sk.Clusters()) { + ai_assert(cluster); + + const WeightIndexArray& indices = cluster->GetIndices(); + + const MatIndexArray& mats = geo.GetMaterialIndices(); + + const size_t no_index_sentinel = std::numeric_limits::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 + // which should never happen + ai_assert(out_idx != NULL); + + index_out_indices.push_back(no_index_sentinel); + count_out_indices.push_back(0); + + for (unsigned int i = 0; i < count; ++i) { + if (no_mat_check || static_cast(mats[geo.FaceForVertexIndex(out_idx[i])]) == materialIndex) { + + if (index_out_indices.back() == no_index_sentinel) { + index_out_indices.back() = out_indices.size(); + } + + if (no_mat_check) { + out_indices.push_back(out_idx[i]); + } else { + // this extra lookup is in O(logn), so the entire algorithm becomes O(nlogn) + const std::vector::iterator it = std::lower_bound( + outputVertStartIndices->begin(), + outputVertStartIndices->end(), + out_idx[i] + ); + + out_indices.push_back(std::distance(outputVertStartIndices->begin(), it)); + } + + ++count_out_indices.back(); + } + } + } + + // 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. + ConvertCluster(bones, model, *cluster, out_indices, index_out_indices, + count_out_indices, node_global_transform); + } + } + catch (std::exception&) { + std::for_each(bones.begin(), bones.end(), Util::delete_fun()); + throw; + } + + if (bones.empty()) { + return; + } + + out->mBones = new aiBone*[bones.size()](); + out->mNumBones = static_cast(bones.size()); + + std::swap_ranges(bones.begin(), bones.end(), out->mBones); + } + + void FBXConverter::ConvertCluster(std::vector& bones, const Model& /*model*/, const Cluster& cl, + std::vector& out_indices, + std::vector& index_out_indices, + std::vector& count_out_indices, + const aiMatrix4x4& node_global_transform) + { + + aiBone* const bone = new aiBone(); + bones.push_back(bone); + + bone->mName = FixNodeName(cl.TargetNode()->Name()); + + bone->mOffsetMatrix = cl.TransformLink(); + bone->mOffsetMatrix.Inverse(); + + bone->mOffsetMatrix = bone->mOffsetMatrix * node_global_transform; + + bone->mNumWeights = static_cast(out_indices.size()); + aiVertexWeight* cursor = bone->mWeights = new aiVertexWeight[out_indices.size()]; + + const size_t no_index_sentinel = std::numeric_limits::max(); + const WeightArray& weights = cl.GetWeights(); + + const size_t c = index_out_indices.size(); + for (size_t i = 0; i < c; ++i) { + const size_t index_index = index_out_indices[i]; + + if (index_index == no_index_sentinel) { + continue; + } + + const size_t cc = count_out_indices[i]; + for (size_t j = 0; j < cc; ++j) { + aiVertexWeight& out_weight = *cursor++; + + out_weight.mVertexId = static_cast(out_indices[index_index + j]); + out_weight.mWeight = weights[i]; + } + } + } + + void FBXConverter::ConvertMaterialForMesh(aiMesh* out, const Model& model, const MeshGeometry& geo, + MatIndexArray::value_type materialIndex) + { + // locate source materials for this mesh + const std::vector& mats = model.GetMaterials(); + if (static_cast(materialIndex) >= mats.size() || materialIndex < 0) { + FBXImporter::LogError("material index out of bounds, setting default material"); + out->mMaterialIndex = GetDefaultMaterial(); + return; + } + + const Material* const mat = mats[materialIndex]; + MaterialMap::const_iterator it = materials_converted.find(mat); + if (it != materials_converted.end()) { + out->mMaterialIndex = (*it).second; + return; + } + + out->mMaterialIndex = ConvertMaterial(*mat, &geo); + materials_converted[mat] = out->mMaterialIndex; + } + + unsigned int FBXConverter::GetDefaultMaterial() + { + if (defaultMaterialIndex) { + return defaultMaterialIndex - 1; + } + + aiMaterial* out_mat = new aiMaterial(); + materials.push_back(out_mat); + + const aiColor3D diffuse = aiColor3D(0.8f, 0.8f, 0.8f); + out_mat->AddProperty(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE); + + aiString s; + s.Set(AI_DEFAULT_MATERIAL_NAME); + + out_mat->AddProperty(&s, AI_MATKEY_NAME); + + defaultMaterialIndex = static_cast(materials.size()); + return defaultMaterialIndex - 1; + } + + + unsigned int FBXConverter::ConvertMaterial(const Material& material, const MeshGeometry* const mesh) + { + const PropertyTable& props = material.Props(); + + // generate empty output material + aiMaterial* out_mat = new aiMaterial(); + materials_converted[&material] = static_cast(materials.size()); + + materials.push_back(out_mat); + + aiString str; + + // strip Material:: prefix + std::string name = material.Name(); + if (name.substr(0, 10) == "Material::") { + name = name.substr(10); + } + + // set material name if not empty - this could happen + // and there should be no key for it in this case. + if (name.length()) { + str.Set(name); + out_mat->AddProperty(&str, AI_MATKEY_NAME); + } + + // Set the shading mode as best we can: The FBX specification only mentions Lambert and Phong, and only Phong is mentioned in Assimp's aiShadingMode enum. + if (material.GetShadingModel() == "phong") + { + aiShadingMode shadingMode = aiShadingMode_Phong; + out_mat->AddProperty(&shadingMode, 1, AI_MATKEY_SHADING_MODEL); + } + + // shading stuff and colors + SetShadingPropertiesCommon(out_mat, props); + SetShadingPropertiesRaw( out_mat, props, material.Textures(), mesh ); + + // texture assignments + SetTextureProperties(out_mat, material.Textures(), mesh); + SetTextureProperties(out_mat, material.LayeredTextures(), mesh); + + return static_cast(materials.size() - 1); + } + + unsigned int FBXConverter::ConvertVideo(const Video& video) + { + // generate empty output texture + aiTexture* out_tex = new aiTexture(); + textures.push_back(out_tex); + + // assuming the texture is compressed + out_tex->mWidth = static_cast(video.ContentLength()); // total data size + out_tex->mHeight = 0; // fixed to 0 + + // steal the data from the Video to avoid an additional copy + out_tex->pcData = reinterpret_cast(const_cast(video).RelinquishContent()); + + // try to extract a hint from the file extension + const std::string& filename = video.RelativeFilename().empty() ? video.FileName() : video.RelativeFilename(); + std::string ext = BaseImporter::GetExtension(filename); + + if (ext == "jpeg") { + ext = "jpg"; + } + + if (ext.size() <= 3) { + memcpy(out_tex->achFormatHint, ext.c_str(), ext.size()); + } + + out_tex->mFilename.Set(filename.c_str()); + + return static_cast(textures.size() - 1); + } + + aiString FBXConverter::GetTexturePath(const Texture* tex) + { + aiString path; + path.Set(tex->RelativeFilename()); + + const Video* media = tex->Media(); + if (media != nullptr) { + bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found) + unsigned int index; + + VideoMap::const_iterator it = textures_converted.find(media); + if (it != textures_converted.end()) { + index = (*it).second; + textureReady = true; + } + else { + if (media->ContentLength() > 0) { + index = ConvertVideo(*media); + textures_converted[media] = index; + textureReady = true; + } + } + + // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready + if (doc.Settings().useLegacyEmbeddedTextureNaming) { + if (textureReady) { + // TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING" + // In FBX files textures are now stored internally by Assimp with their filename included + // Now Assimp can lookup through the loaded textures after all data is processed + // We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it + // This may occur on this case too, it has to be studied + path.data[0] = '*'; + path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index); + } + } + } + + return path; + } + + void FBXConverter::TrySetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, + const std::string& propName, + aiTextureType target, const MeshGeometry* const mesh) { + TextureMap::const_iterator it = textures.find(propName); + if (it == textures.end()) { + return; + } + + const Texture* const tex = (*it).second; + if (tex != 0) + { + aiString path = GetTexturePath(tex); + out_mat->AddProperty(&path, _AI_MATKEY_TEXTURE_BASE, target, 0); + + aiUVTransform uvTrafo; + // XXX handle all kinds of UV transformations + uvTrafo.mScaling = tex->UVScaling(); + uvTrafo.mTranslation = tex->UVTranslation(); + out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, 0); + + const PropertyTable& props = tex->Props(); + + int uvIndex = 0; + + bool ok; + const std::string& uvSet = PropertyGet(props, "UVSet", ok); + if (ok) { + // "default" is the name which usually appears in the FbxFileTexture template + if (uvSet != "default" && uvSet.length()) { + // this is a bit awkward - we need to find a mesh that uses this + // material and scan its UV channels for the given UV name because + // assimp references UV channels by index, not by name. + + // XXX: the case that UV channels may appear in different orders + // in meshes is unhandled. A possible solution would be to sort + // the UV channels alphabetically, but this would have the side + // effect that the primary (first) UV channel would sometimes + // be moved, causing trouble when users read only the first + // UV channel and ignore UV channel assignments altogether. + + const unsigned int matIndex = static_cast(std::distance(materials.begin(), + std::find(materials.begin(), materials.end(), out_mat) + )); + + + uvIndex = -1; + if (!mesh) + { + for (const MeshMap::value_type& v : meshes_converted) { + const MeshGeometry* const meshGeom = dynamic_cast (v.first); + if (!meshGeom) { + continue; + } + + const MatIndexArray& mats = meshGeom->GetMaterialIndices(); + if (std::find(mats.begin(), mats.end(), matIndex) == mats.end()) { + continue; + } + + int index = -1; + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + if (meshGeom->GetTextureCoords(i).empty()) { + break; + } + const std::string& name = meshGeom->GetTextureCoordChannelName(i); + if (name == uvSet) { + index = static_cast(i); + break; + } + } + if (index == -1) { + FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); + continue; + } + + if (uvIndex == -1) { + uvIndex = index; + } + else { + FBXImporter::LogWarn("the UV channel named " + uvSet + + " appears at different positions in meshes, results will be wrong"); + } + } + } + else + { + int index = -1; + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + if (mesh->GetTextureCoords(i).empty()) { + break; + } + const std::string& name = mesh->GetTextureCoordChannelName(i); + if (name == uvSet) { + index = static_cast(i); + break; + } + } + if (index == -1) { + FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); + } + + if (uvIndex == -1) { + uvIndex = index; + } + } + + if (uvIndex == -1) { + FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); + uvIndex = 0; + } + } + } + + out_mat->AddProperty(&uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, 0); + } + } + + void FBXConverter::TrySetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, + const std::string& propName, + aiTextureType target, const MeshGeometry* const mesh) { + LayeredTextureMap::const_iterator it = layeredTextures.find(propName); + if (it == layeredTextures.end()) { + return; + } + + int texCount = (*it).second->textureCount(); + + // Set the blend mode for layered textures + int blendmode = (*it).second->GetBlendMode(); + out_mat->AddProperty(&blendmode, 1, _AI_MATKEY_TEXOP_BASE, target, 0); + + for (int texIndex = 0; texIndex < texCount; texIndex++) { + + const Texture* const tex = (*it).second->getTexture(texIndex); + + aiString path = GetTexturePath(tex); + out_mat->AddProperty(&path, _AI_MATKEY_TEXTURE_BASE, target, texIndex); + + aiUVTransform uvTrafo; + // XXX handle all kinds of UV transformations + uvTrafo.mScaling = tex->UVScaling(); + uvTrafo.mTranslation = tex->UVTranslation(); + out_mat->AddProperty(&uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, texIndex); + + const PropertyTable& props = tex->Props(); + + int uvIndex = 0; + + bool ok; + const std::string& uvSet = PropertyGet(props, "UVSet", ok); + if (ok) { + // "default" is the name which usually appears in the FbxFileTexture template + if (uvSet != "default" && uvSet.length()) { + // this is a bit awkward - we need to find a mesh that uses this + // material and scan its UV channels for the given UV name because + // assimp references UV channels by index, not by name. + + // XXX: the case that UV channels may appear in different orders + // in meshes is unhandled. A possible solution would be to sort + // the UV channels alphabetically, but this would have the side + // effect that the primary (first) UV channel would sometimes + // be moved, causing trouble when users read only the first + // UV channel and ignore UV channel assignments altogether. + + const unsigned int matIndex = static_cast(std::distance(materials.begin(), + std::find(materials.begin(), materials.end(), out_mat) + )); + + uvIndex = -1; + if (!mesh) + { + for (const MeshMap::value_type& v : meshes_converted) { + const MeshGeometry* const meshGeom = dynamic_cast (v.first); + if (!meshGeom) { + continue; + } + + const MatIndexArray& mats = meshGeom->GetMaterialIndices(); + if (std::find(mats.begin(), mats.end(), matIndex) == mats.end()) { + continue; + } + + int index = -1; + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + if (meshGeom->GetTextureCoords(i).empty()) { + break; + } + const std::string& name = meshGeom->GetTextureCoordChannelName(i); + if (name == uvSet) { + index = static_cast(i); + break; + } + } + if (index == -1) { + FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); + continue; + } + + if (uvIndex == -1) { + uvIndex = index; + } + else { + FBXImporter::LogWarn("the UV channel named " + uvSet + + " appears at different positions in meshes, results will be wrong"); + } + } + } + else + { + int index = -1; + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + if (mesh->GetTextureCoords(i).empty()) { + break; + } + const std::string& name = mesh->GetTextureCoordChannelName(i); + if (name == uvSet) { + index = static_cast(i); + break; + } + } + if (index == -1) { + FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); + } + + if (uvIndex == -1) { + uvIndex = index; + } + } + + if (uvIndex == -1) { + FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); + uvIndex = 0; + } + } + } + + out_mat->AddProperty(&uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, texIndex); + } + } + + void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh) + { + TrySetTextureProperties(out_mat, textures, "DiffuseColor", aiTextureType_DIFFUSE, mesh); + TrySetTextureProperties(out_mat, textures, "AmbientColor", aiTextureType_AMBIENT, mesh); + TrySetTextureProperties(out_mat, textures, "EmissiveColor", aiTextureType_EMISSIVE, mesh); + TrySetTextureProperties(out_mat, textures, "SpecularColor", aiTextureType_SPECULAR, mesh); + TrySetTextureProperties(out_mat, textures, "SpecularFactor", aiTextureType_SPECULAR, mesh); + TrySetTextureProperties(out_mat, textures, "TransparentColor", aiTextureType_OPACITY, mesh); + TrySetTextureProperties(out_mat, textures, "ReflectionColor", aiTextureType_REFLECTION, mesh); + TrySetTextureProperties(out_mat, textures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh); + TrySetTextureProperties(out_mat, textures, "NormalMap", aiTextureType_NORMALS, mesh); + TrySetTextureProperties(out_mat, textures, "Bump", aiTextureType_HEIGHT, mesh); + TrySetTextureProperties(out_mat, textures, "ShininessExponent", aiTextureType_SHININESS, mesh); + TrySetTextureProperties( out_mat, textures, "TransparencyFactor", aiTextureType_OPACITY, mesh ); + TrySetTextureProperties( out_mat, textures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh ); + //Maya counterparts + TrySetTextureProperties(out_mat, textures, "Maya|DiffuseTexture", aiTextureType_DIFFUSE, mesh); + TrySetTextureProperties(out_mat, textures, "Maya|NormalTexture", aiTextureType_NORMALS, mesh); + 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); + } + + void FBXConverter::SetTextureProperties(aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh) + { + TrySetTextureProperties(out_mat, layeredTextures, "DiffuseColor", aiTextureType_DIFFUSE, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "EmissiveColor", aiTextureType_EMISSIVE, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "SpecularColor", aiTextureType_SPECULAR, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "SpecularFactor", aiTextureType_SPECULAR, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "TransparentColor", aiTextureType_OPACITY, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "ReflectionColor", aiTextureType_REFLECTION, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "NormalMap", aiTextureType_NORMALS, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "Bump", aiTextureType_HEIGHT, mesh); + TrySetTextureProperties(out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS, mesh); + TrySetTextureProperties( out_mat, layeredTextures, "EmissiveFactor", aiTextureType_EMISSIVE, mesh ); + TrySetTextureProperties( out_mat, layeredTextures, "TransparencyFactor", aiTextureType_OPACITY, mesh ); + } + + aiColor3D FBXConverter::GetColorPropertyFactored(const PropertyTable& props, const std::string& colorName, + const std::string& factorName, bool& result, bool useTemplate) + { + result = true; + + bool ok; + aiVector3D BaseColor = PropertyGet(props, colorName, ok, useTemplate); + if (!ok) { + result = false; + return aiColor3D(0.0f, 0.0f, 0.0f); + } + + // if no factor name, return the colour as is + if (factorName.empty()) { + return aiColor3D(BaseColor.x, BaseColor.y, BaseColor.z); + } + + // otherwise it should be multiplied by the factor, if found. + float factor = PropertyGet(props, factorName, ok, useTemplate); + if (ok) { + BaseColor *= factor; + } + return aiColor3D(BaseColor.x, BaseColor.y, BaseColor.z); + } + + aiColor3D FBXConverter::GetColorPropertyFromMaterial(const PropertyTable& props, const std::string& baseName, + bool& result) + { + return GetColorPropertyFactored(props, baseName + "Color", baseName + "Factor", result, true); + } + + aiColor3D FBXConverter::GetColorProperty(const PropertyTable& props, const std::string& colorName, + bool& result, bool useTemplate) + { + result = true; + bool ok; + const aiVector3D& ColorVec = PropertyGet(props, colorName, ok, useTemplate); + if (!ok) { + result = false; + return aiColor3D(0.0f, 0.0f, 0.0f); + } + return aiColor3D(ColorVec.x, ColorVec.y, ColorVec.z); + } + + void FBXConverter::SetShadingPropertiesCommon(aiMaterial* out_mat, const PropertyTable& props) + { + // Set shading properties. + // Modern FBX Files have two separate systems for defining these, + // with only the more comprehensive one described in the property template. + // Likely the other values are a legacy system, + // which is still always exported by the official FBX SDK. + // + // Blender's FBX import and export mostly ignore this legacy system, + // and as we only support recent versions of FBX anyway, we can do the same. + bool ok; + + const aiColor3D& Diffuse = GetColorPropertyFromMaterial(props, "Diffuse", ok); + if (ok) { + out_mat->AddProperty(&Diffuse, 1, AI_MATKEY_COLOR_DIFFUSE); + } + + const aiColor3D& Emissive = GetColorPropertyFromMaterial(props, "Emissive", ok); + if (ok) { + out_mat->AddProperty(&Emissive, 1, AI_MATKEY_COLOR_EMISSIVE); + } + + const aiColor3D& Ambient = GetColorPropertyFromMaterial(props, "Ambient", ok); + if (ok) { + out_mat->AddProperty(&Ambient, 1, AI_MATKEY_COLOR_AMBIENT); + } + + // we store specular factor as SHININESS_STRENGTH, so just get the color + const aiColor3D& Specular = GetColorProperty(props, "SpecularColor", ok, true); + if (ok) { + out_mat->AddProperty(&Specular, 1, AI_MATKEY_COLOR_SPECULAR); + } + + // and also try to get SHININESS_STRENGTH + const float SpecularFactor = PropertyGet(props, "SpecularFactor", ok, true); + if (ok) { + out_mat->AddProperty(&SpecularFactor, 1, AI_MATKEY_SHININESS_STRENGTH); + } + + // and the specular exponent + const float ShininessExponent = PropertyGet(props, "ShininessExponent", ok); + if (ok) { + out_mat->AddProperty(&ShininessExponent, 1, AI_MATKEY_SHININESS); + } + + // TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes: + const aiColor3D& Transparent = GetColorPropertyFactored(props, "TransparentColor", "TransparencyFactor", ok); + float CalculatedOpacity = 1.0f; + if (ok) { + out_mat->AddProperty(&Transparent, 1, AI_MATKEY_COLOR_TRANSPARENT); + // as calculated by FBX SDK 2017: + CalculatedOpacity = 1.0f - ((Transparent.r + Transparent.g + Transparent.b) / 3.0f); + } + + // try to get the transparency factor + const float TransparencyFactor = PropertyGet(props, "TransparencyFactor", ok); + if (ok) { + out_mat->AddProperty(&TransparencyFactor, 1, AI_MATKEY_TRANSPARENCYFACTOR); + } + + // use of TransparencyFactor is inconsistent. + // Maya always stores it as 1.0, + // so we can't use it to set AI_MATKEY_OPACITY. + // Blender is more sensible and stores it as the alpha value. + // However both the FBX SDK and Blender always write an additional + // legacy "Opacity" field, so we can try to use that. + // + // If we can't find it, + // we can fall back to the value which the FBX SDK calculates + // from transparency colour (RGB) and factor (F) as + // 1.0 - F*((R+G+B)/3). + // + // There's no consistent way to interpret this opacity value, + // so it's up to clients to do the correct thing. + const float Opacity = PropertyGet(props, "Opacity", ok); + if (ok) { + out_mat->AddProperty(&Opacity, 1, AI_MATKEY_OPACITY); + } + else if (CalculatedOpacity != 1.0) { + out_mat->AddProperty(&CalculatedOpacity, 1, AI_MATKEY_OPACITY); + } + + // reflection color and factor are stored separately + const aiColor3D& Reflection = GetColorProperty(props, "ReflectionColor", ok, true); + if (ok) { + out_mat->AddProperty(&Reflection, 1, AI_MATKEY_COLOR_REFLECTIVE); + } + + float ReflectionFactor = PropertyGet(props, "ReflectionFactor", ok, true); + if (ok) { + out_mat->AddProperty(&ReflectionFactor, 1, AI_MATKEY_REFLECTIVITY); + } + + const float BumpFactor = PropertyGet(props, "BumpFactor", ok); + if (ok) { + out_mat->AddProperty(&BumpFactor, 1, AI_MATKEY_BUMPSCALING); + } + + const float DispFactor = PropertyGet(props, "DisplacementFactor", ok); + if (ok) { + out_mat->AddProperty(&DispFactor, 1, "$mat.displacementscaling", 0, 0); + } +} + + +void FBXConverter::SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTable& props, const TextureMap& textures, const MeshGeometry* const mesh) +{ + // Add all the unparsed properties with a "$raw." prefix + + const std::string prefix = "$raw."; + + for (const DirectPropertyMap::value_type& prop : props.GetUnparsedProperties()) { + + std::string name = prefix + prop.first; + + if (const TypedProperty* interpreted = prop.second->As >()) + { + out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0); + } + else if (const TypedProperty* interpreted = prop.second->As >()) + { + out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0); + } + else if (const TypedProperty* interpreted = prop.second->As >()) + { + out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0); + } + else if (const TypedProperty* interpreted = prop.second->As >()) + { + out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0); + } + else if (const TypedProperty* interpreted = prop.second->As >()) + { + out_mat->AddProperty(&interpreted->Value(), 1, name.c_str(), 0, 0); + } + else if (const TypedProperty* interpreted = prop.second->As >()) + { + int value = interpreted->Value() ? 1 : 0; + out_mat->AddProperty(&value, 1, name.c_str(), 0, 0); + } + else if (const TypedProperty* interpreted = prop.second->As >()) + { + const aiString value = aiString(interpreted->Value()); + out_mat->AddProperty(&value, name.c_str(), 0, 0); + } + } + + // Add the textures' properties + + for (TextureMap::const_iterator it = textures.begin(); it != textures.end(); it++) { + + std::string name = prefix + it->first; + + const Texture* const tex = (*it).second; + if (tex != nullptr) + { + aiString path; + path.Set(tex->RelativeFilename()); + + const Video* media = tex->Media(); + if (media != nullptr && media->ContentLength() > 0) { + unsigned int index; + + VideoMap::const_iterator it = textures_converted.find(media); + if (it != textures_converted.end()) { + index = (*it).second; + } + else { + index = ConvertVideo(*media); + textures_converted[media] = index; + } + + // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture) + path.data[0] = '*'; + path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index); + } + + out_mat->AddProperty(&path, (name + "|file").c_str(), aiTextureType_UNKNOWN, 0); + + aiUVTransform uvTrafo; + // XXX handle all kinds of UV transformations + uvTrafo.mScaling = tex->UVScaling(); + uvTrafo.mTranslation = tex->UVTranslation(); + out_mat->AddProperty(&uvTrafo, 1, (name + "|uvtrafo").c_str(), aiTextureType_UNKNOWN, 0); + + int uvIndex = 0; + + bool uvFound = false; + const std::string& uvSet = PropertyGet(tex->Props(), "UVSet", uvFound); + if (uvFound) { + // "default" is the name which usually appears in the FbxFileTexture template + if (uvSet != "default" && uvSet.length()) { + // this is a bit awkward - we need to find a mesh that uses this + // material and scan its UV channels for the given UV name because + // assimp references UV channels by index, not by name. + + // XXX: the case that UV channels may appear in different orders + // in meshes is unhandled. A possible solution would be to sort + // the UV channels alphabetically, but this would have the side + // effect that the primary (first) UV channel would sometimes + // be moved, causing trouble when users read only the first + // UV channel and ignore UV channel assignments altogether. + + std::vector::iterator materialIt = std::find(materials.begin(), materials.end(), out_mat); + const unsigned int matIndex = static_cast(std::distance(materials.begin(), materialIt)); + + uvIndex = -1; + if (!mesh) + { + for (const MeshMap::value_type& v : meshes_converted) { + const MeshGeometry* const meshGeom = dynamic_cast(v.first); + if (!meshGeom) { + continue; + } + + const MatIndexArray& mats = meshGeom->GetMaterialIndices(); + if (std::find(mats.begin(), mats.end(), matIndex) == mats.end()) { + continue; + } + + int index = -1; + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + if (meshGeom->GetTextureCoords(i).empty()) { + break; + } + const std::string& name = meshGeom->GetTextureCoordChannelName(i); + if (name == uvSet) { + index = static_cast(i); + break; + } + } + if (index == -1) { + FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); + continue; + } + + if (uvIndex == -1) { + uvIndex = index; + } + else { + FBXImporter::LogWarn("the UV channel named " + uvSet + " appears at different positions in meshes, results will be wrong"); + } + } + } + else + { + int index = -1; + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + if (mesh->GetTextureCoords(i).empty()) { + break; + } + const std::string& name = mesh->GetTextureCoordChannelName(i); + if (name == uvSet) { + index = static_cast(i); + break; + } + } + if (index == -1) { + FBXImporter::LogWarn("did not find UV channel named " + uvSet + " in a mesh using this material"); + } + + if (uvIndex == -1) { + uvIndex = index; + } + } + + if (uvIndex == -1) { + FBXImporter::LogWarn("failed to resolve UV channel " + uvSet + ", using first UV channel"); + uvIndex = 0; + } + } + } + + out_mat->AddProperty(&uvIndex, 1, (name + "|uvwsrc").c_str(), aiTextureType_UNKNOWN, 0); + } + } + } + + + double FBXConverter::FrameRateToDouble(FileGlobalSettings::FrameRate fp, double customFPSVal) { + switch (fp) { + case FileGlobalSettings::FrameRate_DEFAULT: + return 1.0; + + case FileGlobalSettings::FrameRate_120: + return 120.0; + + case FileGlobalSettings::FrameRate_100: + return 100.0; + + case FileGlobalSettings::FrameRate_60: + return 60.0; + + case FileGlobalSettings::FrameRate_50: + return 50.0; + + case FileGlobalSettings::FrameRate_48: + return 48.0; + + case FileGlobalSettings::FrameRate_30: + case FileGlobalSettings::FrameRate_30_DROP: + return 30.0; + + case FileGlobalSettings::FrameRate_NTSC_DROP_FRAME: + case FileGlobalSettings::FrameRate_NTSC_FULL_FRAME: + return 29.9700262; + + case FileGlobalSettings::FrameRate_PAL: + return 25.0; + + case FileGlobalSettings::FrameRate_CINEMA: + return 24.0; + + case FileGlobalSettings::FrameRate_1000: + return 1000.0; + + case FileGlobalSettings::FrameRate_CINEMA_ND: + return 23.976; + + case FileGlobalSettings::FrameRate_CUSTOM: + return customFPSVal; + + case FileGlobalSettings::FrameRate_MAX: // this is to silence compiler warnings + break; + } + + ai_assert(false); + + return -1.0f; + } + + + void FBXConverter::ConvertAnimations() + { + // first of all determine framerate + const FileGlobalSettings::FrameRate fps = doc.GlobalSettings().TimeMode(); + const float custom = doc.GlobalSettings().CustomFrameRate(); + anim_fps = FrameRateToDouble(fps, custom); + + const std::vector& animations = doc.AnimationStacks(); + for (const AnimationStack* stack : animations) { + ConvertAnimationStack(*stack); + } + } + + std::string FBXConverter::FixNodeName(const std::string& name) { + // strip Model:: prefix, avoiding ambiguities (i.e. don't strip if + // this causes ambiguities, well possible between empty identifiers, + // such as "Model::" and ""). Make sure the behaviour is consistent + // across multiple calls to FixNodeName(). + if (name.substr(0, 7) == "Model::") { + std::string temp = name.substr(7); + return temp; + } + + return name; + } + + std::string FBXConverter::FixAnimMeshName(const std::string& name) { + if (name.length()) { + size_t indexOf = name.find_first_of("::"); + if (indexOf != std::string::npos && indexOf < name.size() - 2) { + return name.substr(indexOf + 2); + } + } + return name.length() ? name : "AnimMesh"; + } + + void FBXConverter::ConvertAnimationStack(const AnimationStack& st) + { + const AnimationLayerList& layers = st.Layers(); + if (layers.empty()) { + return; + } + + aiAnimation* const anim = new aiAnimation(); + animations.push_back(anim); + + // strip AnimationStack:: prefix + std::string name = st.Name(); + if (name.substr(0, 16) == "AnimationStack::") { + name = name.substr(16); + } + else if (name.substr(0, 11) == "AnimStack::") { + name = name.substr(11); + } + + anim->mName.Set(name); + + // need to find all nodes for which we need to generate node animations - + // it may happen that we need to merge multiple layers, though. + NodeMap node_map; + + // reverse mapping from curves to layers, much faster than querying + // the FBX DOM for it. + LayerMap layer_map; + + const char* prop_whitelist[] = { + "Lcl Scaling", + "Lcl Rotation", + "Lcl Translation", + "DeformPercent" + }; + + std::map morphAnimDatas; + + for (const AnimationLayer* layer : layers) { + ai_assert(layer); + const AnimationCurveNodeList& nodes = layer->Nodes(prop_whitelist, 4); + for (const AnimationCurveNode* node : nodes) { + ai_assert(node); + const Model* const model = dynamic_cast(node->Target()); + if (model) { + const std::string& name = FixNodeName(model->Name()); + node_map[name].push_back(node); + layer_map[node] = layer; + continue; + } + const BlendShapeChannel* const bsc = dynamic_cast(node->Target()); + if (bsc) { + ProcessMorphAnimDatas(&morphAnimDatas, bsc, node); + } + } + } + + // generate node animations + std::vector node_anims; + + double min_time = 1e10; + double max_time = -1e10; + + int64_t start_time = st.LocalStart(); + int64_t stop_time = st.LocalStop(); + bool has_local_startstop = start_time != 0 || stop_time != 0; + if (!has_local_startstop) { + // no time range given, so accept every keyframe and use the actual min/max time + // the numbers are INT64_MIN/MAX, the 20000 is for safety because GenerateNodeAnimations uses an epsilon of 10000 + start_time = -9223372036854775807ll + 20000; + stop_time = 9223372036854775807ll - 20000; + } + + try { + for (const NodeMap::value_type& kv : node_map) { + GenerateNodeAnimations(node_anims, + kv.first, + kv.second, + layer_map, + start_time, stop_time, + max_time, + min_time); + } + } + catch (std::exception&) { + std::for_each(node_anims.begin(), node_anims.end(), Util::delete_fun()); + throw; + } + + if (node_anims.size() || morphAnimDatas.size()) { + if (node_anims.size()) { + anim->mChannels = new aiNodeAnim*[node_anims.size()](); + anim->mNumChannels = static_cast(node_anims.size()); + std::swap_ranges(node_anims.begin(), node_anims.end(), anim->mChannels); + } + if (morphAnimDatas.size()) { + unsigned int numMorphMeshChannels = static_cast(morphAnimDatas.size()); + anim->mMorphMeshChannels = new aiMeshMorphAnim*[numMorphMeshChannels]; + anim->mNumMorphMeshChannels = numMorphMeshChannels; + unsigned int i = 0; + for (auto morphAnimIt : morphAnimDatas) { + morphAnimData* animData = morphAnimIt.second; + unsigned int numKeys = static_cast(animData->size()); + aiMeshMorphAnim* meshMorphAnim = new aiMeshMorphAnim(); + meshMorphAnim->mName.Set(morphAnimIt.first); + meshMorphAnim->mNumKeys = numKeys; + meshMorphAnim->mKeys = new aiMeshMorphKey[numKeys]; + unsigned int j = 0; + for (auto animIt : *animData) { + morphKeyData* keyData = animIt.second; + unsigned int numValuesAndWeights = static_cast(keyData->values.size()); + meshMorphAnim->mKeys[j].mNumValuesAndWeights = numValuesAndWeights; + meshMorphAnim->mKeys[j].mValues = new unsigned int[numValuesAndWeights]; + meshMorphAnim->mKeys[j].mWeights = new double[numValuesAndWeights]; + meshMorphAnim->mKeys[j].mTime = CONVERT_FBX_TIME(animIt.first) * anim_fps; + for (unsigned int k = 0; k < numValuesAndWeights; k++) { + meshMorphAnim->mKeys[j].mValues[k] = keyData->values.at(k); + meshMorphAnim->mKeys[j].mWeights[k] = keyData->weights.at(k); + } + j++; + } + anim->mMorphMeshChannels[i++] = meshMorphAnim; + } + } + } + else { + // empty animations would fail validation, so drop them + delete anim; + animations.pop_back(); + FBXImporter::LogInfo("ignoring empty AnimationStack (using IK?): " + name); + return; + } + + double start_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(start_time) * anim_fps) : min_time; + double stop_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(stop_time) * anim_fps) : max_time; + + // adjust relative timing for animation + for (unsigned int c = 0; c < anim->mNumChannels; c++) { + aiNodeAnim* channel = anim->mChannels[c]; + for (uint32_t i = 0; i < channel->mNumPositionKeys; i++) { + channel->mPositionKeys[i].mTime -= start_time_fps; + } + for (uint32_t i = 0; i < channel->mNumRotationKeys; i++) { + channel->mRotationKeys[i].mTime -= start_time_fps; + } + for (uint32_t i = 0; i < channel->mNumScalingKeys; i++) { + channel->mScalingKeys[i].mTime -= start_time_fps; + } + } + for (unsigned int c = 0; c < anim->mNumMorphMeshChannels; c++) { + aiMeshMorphAnim* channel = anim->mMorphMeshChannels[c]; + for (uint32_t i = 0; i < channel->mNumKeys; i++) { + channel->mKeys[i].mTime -= start_time_fps; + } + } + + // for some mysterious reason, mDuration is simply the maximum key -- the + // validator always assumes animations to start at zero. + anim->mDuration = stop_time_fps - start_time_fps; + anim->mTicksPerSecond = anim_fps; + } + + // ------------------------------------------------------------------------------------------------ + void FBXConverter::ProcessMorphAnimDatas(std::map* morphAnimDatas, const BlendShapeChannel* bsc, const AnimationCurveNode* node) { + std::vector bscConnections = doc.GetConnectionsBySourceSequenced(bsc->ID(), "Deformer"); + for (const Connection* bscConnection : bscConnections) { + auto bs = dynamic_cast(bscConnection->DestinationObject()); + if (bs) { + auto channelIt = std::find(bs->BlendShapeChannels().begin(), bs->BlendShapeChannels().end(), bsc); + if (channelIt != bs->BlendShapeChannels().end()) { + auto channelIndex = static_cast(std::distance(bs->BlendShapeChannels().begin(), channelIt)); + std::vector bsConnections = doc.GetConnectionsBySourceSequenced(bs->ID(), "Geometry"); + for (const Connection* bsConnection : bsConnections) { + auto geo = dynamic_cast(bsConnection->DestinationObject()); + if (geo) { + std::vector geoConnections = doc.GetConnectionsBySourceSequenced(geo->ID(), "Model"); + for (const Connection* geoConnection : geoConnections) { + auto model = dynamic_cast(geoConnection->DestinationObject()); + if (model) { + auto geoIt = std::find(model->GetGeometry().begin(), model->GetGeometry().end(), geo); + auto geoIndex = static_cast(std::distance(model->GetGeometry().begin(), geoIt)); + auto name = aiString(FixNodeName(model->Name() + "*")); + name.length = 1 + ASSIMP_itoa10(name.data + name.length, MAXLEN - 1, geoIndex); + morphAnimData* animData; + auto animIt = morphAnimDatas->find(name.C_Str()); + if (animIt == morphAnimDatas->end()) { + animData = new morphAnimData(); + morphAnimDatas->insert(std::make_pair(name.C_Str(), animData)); + } + else { + animData = animIt->second; + } + for (std::pair curvesIt : node->Curves()) { + if (curvesIt.first == "d|DeformPercent") { + const AnimationCurve* animationCurve = curvesIt.second; + const KeyTimeList& keys = animationCurve->GetKeys(); + const KeyValueList& values = animationCurve->GetValues(); + unsigned int k = 0; + for (auto key : keys) { + morphKeyData* keyData; + auto keyIt = animData->find(key); + if (keyIt == animData->end()) { + keyData = new morphKeyData(); + animData->insert(std::make_pair(key, keyData)); + } + else { + keyData = keyIt->second; + } + keyData->values.push_back(channelIndex); + keyData->weights.push_back(values.at(k) / 100.0f); + k++; + } + } + } + } + } + } + } + } + } + } + } + + // ------------------------------------------------------------------------------------------------ +#ifdef ASSIMP_BUILD_DEBUG + // ------------------------------------------------------------------------------------------------ + // sanity check whether the input is ok + static void validateAnimCurveNodes(const std::vector& curves, + bool strictMode) { + const Object* target(NULL); + for (const AnimationCurveNode* node : curves) { + if (!target) { + target = node->Target(); + } + if (node->Target() != target) { + FBXImporter::LogWarn("Node target is nullptr type."); + } + if (strictMode) { + ai_assert(node->Target() == target); + } + } + } +#endif // ASSIMP_BUILD_DEBUG + + // ------------------------------------------------------------------------------------------------ + void FBXConverter::GenerateNodeAnimations(std::vector& node_anims, + const std::string& fixed_name, + const std::vector& curves, + const LayerMap& layer_map, + int64_t start, int64_t stop, + double& max_time, + double& min_time) + { + + NodeMap node_property_map; + ai_assert(curves.size()); + +#ifdef ASSIMP_BUILD_DEBUG + validateAnimCurveNodes(curves, doc.Settings().strictMode); +#endif + const AnimationCurveNode* curve_node = NULL; + for (const AnimationCurveNode* node : curves) { + ai_assert(node); + + if (node->TargetProperty().empty()) { + FBXImporter::LogWarn("target property for animation curve not set: " + node->Name()); + continue; + } + + curve_node = node; + if (node->Curves().empty()) { + FBXImporter::LogWarn("no animation curves assigned to AnimationCurveNode: " + node->Name()); + continue; + } + + node_property_map[node->TargetProperty()].push_back(node); + } + + ai_assert(curve_node); + ai_assert(curve_node->TargetAsModel()); + + const Model& target = *curve_node->TargetAsModel(); + + // check for all possible transformation components + NodeMap::const_iterator chain[TransformationComp_MAXIMUM]; + + bool has_any = false; + bool has_complex = false; + + for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i) { + const TransformationComp comp = static_cast(i); + + // inverse pivots don't exist in the input, we just generate them + if (comp == TransformationComp_RotationPivotInverse || comp == TransformationComp_ScalingPivotInverse) { + chain[i] = node_property_map.end(); + continue; + } + + chain[i] = node_property_map.find(NameTransformationCompProperty(comp)); + if (chain[i] != node_property_map.end()) { + + // check if this curves contains redundant information by looking + // up the corresponding node's transformation chain. + if (doc.Settings().optimizeEmptyAnimationCurves && + IsRedundantAnimationData(target, comp, (*chain[i]).second)) { + + FBXImporter::LogDebug("dropping redundant animation channel for node " + target.Name()); + continue; + } + + has_any = true; + + if (comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation) + { + has_complex = true; + } + } + } + + if (!has_any) { + FBXImporter::LogWarn("ignoring node animation, did not find any transformation key frames"); + return; + } + + // this needs to play nicely with GenerateTransformationNodeChain() which will + // be invoked _later_ (animations come first). If this node has only rotation, + // scaling and translation _and_ there are no animated other components either, + // we can use a single node and also a single node animation channel. + if (!has_complex && !NeedsComplexTransformationChain(target)) { + + aiNodeAnim* const nd = GenerateSimpleNodeAnim(fixed_name, target, chain, + node_property_map.end(), + layer_map, + start, stop, + max_time, + min_time, + true // input is TRS order, assimp is SRT + ); + + ai_assert(nd); + if (nd->mNumPositionKeys == 0 && nd->mNumRotationKeys == 0 && nd->mNumScalingKeys == 0) { + delete nd; + } + else { + node_anims.push_back(nd); + } + return; + } + + // otherwise, things get gruesome and we need separate animation channels + // for each part of the transformation chain. Remember which channels + // we generated and pass this information to the node conversion + // code to avoid nodes that have identity transform, but non-identity + // animations, being dropped. + unsigned int flags = 0, bit = 0x1; + for (size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1) { + const TransformationComp comp = static_cast(i); + + if (chain[i] != node_property_map.end()) { + flags |= bit; + + ai_assert(comp != TransformationComp_RotationPivotInverse); + ai_assert(comp != TransformationComp_ScalingPivotInverse); + + const std::string& chain_name = NameTransformationChainNode(fixed_name, comp); + + aiNodeAnim* na = nullptr; + switch (comp) + { + case TransformationComp_Rotation: + case TransformationComp_PreRotation: + case TransformationComp_PostRotation: + case TransformationComp_GeometricRotation: + na = GenerateRotationNodeAnim(chain_name, + target, + (*chain[i]).second, + layer_map, + start, stop, + max_time, + min_time); + + break; + + case TransformationComp_RotationOffset: + case TransformationComp_RotationPivot: + case TransformationComp_ScalingOffset: + case TransformationComp_ScalingPivot: + case TransformationComp_Translation: + case TransformationComp_GeometricTranslation: + na = GenerateTranslationNodeAnim(chain_name, + target, + (*chain[i]).second, + layer_map, + start, stop, + max_time, + min_time); + + // pivoting requires us to generate an implicit inverse channel to undo the pivot translation + if (comp == TransformationComp_RotationPivot) { + const std::string& invName = NameTransformationChainNode(fixed_name, + TransformationComp_RotationPivotInverse); + + aiNodeAnim* const inv = GenerateTranslationNodeAnim(invName, + target, + (*chain[i]).second, + layer_map, + start, stop, + max_time, + min_time, + true); + + ai_assert(inv); + if (inv->mNumPositionKeys == 0 && inv->mNumRotationKeys == 0 && inv->mNumScalingKeys == 0) { + delete inv; + } + else { + node_anims.push_back(inv); + } + + ai_assert(TransformationComp_RotationPivotInverse > i); + flags |= bit << (TransformationComp_RotationPivotInverse - i); + } + else if (comp == TransformationComp_ScalingPivot) { + const std::string& invName = NameTransformationChainNode(fixed_name, + TransformationComp_ScalingPivotInverse); + + aiNodeAnim* const inv = GenerateTranslationNodeAnim(invName, + target, + (*chain[i]).second, + layer_map, + start, stop, + max_time, + min_time, + true); + + ai_assert(inv); + if (inv->mNumPositionKeys == 0 && inv->mNumRotationKeys == 0 && inv->mNumScalingKeys == 0) { + delete inv; + } + else { + node_anims.push_back(inv); + } + + ai_assert(TransformationComp_RotationPivotInverse > i); + flags |= bit << (TransformationComp_RotationPivotInverse - i); + } + + break; + + case TransformationComp_Scaling: + case TransformationComp_GeometricScaling: + na = GenerateScalingNodeAnim(chain_name, + target, + (*chain[i]).second, + layer_map, + start, stop, + max_time, + min_time); + + break; + + default: + ai_assert(false); + } + + ai_assert(na); + if (na->mNumPositionKeys == 0 && na->mNumRotationKeys == 0 && na->mNumScalingKeys == 0) { + delete na; + } + else { + node_anims.push_back(na); + } + continue; + } + } + + node_anim_chain_bits[fixed_name] = flags; + } + + + bool FBXConverter::IsRedundantAnimationData(const Model& target, + TransformationComp comp, + const std::vector& curves) { + ai_assert(curves.size()); + + // look for animation nodes with + // * sub channels for all relevant components set + // * one key/value pair per component + // * combined values match up the corresponding value in the bind pose node transformation + // only such nodes are 'redundant' for this function. + + if (curves.size() > 1) { + return false; + } + + const AnimationCurveNode& nd = *curves.front(); + const AnimationCurveMap& sub_curves = nd.Curves(); + + const AnimationCurveMap::const_iterator dx = sub_curves.find("d|X"); + const AnimationCurveMap::const_iterator dy = sub_curves.find("d|Y"); + const AnimationCurveMap::const_iterator dz = sub_curves.find("d|Z"); + + if (dx == sub_curves.end() || dy == sub_curves.end() || dz == sub_curves.end()) { + return false; + } + + const KeyValueList& vx = (*dx).second->GetValues(); + const KeyValueList& vy = (*dy).second->GetValues(); + const KeyValueList& vz = (*dz).second->GetValues(); + + if (vx.size() != 1 || vy.size() != 1 || vz.size() != 1) { + return false; + } + + const aiVector3D dyn_val = aiVector3D(vx[0], vy[0], vz[0]); + const aiVector3D& static_val = PropertyGet(target.Props(), + NameTransformationCompProperty(comp), + TransformationCompDefaultValue(comp) + ); + + const float epsilon = Math::getEpsilon(); + return (dyn_val - static_val).SquareLength() < epsilon; + } + + + aiNodeAnim* FBXConverter::GenerateRotationNodeAnim(const std::string& name, + const Model& target, + const std::vector& curves, + const LayerMap& layer_map, + int64_t start, int64_t stop, + double& max_time, + double& min_time) + { + std::unique_ptr na(new aiNodeAnim()); + na->mNodeName.Set(name); + + ConvertRotationKeys(na.get(), curves, layer_map, start, stop, max_time, min_time, target.RotationOrder()); + + // dummy scaling key + na->mScalingKeys = new aiVectorKey[1]; + na->mNumScalingKeys = 1; + + na->mScalingKeys[0].mTime = 0.; + na->mScalingKeys[0].mValue = aiVector3D(1.0f, 1.0f, 1.0f); + + // dummy position key + na->mPositionKeys = new aiVectorKey[1]; + na->mNumPositionKeys = 1; + + na->mPositionKeys[0].mTime = 0.; + na->mPositionKeys[0].mValue = aiVector3D(); + + return na.release(); + } + + aiNodeAnim* FBXConverter::GenerateScalingNodeAnim(const std::string& name, + const Model& /*target*/, + const std::vector& curves, + const LayerMap& layer_map, + int64_t start, int64_t stop, + double& max_time, + double& min_time) + { + std::unique_ptr na(new aiNodeAnim()); + na->mNodeName.Set(name); + + ConvertScaleKeys(na.get(), curves, layer_map, start, stop, max_time, min_time); + + // dummy rotation key + na->mRotationKeys = new aiQuatKey[1]; + na->mNumRotationKeys = 1; + + na->mRotationKeys[0].mTime = 0.; + na->mRotationKeys[0].mValue = aiQuaternion(); + + // dummy position key + na->mPositionKeys = new aiVectorKey[1]; + na->mNumPositionKeys = 1; + + na->mPositionKeys[0].mTime = 0.; + na->mPositionKeys[0].mValue = aiVector3D(); + + return na.release(); + } + + aiNodeAnim* FBXConverter::GenerateTranslationNodeAnim(const std::string& name, + const Model& /*target*/, + const std::vector& curves, + const LayerMap& layer_map, + int64_t start, int64_t stop, + double& max_time, + double& min_time, + bool inverse) { + std::unique_ptr na(new aiNodeAnim()); + na->mNodeName.Set(name); + + ConvertTranslationKeys(na.get(), curves, layer_map, start, stop, max_time, min_time); + + if (inverse) { + for (unsigned int i = 0; i < na->mNumPositionKeys; ++i) { + na->mPositionKeys[i].mValue *= -1.0f; + } + } + + // dummy scaling key + na->mScalingKeys = new aiVectorKey[1]; + na->mNumScalingKeys = 1; + + na->mScalingKeys[0].mTime = 0.; + na->mScalingKeys[0].mValue = aiVector3D(1.0f, 1.0f, 1.0f); + + // dummy rotation key + na->mRotationKeys = new aiQuatKey[1]; + na->mNumRotationKeys = 1; + + na->mRotationKeys[0].mTime = 0.; + na->mRotationKeys[0].mValue = aiQuaternion(); + + return na.release(); + } + + aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim(const std::string& name, + const Model& target, + NodeMap::const_iterator chain[TransformationComp_MAXIMUM], + NodeMap::const_iterator iter_end, + const LayerMap& layer_map, + int64_t start, int64_t stop, + double& max_time, + double& min_time, + bool reverse_order) + + { + std::unique_ptr na(new aiNodeAnim()); + na->mNodeName.Set(name); + + const PropertyTable& props = target.Props(); + + // need to convert from TRS order to SRT? + if (reverse_order) { + + aiVector3D def_scale = PropertyGet(props, "Lcl Scaling", aiVector3D(1.f, 1.f, 1.f)); + aiVector3D def_translate = PropertyGet(props, "Lcl Translation", aiVector3D(0.f, 0.f, 0.f)); + aiVector3D def_rot = PropertyGet(props, "Lcl Rotation", aiVector3D(0.f, 0.f, 0.f)); + + KeyFrameListList scaling; + KeyFrameListList translation; + KeyFrameListList rotation; + + if (chain[TransformationComp_Scaling] != iter_end) { + scaling = GetKeyframeList((*chain[TransformationComp_Scaling]).second, start, stop); + } + + if (chain[TransformationComp_Translation] != iter_end) { + translation = GetKeyframeList((*chain[TransformationComp_Translation]).second, start, stop); + } + + if (chain[TransformationComp_Rotation] != iter_end) { + rotation = GetKeyframeList((*chain[TransformationComp_Rotation]).second, start, stop); + } + + KeyFrameListList joined; + joined.insert(joined.end(), scaling.begin(), scaling.end()); + joined.insert(joined.end(), translation.begin(), translation.end()); + joined.insert(joined.end(), rotation.begin(), rotation.end()); + + const KeyTimeList& times = GetKeyTimeList(joined); + + aiQuatKey* out_quat = new aiQuatKey[times.size()]; + aiVectorKey* out_scale = new aiVectorKey[times.size()]; + aiVectorKey* out_translation = new aiVectorKey[times.size()]; + + if (times.size()) + { + ConvertTransformOrder_TRStoSRT(out_quat, out_scale, out_translation, + scaling, + translation, + rotation, + times, + max_time, + min_time, + target.RotationOrder(), + def_scale, + def_translate, + def_rot); + } + + // XXX remove duplicates / redundant keys which this operation did + // likely produce if not all three channels were equally dense. + + na->mNumScalingKeys = static_cast(times.size()); + na->mNumRotationKeys = na->mNumScalingKeys; + na->mNumPositionKeys = na->mNumScalingKeys; + + na->mScalingKeys = out_scale; + na->mRotationKeys = out_quat; + na->mPositionKeys = out_translation; + } + else { + + // if a particular transformation is not given, grab it from + // the corresponding node to meet the semantics of aiNodeAnim, + // which requires all of rotation, scaling and translation + // to be set. + if (chain[TransformationComp_Scaling] != iter_end) { + ConvertScaleKeys(na.get(), (*chain[TransformationComp_Scaling]).second, + layer_map, + start, stop, + max_time, + min_time); + } + else { + na->mScalingKeys = new aiVectorKey[1]; + na->mNumScalingKeys = 1; + + na->mScalingKeys[0].mTime = 0.; + na->mScalingKeys[0].mValue = PropertyGet(props, "Lcl Scaling", + aiVector3D(1.f, 1.f, 1.f)); + } + + if (chain[TransformationComp_Rotation] != iter_end) { + ConvertRotationKeys(na.get(), (*chain[TransformationComp_Rotation]).second, + layer_map, + start, stop, + max_time, + min_time, + target.RotationOrder()); + } + else { + na->mRotationKeys = new aiQuatKey[1]; + na->mNumRotationKeys = 1; + + na->mRotationKeys[0].mTime = 0.; + na->mRotationKeys[0].mValue = EulerToQuaternion( + PropertyGet(props, "Lcl Rotation", aiVector3D(0.f, 0.f, 0.f)), + target.RotationOrder()); + } + + if (chain[TransformationComp_Translation] != iter_end) { + ConvertTranslationKeys(na.get(), (*chain[TransformationComp_Translation]).second, + layer_map, + start, stop, + max_time, + min_time); + } + else { + na->mPositionKeys = new aiVectorKey[1]; + na->mNumPositionKeys = 1; + + na->mPositionKeys[0].mTime = 0.; + na->mPositionKeys[0].mValue = PropertyGet(props, "Lcl Translation", + aiVector3D(0.f, 0.f, 0.f)); + } + + } + return na.release(); + } + + FBXConverter::KeyFrameListList FBXConverter::GetKeyframeList(const std::vector& nodes, int64_t start, int64_t stop) + { + KeyFrameListList inputs; + inputs.reserve(nodes.size() * 3); + + //give some breathing room for rounding errors + int64_t adj_start = start - 10000; + int64_t adj_stop = stop + 10000; + + for (const AnimationCurveNode* node : nodes) { + ai_assert(node); + + const AnimationCurveMap& curves = node->Curves(); + for (const AnimationCurveMap::value_type& kv : curves) { + + unsigned int mapto; + if (kv.first == "d|X") { + mapto = 0; + } + else if (kv.first == "d|Y") { + mapto = 1; + } + else if (kv.first == "d|Z") { + mapto = 2; + } + else { + FBXImporter::LogWarn("ignoring scale animation curve, did not recognize target component"); + continue; + } + + const AnimationCurve* const curve = kv.second; + ai_assert(curve->GetKeys().size() == curve->GetValues().size() && curve->GetKeys().size()); + + //get values within the start/stop time window + std::shared_ptr Keys(new KeyTimeList()); + std::shared_ptr Values(new KeyValueList()); + const size_t count = curve->GetKeys().size(); + Keys->reserve(count); + Values->reserve(count); + for (size_t n = 0; n < count; n++) + { + int64_t k = curve->GetKeys().at(n); + if (k >= adj_start && k <= adj_stop) + { + Keys->push_back(k); + Values->push_back(curve->GetValues().at(n)); + } + } + + inputs.push_back(std::make_tuple(Keys, Values, mapto)); + } + } + return inputs; // pray for NRVO :-) + } + + + KeyTimeList FBXConverter::GetKeyTimeList(const KeyFrameListList& inputs) { + ai_assert(!inputs.empty()); + + // reserve some space upfront - it is likely that the key-frame lists + // have matching time values, so max(of all key-frame lists) should + // be a good estimate. + KeyTimeList keys; + + size_t estimate = 0; + for (const KeyFrameList& kfl : inputs) { + estimate = std::max(estimate, std::get<0>(kfl)->size()); + } + + keys.reserve(estimate); + + std::vector next_pos; + next_pos.resize(inputs.size(), 0); + + const size_t count = inputs.size(); + while (true) { + + int64_t min_tick = std::numeric_limits::max(); + for (size_t i = 0; i < count; ++i) { + const KeyFrameList& kfl = inputs[i]; + + if (std::get<0>(kfl)->size() > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) < min_tick) { + min_tick = std::get<0>(kfl)->at(next_pos[i]); + } + } + + if (min_tick == std::numeric_limits::max()) { + break; + } + keys.push_back(min_tick); + + for (size_t i = 0; i < count; ++i) { + const KeyFrameList& kfl = inputs[i]; + + + while (std::get<0>(kfl)->size() > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) == min_tick) { + ++next_pos[i]; + } + } + } + + return keys; + } + + void FBXConverter::InterpolateKeys(aiVectorKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, + const aiVector3D& def_value, + double& max_time, + double& min_time) { + ai_assert(!keys.empty()); + ai_assert(nullptr != valOut); + + std::vector next_pos; + const size_t count(inputs.size()); + + next_pos.resize(inputs.size(), 0); + + for (KeyTimeList::value_type time : keys) { + ai_real result[3] = { def_value.x, def_value.y, def_value.z }; + + for (size_t i = 0; i < count; ++i) { + const KeyFrameList& kfl = inputs[i]; + + const size_t ksize = std::get<0>(kfl)->size(); + if (ksize == 0) { + continue; + } + if (ksize > next_pos[i] && std::get<0>(kfl)->at(next_pos[i]) == time) { + ++next_pos[i]; + } + + const size_t id0 = next_pos[i] > 0 ? next_pos[i] - 1 : 0; + const size_t id1 = next_pos[i] == ksize ? ksize - 1 : next_pos[i]; + + // use lerp for interpolation + const KeyValueList::value_type valueA = std::get<1>(kfl)->at(id0); + const KeyValueList::value_type valueB = std::get<1>(kfl)->at(id1); + + const KeyTimeList::value_type timeA = std::get<0>(kfl)->at(id0); + const KeyTimeList::value_type timeB = std::get<0>(kfl)->at(id1); + + const ai_real factor = timeB == timeA ? ai_real(0.) : static_cast((time - timeA)) / (timeB - timeA); + const ai_real interpValue = static_cast(valueA + (valueB - valueA) * factor); + + result[std::get<2>(kfl)] = interpValue; + } + + // magic value to convert fbx times to seconds + valOut->mTime = CONVERT_FBX_TIME(time) * anim_fps; + + min_time = std::min(min_time, valOut->mTime); + max_time = std::max(max_time, valOut->mTime); + + valOut->mValue.x = result[0]; + valOut->mValue.y = result[1]; + valOut->mValue.z = result[2]; + + ++valOut; + } + } + + void FBXConverter::InterpolateKeys(aiQuatKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, + const aiVector3D& def_value, + double& maxTime, + double& minTime, + Model::RotOrder order) + { + ai_assert(!keys.empty()); + ai_assert(nullptr != valOut); + + std::unique_ptr temp(new aiVectorKey[keys.size()]); + InterpolateKeys(temp.get(), keys, inputs, def_value, maxTime, minTime); + + aiMatrix4x4 m; + + aiQuaternion lastq; + + for (size_t i = 0, c = keys.size(); i < c; ++i) { + + valOut[i].mTime = temp[i].mTime; + + GetRotationMatrix(order, temp[i].mValue, m); + aiQuaternion quat = aiQuaternion(aiMatrix3x3(m)); + + // take shortest path by checking the inner product + // http://www.3dkingdoms.com/weekly/weekly.php?a=36 + if (quat.x * lastq.x + quat.y * lastq.y + quat.z * lastq.z + quat.w * lastq.w < 0) + { + quat.x = -quat.x; + quat.y = -quat.y; + quat.z = -quat.z; + quat.w = -quat.w; + } + lastq = quat; + + valOut[i].mValue = quat; + } + } + + void FBXConverter::ConvertTransformOrder_TRStoSRT(aiQuatKey* out_quat, aiVectorKey* out_scale, + aiVectorKey* out_translation, + const KeyFrameListList& scaling, + const KeyFrameListList& translation, + const KeyFrameListList& rotation, + const KeyTimeList& times, + double& maxTime, + double& minTime, + Model::RotOrder order, + const aiVector3D& def_scale, + const aiVector3D& def_translate, + const aiVector3D& def_rotation) + { + if (rotation.size()) { + InterpolateKeys(out_quat, times, rotation, def_rotation, maxTime, minTime, order); + } + else { + for (size_t i = 0; i < times.size(); ++i) { + out_quat[i].mTime = CONVERT_FBX_TIME(times[i]) * anim_fps; + out_quat[i].mValue = EulerToQuaternion(def_rotation, order); + } + } + + if (scaling.size()) { + InterpolateKeys(out_scale, times, scaling, def_scale, maxTime, minTime); + } + else { + for (size_t i = 0; i < times.size(); ++i) { + out_scale[i].mTime = CONVERT_FBX_TIME(times[i]) * anim_fps; + out_scale[i].mValue = def_scale; + } + } + + if (translation.size()) { + InterpolateKeys(out_translation, times, translation, def_translate, maxTime, minTime); + } + else { + for (size_t i = 0; i < times.size(); ++i) { + out_translation[i].mTime = CONVERT_FBX_TIME(times[i]) * anim_fps; + out_translation[i].mValue = def_translate; + } + } + + const size_t count = times.size(); + for (size_t i = 0; i < count; ++i) { + aiQuaternion& r = out_quat[i].mValue; + aiVector3D& s = out_scale[i].mValue; + aiVector3D& t = out_translation[i].mValue; + + aiMatrix4x4 mat, temp; + aiMatrix4x4::Translation(t, mat); + mat *= aiMatrix4x4(r.GetMatrix()); + mat *= aiMatrix4x4::Scaling(s, temp); + + mat.Decompose(s, r, t); + } + } + + aiQuaternion FBXConverter::EulerToQuaternion(const aiVector3D& rot, Model::RotOrder order) + { + aiMatrix4x4 m; + GetRotationMatrix(order, rot, m); + + return aiQuaternion(aiMatrix3x3(m)); + } + + void FBXConverter::ConvertScaleKeys(aiNodeAnim* na, const std::vector& nodes, const LayerMap& /*layers*/, + int64_t start, int64_t stop, + double& maxTime, + double& minTime) + { + ai_assert(nodes.size()); + + // XXX for now, assume scale should be blended geometrically (i.e. two + // layers should be multiplied with each other). There is a FBX + // property in the layer to specify the behaviour, though. + + const KeyFrameListList& inputs = GetKeyframeList(nodes, start, stop); + const KeyTimeList& keys = GetKeyTimeList(inputs); + + na->mNumScalingKeys = static_cast(keys.size()); + na->mScalingKeys = new aiVectorKey[keys.size()]; + if (keys.size() > 0) { + InterpolateKeys(na->mScalingKeys, keys, inputs, aiVector3D(1.0f, 1.0f, 1.0f), maxTime, minTime); + } + } + + void FBXConverter::ConvertTranslationKeys(aiNodeAnim* na, const std::vector& nodes, + const LayerMap& /*layers*/, + int64_t start, int64_t stop, + double& maxTime, + double& minTime) + { + ai_assert(nodes.size()); + + // XXX see notes in ConvertScaleKeys() + const KeyFrameListList& inputs = GetKeyframeList(nodes, start, stop); + const KeyTimeList& keys = GetKeyTimeList(inputs); + + na->mNumPositionKeys = static_cast(keys.size()); + na->mPositionKeys = new aiVectorKey[keys.size()]; + if (keys.size() > 0) + InterpolateKeys(na->mPositionKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime); + } + + void FBXConverter::ConvertRotationKeys(aiNodeAnim* na, const std::vector& nodes, + const LayerMap& /*layers*/, + int64_t start, int64_t stop, + double& maxTime, + double& minTime, + Model::RotOrder order) + { + ai_assert(nodes.size()); + + // XXX see notes in ConvertScaleKeys() + const std::vector< KeyFrameList >& inputs = GetKeyframeList(nodes, start, stop); + const KeyTimeList& keys = GetKeyTimeList(inputs); + + na->mNumRotationKeys = static_cast(keys.size()); + na->mRotationKeys = new aiQuatKey[keys.size()]; + if (!keys.empty()) { + InterpolateKeys(na->mRotationKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime, order); + } + } + + void FBXConverter::ConvertGlobalSettings() { + if (nullptr == out) { + return; + } + + out->mMetaData = aiMetadata::Alloc(15); + out->mMetaData->Set(0, "UpAxis", doc.GlobalSettings().UpAxis()); + out->mMetaData->Set(1, "UpAxisSign", doc.GlobalSettings().UpAxisSign()); + out->mMetaData->Set(2, "FrontAxis", doc.GlobalSettings().FrontAxis()); + out->mMetaData->Set(3, "FrontAxisSign", doc.GlobalSettings().FrontAxisSign()); + out->mMetaData->Set(4, "CoordAxis", doc.GlobalSettings().CoordAxis()); + out->mMetaData->Set(5, "CoordAxisSign", doc.GlobalSettings().CoordAxisSign()); + out->mMetaData->Set(6, "OriginalUpAxis", doc.GlobalSettings().OriginalUpAxis()); + out->mMetaData->Set(7, "OriginalUpAxisSign", doc.GlobalSettings().OriginalUpAxisSign()); + out->mMetaData->Set(8, "UnitScaleFactor", (double)doc.GlobalSettings().UnitScaleFactor()); + out->mMetaData->Set(9, "OriginalUnitScaleFactor", doc.GlobalSettings().OriginalUnitScaleFactor()); + out->mMetaData->Set(10, "AmbientColor", doc.GlobalSettings().AmbientColor()); + out->mMetaData->Set(11, "FrameRate", (int)doc.GlobalSettings().TimeMode()); + 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::TransferDataToScene() + { + ai_assert(!out->mMeshes); + ai_assert(!out->mNumMeshes); + + // note: the trailing () ensures initialization with NULL - not + // many C++ users seem to know this, so pointing it out to avoid + // confusion why this code works. + + if (meshes.size()) { + out->mMeshes = new aiMesh*[meshes.size()](); + out->mNumMeshes = static_cast(meshes.size()); + + std::swap_ranges(meshes.begin(), meshes.end(), out->mMeshes); + } + + if (materials.size()) { + out->mMaterials = new aiMaterial*[materials.size()](); + out->mNumMaterials = static_cast(materials.size()); + + std::swap_ranges(materials.begin(), materials.end(), out->mMaterials); + } + + if (animations.size()) { + out->mAnimations = new aiAnimation*[animations.size()](); + out->mNumAnimations = static_cast(animations.size()); + + std::swap_ranges(animations.begin(), animations.end(), out->mAnimations); + } + + if (lights.size()) { + out->mLights = new aiLight*[lights.size()](); + out->mNumLights = static_cast(lights.size()); + + std::swap_ranges(lights.begin(), lights.end(), out->mLights); + } + + if (cameras.size()) { + out->mCameras = new aiCamera*[cameras.size()](); + out->mNumCameras = static_cast(cameras.size()); + + std::swap_ranges(cameras.begin(), cameras.end(), out->mCameras); + } + + if (textures.size()) { + out->mTextures = new aiTexture*[textures.size()](); + out->mNumTextures = static_cast(textures.size()); + + std::swap_ranges(textures.begin(), textures.end(), out->mTextures); + } + } + + // ------------------------------------------------------------------------------------------------ + void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones) + { + FBXConverter converter(out, doc, removeEmptyBones); + } + + } // !FBX +} // !Assimp + +#endif diff --git a/code/FBXConverter.h b/code/FBX/FBXConverter.h similarity index 90% rename from code/FBXConverter.h rename to code/FBX/FBXConverter.h index ca8dcba2e..77ced1950 100644 --- a/code/FBXConverter.h +++ b/code/FBX/FBXConverter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -52,30 +52,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXUtil.h" #include "FBXProperties.h" #include "FBXImporter.h" + #include #include #include #include #include #include +#include +#include struct aiScene; struct aiNode; struct aiMaterial; +struct morphKeyData { + std::vector values; + std::vector weights; +}; +typedef std::map morphAnimData; + namespace Assimp { namespace FBX { class Document; - -using NodeNameCache = std::set; - /** * Convert a FBX #Document to #aiScene * @param out Empty scene to be populated - * @param doc Parsed FBX document + * @param doc Parsed FBX document + * @param removeEmptyBones Will remove bones, which do not have any references to vertices. */ -void ConvertToAssimpScene(aiScene* out, const Document& doc); +void ConvertToAssimpScene(aiScene* out, const Document& doc, bool removeEmptyBones); /** Dummy class to encapsulate the conversion process */ class FBXConverter { @@ -106,7 +113,7 @@ public: }; public: - FBXConverter(aiScene* out, const Document& doc); + FBXConverter(aiScene* out, const Document& doc, bool removeEmptyBones); ~FBXConverter(); private: @@ -138,6 +145,11 @@ private: // while these would be allowed, they are a potential trouble spot so better not use them). const char* NameTransformationComp(TransformationComp comp); + // ------------------------------------------------------------------------------------------------ + // Returns an unique name for a node or traverses up a hierarchy until a non-empty name is found and + // then makes this name unique + std::string MakeUniqueNodeName(const Model* const model, const aiNode& parent); + // ------------------------------------------------------------------------------------------------ // note: this returns the REAL fbx property names const char* NameTransformationCompProperty(TransformationComp comp); @@ -161,21 +173,25 @@ private: /** * note: memory for output_nodes will be managed by the caller */ - void GenerateTransformationNodeChain(const Model& model, std::vector& output_nodes, std::vector& post_output_nodes); + bool GenerateTransformationNodeChain(const Model& model, const std::string& name, std::vector& output_nodes, std::vector& post_output_nodes); // ------------------------------------------------------------------------------------------------ void SetupNodeMetadata(const Model& model, aiNode& nd); // ------------------------------------------------------------------------------------------------ void ConvertModel(const Model& model, aiNode& nd, const aiMatrix4x4& node_global_transform); - + // ------------------------------------------------------------------------------------------------ // MeshGeometry -> aiMesh, return mesh index + 1 or 0 if the conversion failed std::vector ConvertMesh(const MeshGeometry& mesh, const Model& model, const aiMatrix4x4& node_global_transform, aiNode& nd); // ------------------------------------------------------------------------------------------------ - aiMesh* SetupEmptyMesh(const MeshGeometry& mesh, aiNode& nd); + std::vector ConvertLine(const LineGeometry& line, const Model& model, + const aiMatrix4x4& node_global_transform, aiNode& nd); + + // ------------------------------------------------------------------------------------------------ + aiMesh* SetupEmptyMesh(const Geometry& mesh, aiNode& nd); // ------------------------------------------------------------------------------------------------ unsigned int ConvertMeshSingleMaterial(const MeshGeometry& mesh, const Model& model, @@ -258,6 +274,7 @@ private: // ------------------------------------------------------------------------------------------------ void SetShadingPropertiesCommon(aiMaterial* out_mat, const PropertyTable& props); + void SetShadingPropertiesRaw(aiMaterial* out_mat, const PropertyTable& props, const TextureMap& textures, const MeshGeometry* const mesh); // ------------------------------------------------------------------------------------------------ // get the number of fps for a FrameRate enumerated value @@ -272,6 +289,7 @@ private: // the function is guaranteed to provide consistent results over multiple invocations // UNLESS RenameNode() is called for a particular node name. std::string FixNodeName(const std::string& name); + std::string FixAnimMeshName(const std::string& name); typedef std::map LayerMap; @@ -281,6 +299,9 @@ private: // ------------------------------------------------------------------------------------------------ void ConvertAnimationStack(const AnimationStack& st); + // ------------------------------------------------------------------------------------------------ + void ProcessMorphAnimDatas(std::map* morphAnimDatas, const BlendShapeChannel* bsc, const AnimationCurveNode* node); + // ------------------------------------------------------------------------------------------------ void GenerateNodeAnimations(std::vector& node_anims, const std::string& fixed_name, @@ -404,7 +425,6 @@ private: void TransferDataToScene(); private: - // 0: not assigned yet, others: index is value - 1 unsigned int defaultMaterialIndex; @@ -415,20 +435,23 @@ private: std::vector cameras; std::vector textures; - typedef std::map MaterialMap; + using MaterialMap = std::map; MaterialMap materials_converted; - typedef std::map VideoMap; + using VideoMap = std::map; VideoMap textures_converted; - typedef std::map > MeshMap; + using MeshMap = std::map >; MeshMap meshes_converted; // fixed node name -> which trafo chain components have animations? - typedef std::map NodeAnimBitMap; + using NodeAnimBitMap = std::map ; NodeAnimBitMap node_anim_chain_bits; + // number of nodes with the same name + using NodeNameCache = std::unordered_map; NodeNameCache mNodeNames; + double anim_fps; aiScene* const out; diff --git a/code/FBXDeformer.cpp b/code/FBX/FBXDeformer.cpp similarity index 70% rename from code/FBXDeformer.cpp rename to code/FBX/FBXDeformer.cpp index 9c7c7a4c4..692755345 100644 --- a/code/FBXDeformer.cpp +++ b/code/FBX/FBXDeformer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -48,6 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXParser.h" #include "FBXDocument.h" +#include "FBXMeshGeometry.h" #include "FBXImporter.h" #include "FBXDocumentUtil.h" @@ -158,9 +159,55 @@ Skin::~Skin() { } +// ------------------------------------------------------------------------------------------------ +BlendShape::BlendShape(uint64_t id, const Element& element, const Document& doc, const std::string& name) + : Deformer(id, element, doc, name) +{ + const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID(), "Deformer"); + blendShapeChannels.reserve(conns.size()); + for (const Connection* con : conns) { + const BlendShapeChannel* const bspc = ProcessSimpleConnection(*con, false, "BlendShapeChannel -> BlendShape", element); + if (bspc) { + blendShapeChannels.push_back(bspc); + continue; + } + } +} +// ------------------------------------------------------------------------------------------------ +BlendShape::~BlendShape() +{ } +// ------------------------------------------------------------------------------------------------ +BlendShapeChannel::BlendShapeChannel(uint64_t id, const Element& element, const Document& doc, const std::string& name) + : Deformer(id, element, doc, name) +{ + const Scope& sc = GetRequiredScope(element); + const Element* const DeformPercent = sc["DeformPercent"]; + if (DeformPercent) { + percent = ParseTokenAsFloat(GetRequiredToken(*DeformPercent, 0)); + } + const Element* const FullWeights = sc["FullWeights"]; + if (FullWeights) { + ParseVectorDataArray(fullWeights, *FullWeights); + } + const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID(), "Geometry"); + shapeGeometries.reserve(conns.size()); + for (const Connection* con : conns) { + const ShapeGeometry* const sg = ProcessSimpleConnection(*con, false, "Shape -> BlendShapeChannel", element); + if (sg) { + shapeGeometries.push_back(sg); + continue; + } + } } +// ------------------------------------------------------------------------------------------------ +BlendShapeChannel::~BlendShapeChannel() +{ +} +// ------------------------------------------------------------------------------------------------ +} +} #endif diff --git a/code/FBXDocument.cpp b/code/FBX/FBXDocument.cpp similarity index 97% rename from code/FBXDocument.cpp rename to code/FBX/FBXDocument.cpp index f53ae4405..506fd978d 100644 --- a/code/FBXDocument.cpp +++ b/code/FBX/FBXDocument.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -69,8 +69,7 @@ LazyObject::LazyObject(uint64_t id, const Element& element, const Document& doc) : doc(doc) , element(element) , id(id) -, flags() -{ +, flags() { // empty } @@ -84,21 +83,13 @@ LazyObject::~LazyObject() const Object* LazyObject::Get(bool dieOnError) { if(IsBeingConstructed() || FailedToConstruct()) { - return NULL; + return nullptr; } if (object.get()) { return object.get(); } - // if this is the root object, we return a dummy since there - // is no root object int he fbx file - it is just referenced - // with id 0. - if(id == 0L) { - object.reset(new Object(id, element, "Model::RootNode")); - return object.get(); - } - const Token& key = element.KeyToken(); const TokenList& tokens = element.Tokens(); @@ -146,6 +137,12 @@ const Object* LazyObject::Get(bool dieOnError) if (!strcmp(classtag.c_str(),"Mesh")) { object.reset(new MeshGeometry(id,element,name,doc)); } + if (!strcmp(classtag.c_str(), "Shape")) { + object.reset(new ShapeGeometry(id, element, name, doc)); + } + if (!strcmp(classtag.c_str(), "Line")) { + object.reset(new LineGeometry(id, element, name, doc)); + } } else if (!strncmp(obtype,"NodeAttribute",length)) { if (!strcmp(classtag.c_str(),"Camera")) { @@ -171,6 +168,12 @@ const Object* LazyObject::Get(bool dieOnError) else if (!strcmp(classtag.c_str(),"Skin")) { object.reset(new Skin(id,element,doc,name)); } + else if (!strcmp(classtag.c_str(), "BlendShape")) { + object.reset(new BlendShape(id, element, doc, name)); + } + else if (!strcmp(classtag.c_str(), "BlendShapeChannel")) { + object.reset(new BlendShapeChannel(id, element, doc, name)); + } } else if ( !strncmp( obtype, "Model", length ) ) { // FK and IK effectors are not supported @@ -541,7 +544,7 @@ const std::vector& Document::AnimationStacks() const LazyObject* Document::GetObject(uint64_t id) const { ObjectMap::const_iterator it = objects.find(id); - return it == objects.end() ? NULL : (*it).second; + return it == objects.end() ? nullptr : (*it).second; } #define MAX_CLASSNAMES 6 @@ -598,7 +601,7 @@ std::vector Document::GetConnectionsSequenced(uint64_t id, bo for (size_t i = 0; i < c; ++i) { ai_assert(classnames[i]); if(static_cast(std::distance(key.begin(),key.end())) == lengths[i] && !strncmp(classnames[i],obtype,lengths[i])) { - obtype = NULL; + obtype = nullptr; break; } } diff --git a/code/FBXDocument.h b/code/FBX/FBXDocument.h similarity index 93% rename from code/FBXDocument.h rename to code/FBX/FBXDocument.h index 654f5bfa8..18e5c38f1 100644 --- a/code/FBXDocument.h +++ b/code/FBX/FBXDocument.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -65,6 +65,8 @@ struct ImportSettings; class PropertyTable; class Document; class Material; +class ShapeGeometry; +class LineGeometry; class Geometry; class Video; @@ -74,6 +76,8 @@ class AnimationCurveNode; class AnimationLayer; class AnimationStack; +class BlendShapeChannel; +class BlendShape; class Skin; class Cluster; @@ -81,13 +85,11 @@ class Cluster; /** Represents a delay-parsed FBX objects. Many objects in the scene * are not needed by assimp, so it makes no sense to parse them * upfront. */ -class LazyObject -{ +class LazyObject { public: LazyObject(uint64_t id, const Element& element, const Document& doc); - ~LazyObject(); -public: + ~LazyObject(); const Object* Get(bool dieOnError = false); @@ -132,11 +134,8 @@ private: unsigned int flags; }; - - /** Base class for in-memory (DOM) representations of FBX objects */ -class Object -{ +class Object { public: Object(uint64_t id, const Element& element, const std::string& name); @@ -160,14 +159,12 @@ protected: const uint64_t id; }; - - /** DOM class for generic FBX NoteAttribute blocks. NoteAttribute's just hold a property table, * fixed members are added by deriving classes. */ -class NodeAttribute : public Object -{ +class NodeAttribute : public Object { public: NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name); + virtual ~NodeAttribute(); const PropertyTable& Props() const { @@ -179,12 +176,11 @@ private: std::shared_ptr props; }; - /** DOM base class for FBX camera settings attached to a node */ -class CameraSwitcher : public NodeAttribute -{ +class CameraSwitcher : public NodeAttribute { public: CameraSwitcher(uint64_t id, const Element& element, const Document& doc, const std::string& name); + virtual ~CameraSwitcher(); int CameraID() const { @@ -205,7 +201,6 @@ private: std::string cameraIndexName; }; - #define fbx_stringize(a) #a #define fbx_simple_property(name, type, default_value) \ @@ -226,13 +221,12 @@ private: /** DOM base class for FBX cameras attached to a node */ -class Camera : public NodeAttribute -{ +class Camera : public NodeAttribute { public: Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name); + virtual ~Camera(); -public: fbx_simple_property(Position, aiVector3D, aiVector3D(0,0,0)) fbx_simple_property(UpVector, aiVector3D, aiVector3D(0,1,0)) fbx_simple_property(InterestPosition, aiVector3D, aiVector3D(0,0,0)) @@ -252,33 +246,26 @@ public: fbx_simple_property(FocalLength, float, 1.0f) }; - /** DOM base class for FBX null markers attached to a node */ -class Null : public NodeAttribute -{ +class Null : public NodeAttribute { public: Null(uint64_t id, const Element& element, const Document& doc, const std::string& name); virtual ~Null(); }; - /** DOM base class for FBX limb node markers attached to a node */ -class LimbNode : public NodeAttribute -{ +class LimbNode : public NodeAttribute { public: LimbNode(uint64_t id, const Element& element, const Document& doc, const std::string& name); virtual ~LimbNode(); }; - /** DOM base class for FBX lights attached to a node */ -class Light : public NodeAttribute -{ +class Light : public NodeAttribute { public: Light(uint64_t id, const Element& element, const Document& doc, const std::string& name); virtual ~Light(); -public: enum Type { Type_Point, @@ -300,7 +287,6 @@ public: Decay_MAX // end-of-enum sentinel }; -public: fbx_simple_property(Color, aiVector3D, aiVector3D(1,1,1)) fbx_simple_enum_property(LightType, Type, 0) fbx_simple_property(CastLightOnObject, bool, false) @@ -334,10 +320,8 @@ public: fbx_simple_property(EnableBarnDoor, bool, true) }; - /** DOM base class for FBX models (even though its semantics are more "node" than "model" */ -class Model : public Object -{ +class Model : public Object { public: enum RotOrder { RotOrder_EulerXYZ = 0, @@ -352,7 +336,6 @@ public: RotOrder_MAX // end-of-enum sentinel }; - enum TransformInheritance { TransformInheritance_RrSs = 0, TransformInheritance_RSrs, @@ -486,13 +469,12 @@ private: }; /** DOM class for generic FBX textures */ -class Texture : public Object -{ +class Texture : public Object { public: Texture(uint64_t id, const Element& element, const Document& doc, const std::string& name); + virtual ~Texture(); -public: const std::string& Type() const { return type; } @@ -547,17 +529,15 @@ private: }; /** DOM class for layered FBX textures */ -class LayeredTexture : public Object -{ +class LayeredTexture : public Object { public: LayeredTexture(uint64_t id, const Element& element, const Document& doc, const std::string& name); virtual ~LayeredTexture(); - //Can only be called after construction of the layered texture object due to construction flag. + // Can only be called after construction of the layered texture object due to construction flag. void fillTexture(const Document& doc); - enum BlendMode - { + enum BlendMode { BlendMode_Translucent, BlendMode_Additive, BlendMode_Modulate, @@ -619,13 +599,12 @@ typedef std::fbx_unordered_map LayeredTextur /** DOM class for generic FBX videos */ -class Video : public Object -{ +class Video : public Object { public: Video(uint64_t id, const Element& element, const Document& doc, const std::string& name); + virtual ~Video(); -public: const std::string& Type() const { return type; } @@ -648,7 +627,7 @@ public: return content; } - uint32_t ContentLength() const { + uint64_t ContentLength() const { return contentLength; } @@ -664,15 +643,15 @@ private: std::string fileName; std::shared_ptr props; - uint32_t contentLength; + uint64_t contentLength; uint8_t* content; }; /** DOM class for generic FBX materials */ -class Material : public Object -{ +class Material : public Object { public: Material(uint64_t id, const Element& element, const Document& doc, const std::string& name); + virtual ~Material(); const std::string& GetShadingModel() const { @@ -709,8 +688,7 @@ typedef std::vector KeyTimeList; typedef std::vector KeyValueList; /** Represents a FBX animation curve (i.e. a 1-dimensional set of keyframes and values therefor) */ -class AnimationCurve : public Object -{ +class AnimationCurve : public Object { public: AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& doc); virtual ~AnimationCurve(); @@ -721,14 +699,12 @@ public: return keys; } - /** get list of keyframe values. * Invariant: |GetKeys()| == |GetValues()| && |GetKeys()| > 0*/ const KeyValueList& GetValues() const { return values; } - const std::vector& GetAttributes() const { return attributes; } @@ -747,10 +723,8 @@ private: // property-name -> animation curve typedef std::map AnimationCurveMap; - /** Represents a FBX animation curve (i.e. a mapping from single animation curves to nodes) */ -class AnimationCurveNode : public Object -{ +class AnimationCurveNode : public Object { public: /* the optional white list specifies a list of property names for which the caller wants animations for. If the curve node does not match one of these, std::range_error @@ -800,8 +774,7 @@ private: typedef std::vector AnimationCurveNodeList; /** Represents a FBX animation layer (i.e. a list of node animations) */ -class AnimationLayer : public Object -{ +class AnimationLayer : public Object { public: AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc); virtual ~AnimationLayer(); @@ -814,7 +787,7 @@ public: /* the optional white list specifies a list of property names for which the caller wants animations for. Curves not matching this list will not be added to the animation layer. */ - AnimationCurveNodeList Nodes(const char* const * target_prop_whitelist = NULL, size_t whitelist_size = 0) const; + AnimationCurveNodeList Nodes(const char* const * target_prop_whitelist = nullptr, size_t whitelist_size = 0) const; private: std::shared_ptr props; @@ -824,8 +797,7 @@ private: typedef std::vector AnimationLayerList; /** Represents a FBX animation stack (i.e. a list of animation layers) */ -class AnimationStack : public Object -{ +class AnimationStack : public Object { public: AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc); virtual ~AnimationStack(); @@ -851,8 +823,7 @@ private: /** DOM class for deformers */ -class Deformer : public Object -{ +class Deformer : public Object { public: Deformer(uint64_t id, const Element& element, const Document& doc, const std::string& name); virtual ~Deformer(); @@ -869,11 +840,52 @@ private: typedef std::vector WeightArray; typedef std::vector WeightIndexArray; -/** DOM class for skin deformer clusters (aka subdeformers) */ -class Cluster : public Deformer -{ + +/** DOM class for BlendShapeChannel deformers */ +class BlendShapeChannel : public Deformer { +public: + BlendShapeChannel(uint64_t id, const Element& element, const Document& doc, const std::string& name); + + virtual ~BlendShapeChannel(); + + float DeformPercent() const { + return percent; + } + + const WeightArray& GetFullWeights() const { + return fullWeights; + } + + const std::vector& GetShapeGeometries() const { + return shapeGeometries; + } + +private: + float percent; + WeightArray fullWeights; + std::vector shapeGeometries; +}; + +/** DOM class for BlendShape deformers */ +class BlendShape : public Deformer { +public: + BlendShape(uint64_t id, const Element& element, const Document& doc, const std::string& name); + + virtual ~BlendShape(); + + const std::vector& BlendShapeChannels() const { + return blendShapeChannels; + } + +private: + std::vector blendShapeChannels; +}; + +/** DOM class for skin deformer clusters (aka sub-deformers) */ +class Cluster : public Deformer { public: Cluster(uint64_t id, const Element& element, const Document& doc, const std::string& name); + virtual ~Cluster(); /** get the list of deformer weights associated with this cluster. @@ -914,10 +926,10 @@ private: }; /** DOM class for skin deformers */ -class Skin : public Deformer -{ +class Skin : public Deformer { public: Skin(uint64_t id, const Element& element, const Document& doc, const std::string& name); + virtual ~Skin(); float DeformAccuracy() const { @@ -934,10 +946,10 @@ private: }; /** Represents a link between two FBX objects. */ -class Connection -{ +class Connection { public: Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string& prop, const Document& doc); + ~Connection(); // note: a connection ensures that the source and dest objects exist, but @@ -962,7 +974,7 @@ public: } int CompareTo(const Connection* c) const { - ai_assert( NULL != c ); + ai_assert( nullptr != c ); // note: can't subtract because this would overflow uint64_t if(InsertionOrder() > c->InsertionOrder()) { @@ -975,7 +987,7 @@ public: } bool Compare(const Connection* c) const { - ai_assert( NULL != c ); + ai_assert( nullptr != c ); return InsertionOrder() < c->InsertionOrder(); } @@ -1003,6 +1015,7 @@ typedef std::multimap ConnectionMap; class FileGlobalSettings { public: FileGlobalSettings(const Document& doc, std::shared_ptr props); + ~FileGlobalSettings(); const PropertyTable& Props() const { @@ -1059,10 +1072,10 @@ private: }; /** DOM root for a FBX file */ -class Document -{ +class Document { public: Document(const Parser& parser, const ImportSettings& settings); + ~Document(); LazyObject* GetObject(uint64_t id) const; diff --git a/code/FBXDocumentUtil.cpp b/code/FBX/FBXDocumentUtil.cpp similarity index 99% rename from code/FBXDocumentUtil.cpp rename to code/FBX/FBXDocumentUtil.cpp index 6f1e18e42..f84691479 100644 --- a/code/FBXDocumentUtil.cpp +++ b/code/FBX/FBXDocumentUtil.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/FBXDocumentUtil.h b/code/FBX/FBXDocumentUtil.h similarity index 95% rename from code/FBXDocumentUtil.h rename to code/FBX/FBXDocumentUtil.h index c0435a663..2450109e5 100644 --- a/code/FBXDocumentUtil.h +++ b/code/FBX/FBXDocumentUtil.h @@ -56,7 +56,6 @@ namespace Assimp { namespace FBX { namespace Util { - /* DOM/Parse error reporting - does not return */ AI_WONT_RETURN void DOMError(const std::string& message, const Token& token) AI_WONT_RETURN_SUFFIX; AI_WONT_RETURN void DOMError(const std::string& message, const Element* element = NULL) AI_WONT_RETURN_SUFFIX; @@ -73,28 +72,28 @@ std::shared_ptr GetPropertyTable(const Document& doc, const Scope& sc, bool no_warn = false); - // ------------------------------------------------------------------------------------------------ template -inline const T* ProcessSimpleConnection(const Connection& con, +inline +const T* ProcessSimpleConnection(const Connection& con, bool is_object_property_conn, const char* name, const Element& element, - const char** propNameOut = NULL) + const char** propNameOut = nullptr) { if (is_object_property_conn && !con.PropertyName().length()) { DOMWarning("expected incoming " + std::string(name) + " link to be an object-object connection, ignoring", &element ); - return NULL; + return nullptr; } else if (!is_object_property_conn && con.PropertyName().length()) { DOMWarning("expected incoming " + std::string(name) + " link to be an object-property connection, ignoring", &element ); - return NULL; + return nullptr; } if(is_object_property_conn && propNameOut) { @@ -108,13 +107,12 @@ inline const T* ProcessSimpleConnection(const Connection& con, DOMWarning("failed to read source object for incoming " + std::string(name) + " link, ignoring", &element); - return NULL; + return nullptr; } return dynamic_cast(ob); } - } //!Util } //!FBX } //!Assimp diff --git a/code/FBXExportNode.cpp b/code/FBX/FBXExportNode.cpp similarity index 97% rename from code/FBXExportNode.cpp rename to code/FBX/FBXExportNode.cpp index a1171eca8..06c89cee4 100644 --- a/code/FBXExportNode.cpp +++ b/code/FBX/FBXExportNode.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -54,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include // ostringstream #include // shared_ptr +namespace Assimp { // AddP70 helpers... there's no usable pattern here, // so all are defined as separate functions. // Even "animatable" properties are often completely different @@ -252,7 +253,8 @@ void FBX::Node::DumpChildren( } else { std::ostringstream ss; DumpChildrenAscii(ss, indent); - s.PutString(ss.str()); + if (ss.tellp() > 0) + s.PutString(ss.str()); } } @@ -266,7 +268,8 @@ void FBX::Node::End( } else { std::ostringstream ss; EndAscii(ss, indent, has_children); - s.PutString(ss.str()); + if (ss.tellp() > 0) + s.PutString(ss.str()); } } @@ -367,7 +370,7 @@ void FBX::Node::EndBinary( bool has_children ) { // if there were children, add a null record - if (has_children) { s.PutString(FBX::NULL_RECORD); } + if (has_children) { s.PutString(Assimp::FBX::NULL_RECORD); } // now go back and write initial pos this->end_pos = s.Tell(); @@ -432,7 +435,7 @@ void FBX::Node::WritePropertyNodeAscii( char buffer[32]; FBX::Node node(name); node.Begin(s, false, indent); - std::string vsize = std::to_string(v.size()); + std::string vsize = to_string(v.size()); // * { s.PutChar('*'); s.PutString(vsize); s.PutString(" {\n"); // indent + 1 @@ -468,7 +471,7 @@ void FBX::Node::WritePropertyNodeAscii( char buffer[32]; FBX::Node node(name); node.Begin(s, false, indent); - std::string vsize = std::to_string(v.size()); + std::string vsize = to_string(v.size()); // * { s.PutChar('*'); s.PutString(vsize); s.PutString(" {\n"); // indent + 1 @@ -563,6 +566,6 @@ void FBX::Node::WritePropertyNode( FBX::Node::WritePropertyNodeAscii(name, v, s, indent); } } - +} #endif // ASSIMP_BUILD_NO_FBX_EXPORTER #endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/FBXExportNode.h b/code/FBX/FBXExportNode.h similarity index 94% rename from code/FBXExportNode.h rename to code/FBX/FBXExportNode.h index 5ddd8c77b..ef3bc781a 100644 --- a/code/FBXExportNode.h +++ b/code/FBX/FBXExportNode.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -54,30 +54,43 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +namespace Assimp { namespace FBX { class Node; } -class FBX::Node -{ -public: // public data members +class FBX::Node { +public: // TODO: accessors std::string name; // node name - std::vector properties; // node properties + std::vector properties; // node properties std::vector children; // child nodes // some nodes always pretend they have children... bool force_has_children = false; public: // constructors + /// The default class constructor. Node() = default; - Node(const std::string& n) : name(n) {} + + /// The class constructor with the name. + Node(const std::string& n) + : name(n) + , properties() + , children() + , force_has_children( false ) { + // empty + } // convenience template to construct with properties directly template Node(const std::string& n, const More... more) - : name(n) - { AddProperties(more...); } + : name(n) + , properties() + , children() + , force_has_children(false) { + AddProperties(more...); + } public: // functions to add properties or children // add a single property to the node @@ -201,7 +214,7 @@ public: // static member functions Assimp::StreamWriterLE& s, bool binary, int indent ) { - FBX::Property p(value); + FBX::FBXExportProperty p(value); FBX::Node node(name, p); node.Dump(s, binary, indent); } @@ -251,7 +264,7 @@ private: // static helper functions ); }; - +} #endif // ASSIMP_BUILD_NO_FBX_EXPORTER diff --git a/code/FBXExportProperty.cpp b/code/FBX/FBXExportProperty.cpp similarity index 60% rename from code/FBXExportProperty.cpp rename to code/FBX/FBXExportProperty.cpp index 431750274..f2a63b72b 100644 --- a/code/FBXExportProperty.cpp +++ b/code/FBX/FBXExportProperty.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -52,187 +52,206 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include // ostringstream +namespace Assimp { +namespace FBX { // constructors for single element properties -FBX::Property::Property(bool v) - : type('C'), data(1) -{ - data = {uint8_t(v)}; -} +FBXExportProperty::FBXExportProperty(bool v) +: type('C') +, data(1, uint8_t(v)) {} -FBX::Property::Property(int16_t v) : type('Y'), data(2) -{ +FBXExportProperty::FBXExportProperty(int16_t v) +: type('Y') +, data(2) { uint8_t* d = data.data(); (reinterpret_cast(d))[0] = v; } -FBX::Property::Property(int32_t v) : type('I'), data(4) -{ +FBXExportProperty::FBXExportProperty(int32_t v) +: type('I') +, data(4) { uint8_t* d = data.data(); (reinterpret_cast(d))[0] = v; } -FBX::Property::Property(float v) : type('F'), data(4) -{ +FBXExportProperty::FBXExportProperty(float v) +: type('F') +, data(4) { uint8_t* d = data.data(); (reinterpret_cast(d))[0] = v; } -FBX::Property::Property(double v) : type('D'), data(8) -{ +FBXExportProperty::FBXExportProperty(double v) +: type('D') +, data(8) { uint8_t* d = data.data(); (reinterpret_cast(d))[0] = v; } -FBX::Property::Property(int64_t v) : type('L'), data(8) -{ +FBXExportProperty::FBXExportProperty(int64_t v) +: type('L') +, data(8) { uint8_t* d = data.data(); (reinterpret_cast(d))[0] = v; } - // constructors for array-type properties -FBX::Property::Property(const char* c, bool raw) - : Property(std::string(c), raw) -{} +FBXExportProperty::FBXExportProperty(const char* c, bool raw) +: FBXExportProperty(std::string(c), raw) { + // empty +} // strings can either be saved as "raw" (R) data, or "string" (S) data -FBX::Property::Property(const std::string& s, bool raw) - : type(raw ? 'R' : 'S'), data(s.size()) -{ +FBXExportProperty::FBXExportProperty(const std::string& s, bool raw) +: type(raw ? 'R' : 'S') +, data(s.size()) { for (size_t i = 0; i < s.size(); ++i) { data[i] = uint8_t(s[i]); } } -FBX::Property::Property(const std::vector& r) - : type('R'), data(r) -{} +FBXExportProperty::FBXExportProperty(const std::vector& r) +: type('R') +, data(r) { + // empty +} -FBX::Property::Property(const std::vector& va) - : type('i'), data(4*va.size()) -{ +FBXExportProperty::FBXExportProperty(const std::vector& va) +: type('i') +, data(4 * va.size() ) { int32_t* d = reinterpret_cast(data.data()); - for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; } + for (size_t i = 0; i < va.size(); ++i) { + d[i] = va[i]; + } } -FBX::Property::Property(const std::vector& va) - : type('l'), data(8*va.size()) -{ +FBXExportProperty::FBXExportProperty(const std::vector& va) +: type('l') +, data(8 * va.size()) { int64_t* d = reinterpret_cast(data.data()); - for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; } + for (size_t i = 0; i < va.size(); ++i) { + d[i] = va[i]; + } } -FBX::Property::Property(const std::vector& va) - : type('f'), data(4*va.size()) -{ +FBXExportProperty::FBXExportProperty(const std::vector& va) +: type('f') +, data(4 * va.size()) { float* d = reinterpret_cast(data.data()); - for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; } + for (size_t i = 0; i < va.size(); ++i) { + d[i] = va[i]; + } } -FBX::Property::Property(const std::vector& va) - : type('d'), data(8*va.size()) -{ +FBXExportProperty::FBXExportProperty(const std::vector& va) +: type('d') +, data(8 * va.size()) { double* d = reinterpret_cast(data.data()); - for (size_t i = 0; i < va.size(); ++i) { d[i] = va[i]; } + for (size_t i = 0; i < va.size(); ++i) { + d[i] = va[i]; + } } -FBX::Property::Property(const aiMatrix4x4& vm) - : type('d'), data(8*16) -{ +FBXExportProperty::FBXExportProperty(const aiMatrix4x4& vm) +: type('d') +, data(8 * 16) { double* d = reinterpret_cast(data.data()); for (unsigned int c = 0; c < 4; ++c) { for (unsigned int r = 0; r < 4; ++r) { - d[4*c+r] = vm[r][c]; + d[4 * c + r] = vm[r][c]; } } } // public member functions -size_t FBX::Property::size() -{ +size_t FBXExportProperty::size() { switch (type) { - case 'C': case 'Y': case 'I': case 'F': case 'D': case 'L': - return data.size() + 1; - case 'S': case 'R': - return data.size() + 5; - case 'i': case 'd': - return data.size() + 13; - default: - throw DeadlyExportError("Requested size on property of unknown type"); + case 'C': + case 'Y': + case 'I': + case 'F': + case 'D': + case 'L': + return data.size() + 1; + case 'S': + case 'R': + return data.size() + 5; + case 'i': + case 'd': + return data.size() + 13; + default: + throw DeadlyExportError("Requested size on property of unknown type"); } } -void FBX::Property::DumpBinary(Assimp::StreamWriterLE &s) -{ +void FBXExportProperty::DumpBinary(Assimp::StreamWriterLE& s) { s.PutU1(type); uint8_t* d = data.data(); size_t N; switch (type) { - case 'C': s.PutU1(*(reinterpret_cast(d))); return; - case 'Y': s.PutI2(*(reinterpret_cast(d))); return; - case 'I': s.PutI4(*(reinterpret_cast(d))); return; - case 'F': s.PutF4(*(reinterpret_cast(d))); return; - case 'D': s.PutF8(*(reinterpret_cast(d))); return; - case 'L': s.PutI8(*(reinterpret_cast(d))); return; - case 'S': - case 'R': - s.PutU4(uint32_t(data.size())); - for (size_t i = 0; i < data.size(); ++i) { s.PutU1(data[i]); } - return; - case 'i': - N = data.size() / 4; - s.PutU4(uint32_t(N)); // number of elements - s.PutU4(0); // no encoding (1 would be zip-compressed) - // TODO: compress if large? - s.PutU4(uint32_t(data.size())); // data size - for (size_t i = 0; i < N; ++i) { - s.PutI4((reinterpret_cast(d))[i]); - } - return; - case 'l': - N = data.size() / 8; - s.PutU4(uint32_t(N)); // number of elements - s.PutU4(0); // no encoding (1 would be zip-compressed) - // TODO: compress if large? - s.PutU4(uint32_t(data.size())); // data size - for (size_t i = 0; i < N; ++i) { - s.PutI8((reinterpret_cast(d))[i]); - } - return; - case 'f': - N = data.size() / 4; - s.PutU4(uint32_t(N)); // number of elements - s.PutU4(0); // no encoding (1 would be zip-compressed) - // TODO: compress if large? - s.PutU4(uint32_t(data.size())); // data size - for (size_t i = 0; i < N; ++i) { - s.PutF4((reinterpret_cast(d))[i]); - } - return; - case 'd': - N = data.size() / 8; - s.PutU4(uint32_t(N)); // number of elements - s.PutU4(0); // no encoding (1 would be zip-compressed) - // TODO: compress if large? - s.PutU4(uint32_t(data.size())); // data size - for (size_t i = 0; i < N; ++i) { - s.PutF8((reinterpret_cast(d))[i]); - } - return; - default: - std::ostringstream err; - err << "Tried to dump property with invalid type '"; - err << type << "'!"; - throw DeadlyExportError(err.str()); + case 'C': s.PutU1(*(reinterpret_cast(d))); return; + case 'Y': s.PutI2(*(reinterpret_cast(d))); return; + case 'I': s.PutI4(*(reinterpret_cast(d))); return; + case 'F': s.PutF4(*(reinterpret_cast(d))); return; + case 'D': s.PutF8(*(reinterpret_cast(d))); return; + case 'L': s.PutI8(*(reinterpret_cast(d))); return; + case 'S': + case 'R': + s.PutU4(uint32_t(data.size())); + for (size_t i = 0; i < data.size(); ++i) { s.PutU1(data[i]); } + return; + case 'i': + N = data.size() / 4; + s.PutU4(uint32_t(N)); // number of elements + s.PutU4(0); // no encoding (1 would be zip-compressed) + // TODO: compress if large? + s.PutU4(uint32_t(data.size())); // data size + for (size_t i = 0; i < N; ++i) { + s.PutI4((reinterpret_cast(d))[i]); + } + return; + case 'l': + N = data.size() / 8; + s.PutU4(uint32_t(N)); // number of elements + s.PutU4(0); // no encoding (1 would be zip-compressed) + // TODO: compress if large? + s.PutU4(uint32_t(data.size())); // data size + for (size_t i = 0; i < N; ++i) { + s.PutI8((reinterpret_cast(d))[i]); + } + return; + case 'f': + N = data.size() / 4; + s.PutU4(uint32_t(N)); // number of elements + s.PutU4(0); // no encoding (1 would be zip-compressed) + // TODO: compress if large? + s.PutU4(uint32_t(data.size())); // data size + for (size_t i = 0; i < N; ++i) { + s.PutF4((reinterpret_cast(d))[i]); + } + return; + case 'd': + N = data.size() / 8; + s.PutU4(uint32_t(N)); // number of elements + s.PutU4(0); // no encoding (1 would be zip-compressed) + // TODO: compress if large? + s.PutU4(uint32_t(data.size())); // data size + for (size_t i = 0; i < N; ++i) { + s.PutF8((reinterpret_cast(d))[i]); + } + return; + default: + std::ostringstream err; + err << "Tried to dump property with invalid type '"; + err << type << "'!"; + throw DeadlyExportError(err.str()); } } -void FBX::Property::DumpAscii(Assimp::StreamWriterLE &outstream, int indent) -{ +void FBXExportProperty::DumpAscii(Assimp::StreamWriterLE& outstream, int indent) { std::ostringstream ss; ss.imbue(std::locale::classic()); ss.precision(15); // this seems to match official FBX SDK exports @@ -240,8 +259,7 @@ void FBX::Property::DumpAscii(Assimp::StreamWriterLE &outstream, int indent) outstream.PutString(ss.str()); } -void FBX::Property::DumpAscii(std::ostream& s, int indent) -{ +void FBXExportProperty::DumpAscii(std::ostream& s, int indent) { // no writing type... or anything. just shove it into the stream. uint8_t* d = data.data(); size_t N; @@ -360,5 +378,8 @@ void FBX::Property::DumpAscii(std::ostream& s, int indent) } } +} // Namespace FBX +} // Namespace Assimp + #endif // ASSIMP_BUILD_NO_FBX_EXPORTER #endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/FBXExportProperty.h b/code/FBX/FBXExportProperty.h similarity index 76% rename from code/FBXExportProperty.h rename to code/FBX/FBXExportProperty.h index cb3b0113f..d692fe6ee 100644 --- a/code/FBXExportProperty.h +++ b/code/FBX/FBXExportProperty.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -47,7 +47,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_FBX_EXPORTER - #include // aiMatrix4x4 #include // StreamWriterLE @@ -56,11 +55,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include // is_void +namespace Assimp { namespace FBX { - class Property; -} -/** FBX::Property +/** @brief FBX::Property * * Holds a value of any of FBX's recognized types, * each represented by a particular one-character code. @@ -78,35 +76,34 @@ namespace FBX { * S : string (array of 1-byte char) * R : raw data (array of bytes) */ -class FBX::Property -{ +class FBXExportProperty { public: // constructors for basic types. // all explicit to avoid accidental typecasting - explicit Property(bool v); + explicit FBXExportProperty(bool v); // TODO: determine if there is actually a byte type, // or if this always means . 'C' seems to imply , // so possibly the above was intended to represent both. - explicit Property(int16_t v); - explicit Property(int32_t v); - explicit Property(float v); - explicit Property(double v); - explicit Property(int64_t v); + explicit FBXExportProperty(int16_t v); + explicit FBXExportProperty(int32_t v); + explicit FBXExportProperty(float v); + explicit FBXExportProperty(double v); + explicit FBXExportProperty(int64_t v); // strings can either be stored as 'R' (raw) or 'S' (string) type - explicit Property(const char* c, bool raw=false); - explicit Property(const std::string& s, bool raw=false); - explicit Property(const std::vector& r); - explicit Property(const std::vector& va); - explicit Property(const std::vector& va); - explicit Property(const std::vector& va); - explicit Property(const std::vector& va); - explicit Property(const aiMatrix4x4& vm); + explicit FBXExportProperty(const char* c, bool raw = false); + explicit FBXExportProperty(const std::string& s, bool raw = false); + explicit FBXExportProperty(const std::vector& r); + explicit FBXExportProperty(const std::vector& va); + explicit FBXExportProperty(const std::vector& va); + explicit FBXExportProperty(const std::vector& va); + explicit FBXExportProperty(const std::vector& va); + explicit FBXExportProperty(const aiMatrix4x4& vm); // this will catch any type not defined above, // so that we don't accidentally convert something we don't want. // for example (const char*) --> (bool)... seriously wtf C++ template - explicit Property(T v) : type('X') { + explicit FBXExportProperty(T v) : type('X') { static_assert(std::is_void::value, "TRIED TO CREATE FBX PROPERTY WITH UNSUPPORTED TYPE, CHECK YOUR PROPERTY INSTANTIATION"); } // note: no line wrap so it appears verbatim on the compiler error @@ -114,9 +111,9 @@ public: size_t size(); // write this property node as binary data to the given stream - void DumpBinary(Assimp::StreamWriterLE &s); - void DumpAscii(Assimp::StreamWriterLE &s, int indent=0); - void DumpAscii(std::ostream &s, int indent=0); + void DumpBinary(Assimp::StreamWriterLE& s); + void DumpAscii(Assimp::StreamWriterLE& s, int indent = 0); + void DumpAscii(std::ostream& s, int indent = 0); // note: make sure the ostream is in classic "C" locale private: @@ -124,6 +121,9 @@ private: std::vector data; }; +} // Namespace FBX +} // Namespace Assimp + #endif // ASSIMP_BUILD_NO_FBX_EXPORTER #endif // AI_FBXEXPORTPROPERTY_H_INC diff --git a/code/FBXExporter.cpp b/code/FBX/FBXExporter.cpp similarity index 91% rename from code/FBXExporter.cpp rename to code/FBX/FBXExporter.cpp index 037520641..9316dc4f0 100644 --- a/code/FBXExporter.cpp +++ b/code/FBX/FBXExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,6 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXExportNode.h" #include "FBXExportProperty.h" #include "FBXCommon.h" +#include "FBXUtil.h" #include // aiGetVersion #include @@ -66,6 +67,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include // RESOURCES: // https://code.blender.org/2013/08/fbx-binary-file-format-specification/ @@ -73,7 +75,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. const ai_real DEG = ai_real( 57.29577951308232087679815481 ); // degrees per radian +using namespace Assimp; +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 @@ -92,11 +98,6 @@ namespace FBX { ";------------------------------------------------------------------"; } -using namespace Assimp; -using namespace FBX; - -namespace Assimp { - // --------------------------------------------------------------------- // Worker function for exporting a scene to binary FBX. // Prototyped and registered in Exporter.cpp @@ -121,6 +122,7 @@ namespace Assimp { IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties + ){ // initialize the exporter FBXExporter exporter(pScene, pProperties); @@ -131,13 +133,15 @@ namespace Assimp { } // end of namespace Assimp -FBXExporter::FBXExporter ( - const aiScene* pScene, - const ExportProperties* pProperties -) - : mScene(pScene) - , mProperties(pProperties) -{ +FBXExporter::FBXExporter ( const aiScene* pScene, const ExportProperties* pProperties ) +: binary(false) +, mScene(pScene) +, mProperties(pProperties) +, outfile() +, connections() +, mesh_uids() +, material_uids() +, node_uids() { // will probably need to determine UIDs, connections, etc here. // basically anything that needs to be known // before we start writing sections to the stream. @@ -1002,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> vVertexIndice;//save vertex_indices as it is needed later + // geometry (aiMesh) mesh_uids.clear(); indent = 1; @@ -1028,21 +1035,35 @@ void FBXExporter::WriteObjects () std::vector vertex_indices; // map of vertex value to its index in the data vector std::map 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; - flattened_vertices.push_back(vtx[0]); - flattened_vertices.push_back(vtx[1]); - flattened_vertices.push_back(vtx[2]); - ++index; - } else { - vertex_indices.push_back(int32_t(elem->second)); + if(bJoinIdenticalVertices){ + 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; + flattened_vertices.push_back(vtx[0]); + flattened_vertices.push_back(vtx[1]); + flattened_vertices.push_back(vtx[2]); + ++index; + } else { + 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 ); @@ -1113,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 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) { @@ -1206,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)); @@ -1216,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); @@ -1391,10 +1472,6 @@ void FBXExporter::WriteObjects () // FbxVideo - stores images used by textures. for (const auto &it : uid_by_image) { - if (it.first.compare(0, 1, "*") == 0) { - // TODO: embedded textures - continue; - } FBX::Node n("Video"); const int64_t& uid = it.second; const std::string name = ""; // TODO: ... name??? @@ -1404,7 +1481,33 @@ void FBXExporter::WriteObjects () // TODO: get full path... relative path... etc... ugh... // for now just use the same path for everything, // and hopefully one of them will work out. - const std::string& path = it.first; + std::string path = it.first; + // try get embedded texture + const aiTexture* embedded_texture = mScene->GetEmbeddedTexture(it.first.c_str()); + if (embedded_texture != nullptr) { + // change the path (use original filename, if available. If name is empty, concatenate texture index with file extension) + std::stringstream newPath; + if (embedded_texture->mFilename.length > 0) { + newPath << embedded_texture->mFilename.C_Str(); + } else if (embedded_texture->achFormatHint[0]) { + int texture_index = std::stoi(path.substr(1, path.size() - 1)); + newPath << texture_index << "." << embedded_texture->achFormatHint; + } + path = newPath.str(); + // embed the texture + size_t texture_size = static_cast(embedded_texture->mWidth * std::max(embedded_texture->mHeight, 1u)); + if (binary) { + // embed texture as binary data + std::vector tex_data; + tex_data.resize(texture_size); + memcpy(&tex_data[0], (char*)embedded_texture->pcData, texture_size); + n.AddChild("Content", tex_data); + } else { + // embed texture in base64 encoding + std::string encoded_texture = FBX::Util::EncodeBase64((char*)embedded_texture->pcData, texture_size); + n.AddChild("Content", encoded_texture); + } + } p.AddP70("Path", "KString", "XRefUrl", "", path); n.AddChild(p); n.AddChild("UseMipMap", int32_t(0)); @@ -1417,17 +1520,17 @@ void FBXExporter::WriteObjects () // referenced by material_index/texture_type pairs. std::map,int64_t> texture_uids; const std::map prop_name_by_tt = { - {aiTextureType_DIFFUSE, "DiffuseColor"}, - {aiTextureType_SPECULAR, "SpecularColor"}, - {aiTextureType_AMBIENT, "AmbientColor"}, - {aiTextureType_EMISSIVE, "EmissiveColor"}, - {aiTextureType_HEIGHT, "Bump"}, - {aiTextureType_NORMALS, "NormalMap"}, - {aiTextureType_SHININESS, "ShininessExponent"}, - {aiTextureType_OPACITY, "TransparentColor"}, + {aiTextureType_DIFFUSE, "DiffuseColor"}, + {aiTextureType_SPECULAR, "SpecularColor"}, + {aiTextureType_AMBIENT, "AmbientColor"}, + {aiTextureType_EMISSIVE, "EmissiveColor"}, + {aiTextureType_HEIGHT, "Bump"}, + {aiTextureType_NORMALS, "NormalMap"}, + {aiTextureType_SHININESS, "ShininessExponent"}, + {aiTextureType_OPACITY, "TransparentColor"}, {aiTextureType_DISPLACEMENT, "DisplacementColor"}, //{aiTextureType_LIGHTMAP, "???"}, - {aiTextureType_REFLECTION, "ReflectionColor"} + {aiTextureType_REFLECTION, "ReflectionColor"} //{aiTextureType_UNKNOWN, ""} }; for (size_t i = 0; i < mScene->mNumMaterials; ++i) { @@ -1573,19 +1676,41 @@ void FBXExporter::WriteObjects () // one sticky point is that the number of vertices may not match, // because assimp splits vertices by normal, uv, etc. + // functor for aiNode sorting + struct SortNodeByName + { + bool operator()(const aiNode *lhs, const aiNode *rhs) const + { + return strcmp(lhs->mName.C_Str(), rhs->mName.C_Str()) < 0; + } + }; + // first we should mark the skeleton for each mesh. // the skeleton must include not only the aiBones, // but also all their parent nodes. // anything that affects the position of any bone node must be included. - std::vector> skeleton_by_mesh(mScene->mNumMeshes); + // Use SorNodeByName to make sure the exported result will be the same across all systems + // Otherwise the aiNodes of the skeleton would be sorted based on the pointer address, which isn't consistent + std::vector> skeleton_by_mesh(mScene->mNumMeshes); // 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 limbnodes; + + //actual bone nodes in fbx, without parenting-up + std::unordered_set 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 node_by_bone; for (size_t mi = 0; mi < mScene->mNumMeshes; ++mi) { const aiMesh* m = mScene->mMeshes[mi]; - std::set skeleton; + std::set skeleton; for (size_t bi =0; bi < m->mNumBones; ++bi) { const aiBone* b = m->mBones[bi]; const std::string name(b->mName.C_Str()); @@ -1624,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? @@ -1644,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; } } @@ -1687,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 vertex_indices; - // map of vertex value to its index in the data vector - std::map 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& 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. @@ -1726,7 +1835,7 @@ void FBXExporter::WriteObjects () aiMatrix4x4 mesh_xform = get_world_transform(mesh_node, mScene); // now make a subdeformer for each bone in the skeleton - const std::set &skeleton = skeleton_by_mesh[mi]; + const std::set skeleton= skeleton_by_mesh[mi]; for (const aiNode* bone_node : skeleton) { // if there's a bone for this node, find it const aiBone* b = nullptr; @@ -1786,41 +1895,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; - } + sdnode.AddChild("Transform", tr); - // 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); - } + sdnode.AddChild("TransformLink", bone_xform); // 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. @@ -2235,8 +2313,8 @@ void FBXExporter::WriteModelNode( // not sure what these are for, // but they seem to be omnipresent - m.AddChild("Shading", Property(true)); - m.AddChild("Culling", Property("CullingOff")); + m.AddChild("Shading", FBXExportProperty(true)); + m.AddChild("Culling", FBXExportProperty("CullingOff")); m.Dump(outstream, binary, 1); } @@ -2349,7 +2427,7 @@ void FBXExporter::WriteModelNodes( na.AddProperties( node_attribute_uid, FBX::SEPARATOR + "NodeAttribute", "LimbNode" ); - na.AddChild("TypeFlags", Property("Skeleton")); + na.AddChild("TypeFlags", FBXExportProperty("Skeleton")); na.Dump(outstream, binary, 1); // and connect them connections.emplace_back("C", "OO", node_attribute_uid, node_uid); @@ -2405,7 +2483,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, @@ -2444,7 +2522,6 @@ void FBXExporter::WriteAnimationCurve( // TODO: keyattr flags and data (STUB for now) n.AddChild("KeyAttrFlags", std::vector{0}); n.AddChild("KeyAttrDataFloat", std::vector{0,0,0,0}); - ai_assert(static_cast(times.size()) <= std::numeric_limits::max()); n.AddChild( "KeyAttrRefCount", std::vector{static_cast(times.size())} diff --git a/code/FBXExporter.h b/code/FBX/FBXExporter.h similarity index 98% rename from code/FBXExporter.h rename to code/FBX/FBXExporter.h index c27d1a8ce..1ae727eda 100644 --- a/code/FBXExporter.h +++ b/code/FBX/FBXExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -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, diff --git a/code/FBXImportSettings.h b/code/FBX/FBXImportSettings.h similarity index 87% rename from code/FBXImportSettings.h rename to code/FBX/FBXImportSettings.h index e612fddef..1a4c80f8b 100644 --- a/code/FBXImportSettings.h +++ b/code/FBX/FBXImportSettings.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -53,19 +53,22 @@ namespace FBX { struct ImportSettings { ImportSettings() - : strictMode(true) - , readAllLayers(true) - , readAllMaterials(false) - , readMaterials(true) - , readTextures(true) - , readCameras(true) - , readLights(true) - , readAnimations(true) - , readWeights(true) - , preservePivots(true) - , optimizeEmptyAnimationCurves(true) - , useLegacyEmbeddedTextureNaming(false) - {} + : strictMode(true) + , readAllLayers(true) + , readAllMaterials(false) + , readMaterials(true) + , readTextures(true) + , readCameras(true) + , readLights(true) + , readAnimations(true) + , readWeights(true) + , preservePivots(true) + , optimizeEmptyAnimationCurves(true) + , useLegacyEmbeddedTextureNaming(false) + , removeEmptyBones( true ) + , convertToMeters( false ) { + // empty + } /** enable strict mode: @@ -141,8 +144,16 @@ struct ImportSettings bool optimizeEmptyAnimationCurves; /** use legacy naming for embedded textures eg: (*0, *1, *2) - **/ + */ bool useLegacyEmbeddedTextureNaming; + + /** Empty bones shall be removed + */ + bool removeEmptyBones; + + /** Set to true to perform a conversion from cm to meter after the import + */ + bool convertToMeters; }; diff --git a/code/FBXImporter.cpp b/code/FBX/FBXImporter.cpp similarity index 90% rename from code/FBXImporter.cpp rename to code/FBX/FBXImporter.cpp index b004bcd8c..c8c1a6853 100644 --- a/code/FBXImporter.cpp +++ b/code/FBX/FBXImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -60,11 +60,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include namespace Assimp { - template<> const char* LogFunctions::Prefix() - { - static auto prefix = "FBX: "; - return prefix; - } + +template<> +const char* LogFunctions::Prefix() { + static auto prefix = "FBX: "; + return prefix; +} + } using namespace Assimp; @@ -72,6 +74,7 @@ using namespace Assimp::Formatter; using namespace Assimp::FBX; namespace { + static const aiImporterDesc desc = { "Autodesk FBX Importer", "", @@ -137,6 +140,8 @@ void FBXImporter::SetupProperties(const Importer* pImp) settings.preservePivots = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_PRESERVE_PIVOTS, true); settings.optimizeEmptyAnimationCurves = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES, true); settings.useLegacyEmbeddedTextureNaming = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING, false); + settings.removeEmptyBones = pImp->GetPropertyBool(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, true); + settings.convertToMeters = pImp->GetPropertyBool(AI_CONFIG_FBX_CONVERT_TO_M, false); } // ------------------------------------------------------------------------------------------------ @@ -167,7 +172,7 @@ void FBXImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS bool is_binary = false; if (!strncmp(begin,"Kaydara FBX Binary",18)) { is_binary = true; - TokenizeBinary(tokens,begin,static_cast(contents.size())); + TokenizeBinary(tokens,begin,contents.size()); } else { Tokenize(tokens,begin); @@ -181,7 +186,14 @@ void FBXImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS Document doc(parser,settings); // convert the FBX DOM to aiScene - ConvertToAssimpScene(pScene,doc); + ConvertToAssimpScene(pScene, doc, settings.removeEmptyBones); + + // 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()); } diff --git a/code/FBXImporter.h b/code/FBX/FBXImporter.h similarity index 98% rename from code/FBXImporter.h rename to code/FBX/FBXImporter.h index 870f1c49b..c365b2cdd 100644 --- a/code/FBXImporter.h +++ b/code/FBX/FBXImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/FBXMaterial.cpp b/code/FBX/FBXMaterial.cpp similarity index 78% rename from code/FBXMaterial.cpp rename to code/FBX/FBXMaterial.cpp index 75b2e3b4b..f43a8b84b 100644 --- a/code/FBXMaterial.cpp +++ b/code/FBX/FBXMaterial.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -55,6 +55,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include // std::transform +#include "FBXUtil.h" namespace Assimp { namespace FBX { @@ -206,6 +207,20 @@ Texture::Texture(uint64_t id, const Element& element, const Document& doc, const props = GetPropertyTable(doc,"Texture.FbxFileTexture",element,sc); + // 3DS Max and FBX SDK use "Scaling" and "Translation" instead of "ModelUVScaling" and "ModelUVTranslation". Use these properties if available. + bool ok; + const aiVector3D& scaling = PropertyGet(*props, "Scaling", ok); + if (ok) { + uvScaling.x = scaling.x; + uvScaling.y = scaling.y; + } + + const aiVector3D& trans = PropertyGet(*props, "Translation", ok); + if (ok) { + uvTrans.x = trans.x; + uvTrans.y = trans.y; + } + // resolve video links if(doc.Settings().readTextures) { const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID()); @@ -301,13 +316,52 @@ Video::Video(uint64_t id, const Element& element, const Document& doc, const std relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0)); } - if(Content) { + if(Content && !Content->Tokens().empty()) { //this field is omitted when the embedded texture is already loaded, let's ignore if it's not found try { const Token& token = GetRequiredToken(*Content, 0); const char* data = token.begin(); if (!token.IsBinary()) { - DOMWarning("video content is not binary data, ignoring", &element); + if (*data != '"') { + DOMError("embedded content is not surrounded by quotation marks", &element); + } + else { + size_t targetLength = 0; + auto numTokens = Content->Tokens().size(); + // First time compute size (it could be large like 64Gb and it is good to allocate it once) + for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) + { + const Token& dataToken = GetRequiredToken(*Content, tokenIdx); + size_t tokenLength = dataToken.end() - dataToken.begin() - 2; // ignore double quotes + const char* base64data = dataToken.begin() + 1; + const size_t outLength = Util::ComputeDecodedSizeBase64(base64data, tokenLength); + if (outLength == 0) + { + DOMError("Corrupted embedded content found", &element); + } + targetLength += outLength; + } + if (targetLength == 0) + { + DOMError("Corrupted embedded content found", &element); + } + content = new uint8_t[targetLength]; + contentLength = static_cast(targetLength); + size_t dst_offset = 0; + for (uint32_t tokenIdx = 0; tokenIdx < numTokens; ++tokenIdx) + { + const Token& dataToken = GetRequiredToken(*Content, tokenIdx); + size_t tokenLength = dataToken.end() - dataToken.begin() - 2; // ignore double quotes + const char* base64data = dataToken.begin() + 1; + dst_offset += Util::DecodeBase64(base64data, tokenLength, content + dst_offset, targetLength - dst_offset); + } + if (targetLength != dst_offset) + { + delete[] content; + contentLength = 0; + DOMError("Corrupted embedded content found", &element); + } + } } else if (static_cast(token.end() - data) < 5) { DOMError("binary data array is too short, need five (5) bytes for type signature and element count", &element); @@ -326,8 +380,11 @@ Video::Video(uint64_t id, const Element& element, const Document& doc, const std content = new uint8_t[len]; ::memcpy(content, data + 5, len); } - } catch (runtime_error runtimeError) { + } catch (const runtime_error& runtimeError) + { //we don't need the content data for contents that has already been loaded + ASSIMP_LOG_DEBUG_F("Caught exception in FBXMaterial (likely because content was already loaded): ", + runtimeError.what()); } } diff --git a/code/FBXMeshGeometry.cpp b/code/FBX/FBXMeshGeometry.cpp similarity index 86% rename from code/FBXMeshGeometry.cpp rename to code/FBX/FBXMeshGeometry.cpp index aa794d4df..1386e2383 100644 --- a/code/FBXMeshGeometry.cpp +++ b/code/FBX/FBXMeshGeometry.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -62,7 +62,7 @@ using namespace Util; // ------------------------------------------------------------------------------------------------ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Document& doc) - : Object(id, element,name) + : Object(id, element, name) , skin() { const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID(),"Deformer"); @@ -70,18 +70,26 @@ Geometry::Geometry(uint64_t id, const Element& element, const std::string& name, const Skin* const sk = ProcessSimpleConnection(*con, false, "Skin -> Geometry", element); if(sk) { skin = sk; - break; + } + const BlendShape* const bsp = ProcessSimpleConnection(*con, false, "BlendShape -> Geometry", element); + if (bsp) { + blendShapes.push_back(bsp); } } } - // ------------------------------------------------------------------------------------------------ Geometry::~Geometry() { // empty } +// ------------------------------------------------------------------------------------------------ +const std::vector& Geometry::GetBlendShapes() const { + return blendShapes; +} + +// ------------------------------------------------------------------------------------------------ const Skin* Geometry::DeformerSkin() const { return skin; } @@ -107,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 tempFaces; @@ -115,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()); @@ -232,7 +238,6 @@ const std::vector& MeshGeometry::GetVertexColors( unsigned int index const MatIndexArray& MeshGeometry::GetMaterialIndices() const { return m_materials; } - // ------------------------------------------------------------------------------------------------ const unsigned int* MeshGeometry::ToOutputVertexIndex( unsigned int in_index, unsigned int& count ) const { if ( in_index >= m_mapping_counts.size() ) { @@ -561,15 +566,15 @@ void MeshGeometry::ReadVertexDataColors(std::vector& colors_out, cons } // ------------------------------------------------------------------------------------------------ -static const std::string TangentIndexToken = "TangentIndex"; -static const std::string TangentsIndexToken = "TangentsIndex"; +static const char *TangentIndexToken = "TangentIndex"; +static const char *TangentsIndexToken = "TangentsIndex"; void MeshGeometry::ReadVertexDataTangents(std::vector& tangents_out, const Scope& source, const std::string& MappingInformationType, const std::string& ReferenceInformationType) { const char * str = source.Elements().count( "Tangents" ) > 0 ? "Tangents" : "Tangent"; - const char * strIdx = source.Elements().count( "Tangents" ) > 0 ? TangentsIndexToken.c_str() : TangentIndexToken.c_str(); + const char * strIdx = source.Elements().count( "Tangents" ) > 0 ? TangentsIndexToken : TangentIndexToken; ResolveVertexDataArray(tangents_out,source,MappingInformationType,ReferenceInformationType, str, strIdx, @@ -605,8 +610,11 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector& 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 // has a slightly different meaning for materials. @@ -617,16 +625,15 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector& 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(); } - m_materials.assign(m_vertices.size(),materials_out[0]); - } - else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") { - m_materials.resize(face_count); + materials_out.resize(m_vertices.size()); + std::fill(materials_out.begin(), materials_out.end(), materials_out.at(0)); + } else if (MappingInformationType == "ByPolygon" && ReferenceInformationType == "IndexToDirect") { + materials_out.resize(face_count); if(materials_out.size() != face_count) { FBXImporter::LogError(Formatter::format("length of input data unexpected for ByPolygon mapping: ") @@ -634,15 +641,69 @@ void MeshGeometry::ReadVertexDataMaterials(std::vector& 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 (nullptr == sc) { + DOMError("failed to read Geometry object (class: Shape), no data scope found"); + } + const Element& Indexes = GetRequiredElement(*sc, "Indexes", &element); + const Element& Normals = GetRequiredElement(*sc, "Normals", &element); + const Element& Vertices = GetRequiredElement(*sc, "Vertices", &element); + ParseVectorDataArray(m_indices, Indexes); + ParseVectorDataArray(m_vertices, Vertices); + ParseVectorDataArray(m_normals, Normals); +} +// ------------------------------------------------------------------------------------------------ +ShapeGeometry::~ShapeGeometry() { + // empty +} +// ------------------------------------------------------------------------------------------------ +const std::vector& ShapeGeometry::GetVertices() const { + return m_vertices; +} +// ------------------------------------------------------------------------------------------------ +const std::vector& ShapeGeometry::GetNormals() const { + return m_normals; +} +// ------------------------------------------------------------------------------------------------ +const std::vector& ShapeGeometry::GetIndices() const { + return m_indices; +} +// ------------------------------------------------------------------------------------------------ +LineGeometry::LineGeometry(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) { + DOMError("failed to read Geometry object (class: Line), no data scope found"); + } + const Element& Points = GetRequiredElement(*sc, "Points", &element); + const Element& PointsIndex = GetRequiredElement(*sc, "PointsIndex", &element); + ParseVectorDataArray(m_vertices, Points); + ParseVectorDataArray(m_indices, PointsIndex); +} + +// ------------------------------------------------------------------------------------------------ +LineGeometry::~LineGeometry() { + // empty +} +// ------------------------------------------------------------------------------------------------ +const std::vector& LineGeometry::GetVertices() const { + return m_vertices; +} +// ------------------------------------------------------------------------------------------------ +const std::vector& LineGeometry::GetIndices() const { + return m_indices; +} } // !FBX } // !Assimp - #endif diff --git a/code/FBXMeshGeometry.h b/code/FBX/FBXMeshGeometry.h similarity index 80% rename from code/FBXMeshGeometry.h rename to code/FBX/FBXMeshGeometry.h index acd44668a..d6d451217 100644 --- a/code/FBXMeshGeometry.h +++ b/code/FBX/FBXMeshGeometry.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -64,8 +64,13 @@ public: /** Get the Skin attached to this geometry or NULL */ const Skin* DeformerSkin() const; + /** Get the BlendShape attached to this geometry or NULL */ + const std::vector& GetBlendShapes() const; + private: const Skin* skin; + std::vector blendShapes; + }; typedef std::vector MatIndexArray; @@ -125,7 +130,6 @@ public: /** Determine the face to which a particular output vertex index belongs. * This mapping is always unique. */ unsigned int FaceForVertexIndex( unsigned int in_index ) const; - private: void ReadLayer( const Scope& layer ); void ReadLayerElement( const Scope& layerElement ); @@ -174,6 +178,56 @@ private: std::vector m_mappings; }; +/** +* DOM class for FBX geometry of type "Shape" +*/ +class ShapeGeometry : public Geometry +{ +public: + /** The class constructor */ + ShapeGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc); + + /** The class destructor */ + virtual ~ShapeGeometry(); + + /** Get a list of all vertex points, non-unique*/ + const std::vector& GetVertices() const; + + /** Get a list of all vertex normals or an empty array if + * no normals are specified. */ + const std::vector& GetNormals() const; + + /** Return list of vertex indices. */ + const std::vector& GetIndices() const; + +private: + std::vector m_vertices; + std::vector m_normals; + std::vector m_indices; +}; +/** +* DOM class for FBX geometry of type "Line" +*/ +class LineGeometry : public Geometry +{ +public: + /** The class constructor */ + LineGeometry(uint64_t id, const Element& element, const std::string& name, const Document& doc); + + /** The class destructor */ + virtual ~LineGeometry(); + + /** Get a list of all vertex points, non-unique*/ + const std::vector& GetVertices() const; + + /** Return list of vertex indices. */ + const std::vector& GetIndices() const; + +private: + std::vector m_vertices; + std::vector m_indices; +}; + } } diff --git a/code/FBXModel.cpp b/code/FBX/FBXModel.cpp similarity index 99% rename from code/FBXModel.cpp rename to code/FBX/FBXModel.cpp index c16ca841c..589af36ac 100644 --- a/code/FBXModel.cpp +++ b/code/FBX/FBXModel.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/FBXNodeAttribute.cpp b/code/FBX/FBXNodeAttribute.cpp similarity index 99% rename from code/FBXNodeAttribute.cpp rename to code/FBX/FBXNodeAttribute.cpp index 1064151b3..b72e5637e 100644 --- a/code/FBXNodeAttribute.cpp +++ b/code/FBX/FBXNodeAttribute.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/FBXParser.cpp b/code/FBX/FBXParser.cpp similarity index 99% rename from code/FBXParser.cpp rename to code/FBX/FBXParser.cpp index 96d113bd1..4a9346040 100644 --- a/code/FBXParser.cpp +++ b/code/FBX/FBXParser.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -117,7 +117,7 @@ namespace FBX { Element::Element(const Token& key_token, Parser& parser) : key_token(key_token) { - TokenPtr n = NULL; + TokenPtr n = nullptr; do { n = parser.AdvanceToNextToken(); if(!n) { @@ -643,9 +643,9 @@ void ParseVectorDataArray(std::vector& out, const Element& el) if (type == 'd') { const double* d = reinterpret_cast(&buff[0]); for (unsigned int i = 0; i < count3; ++i, d += 3) { - out.push_back(aiVector3D(static_cast(d[0]), - static_cast(d[1]), - static_cast(d[2]))); + out.push_back(aiVector3D(static_cast(d[0]), + static_cast(d[1]), + static_cast(d[2]))); } // for debugging /*for ( size_t i = 0; i < out.size(); i++ ) { @@ -963,7 +963,6 @@ void ParseVectorDataArray(std::vector& out, const Element& el) } } - // ------------------------------------------------------------------------------------------------ // read an array of uints void ParseVectorDataArray(std::vector& out, const Element& el) @@ -1280,7 +1279,6 @@ float ParseTokenAsFloat(const Token& t) return i; } - // ------------------------------------------------------------------------------------------------ // wrapper around ParseTokenAsInt() with ParseError handling int ParseTokenAsInt(const Token& t) @@ -1293,8 +1291,6 @@ int ParseTokenAsInt(const Token& t) return i; } - - // ------------------------------------------------------------------------------------------------ // wrapper around ParseTokenAsInt64() with ParseError handling int64_t ParseTokenAsInt64(const Token& t) diff --git a/code/FBXParser.h b/code/FBX/FBXParser.h similarity index 99% rename from code/FBXParser.h rename to code/FBX/FBXParser.h index 389da3fed..7b0cf7203 100644 --- a/code/FBXParser.h +++ b/code/FBX/FBXParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/FBXProperties.cpp b/code/FBX/FBXProperties.cpp similarity index 99% rename from code/FBXProperties.cpp rename to code/FBX/FBXProperties.cpp index ca89743ca..8d7036b6a 100644 --- a/code/FBXProperties.cpp +++ b/code/FBX/FBXProperties.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/FBXProperties.h b/code/FBX/FBXProperties.h similarity index 99% rename from code/FBXProperties.h rename to code/FBX/FBXProperties.h index 404e04deb..58755542f 100644 --- a/code/FBXProperties.h +++ b/code/FBX/FBXProperties.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/FBXTokenizer.cpp b/code/FBX/FBXTokenizer.cpp similarity index 99% rename from code/FBXTokenizer.cpp rename to code/FBX/FBXTokenizer.cpp index c9dd1697a..252cce355 100644 --- a/code/FBXTokenizer.cpp +++ b/code/FBX/FBXTokenizer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/FBXTokenizer.h b/code/FBX/FBXTokenizer.h similarity index 96% rename from code/FBXTokenizer.h rename to code/FBX/FBXTokenizer.h index e93982617..afa588a47 100644 --- a/code/FBXTokenizer.h +++ b/code/FBX/FBXTokenizer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -93,7 +93,7 @@ public: Token(const char* sbegin, const char* send, TokenType type, unsigned int line, unsigned int column); /** construct a binary token */ - Token(const char* sbegin, const char* send, TokenType type, unsigned int offset); + Token(const char* sbegin, const char* send, TokenType type, size_t offset); ~Token(); @@ -118,14 +118,14 @@ public: return type; } - unsigned int Offset() const { + size_t Offset() const { ai_assert(IsBinary()); return offset; } unsigned int Line() const { ai_assert(!IsBinary()); - return line; + return static_cast(line); } unsigned int Column() const { @@ -147,8 +147,8 @@ private: const TokenType type; union { - const unsigned int line; - unsigned int offset; + size_t line; + size_t offset; }; const unsigned int column; }; @@ -178,7 +178,7 @@ void Tokenize(TokenList& output_tokens, const char* input); * @param input_buffer Binary input buffer to be processed. * @param length Length of input buffer, in bytes. There is no 0-terminal. * @throw DeadlyImportError if something goes wrong */ -void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int length); +void TokenizeBinary(TokenList& output_tokens, const char* input, size_t length); } // ! FBX diff --git a/code/FBX/FBXUtil.cpp b/code/FBX/FBXUtil.cpp new file mode 100644 index 000000000..c10e057c8 --- /dev/null +++ b/code/FBX/FBXUtil.cpp @@ -0,0 +1,243 @@ +/* +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 FBXUtil.cpp + * @brief Implementation of internal FBX utility functions + */ + +#include "FBXUtil.h" +#include "FBXTokenizer.h" + +#include +#include +#include + +#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER + +namespace Assimp { +namespace FBX { +namespace Util { + +// ------------------------------------------------------------------------------------------------ +const char* TokenTypeString(TokenType t) +{ + switch(t) { + case TokenType_OPEN_BRACKET: + return "TOK_OPEN_BRACKET"; + + case TokenType_CLOSE_BRACKET: + return "TOK_CLOSE_BRACKET"; + + case TokenType_DATA: + return "TOK_DATA"; + + case TokenType_COMMA: + return "TOK_COMMA"; + + case TokenType_KEY: + return "TOK_KEY"; + + case TokenType_BINARY_DATA: + return "TOK_BINARY_DATA"; + } + + ai_assert(false); + return ""; +} + + +// ------------------------------------------------------------------------------------------------ +std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset) +{ + return static_cast( (Formatter::format() << prefix << " (offset 0x" << std::hex << offset << ") " << text) ); +} + +// ------------------------------------------------------------------------------------------------ +std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column) +{ + return static_cast( (Formatter::format() << prefix << " (line " << line << " << col " << column << ") " << text) ); +} + +// ------------------------------------------------------------------------------------------------ +std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok) +{ + if(tok->IsBinary()) { + return static_cast( (Formatter::format() << prefix << + " (" << TokenTypeString(tok->Type()) << + ", offset 0x" << std::hex << tok->Offset() << ") " << + text) ); + } + + return static_cast( (Formatter::format() << prefix << + " (" << TokenTypeString(tok->Type()) << + ", line " << tok->Line() << + ", col " << tok->Column() << ") " << + text) ); +} + +// Generated by this formula: T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i; +static const uint8_t base64DecodeTable[128] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 255, 255, 255, + 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, + 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255 +}; + +uint8_t DecodeBase64(char ch) +{ + const auto idx = static_cast(ch); + if (idx > 127) + return 255; + return base64DecodeTable[idx]; +} + +size_t ComputeDecodedSizeBase64(const char* in, size_t inLength) +{ + if (inLength < 2) + { + return 0; + } + const size_t equals = size_t(in[inLength - 1] == '=') + size_t(in[inLength - 2] == '='); + const size_t full_length = (inLength * 3) >> 2; // div by 4 + if (full_length < equals) + { + return 0; + } + return full_length - equals; +} + +size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOutLength) +{ + if (maxOutLength == 0 || inLength < 2) { + return 0; + } + const size_t realLength = inLength - size_t(in[inLength - 1] == '=') - size_t(in[inLength - 2] == '='); + size_t dst_offset = 0; + int val = 0, valb = -8; + for (size_t src_offset = 0; src_offset < realLength; ++src_offset) + { + const uint8_t table_value = Util::DecodeBase64(in[src_offset]); + if (table_value == 255) + { + return 0; + } + val = (val << 6) + table_value; + valb += 6; + if (valb >= 0) + { + out[dst_offset++] = static_cast((val >> valb) & 0xFF); + valb -= 8; + val &= 0xFFF; + } + } + return dst_offset; +} + +static const char to_base64_string[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +char EncodeBase64(char byte) +{ + return to_base64_string[(size_t)byte]; +} + +/** Encodes a block of 4 bytes to base64 encoding +* +* @param bytes Bytes to encode. +* @param out_string String to write encoded values to. +* @param string_pos Position in out_string.*/ +void EncodeByteBlock(const char* bytes, std::string& out_string, size_t string_pos) +{ + char b0 = (bytes[0] & 0xFC) >> 2; + char b1 = (bytes[0] & 0x03) << 4 | ((bytes[1] & 0xF0) >> 4); + char b2 = (bytes[1] & 0x0F) << 2 | ((bytes[2] & 0xC0) >> 6); + char b3 = (bytes[2] & 0x3F); + + out_string[string_pos + 0] = EncodeBase64(b0); + out_string[string_pos + 1] = EncodeBase64(b1); + out_string[string_pos + 2] = EncodeBase64(b2); + out_string[string_pos + 3] = EncodeBase64(b3); +} + +std::string EncodeBase64(const char* data, size_t length) +{ + // calculate extra bytes needed to get a multiple of 3 + size_t extraBytes = 3 - length % 3; + + // number of base64 bytes + size_t encodedBytes = 4 * (length + extraBytes) / 3; + + std::string encoded_string(encodedBytes, '='); + + // read blocks of 3 bytes + for (size_t ib3 = 0; ib3 < length / 3; ib3++) + { + const size_t iByte = ib3 * 3; + const size_t iEncodedByte = ib3 * 4; + const char* currData = &data[iByte]; + + EncodeByteBlock(currData, encoded_string, iEncodedByte); + } + + // if size of data is not a multiple of 3, also encode the final bytes (and add zeros where needed) + if (extraBytes > 0) + { + char finalBytes[4] = { 0,0,0,0 }; + memcpy(&finalBytes[0], &data[length - length % 3], length % 3); + + const size_t iEncodedByte = encodedBytes - 4; + EncodeByteBlock(&finalBytes[0], encoded_string, iEncodedByte); + + // add '=' at the end + for (size_t i = 0; i < 4 * extraBytes / 3; i++) + encoded_string[encodedBytes - i - 1] = '='; + } + return encoded_string; +} + +} // !Util +} // !FBX +} // !Assimp + +#endif diff --git a/code/FBXUtil.h b/code/FBX/FBXUtil.h similarity index 75% rename from code/FBXUtil.h rename to code/FBX/FBXUtil.h index caea7f115..b63441885 100644 --- a/code/FBXUtil.h +++ b/code/FBX/FBXUtil.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -48,6 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXCompileConfig.h" #include "FBXTokenizer.h" +#include namespace Assimp { namespace FBX { @@ -77,7 +78,7 @@ const char* TokenTypeString(TokenType t); * @param line Line index, 1-based * @param column Column index, 1-based * @return A string of the following format: {prefix} (offset 0x{offset}) {text}*/ -std::string AddOffset(const std::string& prefix, const std::string& text, unsigned int offset); +std::string AddOffset(const std::string& prefix, const std::string& text, size_t offset); /** Format log/error messages using a given line location in the source file. @@ -98,6 +99,37 @@ std::string AddLineAndColumn(const std::string& prefix, const std::string& text, * @return A string of the following format: {prefix} ({token-type}, line {line}, col {column}) {text}*/ std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok); +/** Decode a single Base64-encoded character. +* +* @param ch Character to decode (from base64 to binary). +* @return decoded byte value*/ +uint8_t DecodeBase64(char ch); + +/** Compute decoded size of a Base64-encoded string +* +* @param in Characters to decode. +* @param inLength Number of characters to decode. +* @return size of the decoded data (number of bytes)*/ +size_t ComputeDecodedSizeBase64(const char* in, size_t inLength); + +/** Decode a Base64-encoded string +* +* @param in Characters to decode. +* @param inLength Number of characters to decode. +* @param out Pointer where we will store the decoded data. +* @param maxOutLength Size of output buffer. +* @return size of the decoded data (number of bytes)*/ +size_t DecodeBase64(const char* in, size_t inLength, uint8_t* out, size_t maxOutLength); + +char EncodeBase64(char byte); + +/** Encode bytes in base64-encoding +* +* @param data Binary data to encode. +* @param inLength Number of bytes to encode. +* @return base64-encoded string*/ +std::string EncodeBase64(const char* data, size_t length); + } } } diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp deleted file mode 100644 index 0cbe04d8f..000000000 --- a/code/FBXConverter.cpp +++ /dev/null @@ -1,3092 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2018, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXConverter.cpp - * @brief Implementation of the FBX DOM -> aiScene converter - */ - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -#include "FBXConverter.h" -#include "FBXParser.h" -#include "FBXMeshGeometry.h" -#include "FBXDocument.h" -#include "FBXUtil.h" -#include "FBXProperties.h" -#include "FBXImporter.h" -#include - -#include - -#include -#include -#include -#include -#include -#include - -namespace Assimp { -namespace FBX { - -using namespace Util; - -#define MAGIC_NODE_TAG "_$AssimpFbx$" - -#define CONVERT_FBX_TIME(time) static_cast(time) / 46186158000L - -FBXConverter::FBXConverter( aiScene* out, const Document& doc ) -: defaultMaterialIndex() -, out( out ) -, 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(); - ConvertRootNode(); - - if ( doc.Settings().readAllMaterials ) { - // unfortunately this means we have to evaluate all objects - for( const ObjectMap::value_type& v : doc.Objects() ) { - - const Object* ob = v.second->Get(); - if ( !ob ) { - continue; - } - - const Material* mat = dynamic_cast( ob ); - if ( mat ) { - - if ( materials_converted.find( mat ) == materials_converted.end() ) { - ConvertMaterial( *mat, 0 ); - } - } - } - } - - ConvertGlobalSettings(); - TransferDataToScene(); - - // if we didn't read any meshes set the AI_SCENE_FLAGS_INCOMPLETE - // to make sure the scene passes assimp's validation. FBX files - // need not contain geometry (i.e. camera animations, raw armatures). - if ( out->mNumMeshes == 0 ) { - out->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; - } -} - - -FBXConverter::~FBXConverter() { - std::for_each( meshes.begin(), meshes.end(), Util::delete_fun() ); - std::for_each( materials.begin(), materials.end(), Util::delete_fun() ); - std::for_each( animations.begin(), animations.end(), Util::delete_fun() ); - std::for_each( lights.begin(), lights.end(), Util::delete_fun() ); - std::for_each( cameras.begin(), cameras.end(), Util::delete_fun() ); - std::for_each( textures.begin(), textures.end(), Util::delete_fun() ); -} - -void FBXConverter::ConvertRootNode() { - out->mRootNode = new aiNode(); - out->mRootNode->mName.Set( "RootNode" ); - - // root has ID 0 - ConvertNodes( 0L, *out->mRootNode ); -} - -void FBXConverter::ConvertNodes( uint64_t id, aiNode& parent, const aiMatrix4x4& parent_transform ) { - const std::vector& conns = doc.GetConnectionsByDestinationSequenced( id, "Model" ); - - std::vector nodes; - nodes.reserve( conns.size() ); - - std::vector nodes_chain; - std::vector post_nodes_chain; - - try { - for( const Connection* con : conns ) { - - // ignore object-property links - if ( con->PropertyName().length() ) { - continue; - } - - const Object* const object = con->SourceObject(); - if ( nullptr == object ) { - FBXImporter::LogWarn( "failed to convert source object for Model link" ); - continue; - } - - const Model* const model = dynamic_cast( object ); - - if ( nullptr != model ) { - nodes_chain.clear(); - post_nodes_chain.clear(); - - aiMatrix4x4 new_abs_transform = parent_transform; - - // 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. - GenerateTransformationNodeChain( *model, nodes_chain, post_nodes_chain ); - - ai_assert( nodes_chain.size() ); - - std::string original_name = FixNodeName( model->Name() ); - - // check if any of the nodes in the chain has the name the fbx node - // is supposed to have. If there is none, add another node to - // preserve the name - people might have scripts etc. that rely - // on specific node names. - aiNode* name_carrier = NULL; - for( aiNode* prenode : nodes_chain ) { - if ( !strcmp( prenode->mName.C_Str(), original_name.c_str() ) ) { - name_carrier = prenode; - break; - } - } - - if ( !name_carrier ) { - std::string old_original_name = original_name; - GetUniqueName(old_original_name, original_name); - nodes_chain.push_back( new aiNode( original_name ) ); - } else { - original_name = nodes_chain.back()->mName.C_Str(); - } - - //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 ); - - if ( last_parent != &parent ) { - last_parent->mNumChildren = 1; - last_parent->mChildren = new aiNode*[ 1 ]; - last_parent->mChildren[ 0 ] = prenode; - } - - prenode->mParent = last_parent; - last_parent = prenode; - - new_abs_transform *= prenode->mTransformation; - } - - // attach geometry - ConvertModel( *model, *nodes_chain.back(), new_abs_transform ); - - // check if there will be any child nodes - const std::vector& child_conns - = doc.GetConnectionsByDestinationSequenced( model->ID(), "Model" ); - - // if so, link the geometric transform inverse nodes - // before we attach any child nodes - if (child_conns.size()) { - for( aiNode* postnode : post_nodes_chain ) { - ai_assert( postnode ); - - if ( last_parent != &parent ) { - last_parent->mNumChildren = 1; - last_parent->mChildren = new aiNode*[ 1 ]; - last_parent->mChildren[ 0 ] = postnode; - } - - postnode->mParent = last_parent; - last_parent = postnode; - - new_abs_transform *= postnode->mTransformation; - } - } else { - // free the nodes we allocated as we don't need them - Util::delete_fun deleter; - std::for_each( - post_nodes_chain.begin(), - post_nodes_chain.end(), - deleter - ); - } - - // attach sub-nodes (if any) - ConvertNodes( model->ID(), *last_parent, new_abs_transform ); - - if ( doc.Settings().readLights ) { - ConvertLights( *model, original_name ); - } - - if ( doc.Settings().readCameras ) { - ConvertCameras( *model, original_name ); - } - - nodes.push_back( nodes_chain.front() ); - nodes_chain.clear(); - } - } - - if ( nodes.size() ) { - parent.mChildren = new aiNode*[ nodes.size() ](); - parent.mNumChildren = static_cast( nodes.size() ); - - std::swap_ranges( nodes.begin(), nodes.end(), parent.mChildren ); - } - } - catch ( std::exception& ) { - Util::delete_fun deleter; - std::for_each( nodes.begin(), nodes.end(), deleter ); - std::for_each( nodes_chain.begin(), nodes_chain.end(), deleter ); - std::for_each( post_nodes_chain.begin(), post_nodes_chain.end(), deleter ); - } -} - - -void FBXConverter::ConvertLights( const Model& model, const std::string &orig_name ) { - const std::vector& node_attrs = model.GetAttributes(); - for( const NodeAttribute* attr : node_attrs ) { - const Light* const light = dynamic_cast( attr ); - if ( light ) { - ConvertLight( *light, orig_name ); - } - } -} - -void FBXConverter::ConvertCameras( const Model& model, const std::string &orig_name ) { - const std::vector& node_attrs = model.GetAttributes(); - for( const NodeAttribute* attr : node_attrs ) { - const Camera* const cam = dynamic_cast( attr ); - if ( cam ) { - ConvertCamera( *cam, orig_name ); - } - } -} - -void FBXConverter::ConvertLight( const Light& light, const std::string &orig_name ) { - lights.push_back( new aiLight() ); - aiLight* const out_light = lights.back(); - - out_light->mName.Set( orig_name ); - - const float intensity = light.Intensity() / 100.0f; - const aiVector3D& col = light.Color(); - - out_light->mColorDiffuse = aiColor3D( col.x, col.y, col.z ); - out_light->mColorDiffuse.r *= intensity; - out_light->mColorDiffuse.g *= intensity; - out_light->mColorDiffuse.b *= intensity; - - out_light->mColorSpecular = out_light->mColorDiffuse; - - //lights are defined along negative y direction - out_light->mPosition = aiVector3D(0.0f); - out_light->mDirection = aiVector3D(0.0f, -1.0f, 0.0f); - out_light->mUp = aiVector3D(0.0f, 0.0f, -1.0f); - - switch ( light.LightType() ) - { - case Light::Type_Point: - out_light->mType = aiLightSource_POINT; - break; - - case Light::Type_Directional: - out_light->mType = aiLightSource_DIRECTIONAL; - break; - - case Light::Type_Spot: - out_light->mType = aiLightSource_SPOT; - out_light->mAngleOuterCone = AI_DEG_TO_RAD( light.OuterAngle() ); - out_light->mAngleInnerCone = AI_DEG_TO_RAD( light.InnerAngle() ); - break; - - case Light::Type_Area: - FBXImporter::LogWarn( "cannot represent area light, set to UNDEFINED" ); - out_light->mType = aiLightSource_UNDEFINED; - break; - - case Light::Type_Volume: - FBXImporter::LogWarn( "cannot represent volume light, set to UNDEFINED" ); - out_light->mType = aiLightSource_UNDEFINED; - break; - default: - ai_assert( false ); - } - - float decay = light.DecayStart(); - switch ( light.DecayType() ) - { - case Light::Decay_None: - out_light->mAttenuationConstant = decay; - out_light->mAttenuationLinear = 0.0f; - out_light->mAttenuationQuadratic = 0.0f; - break; - case Light::Decay_Linear: - out_light->mAttenuationConstant = 0.0f; - out_light->mAttenuationLinear = 2.0f / decay; - out_light->mAttenuationQuadratic = 0.0f; - break; - case Light::Decay_Quadratic: - out_light->mAttenuationConstant = 0.0f; - out_light->mAttenuationLinear = 0.0f; - out_light->mAttenuationQuadratic = 2.0f / (decay * decay); - break; - case Light::Decay_Cubic: - FBXImporter::LogWarn( "cannot represent cubic attenuation, set to Quadratic" ); - out_light->mAttenuationQuadratic = 1.0f; - break; - default: - ai_assert( false ); - } -} - -void FBXConverter::ConvertCamera( const Camera& cam, const std::string &orig_name ) -{ - cameras.push_back( new aiCamera() ); - aiCamera* const out_camera = cameras.back(); - - out_camera->mName.Set( orig_name ); - - out_camera->mAspect = cam.AspectWidth() / cam.AspectHeight(); - - //cameras are defined along positive x direction - out_camera->mPosition = cam.Position(); - out_camera->mLookAt = ( cam.InterestPosition() - out_camera->mPosition ).Normalize(); - out_camera->mUp = cam.UpVector(); - - out_camera->mHorizontalFOV = AI_DEG_TO_RAD( cam.FieldOfView() ); - out_camera->mClipPlaneNear = cam.NearPlane(); - out_camera->mClipPlaneFar = cam.FarPlane(); -} - -void FBXConverter::GetUniqueName( const std::string &name, std::string &uniqueName ) -{ - int i = 0; - uniqueName = name; - while (mNodeNames.find(uniqueName) != mNodeNames.end()) - { - ++i; - std::stringstream ext; - ext << name << std::setfill('0') << std::setw(3) << i; - uniqueName = ext.str(); - } - mNodeNames.insert(uniqueName); -} - - -const char* FBXConverter::NameTransformationComp( TransformationComp comp ) { - switch ( comp ) { - case TransformationComp_Translation: - return "Translation"; - case TransformationComp_RotationOffset: - return "RotationOffset"; - case TransformationComp_RotationPivot: - return "RotationPivot"; - case TransformationComp_PreRotation: - return "PreRotation"; - case TransformationComp_Rotation: - return "Rotation"; - case TransformationComp_PostRotation: - return "PostRotation"; - case TransformationComp_RotationPivotInverse: - return "RotationPivotInverse"; - case TransformationComp_ScalingOffset: - return "ScalingOffset"; - case TransformationComp_ScalingPivot: - return "ScalingPivot"; - case TransformationComp_Scaling: - return "Scaling"; - case TransformationComp_ScalingPivotInverse: - return "ScalingPivotInverse"; - case TransformationComp_GeometricScaling: - return "GeometricScaling"; - case TransformationComp_GeometricRotation: - return "GeometricRotation"; - case TransformationComp_GeometricTranslation: - return "GeometricTranslation"; - case TransformationComp_GeometricScalingInverse: - return "GeometricScalingInverse"; - case TransformationComp_GeometricRotationInverse: - return "GeometricRotationInverse"; - case TransformationComp_GeometricTranslationInverse: - return "GeometricTranslationInverse"; - case TransformationComp_MAXIMUM: // this is to silence compiler warnings - default: - break; - } - - ai_assert( false ); - - return nullptr; -} - -const char* FBXConverter::NameTransformationCompProperty( TransformationComp comp ) { - switch ( comp ) { - case TransformationComp_Translation: - return "Lcl Translation"; - case TransformationComp_RotationOffset: - return "RotationOffset"; - case TransformationComp_RotationPivot: - return "RotationPivot"; - case TransformationComp_PreRotation: - return "PreRotation"; - case TransformationComp_Rotation: - return "Lcl Rotation"; - case TransformationComp_PostRotation: - return "PostRotation"; - case TransformationComp_RotationPivotInverse: - return "RotationPivotInverse"; - case TransformationComp_ScalingOffset: - return "ScalingOffset"; - case TransformationComp_ScalingPivot: - return "ScalingPivot"; - case TransformationComp_Scaling: - return "Lcl Scaling"; - case TransformationComp_ScalingPivotInverse: - return "ScalingPivotInverse"; - case TransformationComp_GeometricScaling: - return "GeometricScaling"; - case TransformationComp_GeometricRotation: - return "GeometricRotation"; - case TransformationComp_GeometricTranslation: - return "GeometricTranslation"; - case TransformationComp_GeometricScalingInverse: - return "GeometricScalingInverse"; - case TransformationComp_GeometricRotationInverse: - return "GeometricRotationInverse"; - case TransformationComp_GeometricTranslationInverse: - return "GeometricTranslationInverse"; - case TransformationComp_MAXIMUM: // this is to silence compiler warnings - break; - } - - ai_assert( false ); - - return nullptr; -} - -aiVector3D FBXConverter::TransformationCompDefaultValue( TransformationComp comp ) -{ - // XXX a neat way to solve the never-ending special cases for scaling - // would be to do everything in log space! - return comp == TransformationComp_Scaling ? aiVector3D( 1.f, 1.f, 1.f ) : aiVector3D(); -} - -void FBXConverter::GetRotationMatrix( Model::RotOrder mode, const aiVector3D& rotation, aiMatrix4x4& out ) -{ - if ( mode == Model::RotOrder_SphericXYZ ) { - FBXImporter::LogError( "Unsupported RotationMode: SphericXYZ" ); - out = aiMatrix4x4(); - return; - } - - const float angle_epsilon = 1e-6f; - - out = aiMatrix4x4(); - - bool is_id[ 3 ] = { true, true, true }; - - aiMatrix4x4 temp[ 3 ]; - if ( std::fabs( rotation.z ) > angle_epsilon ) { - aiMatrix4x4::RotationZ( AI_DEG_TO_RAD( rotation.z ), temp[ 2 ] ); - is_id[ 2 ] = false; - } - if ( std::fabs( rotation.y ) > angle_epsilon ) { - aiMatrix4x4::RotationY( AI_DEG_TO_RAD( rotation.y ), temp[ 1 ] ); - is_id[ 1 ] = false; - } - if ( std::fabs( rotation.x ) > angle_epsilon ) { - aiMatrix4x4::RotationX( AI_DEG_TO_RAD( rotation.x ), temp[ 0 ] ); - is_id[ 0 ] = false; - } - - int order[ 3 ] = { -1, -1, -1 }; - - // note: rotation order is inverted since we're left multiplying as is usual in assimp - switch ( mode ) - { - case Model::RotOrder_EulerXYZ: - order[ 0 ] = 2; - order[ 1 ] = 1; - order[ 2 ] = 0; - break; - - case Model::RotOrder_EulerXZY: - order[ 0 ] = 1; - order[ 1 ] = 2; - order[ 2 ] = 0; - break; - - case Model::RotOrder_EulerYZX: - order[ 0 ] = 0; - order[ 1 ] = 2; - order[ 2 ] = 1; - break; - - case Model::RotOrder_EulerYXZ: - order[ 0 ] = 2; - order[ 1 ] = 0; - order[ 2 ] = 1; - break; - - case Model::RotOrder_EulerZXY: - order[ 0 ] = 1; - order[ 1 ] = 0; - order[ 2 ] = 2; - break; - - case Model::RotOrder_EulerZYX: - order[ 0 ] = 0; - order[ 1 ] = 1; - order[ 2 ] = 2; - break; - - default: - ai_assert( false ); - break; - } - - ai_assert( order[ 0 ] >= 0 ); - ai_assert( order[ 0 ] <= 2 ); - ai_assert( order[ 1 ] >= 0 ); - ai_assert( order[ 1 ] <= 2 ); - ai_assert( order[ 2 ] >= 0 ); - ai_assert( order[ 2 ] <= 2 ); - - if ( !is_id[ order[ 0 ] ] ) { - out = temp[ order[ 0 ] ]; - } - - if ( !is_id[ order[ 1 ] ] ) { - out = out * temp[ order[ 1 ] ]; - } - - if ( !is_id[ order[ 2 ] ] ) { - out = out * temp[ order[ 2 ] ]; - } -} - -bool FBXConverter::NeedsComplexTransformationChain( const Model& model ) -{ - const PropertyTable& props = model.Props(); - bool ok; - - const float zero_epsilon = 1e-6f; - const aiVector3D all_ones(1.0f, 1.0f, 1.0f); - for ( size_t i = 0; i < TransformationComp_MAXIMUM; ++i ) { - const TransformationComp comp = static_cast< TransformationComp >( i ); - - if ( comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation ) { - continue; - } - - bool scale_compare = ( comp == TransformationComp_GeometricScaling || comp == TransformationComp_Scaling ); - - const aiVector3D& v = PropertyGet( props, NameTransformationCompProperty( comp ), ok ); - if ( ok && scale_compare ) { - if ( (v - all_ones).SquareLength() > zero_epsilon ) { - return true; - } - } else if ( ok ) { - if ( v.SquareLength() > zero_epsilon ) { - return true; - } - } - } - - return false; -} - -std::string FBXConverter::NameTransformationChainNode( const std::string& name, TransformationComp comp ) -{ - return name + std::string( MAGIC_NODE_TAG ) + "_" + NameTransformationComp( comp ); -} - -void FBXConverter::GenerateTransformationNodeChain( const Model& model, std::vector& output_nodes, - std::vector& post_output_nodes ) { - const PropertyTable& props = model.Props(); - const Model::RotOrder rot = model.RotationOrder(); - - bool ok; - - aiMatrix4x4 chain[ TransformationComp_MAXIMUM ]; - std::fill_n( chain, static_cast( TransformationComp_MAXIMUM ), aiMatrix4x4() ); - - // generate transformation matrices for all the different transformation components - const float zero_epsilon = 1e-6f; - const aiVector3D all_ones(1.0f, 1.0f, 1.0f); - bool is_complex = false; - - const aiVector3D& PreRotation = PropertyGet( props, "PreRotation", ok ); - if ( ok && PreRotation.SquareLength() > zero_epsilon ) { - is_complex = true; - - GetRotationMatrix( Model::RotOrder::RotOrder_EulerXYZ, PreRotation, chain[ TransformationComp_PreRotation ] ); - } - - const aiVector3D& PostRotation = PropertyGet( props, "PostRotation", ok ); - if ( ok && PostRotation.SquareLength() > zero_epsilon ) { - is_complex = true; - - GetRotationMatrix( Model::RotOrder::RotOrder_EulerXYZ, PostRotation, chain[ TransformationComp_PostRotation ] ); - } - - const aiVector3D& RotationPivot = PropertyGet( props, "RotationPivot", ok ); - if ( ok && RotationPivot.SquareLength() > zero_epsilon ) { - is_complex = true; - - aiMatrix4x4::Translation( RotationPivot, chain[ TransformationComp_RotationPivot ] ); - aiMatrix4x4::Translation( -RotationPivot, chain[ TransformationComp_RotationPivotInverse ] ); - } - - const aiVector3D& RotationOffset = PropertyGet( props, "RotationOffset", ok ); - if ( ok && RotationOffset.SquareLength() > zero_epsilon ) { - is_complex = true; - - aiMatrix4x4::Translation( RotationOffset, chain[ TransformationComp_RotationOffset ] ); - } - - const aiVector3D& ScalingOffset = PropertyGet( props, "ScalingOffset", ok ); - if ( ok && ScalingOffset.SquareLength() > zero_epsilon ) { - is_complex = true; - - aiMatrix4x4::Translation( ScalingOffset, chain[ TransformationComp_ScalingOffset ] ); - } - - const aiVector3D& ScalingPivot = PropertyGet( props, "ScalingPivot", ok ); - if ( ok && ScalingPivot.SquareLength() > zero_epsilon ) { - is_complex = true; - - aiMatrix4x4::Translation( ScalingPivot, chain[ TransformationComp_ScalingPivot ] ); - aiMatrix4x4::Translation( -ScalingPivot, chain[ TransformationComp_ScalingPivotInverse ] ); - } - - const aiVector3D& Translation = PropertyGet( props, "Lcl Translation", ok ); - if ( ok && Translation.SquareLength() > zero_epsilon ) { - aiMatrix4x4::Translation( Translation, chain[ TransformationComp_Translation ] ); - } - - const aiVector3D& Scaling = PropertyGet( props, "Lcl Scaling", ok ); - if ( ok && (Scaling - all_ones).SquareLength() > zero_epsilon ) { - aiMatrix4x4::Scaling( Scaling, chain[ TransformationComp_Scaling ] ); - } - - const aiVector3D& Rotation = PropertyGet( props, "Lcl Rotation", ok ); - if ( ok && Rotation.SquareLength() > zero_epsilon ) { - GetRotationMatrix( rot, Rotation, chain[ TransformationComp_Rotation ] ); - } - - const aiVector3D& GeometricScaling = PropertyGet( props, "GeometricScaling", ok ); - if ( ok && (GeometricScaling - all_ones).SquareLength() > zero_epsilon ) { - is_complex = true; - aiMatrix4x4::Scaling( GeometricScaling, chain[ TransformationComp_GeometricScaling ] ); - aiVector3D GeometricScalingInverse = GeometricScaling; - bool canscale = true; - for (unsigned int i = 0; i < 3; ++i) { - if ( std::fabs( GeometricScalingInverse[i] ) > zero_epsilon ) { - GeometricScalingInverse[i] = 1.0f / GeometricScaling[i]; - } else { - FBXImporter::LogError( "cannot invert geometric scaling matrix with a 0.0 scale component" ); - canscale = false; - break; - } - } - if (canscale) { - aiMatrix4x4::Scaling( GeometricScalingInverse, chain[ TransformationComp_GeometricScalingInverse ] ); - } - } - - const aiVector3D& GeometricRotation = PropertyGet( props, "GeometricRotation", ok ); - if ( ok && GeometricRotation.SquareLength() > zero_epsilon ) { - is_complex = true; - GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotation ] ); - GetRotationMatrix( rot, GeometricRotation, chain[ TransformationComp_GeometricRotationInverse ] ); - chain[ TransformationComp_GeometricRotationInverse ].Inverse(); - } - - const aiVector3D& GeometricTranslation = PropertyGet( props, "GeometricTranslation", ok ); - if ( ok && GeometricTranslation.SquareLength() > zero_epsilon ) { - is_complex = true; - aiMatrix4x4::Translation( GeometricTranslation, chain[ TransformationComp_GeometricTranslation ] ); - aiMatrix4x4::Translation( -GeometricTranslation, chain[ TransformationComp_GeometricTranslationInverse ] ); - } - - // 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 ); - - std::string name = FixNodeName( model.Name() ); - - // 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 ) { - FBXImporter::LogInfo( "generating full transformation chain for node: " + name ); - - // query the anim_chain_bits dictionary to find out which chain elements - // have associated node animation channels. These can not be dropped - // even if they have identity transform in bind pose. - NodeAnimBitMap::const_iterator it = node_anim_chain_bits.find( name ); - const unsigned int anim_chain_bitmask = ( it == node_anim_chain_bits.end() ? 0 : ( *it ).second ); - - unsigned int bit = 0x1; - for ( size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1 ) { - const TransformationComp comp = static_cast( i ); - - if ( chain[ i ].IsIdentity() && ( anim_chain_bitmask & bit ) == 0 ) { - continue; - } - - if ( comp == TransformationComp_PostRotation ) { - chain[ i ] = chain[ i ].Inverse(); - } - - aiNode* nd = new aiNode(); - nd->mName.Set( NameTransformationChainNode( name, comp ) ); - nd->mTransformation = chain[ i ]; - - // geometric inverses go in a post-node chain - if ( comp == TransformationComp_GeometricScalingInverse || - comp == TransformationComp_GeometricRotationInverse || - comp == TransformationComp_GeometricTranslationInverse - ) { - post_output_nodes.push_back( nd ); - } else { - output_nodes.push_back( nd ); - } - } - - ai_assert( output_nodes.size() ); - return; - } - - // else, we can just multiply the matrices together - aiNode* nd = new aiNode(); - output_nodes.push_back( nd ); - std::string uniqueName; - GetUniqueName( name, uniqueName ); - - nd->mName.Set( uniqueName ); - - for (const auto &transform : chain) { - nd->mTransformation = nd->mTransformation * transform; - } -} - -void FBXConverter::SetupNodeMetadata( const Model& model, aiNode& nd ) -{ - const PropertyTable& props = model.Props(); - DirectPropertyMap unparsedProperties = props.GetUnparsedProperties(); - - // create metadata on node - const std::size_t numStaticMetaData = 2; - aiMetadata* data = aiMetadata::Alloc( static_cast(unparsedProperties.size() + numStaticMetaData) ); - nd.mMetaData = data; - int index = 0; - - // find user defined properties (3ds Max) - data->Set( index++, "UserProperties", aiString( PropertyGet( props, "UDP3DSMAX", "" ) ) ); - // preserve the info that a node was marked as Null node in the original file. - data->Set( index++, "IsNull", model.IsNull() ? true : false ); - - // add unparsed properties to the node's metadata - for( const DirectPropertyMap::value_type& prop : unparsedProperties ) { - // Interpret the property as a concrete type - if ( const TypedProperty* interpreted = prop.second->As >() ) { - data->Set( index++, prop.first, interpreted->Value() ); - } else if ( const TypedProperty* interpreted = prop.second->As >() ) { - data->Set( index++, prop.first, interpreted->Value() ); - } else if ( const TypedProperty* interpreted = prop.second->As >() ) { - data->Set( index++, prop.first, interpreted->Value() ); - } else if ( const TypedProperty* interpreted = prop.second->As >() ) { - data->Set( index++, prop.first, interpreted->Value() ); - } else if ( const TypedProperty* interpreted = prop.second->As >() ) { - data->Set( index++, prop.first, aiString( interpreted->Value() ) ); - } else if ( const TypedProperty* interpreted = prop.second->As >() ) { - data->Set( index++, prop.first, interpreted->Value() ); - } else { - ai_assert( false ); - } - } -} - -void FBXConverter::ConvertModel( const Model& model, aiNode& nd, const aiMatrix4x4& node_global_transform ) -{ - const std::vector& geos = model.GetGeometry(); - - std::vector meshes; - meshes.reserve( geos.size() ); - - for( const Geometry* geo : geos ) { - - const MeshGeometry* const mesh = dynamic_cast< const MeshGeometry* >( geo ); - if ( mesh ) { - const std::vector& indices = ConvertMesh( *mesh, model, node_global_transform, nd); - std::copy( indices.begin(), indices.end(), std::back_inserter( meshes ) ); - } - else { - FBXImporter::LogWarn( "ignoring unrecognized geometry: " + geo->Name() ); - } - } - - if ( meshes.size() ) { - nd.mMeshes = new unsigned int[ meshes.size() ](); - nd.mNumMeshes = static_cast< unsigned int >( meshes.size() ); - - std::swap_ranges( meshes.begin(), meshes.end(), nd.mMeshes ); - } -} - -std::vector FBXConverter::ConvertMesh( const MeshGeometry& mesh, const Model& model, - const aiMatrix4x4& node_global_transform, aiNode& nd) -{ - std::vector temp; - - MeshMap::const_iterator it = meshes_converted.find( &mesh ); - if ( it != meshes_converted.end() ) { - std::copy( ( *it ).second.begin(), ( *it ).second.end(), std::back_inserter( temp ) ); - return temp; - } - - const std::vector& vertices = mesh.GetVertices(); - const std::vector& faces = mesh.GetFaceIndexCounts(); - if ( vertices.empty() || faces.empty() ) { - FBXImporter::LogWarn( "ignoring empty geometry: " + mesh.Name() ); - return temp; - } - - // one material per mesh maps easily to aiMesh. Multiple material - // meshes need to be split. - const MatIndexArray& mindices = mesh.GetMaterialIndices(); - if ( doc.Settings().readMaterials && !mindices.empty() ) { - const MatIndexArray::value_type base = mindices[ 0 ]; - for( MatIndexArray::value_type index : mindices ) { - if ( index != base ) { - return ConvertMeshMultiMaterial( mesh, model, node_global_transform, nd); - } - } - } - - // faster code-path, just copy the data - temp.push_back( ConvertMeshSingleMaterial( mesh, model, node_global_transform, nd) ); - return temp; -} - -aiMesh* FBXConverter::SetupEmptyMesh( const MeshGeometry& mesh, aiNode& nd) -{ - aiMesh* const out_mesh = new aiMesh(); - meshes.push_back( out_mesh ); - meshes_converted[ &mesh ].push_back( static_cast( meshes.size() - 1 ) ); - - // set name - std::string name = mesh.Name(); - if ( name.substr( 0, 10 ) == "Geometry::" ) { - name = name.substr( 10 ); - } - - if ( name.length() ) { - out_mesh->mName.Set( name ); - } - else - { - out_mesh->mName = nd.mName; - } - - return out_mesh; -} - -unsigned int FBXConverter::ConvertMeshSingleMaterial( const MeshGeometry& mesh, const Model& model, - const aiMatrix4x4& node_global_transform, aiNode& nd) -{ - const MatIndexArray& mindices = mesh.GetMaterialIndices(); - aiMesh* const out_mesh = SetupEmptyMesh(mesh, nd); - - const std::vector& vertices = mesh.GetVertices(); - const std::vector& faces = mesh.GetFaceIndexCounts(); - - // copy vertices - out_mesh->mNumVertices = static_cast( vertices.size() ); - out_mesh->mVertices = new aiVector3D[ vertices.size() ]; - std::copy( vertices.begin(), vertices.end(), out_mesh->mVertices ); - - // generate dummy faces - out_mesh->mNumFaces = static_cast( faces.size() ); - aiFace* fac = out_mesh->mFaces = new aiFace[ faces.size() ](); - - unsigned int cursor = 0; - for( unsigned int pcount : faces ) { - aiFace& f = *fac++; - f.mNumIndices = pcount; - f.mIndices = new unsigned int[ pcount ]; - switch ( pcount ) - { - case 1: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 2: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 3: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - break; - } - for ( unsigned int i = 0; i < pcount; ++i ) { - f.mIndices[ i ] = cursor++; - } - } - - // copy normals - const std::vector& normals = mesh.GetNormals(); - if ( normals.size() ) { - ai_assert( normals.size() == vertices.size() ); - - out_mesh->mNormals = new aiVector3D[ vertices.size() ]; - std::copy( normals.begin(), normals.end(), out_mesh->mNormals ); - } - - // copy tangents - assimp requires both tangents and bitangents (binormals) - // to be present, or neither of them. Compute binormals from normals - // and tangents if needed. - const std::vector& tangents = mesh.GetTangents(); - const std::vector* binormals = &mesh.GetBinormals(); - - if ( tangents.size() ) { - std::vector tempBinormals; - if ( !binormals->size() ) { - if ( normals.size() ) { - tempBinormals.resize( normals.size() ); - for ( unsigned int i = 0; i < tangents.size(); ++i ) { - tempBinormals[ i ] = normals[ i ] ^ tangents[ i ]; - } - - binormals = &tempBinormals; - } - else { - binormals = NULL; - } - } - - if ( binormals ) { - ai_assert( tangents.size() == vertices.size() ); - ai_assert( binormals->size() == vertices.size() ); - - out_mesh->mTangents = new aiVector3D[ vertices.size() ]; - std::copy( tangents.begin(), tangents.end(), out_mesh->mTangents ); - - out_mesh->mBitangents = new aiVector3D[ vertices.size() ]; - std::copy( binormals->begin(), binormals->end(), out_mesh->mBitangents ); - } - } - - // copy texture coords - for ( unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i ) { - const std::vector& uvs = mesh.GetTextureCoords( i ); - if ( uvs.empty() ) { - break; - } - - aiVector3D* out_uv = out_mesh->mTextureCoords[ i ] = new aiVector3D[ vertices.size() ]; - for( const aiVector2D& v : uvs ) { - *out_uv++ = aiVector3D( v.x, v.y, 0.0f ); - } - - out_mesh->mNumUVComponents[ i ] = 2; - } - - // copy vertex colors - for ( unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i ) { - const std::vector& colors = mesh.GetVertexColors( i ); - if ( colors.empty() ) { - break; - } - - out_mesh->mColors[ i ] = new aiColor4D[ vertices.size() ]; - std::copy( colors.begin(), colors.end(), out_mesh->mColors[ i ] ); - } - - if ( !doc.Settings().readMaterials || mindices.empty() ) { - FBXImporter::LogError( "no material assigned to mesh, setting default material" ); - out_mesh->mMaterialIndex = GetDefaultMaterial(); - } - else { - 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 ); - } - - return static_cast( meshes.size() - 1 ); -} - -std::vector FBXConverter::ConvertMeshMultiMaterial( const MeshGeometry& mesh, const Model& model, - const aiMatrix4x4& node_global_transform, aiNode& nd) -{ - const MatIndexArray& mindices = mesh.GetMaterialIndices(); - ai_assert( mindices.size() ); - - std::set had; - std::vector indices; - - for( MatIndexArray::value_type index : mindices ) { - if ( had.find( index ) == had.end() ) { - - indices.push_back( ConvertMeshMultiMaterial( mesh, model, index, node_global_transform, nd) ); - had.insert( index ); - } - } - - return indices; -} - -unsigned int FBXConverter::ConvertMeshMultiMaterial( const MeshGeometry& mesh, const Model& model, - MatIndexArray::value_type index, - const aiMatrix4x4& node_global_transform, - aiNode& nd) -{ - aiMesh* const out_mesh = SetupEmptyMesh(mesh, nd); - - const MatIndexArray& mindices = mesh.GetMaterialIndices(); - const std::vector& vertices = mesh.GetVertices(); - const std::vector& faces = mesh.GetFaceIndexCounts(); - - const bool process_weights = doc.Settings().readWeights && mesh.DeformerSkin() != NULL; - - unsigned int count_faces = 0; - unsigned int count_vertices = 0; - - // count faces - std::vector::const_iterator itf = faces.begin(); - for ( MatIndexArray::const_iterator it = mindices.begin(), - end = mindices.end(); it != end; ++it, ++itf ) - { - if ( ( *it ) != index ) { - continue; - } - ++count_faces; - count_vertices += *itf; - } - - ai_assert( count_faces ); - ai_assert( count_vertices ); - - // mapping from output indices to DOM indexing, needed to resolve weights - std::vector reverseMapping; - - if ( process_weights ) { - reverseMapping.resize( count_vertices ); - } - - // allocate output data arrays, but don't fill them yet - out_mesh->mNumVertices = count_vertices; - out_mesh->mVertices = new aiVector3D[ count_vertices ]; - - out_mesh->mNumFaces = count_faces; - aiFace* fac = out_mesh->mFaces = new aiFace[ count_faces ](); - - - // allocate normals - const std::vector& normals = mesh.GetNormals(); - if ( normals.size() ) { - ai_assert( normals.size() == vertices.size() ); - out_mesh->mNormals = new aiVector3D[ vertices.size() ]; - } - - // allocate tangents, binormals. - const std::vector& tangents = mesh.GetTangents(); - const std::vector* binormals = &mesh.GetBinormals(); - std::vector tempBinormals; - - if ( tangents.size() ) { - if ( !binormals->size() ) { - if ( normals.size() ) { - // XXX this computes the binormals for the entire mesh, not only - // the part for which we need them. - tempBinormals.resize( normals.size() ); - for ( unsigned int i = 0; i < tangents.size(); ++i ) { - tempBinormals[ i ] = normals[ i ] ^ tangents[ i ]; - } - - binormals = &tempBinormals; - } - else { - binormals = NULL; - } - } - - if ( binormals ) { - ai_assert( tangents.size() == vertices.size() && binormals->size() == vertices.size() ); - - out_mesh->mTangents = new aiVector3D[ vertices.size() ]; - out_mesh->mBitangents = new aiVector3D[ vertices.size() ]; - } - } - - // allocate texture coords - unsigned int num_uvs = 0; - for ( unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i, ++num_uvs ) { - const std::vector& uvs = mesh.GetTextureCoords( i ); - if ( uvs.empty() ) { - break; - } - - out_mesh->mTextureCoords[ i ] = new aiVector3D[ vertices.size() ]; - out_mesh->mNumUVComponents[ i ] = 2; - } - - // allocate vertex colors - unsigned int num_vcs = 0; - for ( unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS; ++i, ++num_vcs ) { - const std::vector& colors = mesh.GetVertexColors( i ); - if ( colors.empty() ) { - break; - } - - out_mesh->mColors[ i ] = new aiColor4D[ vertices.size() ]; - } - - unsigned int cursor = 0, in_cursor = 0; - - itf = faces.begin(); - for ( MatIndexArray::const_iterator it = mindices.begin(), - end = mindices.end(); it != end; ++it, ++itf ) - { - const unsigned int pcount = *itf; - if ( ( *it ) != index ) { - in_cursor += pcount; - continue; - } - - aiFace& f = *fac++; - - f.mNumIndices = pcount; - f.mIndices = new unsigned int[ pcount ]; - switch ( pcount ) - { - case 1: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_POINT; - break; - case 2: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_LINE; - break; - case 3: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; - break; - default: - out_mesh->mPrimitiveTypes |= aiPrimitiveType_POLYGON; - break; - } - for ( unsigned int i = 0; i < pcount; ++i, ++cursor, ++in_cursor ) { - f.mIndices[ i ] = cursor; - - if ( reverseMapping.size() ) { - reverseMapping[ cursor ] = in_cursor; - } - - out_mesh->mVertices[ cursor ] = vertices[ in_cursor ]; - - if ( out_mesh->mNormals ) { - out_mesh->mNormals[ cursor ] = normals[ in_cursor ]; - } - - if ( out_mesh->mTangents ) { - out_mesh->mTangents[ cursor ] = tangents[ in_cursor ]; - out_mesh->mBitangents[ cursor ] = ( *binormals )[ in_cursor ]; - } - - for ( unsigned int j = 0; j < num_uvs; ++j ) { - const std::vector& uvs = mesh.GetTextureCoords( j ); - out_mesh->mTextureCoords[ j ][ cursor ] = aiVector3D( uvs[ in_cursor ].x, uvs[ in_cursor ].y, 0.0f ); - } - - for ( unsigned int j = 0; j < num_vcs; ++j ) { - const std::vector& cols = mesh.GetVertexColors( j ); - out_mesh->mColors[ j ][ cursor ] = cols[ in_cursor ]; - } - } - } - - ConvertMaterialForMesh( out_mesh, model, mesh, index ); - - if ( process_weights ) { - ConvertWeights( out_mesh, model, mesh, node_global_transform, index, &reverseMapping ); - } - - return static_cast( meshes.size() - 1 ); -} - -void FBXConverter::ConvertWeights( aiMesh* out, const Model& model, const MeshGeometry& geo, - const aiMatrix4x4& node_global_transform , - unsigned int materialIndex, - std::vector* outputVertStartIndices ) -{ - ai_assert( geo.DeformerSkin() ); - - std::vector out_indices; - std::vector index_out_indices; - std::vector count_out_indices; - - const Skin& sk = *geo.DeformerSkin(); - - std::vector bones; - bones.reserve( sk.Clusters().size() ); - - const bool no_mat_check = materialIndex == NO_MATERIAL_SEPARATION; - ai_assert( no_mat_check || outputVertStartIndices ); - - try { - - for( const Cluster* cluster : sk.Clusters() ) { - ai_assert( cluster ); - - const WeightIndexArray& indices = cluster->GetIndices(); - - if ( indices.empty() ) { - continue; - } - - const MatIndexArray& mats = geo.GetMaterialIndices(); - - bool ok = false; - - const size_t no_index_sentinel = std::numeric_limits::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 - // which should never happen - ai_assert( out_idx != NULL ); - - index_out_indices.push_back( no_index_sentinel ); - count_out_indices.push_back( 0 ); - - for ( unsigned int i = 0; i < count; ++i ) { - if ( no_mat_check || static_cast( mats[ geo.FaceForVertexIndex( out_idx[ i ] ) ] ) == materialIndex ) { - - if ( index_out_indices.back() == no_index_sentinel ) { - index_out_indices.back() = out_indices.size(); - - } - - if ( no_mat_check ) { - out_indices.push_back( out_idx[ i ] ); - } - else { - // this extra lookup is in O(logn), so the entire algorithm becomes O(nlogn) - const std::vector::iterator it = std::lower_bound( - outputVertStartIndices->begin(), - outputVertStartIndices->end(), - out_idx[ i ] - ); - - out_indices.push_back( std::distance( outputVertStartIndices->begin(), it ) ); - } - - ++count_out_indices.back(); - ok = true; - } - } - } - - // 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 ) { - ConvertCluster( bones, model, *cluster, out_indices, index_out_indices, - count_out_indices, node_global_transform ); - } - } - } - catch ( std::exception& ) { - std::for_each( bones.begin(), bones.end(), Util::delete_fun() ); - throw; - } - - if ( bones.empty() ) { - return; - } - - out->mBones = new aiBone*[ bones.size() ](); - out->mNumBones = static_cast( bones.size() ); - - std::swap_ranges( bones.begin(), bones.end(), out->mBones ); -} - -void FBXConverter::ConvertCluster( std::vector& bones, const Model& /*model*/, const Cluster& cl, - std::vector& out_indices, - std::vector& index_out_indices, - std::vector& count_out_indices, - const aiMatrix4x4& node_global_transform ) -{ - - aiBone* const bone = new aiBone(); - bones.push_back( bone ); - - bone->mName = FixNodeName( cl.TargetNode()->Name() ); - - bone->mOffsetMatrix = cl.TransformLink(); - bone->mOffsetMatrix.Inverse(); - - bone->mOffsetMatrix = bone->mOffsetMatrix * node_global_transform; - - bone->mNumWeights = static_cast( out_indices.size() ); - aiVertexWeight* cursor = bone->mWeights = new aiVertexWeight[ out_indices.size() ]; - - const size_t no_index_sentinel = std::numeric_limits::max(); - const WeightArray& weights = cl.GetWeights(); - - const size_t c = index_out_indices.size(); - for ( size_t i = 0; i < c; ++i ) { - const size_t index_index = index_out_indices[ i ]; - - if ( index_index == no_index_sentinel ) { - continue; - } - - const size_t cc = count_out_indices[ i ]; - for ( size_t j = 0; j < cc; ++j ) { - aiVertexWeight& out_weight = *cursor++; - - out_weight.mVertexId = static_cast( out_indices[ index_index + j ] ); - out_weight.mWeight = weights[ i ]; - } - } -} - -void FBXConverter::ConvertMaterialForMesh( aiMesh* out, const Model& model, const MeshGeometry& geo, - MatIndexArray::value_type materialIndex ) -{ - // locate source materials for this mesh - const std::vector& mats = model.GetMaterials(); - if ( static_cast( materialIndex ) >= mats.size() || materialIndex < 0 ) { - FBXImporter::LogError( "material index out of bounds, setting default material" ); - out->mMaterialIndex = GetDefaultMaterial(); - return; - } - - const Material* const mat = mats[ materialIndex ]; - MaterialMap::const_iterator it = materials_converted.find( mat ); - if ( it != materials_converted.end() ) { - out->mMaterialIndex = ( *it ).second; - return; - } - - out->mMaterialIndex = ConvertMaterial( *mat, &geo ); - materials_converted[ mat ] = out->mMaterialIndex; -} - -unsigned int FBXConverter::GetDefaultMaterial() -{ - if ( defaultMaterialIndex ) { - return defaultMaterialIndex - 1; - } - - aiMaterial* out_mat = new aiMaterial(); - materials.push_back( out_mat ); - - const aiColor3D diffuse = aiColor3D( 0.8f, 0.8f, 0.8f ); - out_mat->AddProperty( &diffuse, 1, AI_MATKEY_COLOR_DIFFUSE ); - - aiString s; - s.Set( AI_DEFAULT_MATERIAL_NAME ); - - out_mat->AddProperty( &s, AI_MATKEY_NAME ); - - defaultMaterialIndex = static_cast< unsigned int >( materials.size() ); - return defaultMaterialIndex - 1; -} - - -unsigned int FBXConverter::ConvertMaterial( const Material& material, const MeshGeometry* const mesh ) -{ - const PropertyTable& props = material.Props(); - - // generate empty output material - aiMaterial* out_mat = new aiMaterial(); - materials_converted[ &material ] = static_cast( materials.size() ); - - materials.push_back( out_mat ); - - aiString str; - - // strip Material:: prefix - std::string name = material.Name(); - if ( name.substr( 0, 10 ) == "Material::" ) { - name = name.substr( 10 ); - } - - // set material name if not empty - this could happen - // and there should be no key for it in this case. - if ( name.length() ) { - str.Set( name ); - out_mat->AddProperty( &str, AI_MATKEY_NAME ); - } - - // shading stuff and colors - SetShadingPropertiesCommon( out_mat, props ); - - // texture assignments - SetTextureProperties( out_mat, material.Textures(), mesh ); - SetTextureProperties( out_mat, material.LayeredTextures(), mesh ); - - return static_cast( materials.size() - 1 ); -} - -unsigned int FBXConverter::ConvertVideo( const Video& video ) -{ - // generate empty output texture - aiTexture* out_tex = new aiTexture(); - textures.push_back( out_tex ); - - // assuming the texture is compressed - out_tex->mWidth = static_cast( video.ContentLength() ); // total data size - out_tex->mHeight = 0; // fixed to 0 - - // steal the data from the Video to avoid an additional copy - out_tex->pcData = reinterpret_cast( const_cast( video ).RelinquishContent() ); - - // try to extract a hint from the file extension - const std::string& filename = video.FileName().empty() ? video.RelativeFilename() : video.FileName(); - std::string ext = BaseImporter::GetExtension( filename ); - - if ( ext == "jpeg" ) { - ext = "jpg"; - } - - if ( ext.size() <= 3 ) { - memcpy( out_tex->achFormatHint, ext.c_str(), ext.size() ); - } - - out_tex->mFilename.Set(video.FileName().c_str()); - - return static_cast( textures.size() - 1 ); -} - -aiString FBXConverter::GetTexturePath(const Texture* tex) -{ - aiString path; - path.Set(tex->RelativeFilename()); - - const Video* media = tex->Media(); - if (media != nullptr) { - bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found) - unsigned int index; - - VideoMap::const_iterator it = textures_converted.find(media); - if (it != textures_converted.end()) { - index = (*it).second; - textureReady = true; - } - else { - if (media->ContentLength() > 0) { - index = ConvertVideo(*media); - textures_converted[media] = index; - textureReady = true; - } - } - - // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready - if (doc.Settings().useLegacyEmbeddedTextureNaming) { - if (textureReady) { - // TODO: check the possibility of using the flag "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING" - // In FBX files textures are now stored internally by Assimp with their filename included - // Now Assimp can lookup through the loaded textures after all data is processed - // We need to load all textures before referencing them, as FBX file format order may reference a texture before loading it - // This may occur on this case too, it has to be studied - path.data[0] = '*'; - path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index); - } - } - } - - return path; -} - -void FBXConverter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap& textures, - const std::string& propName, - aiTextureType target, const MeshGeometry* const mesh ) -{ - TextureMap::const_iterator it = textures.find( propName ); - if ( it == textures.end() ) { - return; - } - - const Texture* const tex = ( *it ).second; - if ( tex != 0 ) - { - aiString path = GetTexturePath(tex); - out_mat->AddProperty( &path, _AI_MATKEY_TEXTURE_BASE, target, 0 ); - - aiUVTransform uvTrafo; - // XXX handle all kinds of UV transformations - uvTrafo.mScaling = tex->UVScaling(); - uvTrafo.mTranslation = tex->UVTranslation(); - out_mat->AddProperty( &uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, 0 ); - - const PropertyTable& props = tex->Props(); - - int uvIndex = 0; - - bool ok; - const std::string& uvSet = PropertyGet( props, "UVSet", ok ); - if ( ok ) { - // "default" is the name which usually appears in the FbxFileTexture template - if ( uvSet != "default" && uvSet.length() ) { - // this is a bit awkward - we need to find a mesh that uses this - // material and scan its UV channels for the given UV name because - // assimp references UV channels by index, not by name. - - // XXX: the case that UV channels may appear in different orders - // in meshes is unhandled. A possible solution would be to sort - // the UV channels alphabetically, but this would have the side - // effect that the primary (first) UV channel would sometimes - // be moved, causing trouble when users read only the first - // UV channel and ignore UV channel assignments altogether. - - const unsigned int matIndex = static_cast( std::distance( materials.begin(), - std::find( materials.begin(), materials.end(), out_mat ) - ) ); - - - uvIndex = -1; - if ( !mesh ) - { - for( const MeshMap::value_type& v : meshes_converted ) { - const MeshGeometry* const mesh = dynamic_cast ( v.first ); - if ( !mesh ) { - continue; - } - - const MatIndexArray& mats = mesh->GetMaterialIndices(); - if ( std::find( mats.begin(), mats.end(), matIndex ) == mats.end() ) { - continue; - } - - int index = -1; - for ( unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i ) { - if ( mesh->GetTextureCoords( i ).empty() ) { - break; - } - const std::string& name = mesh->GetTextureCoordChannelName( i ); - if ( name == uvSet ) { - index = static_cast( i ); - break; - } - } - if ( index == -1 ) { - FBXImporter::LogWarn( "did not find UV channel named " + uvSet + " in a mesh using this material" ); - continue; - } - - if ( uvIndex == -1 ) { - uvIndex = index; - } - else { - FBXImporter::LogWarn( "the UV channel named " + uvSet + - " appears at different positions in meshes, results will be wrong" ); - } - } - } - else - { - int index = -1; - for ( unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i ) { - if ( mesh->GetTextureCoords( i ).empty() ) { - break; - } - const std::string& name = mesh->GetTextureCoordChannelName( i ); - if ( name == uvSet ) { - index = static_cast( i ); - break; - } - } - if ( index == -1 ) { - FBXImporter::LogWarn( "did not find UV channel named " + uvSet + " in a mesh using this material" ); - } - - if ( uvIndex == -1 ) { - uvIndex = index; - } - } - - if ( uvIndex == -1 ) { - FBXImporter::LogWarn( "failed to resolve UV channel " + uvSet + ", using first UV channel" ); - uvIndex = 0; - } - } - } - - out_mat->AddProperty( &uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, 0 ); - } -} - -void FBXConverter::TrySetTextureProperties( aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, - const std::string& propName, - aiTextureType target, const MeshGeometry* const mesh ) { - LayeredTextureMap::const_iterator it = layeredTextures.find( propName ); - if ( it == layeredTextures.end() ) { - return; - } - - int texCount = (*it).second->textureCount(); - - // Set the blend mode for layered textures - int blendmode= (*it).second->GetBlendMode(); - out_mat->AddProperty(&blendmode,1,_AI_MATKEY_TEXOP_BASE,target,0); - - for(int texIndex = 0; texIndex < texCount; texIndex++){ - - const Texture* const tex = ( *it ).second->getTexture(texIndex); - - aiString path = GetTexturePath(tex); - out_mat->AddProperty( &path, _AI_MATKEY_TEXTURE_BASE, target, texIndex ); - - aiUVTransform uvTrafo; - // XXX handle all kinds of UV transformations - uvTrafo.mScaling = tex->UVScaling(); - uvTrafo.mTranslation = tex->UVTranslation(); - out_mat->AddProperty( &uvTrafo, 1, _AI_MATKEY_UVTRANSFORM_BASE, target, texIndex ); - - const PropertyTable& props = tex->Props(); - - int uvIndex = 0; - - bool ok; - const std::string& uvSet = PropertyGet( props, "UVSet", ok ); - if ( ok ) { - // "default" is the name which usually appears in the FbxFileTexture template - if ( uvSet != "default" && uvSet.length() ) { - // this is a bit awkward - we need to find a mesh that uses this - // material and scan its UV channels for the given UV name because - // assimp references UV channels by index, not by name. - - // XXX: the case that UV channels may appear in different orders - // in meshes is unhandled. A possible solution would be to sort - // the UV channels alphabetically, but this would have the side - // effect that the primary (first) UV channel would sometimes - // be moved, causing trouble when users read only the first - // UV channel and ignore UV channel assignments altogether. - - const unsigned int matIndex = static_cast( std::distance( materials.begin(), - std::find( materials.begin(), materials.end(), out_mat ) - ) ); - - uvIndex = -1; - if ( !mesh ) - { - for( const MeshMap::value_type& v : meshes_converted ) { - const MeshGeometry* const mesh = dynamic_cast ( v.first ); - if ( !mesh ) { - continue; - } - - const MatIndexArray& mats = mesh->GetMaterialIndices(); - if ( std::find( mats.begin(), mats.end(), matIndex ) == mats.end() ) { - continue; - } - - int index = -1; - for ( unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i ) { - if ( mesh->GetTextureCoords( i ).empty() ) { - break; - } - const std::string& name = mesh->GetTextureCoordChannelName( i ); - if ( name == uvSet ) { - index = static_cast( i ); - break; - } - } - if ( index == -1 ) { - FBXImporter::LogWarn( "did not find UV channel named " + uvSet + " in a mesh using this material" ); - continue; - } - - if ( uvIndex == -1 ) { - uvIndex = index; - } - else { - FBXImporter::LogWarn( "the UV channel named " + uvSet + - " appears at different positions in meshes, results will be wrong" ); - } - } - } - else - { - int index = -1; - for ( unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i ) { - if ( mesh->GetTextureCoords( i ).empty() ) { - break; - } - const std::string& name = mesh->GetTextureCoordChannelName( i ); - if ( name == uvSet ) { - index = static_cast( i ); - break; - } - } - if ( index == -1 ) { - FBXImporter::LogWarn( "did not find UV channel named " + uvSet + " in a mesh using this material" ); - } - - if ( uvIndex == -1 ) { - uvIndex = index; - } - } - - if ( uvIndex == -1 ) { - FBXImporter::LogWarn( "failed to resolve UV channel " + uvSet + ", using first UV channel" ); - uvIndex = 0; - } - } - } - - out_mat->AddProperty( &uvIndex, 1, _AI_MATKEY_UVWSRC_BASE, target, texIndex ); - } -} - -void FBXConverter::SetTextureProperties( aiMaterial* out_mat, const TextureMap& textures, const MeshGeometry* const mesh ) -{ - TrySetTextureProperties( out_mat, textures, "DiffuseColor", aiTextureType_DIFFUSE, mesh ); - TrySetTextureProperties( out_mat, textures, "AmbientColor", aiTextureType_AMBIENT, mesh ); - TrySetTextureProperties( out_mat, textures, "EmissiveColor", aiTextureType_EMISSIVE, mesh ); - TrySetTextureProperties( out_mat, textures, "SpecularColor", aiTextureType_SPECULAR, mesh ); - TrySetTextureProperties( out_mat, textures, "SpecularFactor", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties( out_mat, textures, "TransparentColor", aiTextureType_OPACITY, mesh ); - TrySetTextureProperties( out_mat, textures, "ReflectionColor", aiTextureType_REFLECTION, mesh ); - TrySetTextureProperties( out_mat, textures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh ); - TrySetTextureProperties( out_mat, textures, "NormalMap", aiTextureType_NORMALS, mesh ); - TrySetTextureProperties( out_mat, textures, "Bump", aiTextureType_HEIGHT, mesh ); - TrySetTextureProperties( out_mat, textures, "ShininessExponent", aiTextureType_SHININESS, mesh ); -} - -void FBXConverter::SetTextureProperties( aiMaterial* out_mat, const LayeredTextureMap& layeredTextures, const MeshGeometry* const mesh ) -{ - TrySetTextureProperties( out_mat, layeredTextures, "DiffuseColor", aiTextureType_DIFFUSE, mesh ); - TrySetTextureProperties( out_mat, layeredTextures, "AmbientColor", aiTextureType_AMBIENT, mesh ); - TrySetTextureProperties( out_mat, layeredTextures, "EmissiveColor", aiTextureType_EMISSIVE, mesh ); - TrySetTextureProperties( out_mat, layeredTextures, "SpecularColor", aiTextureType_SPECULAR, mesh ); - TrySetTextureProperties( out_mat, layeredTextures, "SpecularFactor", aiTextureType_SPECULAR, mesh); - TrySetTextureProperties( out_mat, layeredTextures, "TransparentColor", aiTextureType_OPACITY, mesh ); - TrySetTextureProperties( out_mat, layeredTextures, "ReflectionColor", aiTextureType_REFLECTION, mesh ); - TrySetTextureProperties( out_mat, layeredTextures, "DisplacementColor", aiTextureType_DISPLACEMENT, mesh ); - TrySetTextureProperties( out_mat, layeredTextures, "NormalMap", aiTextureType_NORMALS, mesh ); - TrySetTextureProperties( out_mat, layeredTextures, "Bump", aiTextureType_HEIGHT, mesh ); - TrySetTextureProperties( out_mat, layeredTextures, "ShininessExponent", aiTextureType_SHININESS, mesh ); -} - -aiColor3D FBXConverter::GetColorPropertyFactored( const PropertyTable& props, const std::string& colorName, - const std::string& factorName, bool& result, bool useTemplate ) -{ - result = true; - - bool ok; - aiVector3D BaseColor = PropertyGet( props, colorName, ok, useTemplate ); - if ( ! ok ) { - result = false; - return aiColor3D( 0.0f, 0.0f, 0.0f ); - } - - // if no factor name, return the colour as is - if ( factorName.empty() ) { - return aiColor3D( BaseColor.x, BaseColor.y, BaseColor.z ); - } - - // otherwise it should be multiplied by the factor, if found. - float factor = PropertyGet( props, factorName, ok, useTemplate ); - if ( ok ) { - BaseColor *= factor; - } - return aiColor3D( BaseColor.x, BaseColor.y, BaseColor.z ); -} - -aiColor3D FBXConverter::GetColorPropertyFromMaterial( const PropertyTable& props, const std::string& baseName, - bool& result ) -{ - return GetColorPropertyFactored( props, baseName + "Color", baseName + "Factor", result, true ); -} - -aiColor3D FBXConverter::GetColorProperty( const PropertyTable& props, const std::string& colorName, - bool& result, bool useTemplate ) -{ - result = true; - bool ok; - const aiVector3D& ColorVec = PropertyGet( props, colorName, ok, useTemplate ); - if ( ! ok ) { - result = false; - return aiColor3D( 0.0f, 0.0f, 0.0f ); - } - return aiColor3D( ColorVec.x, ColorVec.y, ColorVec.z ); -} - -void FBXConverter::SetShadingPropertiesCommon( aiMaterial* out_mat, const PropertyTable& props ) -{ - // Set shading properties. - // Modern FBX Files have two separate systems for defining these, - // with only the more comprehensive one described in the property template. - // Likely the other values are a legacy system, - // which is still always exported by the official FBX SDK. - // - // Blender's FBX import and export mostly ignore this legacy system, - // and as we only support recent versions of FBX anyway, we can do the same. - bool ok; - - const aiColor3D& Diffuse = GetColorPropertyFromMaterial( props, "Diffuse", ok ); - if ( ok ) { - out_mat->AddProperty( &Diffuse, 1, AI_MATKEY_COLOR_DIFFUSE ); - } - - const aiColor3D& Emissive = GetColorPropertyFromMaterial( props, "Emissive", ok ); - if ( ok ) { - out_mat->AddProperty( &Emissive, 1, AI_MATKEY_COLOR_EMISSIVE ); - } - - const aiColor3D& Ambient = GetColorPropertyFromMaterial( props, "Ambient", ok ); - if ( ok ) { - out_mat->AddProperty( &Ambient, 1, AI_MATKEY_COLOR_AMBIENT ); - } - - // we store specular factor as SHININESS_STRENGTH, so just get the color - const aiColor3D& Specular = GetColorProperty( props, "SpecularColor", ok, true ); - if ( ok ) { - out_mat->AddProperty( &Specular, 1, AI_MATKEY_COLOR_SPECULAR ); - } - - // and also try to get SHININESS_STRENGTH - const float SpecularFactor = PropertyGet( props, "SpecularFactor", ok, true ); - if ( ok ) { - out_mat->AddProperty( &SpecularFactor, 1, AI_MATKEY_SHININESS_STRENGTH ); - } - - // and the specular exponent - const float ShininessExponent = PropertyGet( props, "ShininessExponent", ok ); - if ( ok ) { - out_mat->AddProperty( &ShininessExponent, 1, AI_MATKEY_SHININESS ); - } - - // TransparentColor / TransparencyFactor... gee thanks FBX :rolleyes: - const aiColor3D& Transparent = GetColorPropertyFactored( props, "TransparentColor", "TransparencyFactor", ok ); - float CalculatedOpacity = 1.0f; - if ( ok ) { - out_mat->AddProperty( &Transparent, 1, AI_MATKEY_COLOR_TRANSPARENT ); - // as calculated by FBX SDK 2017: - CalculatedOpacity = 1.0f - ((Transparent.r + Transparent.g + Transparent.b) / 3.0f); - } - - // use of TransparencyFactor is inconsistent. - // Maya always stores it as 1.0, - // so we can't use it to set AI_MATKEY_OPACITY. - // Blender is more sensible and stores it as the alpha value. - // However both the FBX SDK and Blender always write an additional - // legacy "Opacity" field, so we can try to use that. - // - // If we can't find it, - // we can fall back to the value which the FBX SDK calculates - // from transparency colour (RGB) and factor (F) as - // 1.0 - F*((R+G+B)/3). - // - // There's no consistent way to interpret this opacity value, - // so it's up to clients to do the correct thing. - const float Opacity = PropertyGet( props, "Opacity", ok ); - if ( ok ) { - out_mat->AddProperty( &Opacity, 1, AI_MATKEY_OPACITY ); - } - else if ( CalculatedOpacity != 1.0 ) { - out_mat->AddProperty( &CalculatedOpacity, 1, AI_MATKEY_OPACITY ); - } - - // reflection color and factor are stored separately - const aiColor3D& Reflection = GetColorProperty( props, "ReflectionColor", ok, true ); - if ( ok ) { - out_mat->AddProperty( &Reflection, 1, AI_MATKEY_COLOR_REFLECTIVE ); - } - - float ReflectionFactor = PropertyGet( props, "ReflectionFactor", ok, true ); - if ( ok ) { - out_mat->AddProperty( &ReflectionFactor, 1, AI_MATKEY_REFLECTIVITY ); - } - - const float BumpFactor = PropertyGet(props, "BumpFactor", ok); - if (ok) { - out_mat->AddProperty(&BumpFactor, 1, AI_MATKEY_BUMPSCALING); - } - - const float DispFactor = PropertyGet(props, "DisplacementFactor", ok); - if (ok) { - out_mat->AddProperty(&DispFactor, 1, "$mat.displacementscaling", 0, 0); - } -} - - -double FBXConverter::FrameRateToDouble( FileGlobalSettings::FrameRate fp, double customFPSVal ) { - switch ( fp ) { - case FileGlobalSettings::FrameRate_DEFAULT: - return 1.0; - - case FileGlobalSettings::FrameRate_120: - return 120.0; - - case FileGlobalSettings::FrameRate_100: - return 100.0; - - case FileGlobalSettings::FrameRate_60: - return 60.0; - - case FileGlobalSettings::FrameRate_50: - return 50.0; - - case FileGlobalSettings::FrameRate_48: - return 48.0; - - case FileGlobalSettings::FrameRate_30: - case FileGlobalSettings::FrameRate_30_DROP: - return 30.0; - - case FileGlobalSettings::FrameRate_NTSC_DROP_FRAME: - case FileGlobalSettings::FrameRate_NTSC_FULL_FRAME: - return 29.9700262; - - case FileGlobalSettings::FrameRate_PAL: - return 25.0; - - case FileGlobalSettings::FrameRate_CINEMA: - return 24.0; - - case FileGlobalSettings::FrameRate_1000: - return 1000.0; - - case FileGlobalSettings::FrameRate_CINEMA_ND: - return 23.976; - - case FileGlobalSettings::FrameRate_CUSTOM: - return customFPSVal; - - case FileGlobalSettings::FrameRate_MAX: // this is to silence compiler warnings - break; - } - - ai_assert( false ); - - return -1.0f; -} - - -void FBXConverter::ConvertAnimations() -{ - // first of all determine framerate - const FileGlobalSettings::FrameRate fps = doc.GlobalSettings().TimeMode(); - const float custom = doc.GlobalSettings().CustomFrameRate(); - anim_fps = FrameRateToDouble( fps, custom ); - - const std::vector& animations = doc.AnimationStacks(); - for( const AnimationStack* stack : animations ) { - ConvertAnimationStack( *stack ); - } -} - -std::string FBXConverter::FixNodeName( const std::string& name ) { - // strip Model:: prefix, avoiding ambiguities (i.e. don't strip if - // this causes ambiguities, well possible between empty identifiers, - // such as "Model::" and ""). Make sure the behaviour is consistent - // across multiple calls to FixNodeName(). - if ( name.substr( 0, 7 ) == "Model::" ) { - std::string temp = name.substr( 7 ); - return temp; - } - - return name; -} - -void FBXConverter::ConvertAnimationStack( const AnimationStack& st ) -{ - const AnimationLayerList& layers = st.Layers(); - if ( layers.empty() ) { - return; - } - - aiAnimation* const anim = new aiAnimation(); - animations.push_back( anim ); - - // strip AnimationStack:: prefix - std::string name = st.Name(); - if ( name.substr( 0, 16 ) == "AnimationStack::" ) { - name = name.substr( 16 ); - } - else if ( name.substr( 0, 11 ) == "AnimStack::" ) { - name = name.substr( 11 ); - } - - anim->mName.Set( name ); - - // need to find all nodes for which we need to generate node animations - - // it may happen that we need to merge multiple layers, though. - NodeMap node_map; - - // reverse mapping from curves to layers, much faster than querying - // the FBX DOM for it. - LayerMap layer_map; - - const char* prop_whitelist[] = { - "Lcl Scaling", - "Lcl Rotation", - "Lcl Translation" - }; - - for( const AnimationLayer* layer : layers ) { - ai_assert( layer ); - - const AnimationCurveNodeList& nodes = layer->Nodes( prop_whitelist, 3 ); - for( const AnimationCurveNode* node : nodes ) { - ai_assert( node ); - - const Model* const model = dynamic_cast( node->Target() ); - // this can happen - it could also be a NodeAttribute (i.e. for camera animations) - if ( !model ) { - continue; - } - - const std::string& name = FixNodeName( model->Name() ); - node_map[ name ].push_back( node ); - - layer_map[ node ] = layer; - } - } - - // generate node animations - std::vector node_anims; - - double min_time = 1e10; - double max_time = -1e10; - - int64_t start_time = st.LocalStart(); - int64_t stop_time = st.LocalStop(); - bool has_local_startstop = start_time != 0 || stop_time != 0; - if ( !has_local_startstop ) { - // no time range given, so accept every keyframe and use the actual min/max time - // the numbers are INT64_MIN/MAX, the 20000 is for safety because GenerateNodeAnimations uses an epsilon of 10000 - start_time = -9223372036854775807ll + 20000; - stop_time = 9223372036854775807ll - 20000; - } - - try { - for( const NodeMap::value_type& kv : node_map ) { - GenerateNodeAnimations( node_anims, - kv.first, - kv.second, - layer_map, - start_time, stop_time, - max_time, - min_time ); - } - } - catch ( std::exception& ) { - std::for_each( node_anims.begin(), node_anims.end(), Util::delete_fun() ); - throw; - } - - if ( node_anims.size() ) { - anim->mChannels = new aiNodeAnim*[ node_anims.size() ](); - anim->mNumChannels = static_cast( node_anims.size() ); - - std::swap_ranges( node_anims.begin(), node_anims.end(), anim->mChannels ); - } - else { - // empty animations would fail validation, so drop them - delete anim; - animations.pop_back(); - FBXImporter::LogInfo( "ignoring empty AnimationStack (using IK?): " + name ); - return; - } - - double start_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(start_time) * anim_fps) : min_time; - double stop_time_fps = has_local_startstop ? (CONVERT_FBX_TIME(stop_time) * anim_fps) : max_time; - - // adjust relative timing for animation - for ( unsigned int c = 0; c < anim->mNumChannels; c++ ) { - aiNodeAnim* channel = anim->mChannels[ c ]; - for ( uint32_t i = 0; i < channel->mNumPositionKeys; i++ ) - channel->mPositionKeys[ i ].mTime -= start_time_fps; - for ( uint32_t i = 0; i < channel->mNumRotationKeys; i++ ) - channel->mRotationKeys[ i ].mTime -= start_time_fps; - for ( uint32_t i = 0; i < channel->mNumScalingKeys; i++ ) - channel->mScalingKeys[ i ].mTime -= start_time_fps; - } - - // for some mysterious reason, mDuration is simply the maximum key -- the - // validator always assumes animations to start at zero. - anim->mDuration = stop_time_fps - start_time_fps; - anim->mTicksPerSecond = anim_fps; -} - -#ifdef ASSIMP_BUILD_DEBUG -// ------------------------------------------------------------------------------------------------ -// sanity check whether the input is ok -static void validateAnimCurveNodes( const std::vector& curves, - bool strictMode ) { - const Object* target( NULL ); - for( const AnimationCurveNode* node : curves ) { - if ( !target ) { - target = node->Target(); - } - if ( node->Target() != target ) { - FBXImporter::LogWarn( "Node target is nullptr type." ); - } - if ( strictMode ) { - ai_assert( node->Target() == target ); - } - } -} -#endif // ASSIMP_BUILD_DEBUG - -// ------------------------------------------------------------------------------------------------ -void FBXConverter::GenerateNodeAnimations( std::vector& node_anims, - const std::string& fixed_name, - const std::vector& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time ) -{ - - NodeMap node_property_map; - ai_assert( curves.size() ); - -#ifdef ASSIMP_BUILD_DEBUG - validateAnimCurveNodes( curves, doc.Settings().strictMode ); -#endif - const AnimationCurveNode* curve_node = NULL; - for( const AnimationCurveNode* node : curves ) { - ai_assert( node ); - - if ( node->TargetProperty().empty() ) { - FBXImporter::LogWarn( "target property for animation curve not set: " + node->Name() ); - continue; - } - - curve_node = node; - if ( node->Curves().empty() ) { - FBXImporter::LogWarn( "no animation curves assigned to AnimationCurveNode: " + node->Name() ); - continue; - } - - node_property_map[ node->TargetProperty() ].push_back( node ); - } - - ai_assert( curve_node ); - ai_assert( curve_node->TargetAsModel() ); - - const Model& target = *curve_node->TargetAsModel(); - - // check for all possible transformation components - NodeMap::const_iterator chain[ TransformationComp_MAXIMUM ]; - - bool has_any = false; - bool has_complex = false; - - for ( size_t i = 0; i < TransformationComp_MAXIMUM; ++i ) { - const TransformationComp comp = static_cast( i ); - - // inverse pivots don't exist in the input, we just generate them - if ( comp == TransformationComp_RotationPivotInverse || comp == TransformationComp_ScalingPivotInverse ) { - chain[ i ] = node_property_map.end(); - continue; - } - - chain[ i ] = node_property_map.find( NameTransformationCompProperty( comp ) ); - if ( chain[ i ] != node_property_map.end() ) { - - // check if this curves contains redundant information by looking - // up the corresponding node's transformation chain. - if ( doc.Settings().optimizeEmptyAnimationCurves && - IsRedundantAnimationData( target, comp, ( *chain[ i ] ).second ) ) { - - FBXImporter::LogDebug( "dropping redundant animation channel for node " + target.Name() ); - continue; - } - - has_any = true; - - if ( comp != TransformationComp_Rotation && comp != TransformationComp_Scaling && comp != TransformationComp_Translation ) - { - has_complex = true; - } - } - } - - if ( !has_any ) { - FBXImporter::LogWarn( "ignoring node animation, did not find any transformation key frames" ); - return; - } - - // this needs to play nicely with GenerateTransformationNodeChain() which will - // be invoked _later_ (animations come first). If this node has only rotation, - // scaling and translation _and_ there are no animated other components either, - // we can use a single node and also a single node animation channel. - if ( !has_complex && !NeedsComplexTransformationChain( target ) ) { - - aiNodeAnim* const nd = GenerateSimpleNodeAnim( fixed_name, target, chain, - node_property_map.end(), - layer_map, - start, stop, - max_time, - min_time, - true // input is TRS order, assimp is SRT - ); - - ai_assert( nd ); - if ( nd->mNumPositionKeys == 0 && nd->mNumRotationKeys == 0 && nd->mNumScalingKeys == 0 ) { - delete nd; - } - else { - node_anims.push_back( nd ); - } - return; - } - - // otherwise, things get gruesome and we need separate animation channels - // for each part of the transformation chain. Remember which channels - // we generated and pass this information to the node conversion - // code to avoid nodes that have identity transform, but non-identity - // animations, being dropped. - unsigned int flags = 0, bit = 0x1; - for ( size_t i = 0; i < TransformationComp_MAXIMUM; ++i, bit <<= 1 ) { - const TransformationComp comp = static_cast( i ); - - if ( chain[ i ] != node_property_map.end() ) { - flags |= bit; - - ai_assert( comp != TransformationComp_RotationPivotInverse ); - ai_assert( comp != TransformationComp_ScalingPivotInverse ); - - const std::string& chain_name = NameTransformationChainNode( fixed_name, comp ); - - aiNodeAnim* na = nullptr; - switch ( comp ) - { - case TransformationComp_Rotation: - case TransformationComp_PreRotation: - case TransformationComp_PostRotation: - case TransformationComp_GeometricRotation: - na = GenerateRotationNodeAnim( chain_name, - target, - ( *chain[ i ] ).second, - layer_map, - start, stop, - max_time, - min_time ); - - break; - - case TransformationComp_RotationOffset: - case TransformationComp_RotationPivot: - case TransformationComp_ScalingOffset: - case TransformationComp_ScalingPivot: - case TransformationComp_Translation: - case TransformationComp_GeometricTranslation: - na = GenerateTranslationNodeAnim( chain_name, - target, - ( *chain[ i ] ).second, - layer_map, - start, stop, - max_time, - min_time ); - - // pivoting requires us to generate an implicit inverse channel to undo the pivot translation - if ( comp == TransformationComp_RotationPivot ) { - const std::string& invName = NameTransformationChainNode( fixed_name, - TransformationComp_RotationPivotInverse ); - - aiNodeAnim* const inv = GenerateTranslationNodeAnim( invName, - target, - ( *chain[ i ] ).second, - layer_map, - start, stop, - max_time, - min_time, - true ); - - ai_assert( inv ); - if ( inv->mNumPositionKeys == 0 && inv->mNumRotationKeys == 0 && inv->mNumScalingKeys == 0 ) { - delete inv; - } - else { - node_anims.push_back( inv ); - } - - ai_assert( TransformationComp_RotationPivotInverse > i ); - flags |= bit << ( TransformationComp_RotationPivotInverse - i ); - } - else if ( comp == TransformationComp_ScalingPivot ) { - const std::string& invName = NameTransformationChainNode( fixed_name, - TransformationComp_ScalingPivotInverse ); - - aiNodeAnim* const inv = GenerateTranslationNodeAnim( invName, - target, - ( *chain[ i ] ).second, - layer_map, - start, stop, - max_time, - min_time, - true ); - - ai_assert( inv ); - if ( inv->mNumPositionKeys == 0 && inv->mNumRotationKeys == 0 && inv->mNumScalingKeys == 0 ) { - delete inv; - } - else { - node_anims.push_back( inv ); - } - - ai_assert( TransformationComp_RotationPivotInverse > i ); - flags |= bit << ( TransformationComp_RotationPivotInverse - i ); - } - - break; - - case TransformationComp_Scaling: - case TransformationComp_GeometricScaling: - na = GenerateScalingNodeAnim( chain_name, - target, - ( *chain[ i ] ).second, - layer_map, - start, stop, - max_time, - min_time ); - - break; - - default: - ai_assert( false ); - } - - ai_assert( na ); - if ( na->mNumPositionKeys == 0 && na->mNumRotationKeys == 0 && na->mNumScalingKeys == 0 ) { - delete na; - } - else { - node_anims.push_back( na ); - } - continue; - } - } - - node_anim_chain_bits[ fixed_name ] = flags; -} - -bool FBXConverter::IsRedundantAnimationData( const Model& target, - TransformationComp comp, - const std::vector& curves ) { - ai_assert( curves.size() ); - - // look for animation nodes with - // * sub channels for all relevant components set - // * one key/value pair per component - // * combined values match up the corresponding value in the bind pose node transformation - // only such nodes are 'redundant' for this function. - - if ( curves.size() > 1 ) { - return false; - } - - const AnimationCurveNode& nd = *curves.front(); - const AnimationCurveMap& sub_curves = nd.Curves(); - - const AnimationCurveMap::const_iterator dx = sub_curves.find( "d|X" ); - const AnimationCurveMap::const_iterator dy = sub_curves.find( "d|Y" ); - const AnimationCurveMap::const_iterator dz = sub_curves.find( "d|Z" ); - - if ( dx == sub_curves.end() || dy == sub_curves.end() || dz == sub_curves.end() ) { - return false; - } - - const KeyValueList& vx = ( *dx ).second->GetValues(); - const KeyValueList& vy = ( *dy ).second->GetValues(); - const KeyValueList& vz = ( *dz ).second->GetValues(); - - if ( vx.size() != 1 || vy.size() != 1 || vz.size() != 1 ) { - return false; - } - - const aiVector3D dyn_val = aiVector3D( vx[ 0 ], vy[ 0 ], vz[ 0 ] ); - const aiVector3D& static_val = PropertyGet( target.Props(), - NameTransformationCompProperty( comp ), - TransformationCompDefaultValue( comp ) - ); - - const float epsilon = 1e-6f; - return ( dyn_val - static_val ).SquareLength() < epsilon; -} - - -aiNodeAnim* FBXConverter::GenerateRotationNodeAnim( const std::string& name, - const Model& target, - const std::vector& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time ) -{ - std::unique_ptr na( new aiNodeAnim() ); - na->mNodeName.Set( name ); - - ConvertRotationKeys( na.get(), curves, layer_map, start, stop, max_time, min_time, target.RotationOrder() ); - - // dummy scaling key - na->mScalingKeys = new aiVectorKey[ 1 ]; - na->mNumScalingKeys = 1; - - na->mScalingKeys[ 0 ].mTime = 0.; - na->mScalingKeys[ 0 ].mValue = aiVector3D( 1.0f, 1.0f, 1.0f ); - - // dummy position key - na->mPositionKeys = new aiVectorKey[ 1 ]; - na->mNumPositionKeys = 1; - - na->mPositionKeys[ 0 ].mTime = 0.; - na->mPositionKeys[ 0 ].mValue = aiVector3D(); - - return na.release(); -} - -aiNodeAnim* FBXConverter::GenerateScalingNodeAnim( const std::string& name, - const Model& /*target*/, - const std::vector& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time ) -{ - std::unique_ptr na( new aiNodeAnim() ); - na->mNodeName.Set( name ); - - ConvertScaleKeys( na.get(), curves, layer_map, start, stop, max_time, min_time ); - - // dummy rotation key - na->mRotationKeys = new aiQuatKey[ 1 ]; - na->mNumRotationKeys = 1; - - na->mRotationKeys[ 0 ].mTime = 0.; - na->mRotationKeys[ 0 ].mValue = aiQuaternion(); - - // dummy position key - na->mPositionKeys = new aiVectorKey[ 1 ]; - na->mNumPositionKeys = 1; - - na->mPositionKeys[ 0 ].mTime = 0.; - na->mPositionKeys[ 0 ].mValue = aiVector3D(); - - return na.release(); -} - -aiNodeAnim* FBXConverter::GenerateTranslationNodeAnim( const std::string& name, - const Model& /*target*/, - const std::vector& curves, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time, - bool inverse ) { - std::unique_ptr na( new aiNodeAnim() ); - na->mNodeName.Set( name ); - - ConvertTranslationKeys( na.get(), curves, layer_map, start, stop, max_time, min_time ); - - if ( inverse ) { - for ( unsigned int i = 0; i < na->mNumPositionKeys; ++i ) { - na->mPositionKeys[ i ].mValue *= -1.0f; - } - } - - // dummy scaling key - na->mScalingKeys = new aiVectorKey[ 1 ]; - na->mNumScalingKeys = 1; - - na->mScalingKeys[ 0 ].mTime = 0.; - na->mScalingKeys[ 0 ].mValue = aiVector3D( 1.0f, 1.0f, 1.0f ); - - // dummy rotation key - na->mRotationKeys = new aiQuatKey[ 1 ]; - na->mNumRotationKeys = 1; - - na->mRotationKeys[ 0 ].mTime = 0.; - na->mRotationKeys[ 0 ].mValue = aiQuaternion(); - - return na.release(); -} - -aiNodeAnim* FBXConverter::GenerateSimpleNodeAnim( const std::string& name, - const Model& target, - NodeMap::const_iterator chain[ TransformationComp_MAXIMUM ], - NodeMap::const_iterator iter_end, - const LayerMap& layer_map, - int64_t start, int64_t stop, - double& max_time, - double& min_time, - bool reverse_order ) - -{ - std::unique_ptr na( new aiNodeAnim() ); - na->mNodeName.Set( name ); - - const PropertyTable& props = target.Props(); - - // need to convert from TRS order to SRT? - if ( reverse_order ) { - - aiVector3D def_scale = PropertyGet( props, "Lcl Scaling", aiVector3D( 1.f, 1.f, 1.f ) ); - aiVector3D def_translate = PropertyGet( props, "Lcl Translation", aiVector3D( 0.f, 0.f, 0.f ) ); - aiVector3D def_rot = PropertyGet( props, "Lcl Rotation", aiVector3D( 0.f, 0.f, 0.f ) ); - - KeyFrameListList scaling; - KeyFrameListList translation; - KeyFrameListList rotation; - - if ( chain[ TransformationComp_Scaling ] != iter_end ) { - scaling = GetKeyframeList( ( *chain[ TransformationComp_Scaling ] ).second, start, stop ); - } - - if ( chain[ TransformationComp_Translation ] != iter_end ) { - translation = GetKeyframeList( ( *chain[ TransformationComp_Translation ] ).second, start, stop ); - } - - if ( chain[ TransformationComp_Rotation ] != iter_end ) { - rotation = GetKeyframeList( ( *chain[ TransformationComp_Rotation ] ).second, start, stop ); - } - - KeyFrameListList joined; - joined.insert( joined.end(), scaling.begin(), scaling.end() ); - joined.insert( joined.end(), translation.begin(), translation.end() ); - joined.insert( joined.end(), rotation.begin(), rotation.end() ); - - const KeyTimeList& times = GetKeyTimeList( joined ); - - aiQuatKey* out_quat = new aiQuatKey[ times.size() ]; - aiVectorKey* out_scale = new aiVectorKey[ times.size() ]; - aiVectorKey* out_translation = new aiVectorKey[ times.size() ]; - - if ( times.size() ) - { - ConvertTransformOrder_TRStoSRT( out_quat, out_scale, out_translation, - scaling, - translation, - rotation, - times, - max_time, - min_time, - target.RotationOrder(), - def_scale, - def_translate, - def_rot ); - } - - // XXX remove duplicates / redundant keys which this operation did - // likely produce if not all three channels were equally dense. - - na->mNumScalingKeys = static_cast( times.size() ); - na->mNumRotationKeys = na->mNumScalingKeys; - na->mNumPositionKeys = na->mNumScalingKeys; - - na->mScalingKeys = out_scale; - na->mRotationKeys = out_quat; - na->mPositionKeys = out_translation; - } - else { - - // if a particular transformation is not given, grab it from - // the corresponding node to meet the semantics of aiNodeAnim, - // which requires all of rotation, scaling and translation - // to be set. - if ( chain[ TransformationComp_Scaling ] != iter_end ) { - ConvertScaleKeys( na.get(), ( *chain[ TransformationComp_Scaling ] ).second, - layer_map, - start, stop, - max_time, - min_time ); - } - else { - na->mScalingKeys = new aiVectorKey[ 1 ]; - na->mNumScalingKeys = 1; - - na->mScalingKeys[ 0 ].mTime = 0.; - na->mScalingKeys[ 0 ].mValue = PropertyGet( props, "Lcl Scaling", - aiVector3D( 1.f, 1.f, 1.f ) ); - } - - if ( chain[ TransformationComp_Rotation ] != iter_end ) { - ConvertRotationKeys( na.get(), ( *chain[ TransformationComp_Rotation ] ).second, - layer_map, - start, stop, - max_time, - min_time, - target.RotationOrder() ); - } - else { - na->mRotationKeys = new aiQuatKey[ 1 ]; - na->mNumRotationKeys = 1; - - na->mRotationKeys[ 0 ].mTime = 0.; - na->mRotationKeys[ 0 ].mValue = EulerToQuaternion( - PropertyGet( props, "Lcl Rotation", aiVector3D( 0.f, 0.f, 0.f ) ), - target.RotationOrder() ); - } - - if ( chain[ TransformationComp_Translation ] != iter_end ) { - ConvertTranslationKeys( na.get(), ( *chain[ TransformationComp_Translation ] ).second, - layer_map, - start, stop, - max_time, - min_time ); - } - else { - na->mPositionKeys = new aiVectorKey[ 1 ]; - na->mNumPositionKeys = 1; - - na->mPositionKeys[ 0 ].mTime = 0.; - na->mPositionKeys[ 0 ].mValue = PropertyGet( props, "Lcl Translation", - aiVector3D( 0.f, 0.f, 0.f ) ); - } - - } - return na.release(); -} - -FBXConverter::KeyFrameListList FBXConverter::GetKeyframeList( const std::vector& nodes, int64_t start, int64_t stop ) -{ - KeyFrameListList inputs; - inputs.reserve( nodes.size() * 3 ); - - //give some breathing room for rounding errors - int64_t adj_start = start - 10000; - int64_t adj_stop = stop + 10000; - - for( const AnimationCurveNode* node : nodes ) { - ai_assert( node ); - - const AnimationCurveMap& curves = node->Curves(); - for( const AnimationCurveMap::value_type& kv : curves ) { - - unsigned int mapto; - if ( kv.first == "d|X" ) { - mapto = 0; - } - else if ( kv.first == "d|Y" ) { - mapto = 1; - } - else if ( kv.first == "d|Z" ) { - mapto = 2; - } - else { - FBXImporter::LogWarn( "ignoring scale animation curve, did not recognize target component" ); - continue; - } - - const AnimationCurve* const curve = kv.second; - ai_assert( curve->GetKeys().size() == curve->GetValues().size() && curve->GetKeys().size() ); - - //get values within the start/stop time window - std::shared_ptr Keys( new KeyTimeList() ); - std::shared_ptr Values( new KeyValueList() ); - const size_t count = curve->GetKeys().size(); - Keys->reserve( count ); - Values->reserve( count ); - for (size_t n = 0; n < count; n++ ) - { - int64_t k = curve->GetKeys().at( n ); - if ( k >= adj_start && k <= adj_stop ) - { - Keys->push_back( k ); - Values->push_back( curve->GetValues().at( n ) ); - } - } - - inputs.push_back( std::make_tuple( Keys, Values, mapto ) ); - } - } - return inputs; // pray for NRVO :-) -} - - -KeyTimeList FBXConverter::GetKeyTimeList( const KeyFrameListList& inputs ) { - ai_assert( !inputs.empty() ); - - // reserve some space upfront - it is likely that the key-frame lists - // have matching time values, so max(of all key-frame lists) should - // be a good estimate. - KeyTimeList keys; - - size_t estimate = 0; - for( const KeyFrameList& kfl : inputs ) { - estimate = std::max( estimate, std::get<0>(kfl)->size() ); - } - - keys.reserve( estimate ); - - std::vector next_pos; - next_pos.resize( inputs.size(), 0 ); - - const size_t count = inputs.size(); - while ( true ) { - - int64_t min_tick = std::numeric_limits::max(); - for ( size_t i = 0; i < count; ++i ) { - const KeyFrameList& kfl = inputs[ i ]; - - if ( std::get<0>(kfl)->size() > next_pos[ i ] && std::get<0>(kfl)->at( next_pos[ i ] ) < min_tick ) { - min_tick = std::get<0>(kfl)->at( next_pos[ i ] ); - } - } - - if ( min_tick == std::numeric_limits::max() ) { - break; - } - keys.push_back( min_tick ); - - for ( size_t i = 0; i < count; ++i ) { - const KeyFrameList& kfl = inputs[ i ]; - - - while ( std::get<0>(kfl)->size() > next_pos[ i ] && std::get<0>(kfl)->at( next_pos[ i ] ) == min_tick ) { - ++next_pos[ i ]; - } - } - } - - return keys; -} - -void FBXConverter::InterpolateKeys( aiVectorKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, - const aiVector3D& def_value, - double& max_time, - double& min_time ) { - ai_assert( !keys.empty() ); - ai_assert( nullptr != valOut ); - - std::vector next_pos; - const size_t count( inputs.size() ); - - next_pos.resize( inputs.size(), 0 ); - - for( KeyTimeList::value_type time : keys ) { - ai_real result[ 3 ] = { def_value.x, def_value.y, def_value.z }; - - for ( size_t i = 0; i < count; ++i ) { - const KeyFrameList& kfl = inputs[ i ]; - - const size_t ksize = std::get<0>(kfl)->size(); - if (ksize == 0) { - continue; - } - if ( ksize > next_pos[ i ] && std::get<0>(kfl)->at( next_pos[ i ] ) == time ) { - ++next_pos[ i ]; - } - - const size_t id0 = next_pos[ i ]>0 ? next_pos[ i ] - 1 : 0; - const size_t id1 = next_pos[ i ] == ksize ? ksize - 1 : next_pos[ i ]; - - // use lerp for interpolation - const KeyValueList::value_type valueA = std::get<1>(kfl)->at( id0 ); - const KeyValueList::value_type valueB = std::get<1>(kfl)->at( id1 ); - - const KeyTimeList::value_type timeA = std::get<0>(kfl)->at( id0 ); - const KeyTimeList::value_type timeB = std::get<0>(kfl)->at( id1 ); - - const ai_real factor = timeB == timeA ? ai_real(0.) : static_cast( ( time - timeA ) ) / ( timeB - timeA ); - const ai_real interpValue = static_cast( valueA + ( valueB - valueA ) * factor ); - - result[ std::get<2>(kfl) ] = interpValue; - } - - // magic value to convert fbx times to seconds - valOut->mTime = CONVERT_FBX_TIME( time ) * anim_fps; - - min_time = std::min( min_time, valOut->mTime ); - max_time = std::max( max_time, valOut->mTime ); - - valOut->mValue.x = result[ 0 ]; - valOut->mValue.y = result[ 1 ]; - valOut->mValue.z = result[ 2 ]; - - ++valOut; - } -} - -void FBXConverter::InterpolateKeys( aiQuatKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, - const aiVector3D& def_value, - double& maxTime, - double& minTime, - Model::RotOrder order ) -{ - ai_assert( !keys.empty() ); - ai_assert( nullptr != valOut ); - - std::unique_ptr temp( new aiVectorKey[ keys.size() ] ); - InterpolateKeys( temp.get(), keys, inputs, def_value, maxTime, minTime ); - - aiMatrix4x4 m; - - aiQuaternion lastq; - - for ( size_t i = 0, c = keys.size(); i < c; ++i ) { - - valOut[ i ].mTime = temp[ i ].mTime; - - GetRotationMatrix( order, temp[ i ].mValue, m ); - aiQuaternion quat = aiQuaternion( aiMatrix3x3( m ) ); - - // take shortest path by checking the inner product - // http://www.3dkingdoms.com/weekly/weekly.php?a=36 - if ( quat.x * lastq.x + quat.y * lastq.y + quat.z * lastq.z + quat.w * lastq.w < 0 ) - { - quat.x = -quat.x; - quat.y = -quat.y; - quat.z = -quat.z; - quat.w = -quat.w; - } - lastq = quat; - - valOut[ i ].mValue = quat; - } -} - -void FBXConverter::ConvertTransformOrder_TRStoSRT( aiQuatKey* out_quat, aiVectorKey* out_scale, - aiVectorKey* out_translation, - const KeyFrameListList& scaling, - const KeyFrameListList& translation, - const KeyFrameListList& rotation, - const KeyTimeList& times, - double& maxTime, - double& minTime, - Model::RotOrder order, - const aiVector3D& def_scale, - const aiVector3D& def_translate, - const aiVector3D& def_rotation ) -{ - if ( rotation.size() ) { - InterpolateKeys( out_quat, times, rotation, def_rotation, maxTime, minTime, order ); - } - else { - for ( size_t i = 0; i < times.size(); ++i ) { - out_quat[ i ].mTime = CONVERT_FBX_TIME( times[ i ] ) * anim_fps; - out_quat[ i ].mValue = EulerToQuaternion( def_rotation, order ); - } - } - - if ( scaling.size() ) { - InterpolateKeys( out_scale, times, scaling, def_scale, maxTime, minTime ); - } - else { - for ( size_t i = 0; i < times.size(); ++i ) { - out_scale[ i ].mTime = CONVERT_FBX_TIME( times[ i ] ) * anim_fps; - out_scale[ i ].mValue = def_scale; - } - } - - if ( translation.size() ) { - InterpolateKeys( out_translation, times, translation, def_translate, maxTime, minTime ); - } - else { - for ( size_t i = 0; i < times.size(); ++i ) { - out_translation[ i ].mTime = CONVERT_FBX_TIME( times[ i ] ) * anim_fps; - out_translation[ i ].mValue = def_translate; - } - } - - const size_t count = times.size(); - for ( size_t i = 0; i < count; ++i ) { - aiQuaternion& r = out_quat[ i ].mValue; - aiVector3D& s = out_scale[ i ].mValue; - aiVector3D& t = out_translation[ i ].mValue; - - aiMatrix4x4 mat, temp; - aiMatrix4x4::Translation( t, mat ); - mat *= aiMatrix4x4( r.GetMatrix() ); - mat *= aiMatrix4x4::Scaling( s, temp ); - - mat.Decompose( s, r, t ); - } -} - -aiQuaternion FBXConverter::EulerToQuaternion( const aiVector3D& rot, Model::RotOrder order ) -{ - aiMatrix4x4 m; - GetRotationMatrix( order, rot, m ); - - return aiQuaternion( aiMatrix3x3( m ) ); -} - -void FBXConverter::ConvertScaleKeys( aiNodeAnim* na, const std::vector& nodes, const LayerMap& /*layers*/, - int64_t start, int64_t stop, - double& maxTime, - double& minTime ) -{ - ai_assert( nodes.size() ); - - // XXX for now, assume scale should be blended geometrically (i.e. two - // layers should be multiplied with each other). There is a FBX - // property in the layer to specify the behaviour, though. - - const KeyFrameListList& inputs = GetKeyframeList( nodes, start, stop ); - const KeyTimeList& keys = GetKeyTimeList( inputs ); - - na->mNumScalingKeys = static_cast( keys.size() ); - na->mScalingKeys = new aiVectorKey[ keys.size() ]; - if ( keys.size() > 0 ) - InterpolateKeys( na->mScalingKeys, keys, inputs, aiVector3D( 1.0f, 1.0f, 1.0f ), maxTime, minTime ); -} - -void FBXConverter::ConvertTranslationKeys( aiNodeAnim* na, const std::vector& nodes, - const LayerMap& /*layers*/, - int64_t start, int64_t stop, - double& maxTime, - double& minTime ) -{ - ai_assert( nodes.size() ); - - // XXX see notes in ConvertScaleKeys() - const KeyFrameListList& inputs = GetKeyframeList( nodes, start, stop ); - const KeyTimeList& keys = GetKeyTimeList( inputs ); - - na->mNumPositionKeys = static_cast( keys.size() ); - na->mPositionKeys = new aiVectorKey[ keys.size() ]; - if ( keys.size() > 0 ) - InterpolateKeys( na->mPositionKeys, keys, inputs, aiVector3D( 0.0f, 0.0f, 0.0f ), maxTime, minTime ); -} - -void FBXConverter::ConvertRotationKeys( aiNodeAnim* na, const std::vector& nodes, - const LayerMap& /*layers*/, - int64_t start, int64_t stop, - double& maxTime, - double& minTime, - Model::RotOrder order ) -{ - ai_assert( nodes.size() ); - - // XXX see notes in ConvertScaleKeys() - const std::vector< KeyFrameList >& inputs = GetKeyframeList( nodes, start, stop ); - const KeyTimeList& keys = GetKeyTimeList( inputs ); - - na->mNumRotationKeys = static_cast( keys.size() ); - na->mRotationKeys = new aiQuatKey[ keys.size() ]; - if (!keys.empty()) { - InterpolateKeys(na->mRotationKeys, keys, inputs, aiVector3D(0.0f, 0.0f, 0.0f), maxTime, minTime, order); - } -} - -void FBXConverter::ConvertGlobalSettings() { - if (nullptr == out) { - return; - } - - out->mMetaData = aiMetadata::Alloc(1); - unsigned int index(0); - const double unitScalFactor(doc.GlobalSettings().UnitScaleFactor()); - out->mMetaData->Set(index, "UnitScaleFactor", unitScalFactor); -} - -void FBXConverter::TransferDataToScene() -{ - ai_assert( !out->mMeshes ); - ai_assert( !out->mNumMeshes ); - - // note: the trailing () ensures initialization with NULL - not - // many C++ users seem to know this, so pointing it out to avoid - // confusion why this code works. - - if ( meshes.size() ) { - out->mMeshes = new aiMesh*[ meshes.size() ](); - out->mNumMeshes = static_cast( meshes.size() ); - - std::swap_ranges( meshes.begin(), meshes.end(), out->mMeshes ); - } - - if ( materials.size() ) { - out->mMaterials = new aiMaterial*[ materials.size() ](); - out->mNumMaterials = static_cast( materials.size() ); - - std::swap_ranges( materials.begin(), materials.end(), out->mMaterials ); - } - - if ( animations.size() ) { - out->mAnimations = new aiAnimation*[ animations.size() ](); - out->mNumAnimations = static_cast( animations.size() ); - - std::swap_ranges( animations.begin(), animations.end(), out->mAnimations ); - } - - if ( lights.size() ) { - out->mLights = new aiLight*[ lights.size() ](); - out->mNumLights = static_cast( lights.size() ); - - std::swap_ranges( lights.begin(), lights.end(), out->mLights ); - } - - if ( cameras.size() ) { - out->mCameras = new aiCamera*[ cameras.size() ](); - out->mNumCameras = static_cast( cameras.size() ); - - std::swap_ranges( cameras.begin(), cameras.end(), out->mCameras ); - } - - if ( textures.size() ) { - out->mTextures = new aiTexture*[ textures.size() ](); - out->mNumTextures = static_cast( textures.size() ); - - std::swap_ranges( textures.begin(), textures.end(), out->mTextures ); - } -} - -// ------------------------------------------------------------------------------------------------ -void ConvertToAssimpScene(aiScene* out, const Document& doc) -{ - FBXConverter converter(out,doc); -} - -} // !FBX -} // !Assimp - -#endif diff --git a/code/FBXUtil.cpp b/code/FBXUtil.cpp deleted file mode 100644 index 992c30efc..000000000 --- a/code/FBXUtil.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2018, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -/** @file FBXUtil.cpp - * @brief Implementation of internal FBX utility functions - */ - -#include "FBXUtil.h" -#include "FBXTokenizer.h" - -#include -#include - -#ifndef ASSIMP_BUILD_NO_FBX_IMPORTER - -namespace Assimp { -namespace FBX { -namespace Util { - -// ------------------------------------------------------------------------------------------------ -const char* TokenTypeString(TokenType t) -{ - switch(t) { - case TokenType_OPEN_BRACKET: - return "TOK_OPEN_BRACKET"; - - case TokenType_CLOSE_BRACKET: - return "TOK_CLOSE_BRACKET"; - - case TokenType_DATA: - return "TOK_DATA"; - - case TokenType_COMMA: - return "TOK_COMMA"; - - case TokenType_KEY: - return "TOK_KEY"; - - case TokenType_BINARY_DATA: - return "TOK_BINARY_DATA"; - } - - ai_assert(false); - return ""; -} - - -// ------------------------------------------------------------------------------------------------ -std::string AddOffset(const std::string& prefix, const std::string& text, unsigned int offset) -{ - return static_cast( (Formatter::format() << prefix << " (offset 0x" << std::hex << offset << ") " << text) ); -} - -// ------------------------------------------------------------------------------------------------ -std::string AddLineAndColumn(const std::string& prefix, const std::string& text, unsigned int line, unsigned int column) -{ - return static_cast( (Formatter::format() << prefix << " (line " << line << " << col " << column << ") " << text) ); -} - -// ------------------------------------------------------------------------------------------------ -std::string AddTokenText(const std::string& prefix, const std::string& text, const Token* tok) -{ - if(tok->IsBinary()) { - return static_cast( (Formatter::format() << prefix << - " (" << TokenTypeString(tok->Type()) << - ", offset 0x" << std::hex << tok->Offset() << ") " << - text) ); - } - - return static_cast( (Formatter::format() << prefix << - " (" << TokenTypeString(tok->Type()) << - ", line " << tok->Line() << - ", col " << tok->Column() << ") " << - text) ); -} - -} // !Util -} // !FBX -} // !Assimp - -#endif diff --git a/code/HMPFileData.h b/code/HMP/HMPFileData.h similarity index 99% rename from code/HMPFileData.h rename to code/HMP/HMPFileData.h index 962f2f9c7..ab4100174 100644 --- a/code/HMPFileData.h +++ b/code/HMP/HMPFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/HMPLoader.cpp b/code/HMP/HMPLoader.cpp similarity index 99% rename from code/HMPLoader.cpp rename to code/HMP/HMPLoader.cpp index 7f53f9b54..d5469181e 100644 --- a/code/HMPLoader.cpp +++ b/code/HMP/HMPLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -47,14 +47,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_HMP_IMPORTER // internal headers -#include "HMPLoader.h" -#include "MD2FileData.h" -#include +#include "HMP/HMPLoader.h" +#include "MD2/MD2FileData.h" + #include #include #include #include +#include + using namespace Assimp; static const aiImporterDesc desc = { diff --git a/code/HMPLoader.h b/code/HMP/HMPLoader.h similarity index 98% rename from code/HMPLoader.h rename to code/HMP/HMPLoader.h index 4e513aee6..421826c91 100644 --- a/code/HMPLoader.h +++ b/code/HMP/HMPLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -48,8 +48,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers #include -#include "MDLLoader.h" -#include "HMPFileData.h" + +#include "MDL/MDLLoader.h" +#include "HMP/HMPFileData.h" namespace Assimp { using namespace HMP; diff --git a/code/HalfLifeFileData.h b/code/HMP/HalfLifeFileData.h similarity index 99% rename from code/HalfLifeFileData.h rename to code/HMP/HalfLifeFileData.h index 7c55657d4..ef328edf8 100644 --- a/code/HalfLifeFileData.h +++ b/code/HMP/HalfLifeFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/Importer/IFC/IFCBoolean.cpp b/code/Importer/IFC/IFCBoolean.cpp index 337e1d40b..10e7bf3af 100644 --- a/code/Importer/IFC/IFCBoolean.cpp +++ b/code/Importer/IFC/IFCBoolean.cpp @@ -44,8 +44,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER #include "code/Importer/IFC/IFCUtil.h" -#include "code/PolyTools.h" -#include "code/ProcessHelper.h" +#include "code/Common/PolyTools.h" +#include "code/PostProcessing/ProcessHelper.h" #include #include @@ -256,7 +256,7 @@ bool IntersectsBoundaryProfile(const IfcVector3& e0, const IfcVector3& e1, const for( size_t i = 0, bcount = boundary.size(); i < bcount; ++i ) { IfcVector3 b01 = boundary[(i + 1) % bcount] - boundary[i]; IfcVector3 b12 = boundary[(i + 2) % bcount] - boundary[(i + 1) % bcount]; - IfcVector3 b1_side = IfcVector3(b01.y, -b01.x, 0.0); // rotated 90° clockwise in Z plane + IfcVector3 b1_side = IfcVector3(b01.y, -b01.x, 0.0); // rotated 90° clockwise in Z plane // Warning: rough estimate only. A concave poly with lots of small segments each featuring a small counter rotation // could fool the accumulation. Correct implementation would be sum( acos( b01 * b2) * sign( b12 * b1_side)) windingOrder += (b1_side.x*b12.x + b1_side.y*b12.y); diff --git a/code/Importer/IFC/IFCCurve.cpp b/code/Importer/IFC/IFCCurve.cpp index af58e7b10..a817b4f9f 100644 --- a/code/Importer/IFC/IFCCurve.cpp +++ b/code/Importer/IFC/IFCCurve.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -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(Curve::Convert(entity.BasisCurve,conv))) { - base = std::shared_ptr(Curve::Convert(entity.BasisCurve,conv)); - typedef std::shared_ptr 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(); return u - range.first > -epsilon && range.second - u > -epsilon; } #endif diff --git a/code/Importer/IFC/IFCGeometry.cpp b/code/Importer/IFC/IFCGeometry.cpp index 548de4e27..d1c7aee19 100644 --- a/code/Importer/IFC/IFCGeometry.cpp +++ b/code/Importer/IFC/IFCGeometry.cpp @@ -46,17 +46,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER #include "IFCUtil.h" -#include "code/PolyTools.h" -#include "code/ProcessHelper.h" +#include "Common/PolyTools.h" +#include "PostProcessing/ProcessHelper.h" + +#ifdef ASSIMP_USE_HUNTER +# include +# include +#else +# include "../contrib/poly2tri/poly2tri/poly2tri.h" +# include "../contrib/clipper/clipper.hpp" +#endif -#include "../contrib/poly2tri/poly2tri/poly2tri.h" -#include "../contrib/clipper/clipper.hpp" #include - #include namespace Assimp { - namespace IFC { +namespace IFC { // ------------------------------------------------------------------------------------------------ bool ProcessPolyloop(const Schema_2x3::IfcPolyLoop& loop, TempMesh& meshout, ConversionData& /*conv*/) @@ -123,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(); diff --git a/code/Importer/IFC/IFCLoader.cpp b/code/Importer/IFC/IFCLoader.cpp index 473355538..5c705c256 100644 --- a/code/Importer/IFC/IFCLoader.cpp +++ b/code/Importer/IFC/IFCLoader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -52,7 +52,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #ifndef ASSIMP_BUILD_NO_COMPRESSED_IFC -# include +# ifdef ASSIMP_USE_HUNTER +# include +# else +# include +# endif #endif #include "IFCLoader.h" @@ -207,10 +211,21 @@ void IFCImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS } uint8_t* buff = new uint8_t[fileInfo.uncompressed_size]; LogInfo("Decompressing IFCZIP file"); - unzOpenCurrentFile( zip ); - const int ret = unzReadCurrentFile( zip, buff, fileInfo.uncompressed_size); + unzOpenCurrentFile(zip); + size_t total = 0; + int read = 0; + do { + int bufferSize = fileInfo.uncompressed_size < INT16_MAX ? fileInfo.uncompressed_size : INT16_MAX; + void* buffer = malloc(bufferSize); + read = unzReadCurrentFile(zip, buffer, bufferSize); + if (read > 0) { + memcpy((char*)buff + total, buffer, read); + total += read; + } + free(buffer); + } while (read > 0); size_t filesize = fileInfo.uncompressed_size; - if ( ret < 0 || size_t(ret) != filesize ) + if (total == 0 || size_t(total) != filesize) { delete[] buff; ThrowException("Failed to decompress IFC ZIP file"); @@ -659,8 +674,8 @@ void ProcessMetadata(uint64_t relDefinesByPropertiesID, ConversionData& conv, Me } // ------------------------------------------------------------------------------------------------ -aiNode* ProcessSpatialStructure(aiNode* parent, const Schema_2x3::IfcProduct& el, ConversionData& conv, std::vector* collect_openings = NULL) -{ +aiNode* ProcessSpatialStructure(aiNode* parent, const Schema_2x3::IfcProduct& el, ConversionData& conv, + std::vector* collect_openings = nullptr ) { const STEP::DB::RefMap& refs = conv.db.GetRefs(); // skip over space and annotation nodes - usually, these have no meaning in Assimp's context @@ -675,12 +690,12 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const Schema_2x3::IfcProduct& el if(conv.settings.skipAnnotations) { if(el.ToPtr()) { IFCImporter::LogDebug("skipping IfcAnnotation entity due to importer settings"); - return NULL; + return nullptr; } } // add an output node for this spatial structure - std::unique_ptr nd(new aiNode()); + aiNode *nd(new aiNode ); nd->mName.Set(el.GetClassName()+"_"+(el.Name?el.Name.Get():"Unnamed")+"_"+el.GlobalId); nd->mParent = parent; @@ -693,8 +708,7 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const Schema_2x3::IfcProduct& el if (children.first==children.second) { // handles single property set ProcessMetadata((*children.first).second, conv, properties); - } - else { + } else { // handles multiple property sets (currently all property sets are merged, // which may not be the best solution in the long run) for (STEP::DB::RefMap::const_iterator it=children.first; it!=children.second; ++it) { @@ -751,7 +765,7 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const Schema_2x3::IfcProduct& el continue; } - aiNode* const ndnew = ProcessSpatialStructure(nd.get(),pro,conv,NULL); + aiNode* const ndnew = ProcessSpatialStructure(nd,pro,conv,nullptr); if(ndnew) { subnodes.push_back( ndnew ); } @@ -765,7 +779,7 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const Schema_2x3::IfcProduct& el // move opening elements to a separate node since they are semantically different than elements that are just 'contained' std::unique_ptr nd_aggr(new aiNode()); nd_aggr->mName.Set("$RelVoidsElement"); - nd_aggr->mParent = nd.get(); + nd_aggr->mParent = nd; nd_aggr->mTransformation = nd->mTransformation; @@ -810,7 +824,7 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const Schema_2x3::IfcProduct& el // move aggregate elements to a separate node since they are semantically different than elements that are just 'contained' std::unique_ptr nd_aggr(new aiNode()); nd_aggr->mName.Set("$RelAggregates"); - nd_aggr->mParent = nd.get(); + nd_aggr->mParent = nd; nd_aggr->mTransformation = nd->mTransformation; @@ -835,19 +849,18 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const Schema_2x3::IfcProduct& el } if (!skipGeometry) { - ProcessProductRepresentation(el,nd.get(),subnodes,conv); - conv.apply_openings = conv.collect_openings = NULL; + ProcessProductRepresentation(el, nd, subnodes, conv); + conv.apply_openings = conv.collect_openings = nullptr; } if (subnodes.size()) { nd->mChildren = new aiNode*[subnodes.size()](); for(aiNode* nd2 : subnodes) { nd->mChildren[nd->mNumChildren++] = nd2; - nd2->mParent = nd.get(); + nd2->mParent = nd; } } - } - catch(...) { + } catch(...) { // it hurts, but I don't want to pull boost::ptr_vector into -noboost only for these few spots here std::for_each(subnodes.begin(),subnodes.end(),delete_fun()); throw; @@ -855,7 +868,7 @@ aiNode* ProcessSpatialStructure(aiNode* parent, const Schema_2x3::IfcProduct& el ai_assert(conv.already_processed.find(el.GetID()) != conv.already_processed.end()); conv.already_processed.erase(conv.already_processed.find(el.GetID())); - return nd.release(); + return nd; } // ------------------------------------------------------------------------------------------------ diff --git a/code/Importer/IFC/IFCLoader.h b/code/Importer/IFC/IFCLoader.h index 99e3e8ed9..678c60343 100644 --- a/code/Importer/IFC/IFCLoader.h +++ b/code/Importer/IFC/IFCLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/Importer/IFC/IFCMaterial.cpp b/code/Importer/IFC/IFCMaterial.cpp index 423d1471e..5fda0a1de 100644 --- a/code/Importer/IFC/IFCMaterial.cpp +++ b/code/Importer/IFC/IFCMaterial.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/Importer/IFC/IFCOpenings.cpp b/code/Importer/IFC/IFCOpenings.cpp index c5720e943..d6c40b383 100644 --- a/code/Importer/IFC/IFCOpenings.cpp +++ b/code/Importer/IFC/IFCOpenings.cpp @@ -46,11 +46,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER #include "IFCUtil.h" -#include "code/PolyTools.h" -#include "code/ProcessHelper.h" +#include "Common/PolyTools.h" +#include "PostProcessing/ProcessHelper.h" -#include "../contrib/poly2tri/poly2tri/poly2tri.h" -#include "../contrib/clipper/clipper.hpp" +#ifdef ASSIMP_USE_HUNTER +# include +# include +#else +# include "../contrib/poly2tri/poly2tri/poly2tri.h" +# include "../contrib/clipper/clipper.hpp" +#endif #include @@ -588,7 +593,7 @@ typedef std::vector(); 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) || @@ -676,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(1e-8); + const IfcFloat sqlen_epsilon = static_cast(Math::getEpsilon()); const BoundingBox& bb = (*current).bb; // What is to be done here is to populate the skip lists for the contour @@ -753,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(1e-5); + const IfcFloat dot_point_epsilon = static_cast(Math::getEpsilon()); return std::fabs(vdelta.x * vdelta.y) < dot_point_epsilon; } diff --git a/code/Importer/IFC/IFCProfile.cpp b/code/Importer/IFC/IFCProfile.cpp index 2236d0d9b..daafc9afe 100644 --- a/code/Importer/IFC/IFCProfile.cpp +++ b/code/Importer/IFC/IFCProfile.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/Importer/IFC/IFCReaderGen_2x3.h b/code/Importer/IFC/IFCReaderGen_2x3.h index 0362d90b2..8b39ccdc2 100644 --- a/code/Importer/IFC/IFCReaderGen_2x3.h +++ b/code/Importer/IFC/IFCReaderGen_2x3.h @@ -43,7 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef INCLUDED_IFC_READER_GEN_H #define INCLUDED_IFC_READER_GEN_H -#include "code/STEPFile.h" +#include "code/Step/STEPFile.h" namespace Assimp { namespace IFC { diff --git a/code/Importer/IFC/IFCUtil.cpp b/code/Importer/IFC/IFCUtil.cpp index 06cc4405a..f6bca91f5 100644 --- a/code/Importer/IFC/IFCUtil.cpp +++ b/code/Importer/IFC/IFCUtil.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -44,21 +44,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of conversion routines for some common Ifc helper entities. */ - - #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER -#include "code/Importer/IFC/IFCUtil.h" -#include "code/PolyTools.h" -#include "code/ProcessHelper.h" +#include "Importer/IFC/IFCUtil.h" +#include "Common/PolyTools.h" +#include "PostProcessing/ProcessHelper.h" #include namespace Assimp { - namespace IFC { +namespace IFC { // ------------------------------------------------------------------------------------------------ -void TempOpening::Transform(const IfcMatrix4& mat) -{ +void TempOpening::Transform(const IfcMatrix4& mat) { if(profileMesh) { profileMesh->Transform(mat); } diff --git a/code/Importer/IFC/IFCUtil.h b/code/Importer/IFC/IFCUtil.h index 194206d4b..32ae1e07f 100644 --- a/code/Importer/IFC/IFCUtil.h +++ b/code/Importer/IFC/IFCUtil.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "IFCReaderGen_2x3.h" #include "IFCLoader.h" -#include "code/STEPFile.h" +#include "code/Step/STEPFile.h" #include #include diff --git a/code/Importer/STEPParser/STEPFileEncoding.cpp b/code/Importer/STEPParser/STEPFileEncoding.cpp index 70d5f4e4b..101dcdfd7 100644 --- a/code/Importer/STEPParser/STEPFileEncoding.cpp +++ b/code/Importer/STEPParser/STEPFileEncoding.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,7 +45,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "STEPFileEncoding.h" #include -#include +#ifdef ASSIMP_USE_HUNTER +# include +#else +# include +#endif #include diff --git a/code/Importer/STEPParser/STEPFileEncoding.h b/code/Importer/STEPParser/STEPFileEncoding.h index 232cb81ba..09f16ba33 100644 --- a/code/Importer/STEPParser/STEPFileEncoding.h +++ b/code/Importer/STEPParser/STEPFileEncoding.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/Importer/STEPParser/STEPFileReader.cpp b/code/Importer/STEPParser/STEPFileReader.cpp index c7cad05ae..f099d2be7 100644 --- a/code/Importer/STEPParser/STEPFileReader.cpp +++ b/code/Importer/STEPParser/STEPFileReader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -63,7 +63,6 @@ std::string AddLineNumber(const std::string& s,uint64_t line /*= LINE_NOT_SPECIF return line == STEP::SyntaxError::LINE_NOT_SPECIFIED ? prefix+s : static_cast( (Formatter::format(),prefix,"(line ",line,") ",s) ); } - // ------------------------------------------------------------------------------------------------ std::string AddEntityID(const std::string& s,uint64_t entity /*= ENTITY_NOT_SPECIFIED*/, const std::string& prefix = "") { @@ -243,7 +242,6 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, std::string::size_type n2 = s.find_last_of(')'); if (n2 == std::string::npos || n2 < n1 || n2 == s.length() - 1 || s[n2 + 1] != ';') { - has_next = true; bool ok = false; for( ++splitter; splitter; ++splitter) { @@ -251,14 +249,14 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, if (snext.empty()) { continue; } + // the next line doesn't start an entity, so maybe it is // just a continuation for this line, keep going if (!IsEntityDef(snext)) { s.append(snext); n2 = s.find_last_of(')'); ok = !(n2 == std::string::npos || n2 < n1 || n2 == s.length() - 1 || s[n2 + 1] != ';'); - } - else { + } else { break; } } @@ -280,10 +278,10 @@ void STEP::ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, std::transform( type.begin(), type.end(), type.begin(), &Assimp::ToLower ); const char* sz = scheme.GetStaticStringForToken(type); if(sz) { - const std::string::size_type len = n2-n1+1; - char* const copysz = new char[len+1]; + const std::string::size_type szLen = n2-n1+1; + char* const copysz = new char[szLen+1]; std::copy(s.c_str()+n1,s.c_str()+n2+1,copysz); - copysz[len] = '\0'; + copysz[szLen] = '\0'; db.InternInsert(new LazyObject(db,id,line,sz,copysz)); } if(!has_next) { @@ -424,10 +422,8 @@ std::shared_ptr EXPRESS::DataType::Parse(const char*& i return std::make_shared(neg?-num:num); } - // ------------------------------------------------------------------------------------------------ -std::shared_ptr EXPRESS::LIST::Parse(const char*& inout,uint64_t line, const EXPRESS::ConversionSchema* schema /*= NULL*/) -{ +std::shared_ptr EXPRESS::LIST::Parse(const char*& inout,uint64_t line, const EXPRESS::ConversionSchema* schema /*= NULL*/) { const std::shared_ptr list = std::make_shared(); EXPRESS::LIST::MemberList& members = list->members; @@ -468,61 +464,73 @@ std::shared_ptr EXPRESS::LIST::Parse(const char*& inout,uin return list; } +// ------------------------------------------------------------------------------------------------ +static void handleSkippedDepthFromToken(const char *a, int64_t &skip_depth ) { + if (*a == '(') { + ++skip_depth; + } else if (*a == ')') { + --skip_depth; + } +} + +// ------------------------------------------------------------------------------------------------ +static int64_t getIdFromToken(const char *a) { + const char *tmp; + const int64_t num = static_cast(strtoul10_64(a + 1, &tmp)); + + return num; +} // ------------------------------------------------------------------------------------------------ STEP::LazyObject::LazyObject(DB& db, uint64_t id,uint64_t /*line*/, const char* const type,const char* args) - : id(id) - , type(type) - , db(db) - , args(args) - , obj() -{ +: id(id) +, type(type) +, db(db) +, args(args) +, obj() { // find any external references and store them in the database. // this helps us emulate STEPs INVERSE fields. - if (db.KeepInverseIndicesForType(type)) { - const char* a = args; + if (!db.KeepInverseIndicesForType(type)) { + return; + } - // do a quick scan through the argument tuple and watch out for entity references - int64_t skip_depth = 0; - while(*a) { - if (*a == '(') { - ++skip_depth; - } - else if (*a == ')') { - --skip_depth; - } + // do a quick scan through the argument tuple and watch out for entity references + const char *a( args ); + int64_t skip_depth( 0 ); + while ( *a ) { + handleSkippedDepthFromToken(a, skip_depth); + /*if (*a == '(') { + ++skip_depth; + } else if (*a == ')') { + --skip_depth; + }*/ - if (skip_depth >= 1 && *a=='#') { - if (*(a + 1) != '#') - { - const char* tmp; - const int64_t num = static_cast(strtoul10_64(a + 1, &tmp)); - db.MarkRef(num, id); - } - else - { - ++a; - } - } - ++a; + if (skip_depth >= 1 && *a=='#') { + if (*(a + 1) != '#') { + /*const char *tmp; + const int64_t num = static_cast(strtoul10_64(a + 1, &tmp)); + db.MarkRef(num, id);*/ + db.MarkRef(getIdFromToken(a), id); + } else { + ++a; + } } - + ++a; } } // ------------------------------------------------------------------------------------------------ -STEP::LazyObject::~LazyObject() -{ +STEP::LazyObject::~LazyObject() { // make sure the right dtor/operator delete get called if (obj) { delete obj; + } else { + delete[] args; } - else delete[] args; } // ------------------------------------------------------------------------------------------------ -void STEP::LazyObject::LazyInit() const -{ +void STEP::LazyObject::LazyInit() const { const EXPRESS::ConversionSchema& schema = db.GetSchema(); STEP::ConvertObjectProc proc = schema.GetConverterProc(type); diff --git a/code/Importer/STEPParser/STEPFileReader.h b/code/Importer/STEPParser/STEPFileReader.h index 667d28bfd..9c4b77241 100644 --- a/code/Importer/STEPParser/STEPFileReader.h +++ b/code/Importer/STEPParser/STEPFileReader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -43,7 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef INCLUDED_AI_STEPFILEREADER_H #define INCLUDED_AI_STEPFILEREADER_H -#include "code/STEPFile.h" +#include "code/Step/STEPFile.h" namespace Assimp { namespace STEP { @@ -68,4 +68,4 @@ void ReadFile(DB& db,const EXPRESS::ConversionSchema& scheme, const char* const } // ! STEP } // ! Assimp -#endif +#endif // INCLUDED_AI_STEPFILEREADER_H diff --git a/code/Importer/StepFile/StepFileGen1.cpp b/code/Importer/StepFile/StepFileGen1.cpp index 32df66c17..50c54818e 100644 --- a/code/Importer/StepFile/StepFileGen1.cpp +++ b/code/Importer/StepFile/StepFileGen1.cpp @@ -40,7 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** MACHINE-GENERATED by scripts/ICFImporter/CppGenerator.py */ -#ifndef ASSIMP_BUILD_NO_STEPFILE_IMPORTER +#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER #include "code/Importer/StepFile/StepReaderGen.h" diff --git a/code/Importer/StepFile/StepFileImporter.cpp b/code/Importer/StepFile/StepFileImporter.cpp index 9bfaf7051..26c456ac9 100644 --- a/code/Importer/StepFile/StepFileImporter.cpp +++ b/code/Importer/StepFile/StepFileImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -41,7 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -#ifndef ASSIMP_BUILD_NO_STEPFILE_IMPORTER +#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER #include "StepFileImporter.h" #include "../../Importer/STEPParser/STEPFileReader.h" @@ -110,5 +110,5 @@ void StepFileImporter::InternReadFile(const std::string &file, aiScene* pScene, } // Namespace StepFile } // Namespace Assimp -#endif // ASSIMP_BUILD_NO_STEPFILE_IMPORTER +#endif // ASSIMP_BUILD_NO_STEP_IMPORTER diff --git a/code/Importer/StepFile/StepFileImporter.h b/code/Importer/StepFile/StepFileImporter.h index 7314a54f3..70f65fdcf 100644 --- a/code/Importer/StepFile/StepFileImporter.h +++ b/code/Importer/StepFile/StepFileImporter.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -43,7 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#ifndef ASSIMP_BUILD_NO_STEPFILE_IMPORTER +#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER #include @@ -66,4 +66,4 @@ private: } // Namespace StepFile } // Namespace Assimp -#endif // ASSIMP_BUILD_NO_STEPFILE_IMPORTER +#endif // ASSIMP_BUILD_NO_STEP_IMPORTER diff --git a/code/Importer/StepFile/StepReaderGen.h b/code/Importer/StepFile/StepReaderGen.h index 21f2518df..9eb86c332 100644 --- a/code/Importer/StepFile/StepReaderGen.h +++ b/code/Importer/StepFile/StepReaderGen.h @@ -43,7 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef INCLUDED_STEPFILE_READER_GEN_H #define INCLUDED_STEPFILE_READER_GEN_H -#include "code/STEPFile.h" +#include "code/Step/STEPFile.h" namespace Assimp { namespace StepFile { diff --git a/code/IRRLoader.cpp b/code/Irr/IRRLoader.cpp similarity index 97% rename from code/IRRLoader.cpp rename to code/Irr/IRRLoader.cpp index 0640b0d66..e94fd85a4 100644 --- a/code/IRRLoader.cpp +++ b/code/Irr/IRRLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -49,18 +49,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_IRR_IMPORTER -#include "IRRLoader.h" +#include "Irr/IRRLoader.h" +#include "Common/Importer.h" + #include #include #include - #include #include -#include "Importer.h" - -// We need MathFunctions.h to compute the lcm/gcd of a number #include -#include #include #include #include @@ -69,6 +66,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include + using namespace Assimp; using namespace irr; using namespace irr::io; @@ -89,14 +88,16 @@ static const aiImporterDesc desc = { // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer IRRImporter::IRRImporter() - : fps(), - configSpeedFlag() -{} +: fps() +, configSpeedFlag(){ + // empty +} // ------------------------------------------------------------------------------------------------ // Destructor, private as well -IRRImporter::~IRRImporter() -{} +IRRImporter::~IRRImporter() { + // empty +} // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. @@ -107,9 +108,9 @@ bool IRRImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool } else if (extension == "xml" || checkSig) { /* If CanRead() is called in order to check whether we * support a specific file extension in general pIOHandler - * might be NULL and it's our duty to return true here. + * might be nullptr and it's our duty to return true here. */ - if ( nullptr == pIOHandler ) { + if (nullptr == pIOHandler ) { return true; } const char* tokens[] = {"irr_scene"}; @@ -290,31 +291,30 @@ void IRRImporter::CopyMaterial(std::vector& materials, // ------------------------------------------------------------------------------------------------ -inline int ClampSpline(int idx, int size) -{ +inline +int ClampSpline(int idx, int size) { return ( idx<0 ? size+idx : ( idx>=size ? idx-size : idx ) ); } // ------------------------------------------------------------------------------------------------ inline void FindSuitableMultiple(int& angle) { - if (angle < 3)angle = 3; + if (angle < 3) angle = 3; else if (angle < 10) angle = 10; else if (angle < 20) angle = 20; else if (angle < 30) angle = 30; - else - { - } } // ------------------------------------------------------------------------------------------------ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vector& anims) { - ai_assert(NULL != root && NULL != real); + ai_assert(nullptr != root && nullptr != real); // XXX totally WIP - doesn't produce proper results, need to evaluate // whether there's any use for Irrlicht's proprietary scene format // outside Irrlicht ... + // This also applies to the above function of FindSuitableMultiple and ClampSpline which are + // solely used in this function if (root->animators.empty()) { return; @@ -521,7 +521,8 @@ void IRRImporter::ComputeAnimations(Node* root, aiNode* real, std::vectorid); - if (!scene) { + aiScene* localScene = batch.GetImport(root->id); + if (!localScene) { ASSIMP_LOG_ERROR("IRR: Unable to load external file: " + root->meshPath); break; } - attach.push_back(AttachmentInfo(scene,rootOut)); + attach.push_back(AttachmentInfo(localScene,rootOut)); // Now combine the material we've loaded for this mesh // with the real materials we got from the file. As we // don't execute any pp-steps on the file, the numbers // should be equal. If they are not, we can impossibly // do this ... - if (root->materials.size() != (unsigned int)scene->mNumMaterials) { + if (root->materials.size() != (unsigned int)localScene->mNumMaterials) { ASSIMP_LOG_WARN("IRR: Failed to match imported materials " "with the materials found in the IRR scene file"); break; } - for (unsigned int i = 0; i < scene->mNumMaterials;++i) { + for (unsigned int i = 0; i < localScene->mNumMaterials;++i) { // Delete the old material, we don't need it anymore - delete scene->mMaterials[i]; + delete localScene->mMaterials[i]; std::pair& src = root->materials[i]; - scene->mMaterials[i] = src.first; + localScene->mMaterials[i] = src.first; } // NOTE: Each mesh should have exactly one material assigned, // but we do it in a separate loop if this behaviour changes // in future. - for (unsigned int i = 0; i < scene->mNumMeshes;++i) { + for (unsigned int i = 0; i < localScene->mNumMeshes;++i) { // Process material flags - aiMesh* mesh = scene->mMeshes[i]; + aiMesh* mesh = localScene->mMeshes[i]; // If "trans_vertex_alpha" mode is enabled, search all vertex colors @@ -905,8 +906,9 @@ void IRRImporter::InternReadFile( const std::string& pFile, std::unique_ptr file( pIOHandler->Open( pFile)); // Check whether we can read from the file - if( file.get() == NULL) - throw DeadlyImportError( "Failed to open IRR file " + pFile + ""); + if (file.get() == nullptr) { + throw DeadlyImportError("Failed to open IRR file " + pFile + ""); + } // Construct the irrXML parser CIrrXML_IOStreamReader st(file.get()); @@ -914,14 +916,14 @@ void IRRImporter::InternReadFile( const std::string& pFile, // The root node of the scene Node* root = new Node(Node::DUMMY); - root->parent = NULL; + root->parent = nullptr; root->name = ""; // Current node parent Node* curParent = root; // Scenegraph node we're currently working on - Node* curNode = NULL; + Node* curNode = nullptr; // List of output cameras std::vector cameras; @@ -1048,7 +1050,7 @@ void IRRImporter::InternReadFile( const std::string& pFile, continue; } - Animator* curAnim = NULL; + Animator* curAnim = nullptr; // Materials can occur for nearly any type of node if (inMaterials && curNode->type != Node::DUMMY) { @@ -1353,7 +1355,7 @@ void IRRImporter::InternReadFile( const std::string& pFile, } else curParent = curParent->parent; } - else curNode = NULL; + else curNode = nullptr; } // clear all flags else if (!ASSIMP_stricmp(reader->getNodeName(),"materials")) { @@ -1479,7 +1481,8 @@ void IRRImporter::InternReadFile( const std::string& pFile, /* Finished ... everything destructs automatically and all * temporary scenes have already been deleted by MergeScenes() */ - return; + + delete root; } #endif // !! ASSIMP_BUILD_NO_IRR_IMPORTER diff --git a/code/IRRLoader.h b/code/Irr/IRRLoader.h similarity index 94% rename from code/IRRLoader.h rename to code/Irr/IRRLoader.h index 3bd39092a..b3ad81a7d 100644 --- a/code/IRRLoader.h +++ b/code/Irr/IRRLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -48,15 +48,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_IRRLOADER_H_INCLUDED #define AI_IRRLOADER_H_INCLUDED -#include "IRRShared.h" +#include "Irr/IRRShared.h" +#include "Common/Importer.h" + #include -#include "Importer.h" #include #include namespace Assimp { - // --------------------------------------------------------------------------- /** Irr importer class. * @@ -64,15 +64,11 @@ namespace Assimp { * irrEdit. As IrrEdit itself is capable of importing quite many file formats, * it might be a good file format for data exchange. */ -class IRRImporter : public BaseImporter, public IrrlichtBase -{ +class IRRImporter : public BaseImporter, public IrrlichtBase { public: IRRImporter(); ~IRRImporter(); - -public: - // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. @@ -81,32 +77,17 @@ public: bool checkSig) const; protected: - - // ------------------------------------------------------------------- - /** - */ const aiImporterDesc* GetInfo () const; - - // ------------------------------------------------------------------- - /** - */ - void InternReadFile( const std::string& pFile, aiScene* pScene, - IOSystem* pIOHandler); - - // ------------------------------------------------------------------- - /** - */ + void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); void SetupProperties(const Importer* pImp); private: /** Data structure for a scenegraph node animator */ - struct Animator - { + struct Animator { // Type of the animator - enum AT - { + enum AT { UNKNOWN = 0x0, ROTATION = 0x1, FLY_CIRCLE = 0x2, diff --git a/code/IRRMeshLoader.cpp b/code/Irr/IRRMeshLoader.cpp similarity index 99% rename from code/IRRMeshLoader.cpp rename to code/Irr/IRRMeshLoader.cpp index 85de42195..057218464 100644 --- a/code/IRRMeshLoader.cpp +++ b/code/Irr/IRRMeshLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -57,7 +57,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include using namespace Assimp; using namespace irr; diff --git a/code/IRRMeshLoader.h b/code/Irr/IRRMeshLoader.h similarity index 98% rename from code/IRRMeshLoader.h rename to code/Irr/IRRMeshLoader.h index ef6a8a11b..d8b42d78d 100644 --- a/code/IRRMeshLoader.h +++ b/code/Irr/IRRMeshLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/IRRShared.cpp b/code/Irr/IRRShared.cpp similarity index 99% rename from code/IRRShared.cpp rename to code/Irr/IRRShared.cpp index 1e69f1d09..ecac031ab 100644 --- a/code/IRRShared.cpp +++ b/code/Irr/IRRShared.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/IRRShared.h b/code/Irr/IRRShared.h similarity index 100% rename from code/IRRShared.h rename to code/Irr/IRRShared.h diff --git a/code/LWOAnimation.cpp b/code/LWO/LWOAnimation.cpp similarity index 99% rename from code/LWOAnimation.cpp rename to code/LWO/LWOAnimation.cpp index ff02a8eab..3a0d2c392 100644 --- a/code/LWOAnimation.cpp +++ b/code/LWO/LWOAnimation.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/LWOAnimation.h b/code/LWO/LWOAnimation.h similarity index 99% rename from code/LWOAnimation.h rename to code/LWO/LWOAnimation.h index f7b0f177b..dd29695cc 100644 --- a/code/LWOAnimation.h +++ b/code/LWO/LWOAnimation.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/LWOBLoader.cpp b/code/LWO/LWOBLoader.cpp similarity index 99% rename from code/LWOBLoader.cpp rename to code/LWO/LWOBLoader.cpp index fabf99cad..b24957072 100644 --- a/code/LWOBLoader.cpp +++ b/code/LWO/LWOBLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/LWOFileData.h b/code/LWO/LWOFileData.h similarity index 99% rename from code/LWOFileData.h rename to code/LWO/LWOFileData.h index b3a963199..7d1f6b1df 100644 --- a/code/LWOFileData.h +++ b/code/LWO/LWOFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -57,8 +57,8 @@ The chunks are taken from the official LightWave SDK headers. #include // internal headers -#include "IFF.h" -#include "LWOAnimation.h" +#include "Common/IFF.h" +#include "LWO/LWOAnimation.h" namespace Assimp { namespace LWO { diff --git a/code/LWOLoader.cpp b/code/LWO/LWOLoader.cpp similarity index 99% rename from code/LWOLoader.cpp rename to code/LWO/LWOLoader.cpp index fbefe4a1e..1e5b92c32 100644 --- a/code/LWOLoader.cpp +++ b/code/LWO/LWOLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -49,14 +49,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_LWO_IMPORTER // internal headers -#include "LWOLoader.h" +#include "LWO/LWOLoader.h" +#include "PostProcessing/ProcessHelper.h" +#include "PostProcessing/ConvertToLHProcess.h" + #include #include #include -#include "ProcessHelper.h" -#include "ConvertToLHProcess.h" #include #include + #include #include #include @@ -1326,6 +1328,7 @@ void LWOImporter::LoadLWO2File() bool skip = false; LE_NCONST uint8_t* const end = mFileBuffer + fileSize; + unsigned int iUnnamed = 0; while (true) { if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break; @@ -1337,7 +1340,6 @@ void LWOImporter::LoadLWO2File() break; } uint8_t* const next = mFileBuffer+head.length; - unsigned int iUnnamed = 0; if(!head.length) { mFileBuffer = next; diff --git a/code/LWOLoader.h b/code/LWO/LWOLoader.h similarity index 99% rename from code/LWOLoader.h rename to code/LWO/LWOLoader.h index 4d42eb2d2..05b958fd2 100644 --- a/code/LWOLoader.h +++ b/code/LWO/LWOLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/LWOMaterial.cpp b/code/LWO/LWOMaterial.cpp similarity index 99% rename from code/LWOMaterial.cpp rename to code/LWO/LWOMaterial.cpp index 15c210460..b54c21c26 100644 --- a/code/LWOMaterial.cpp +++ b/code/LWO/LWOMaterial.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -320,13 +320,10 @@ void LWOImporter::ConvertMaterial(const LWO::Surface& surf,aiMaterial* pcMat) // opacity ... either additive or default-blended, please if (0.0 != surf.mAdditiveTransparency) { - const int add = aiBlendMode_Additive; pcMat->AddProperty(&surf.mAdditiveTransparency,1,AI_MATKEY_OPACITY); pcMat->AddProperty(&add,1,AI_MATKEY_BLEND_FUNC); - } - - else if (10e10f != surf.mTransparency) { + } else if (10e10f != surf.mTransparency) { const int def = aiBlendMode_Default; const float f = 1.0f-surf.mTransparency; pcMat->AddProperty(&f,1,AI_MATKEY_OPACITY); diff --git a/code/LWSLoader.cpp b/code/LWS/LWSLoader.cpp similarity index 99% rename from code/LWSLoader.cpp rename to code/LWS/LWSLoader.cpp index 6f8cbe78d..b52cafa6d 100644 --- a/code/LWSLoader.cpp +++ b/code/LWS/LWSLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,19 +48,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_LWS_IMPORTER -#include "LWSLoader.h" +#include "LWS/LWSLoader.h" +#include "PostProcessing/ConvertToLHProcess.h" +#include "Common/Importer.h" + #include #include - #include #include #include -#include "ConvertToLHProcess.h" -#include "Importer.h" #include #include #include #include + #include using namespace Assimp; diff --git a/code/LWSLoader.h b/code/LWS/LWSLoader.h similarity index 99% rename from code/LWSLoader.h rename to code/LWS/LWSLoader.h index 9f1636f21..eed0491f3 100644 --- a/code/LWSLoader.h +++ b/code/LWS/LWSLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -46,7 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_LWSLOADER_H_INCLUDED #define AI_LWSLOADER_H_INCLUDED -#include "LWOFileData.h" +#include "LWO/LWOFileData.h" + #include #include diff --git a/code/MD2FileData.h b/code/MD2/MD2FileData.h similarity index 99% rename from code/MD2FileData.h rename to code/MD2/MD2FileData.h index 4b893bbb1..9fcb8b0e2 100644 --- a/code/MD2FileData.h +++ b/code/MD2/MD2FileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/MD2Loader.cpp b/code/MD2/MD2Loader.cpp similarity index 99% rename from code/MD2Loader.cpp rename to code/MD2/MD2Loader.cpp index cfd5458e7..7023c0fa3 100644 --- a/code/MD2Loader.cpp +++ b/code/MD2/MD2Loader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -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; diff --git a/code/MD2Loader.h b/code/MD2/MD2Loader.h similarity index 99% rename from code/MD2Loader.h rename to code/MD2/MD2Loader.h index f26b31736..a3863f366 100644 --- a/code/MD2Loader.h +++ b/code/MD2/MD2Loader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/MD2NormalTable.h b/code/MD2/MD2NormalTable.h similarity index 99% rename from code/MD2NormalTable.h rename to code/MD2/MD2NormalTable.h index dd2c837b4..f82b57683 100644 --- a/code/MD2NormalTable.h +++ b/code/MD2/MD2NormalTable.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/MD3FileData.h b/code/MD3/MD3FileData.h similarity index 97% rename from code/MD3FileData.h rename to code/MD3/MD3FileData.h index 910813fc4..2acd6631f 100644 --- a/code/MD3FileData.h +++ b/code/MD3/MD3FileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -59,7 +59,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -namespace Assimp { +namespace Assimp { namespace MD3 { // to make it easier for us, we test the magic word against both "endianesses" @@ -303,12 +303,12 @@ inline void Vec3NormalToLatLng( const aiVector3D& p_vIn, uint16_t& p_iOut ) b = int(57.2957795f * ( std::acos( p_vIn[2] ) ) * ( 255.0f / 360.0f )); b &= 0xff; - ((unsigned char*)&p_iOut)[0] = b; // longitude - ((unsigned char*)&p_iOut)[1] = a; // latitude + ((unsigned char*)&p_iOut)[0] = (unsigned char) b; // longitude + ((unsigned char*)&p_iOut)[1] = (unsigned char) a; // latitude } } -} -} +} // Namespace MD3 +} // Namespace Assimp #endif // !! AI_MD3FILEHELPER_H_INC diff --git a/code/MD3Loader.cpp b/code/MD3/MD3Loader.cpp similarity index 97% rename from code/MD3Loader.cpp rename to code/MD3/MD3Loader.cpp index d12f2d5fd..1e78b6e05 100644 --- a/code/MD3Loader.cpp +++ b/code/MD3/MD3Loader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -53,19 +53,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_MD3_IMPORTER -#include "MD3Loader.h" +#include "MD3/MD3Loader.h" +#include "Common/Importer.h" + #include #include #include #include -#include "Importer.h" #include -#include #include #include #include #include + #include +#include using namespace Assimp; @@ -258,10 +260,10 @@ bool Q3Shader::LoadSkin(SkinData& fill, const std::string& pFile,IOSystem* io) continue; fill.textures.push_back(SkinData::TextureEntry()); - SkinData::TextureEntry& s = fill.textures.back(); + SkinData::TextureEntry &entry = fill.textures.back(); - s.first = ss; - s.second = GetNextToken(buff); + entry.first = ss; + entry.second = GetNextToken(buff); } return true; } @@ -718,9 +720,7 @@ void MD3Importer::ConvertPath(const char* texture_name, const char* header_name, // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. -void MD3Importer::InternReadFile( const std::string& pFile, - aiScene* pScene, IOSystem* pIOHandler) -{ +void MD3Importer::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { mFile = pFile; mScene = pScene; mIOHandler = pIOHandler; @@ -730,11 +730,13 @@ void MD3Importer::InternReadFile( const std::string& pFile, std::string::size_type s = mFile.find_last_of("/\\"); if (s == std::string::npos) { s = 0; + } else { + ++s; + } + filename = mFile.substr(s), path = mFile.substr(0, s); + for (std::string::iterator it = filename.begin(); it != filename.end(); ++it) { + *it = static_cast( tolower(*it) ); } - else ++s; - filename = mFile.substr(s), path = mFile.substr(0,s); - for( std::string::iterator it = filename .begin(); it != filename.end(); ++it) - *it = tolower( *it); // Load multi-part model file, if necessary if (configHandleMP) { @@ -905,15 +907,15 @@ void MD3Importer::InternReadFile( const std::string& pFile, // Now search the current shader for a record with this name ( // excluding texture file extension) if (!shaders.blocks.empty()) { + std::string::size_type sh = convertedPath.find_last_of('.'); + if (sh == std::string::npos) { + sh = convertedPath.length(); + } - std::string::size_type s = convertedPath.find_last_of('.'); - if (s == std::string::npos) - s = convertedPath.length(); - - const std::string without_ext = convertedPath.substr(0,s); + const std::string without_ext = convertedPath.substr(0,sh); std::list< Q3Shader::ShaderDataBlock >::const_iterator dit = std::find(shaders.blocks.begin(),shaders.blocks.end(),without_ext); if (dit != shaders.blocks.end()) { - // Hurra, wir haben einen. Tolle Sache. + // We made it! shader = &*dit; ASSIMP_LOG_INFO("Found shader record for " +without_ext ); } else { @@ -945,8 +947,7 @@ void MD3Importer::InternReadFile( const std::string& pFile, aiString szString; if (convertedPath.length()) { szString.Set(convertedPath); - } - else { + } else { ASSIMP_LOG_WARN("Texture file name has zero length. Using default name"); szString.Set("dummy_texture.bmp"); } @@ -955,8 +956,7 @@ void MD3Importer::InternReadFile( const std::string& pFile, // prevent transparency by default int no_alpha = aiTextureFlags_IgnoreAlpha; pcHelper->AddProperty(&no_alpha,1,AI_MATKEY_TEXFLAGS_DIFFUSE(0)); - } - else { + } else { Q3Shader::ConvertShaderToMaterial(pcHelper,*shader); } @@ -1026,7 +1026,7 @@ void MD3Importer::InternReadFile( const std::string& pFile, if (!shader || shader->cull == Q3Shader::CULL_CW) { std::swap(pcMesh->mFaces[i].mIndices[2],pcMesh->mFaces[i].mIndices[1]); } - pcTriangles++; + ++pcTriangles; } // Go to the next surface @@ -1042,8 +1042,9 @@ void MD3Importer::InternReadFile( const std::string& pFile, } } - if (!pScene->mNumMeshes) + if (!pScene->mNumMeshes) { throw DeadlyImportError( "MD3: File contains no valid mesh"); + } pScene->mNumMaterials = iNumMaterials; // Now we need to generate an empty node graph @@ -1057,7 +1058,6 @@ void MD3Importer::InternReadFile( const std::string& pFile, pScene->mRootNode->mChildren = new aiNode*[pcHeader->NUM_TAGS]; for (unsigned int i = 0; i < pcHeader->NUM_TAGS; ++i, ++pcTags) { - aiNode* nd = pScene->mRootNode->mChildren[i] = new aiNode(); nd->mName.Set((const char*)pcTags->NAME); nd->mParent = pScene->mRootNode; @@ -1085,8 +1085,12 @@ void MD3Importer::InternReadFile( const std::string& pFile, pScene->mRootNode->mMeshes[i] = i; // Now rotate the whole scene 90 degrees around the x axis to convert to internal coordinate system - pScene->mRootNode->mTransformation = aiMatrix4x4(1.f,0.f,0.f,0.f, - 0.f,0.f,1.f,0.f,0.f,-1.f,0.f,0.f,0.f,0.f,0.f,1.f); + pScene->mRootNode->mTransformation = aiMatrix4x4( + 1.f,0.f,0.f,0.f, + 0.f,0.f,1.f,0.f, + 0.f,-1.f,0.f,0.f, + 0.f,0.f,0.f,1.f + ); } #endif // !! ASSIMP_BUILD_NO_MD3_IMPORTER diff --git a/code/MD3Loader.h b/code/MD3/MD3Loader.h similarity index 99% rename from code/MD3Loader.h rename to code/MD3/MD3Loader.h index 8ac3cdc68..01b840228 100644 --- a/code/MD3Loader.h +++ b/code/MD3/MD3Loader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/MD4FileData.h b/code/MD4/MD4FileData.h similarity index 100% rename from code/MD4FileData.h rename to code/MD4/MD4FileData.h diff --git a/code/MD5Loader.cpp b/code/MD5/MD5Loader.cpp similarity index 97% rename from code/MD5Loader.cpp rename to code/MD5/MD5Loader.cpp index a4285ba03..a4aed8d70 100644 --- a/code/MD5Loader.cpp +++ b/code/MD5/MD5Loader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -53,6 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "MD5Loader.h" #include #include +#include #include #include #include @@ -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() static const aiImporterDesc desc = { @@ -443,10 +444,10 @@ void MD5Importer::LoadMD5MeshFile () for (MD5::VertexList::const_iterator iter = meshSrc.mVertices.begin();iter != meshSrc.mVertices.end();++iter,++pv) { for (unsigned int jub = (*iter).mFirstWeight, w = jub; w < jub + (*iter).mNumWeights;++w) { - MD5::WeightDesc& desc = meshSrc.mWeights[w]; + MD5::WeightDesc& weightDesc = meshSrc.mWeights[w]; /* FIX for some invalid exporters */ - if (!(desc.mWeight < AI_MD5_WEIGHT_EPSILON && desc.mWeight >= -AI_MD5_WEIGHT_EPSILON )) - ++piCount[desc.mBone]; + if (!(weightDesc.mWeight < AI_MD5_WEIGHT_EPSILON && weightDesc.mWeight >= -AI_MD5_WEIGHT_EPSILON )) + ++piCount[weightDesc.mBone]; } } @@ -493,20 +494,20 @@ void MD5Importer::LoadMD5MeshFile () if (w >= meshSrc.mWeights.size()) throw DeadlyImportError("MD5MESH: Invalid weight index"); - MD5::WeightDesc& desc = meshSrc.mWeights[w]; - if ( desc.mWeight < AI_MD5_WEIGHT_EPSILON && desc.mWeight >= -AI_MD5_WEIGHT_EPSILON) { + MD5::WeightDesc& weightDesc = meshSrc.mWeights[w]; + if ( weightDesc.mWeight < AI_MD5_WEIGHT_EPSILON && weightDesc.mWeight >= -AI_MD5_WEIGHT_EPSILON) { continue; } - const ai_real fNewWeight = desc.mWeight / fSum; + const ai_real fNewWeight = weightDesc.mWeight / fSum; // transform the local position into worldspace - MD5::BoneDesc& boneSrc = meshParser.mJoints[desc.mBone]; - const aiVector3D v = boneSrc.mRotationQuatConverted.Rotate (desc.vOffsetPosition); + MD5::BoneDesc& boneSrc = meshParser.mJoints[weightDesc.mBone]; + const aiVector3D v = boneSrc.mRotationQuatConverted.Rotate (weightDesc.vOffsetPosition); // use the original weight to compute the vertex position // (some MD5s seem to depend on the invalid weight values ...) - *pv += ((boneSrc.mPositionXYZ+v)* (ai_real)desc.mWeight); + *pv += ((boneSrc.mPositionXYZ+v)* (ai_real)weightDesc.mWeight); aiBone* bone = mesh->mBones[boneSrc.mMap]; *bone->mWeights++ = aiVertexWeight((unsigned int)(pv-mesh->mVertices),fNewWeight); diff --git a/code/MD5Loader.h b/code/MD5/MD5Loader.h similarity index 99% rename from code/MD5Loader.h rename to code/MD5/MD5Loader.h index 1ba5fea68..e15cc3fb9 100644 --- a/code/MD5Loader.h +++ b/code/MD5/MD5Loader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/MD5Parser.cpp b/code/MD5/MD5Parser.cpp similarity index 99% rename from code/MD5Parser.cpp rename to code/MD5/MD5Parser.cpp index 6f942228c..37490212f 100644 --- a/code/MD5Parser.cpp +++ b/code/MD5/MD5Parser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -47,16 +47,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers -#include "MD5Loader.h" -#include "MaterialSystem.h" +#include "MD5/MD5Loader.h" +#include "Material/MaterialSystem.h" + #include #include #include #include #include - - using namespace Assimp; using namespace Assimp::MD5; @@ -236,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'; // ------------------------------------------------------------------------------------------------ diff --git a/code/MD5Parser.h b/code/MD5/MD5Parser.h similarity index 99% rename from code/MD5Parser.h rename to code/MD5/MD5Parser.h index 853268424..f7ff5303f 100644 --- a/code/MD5Parser.h +++ b/code/MD5/MD5Parser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/MDCFileData.h b/code/MDC/MDCFileData.h similarity index 99% rename from code/MDCFileData.h rename to code/MDC/MDCFileData.h index c599a930a..052473158 100644 --- a/code/MDCFileData.h +++ b/code/MDC/MDCFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/MDCLoader.cpp b/code/MDC/MDCLoader.cpp similarity index 99% rename from code/MDCLoader.cpp rename to code/MDC/MDCLoader.cpp index 03b3336de..084ec6024 100644 --- a/code/MDCLoader.cpp +++ b/code/MDC/MDCLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -47,16 +47,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_MDC_IMPORTER // internal headers -#include "MDCLoader.h" -#include "MD3FileData.h" -#include "MDCNormalTable.h" // shouldn't be included by other units +#include "MDC/MDCLoader.h" +#include "MD3/MD3FileData.h" +#include "MDC/MDCNormalTable.h" // shouldn't be included by other units + #include #include #include #include #include -#include +#include using namespace Assimp; using namespace Assimp::MDC; diff --git a/code/MDCLoader.h b/code/MDC/MDCLoader.h similarity index 99% rename from code/MDCLoader.h rename to code/MDC/MDCLoader.h index 5bbe2b666..a21b8a55a 100644 --- a/code/MDCLoader.h +++ b/code/MDC/MDCLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/MDCNormalTable.h b/code/MDC/MDCNormalTable.h similarity index 100% rename from code/MDCNormalTable.h rename to code/MDC/MDCNormalTable.h diff --git a/code/MDLDefaultColorMap.h b/code/MDL/MDLDefaultColorMap.h similarity index 99% rename from code/MDLDefaultColorMap.h rename to code/MDL/MDLDefaultColorMap.h index b96a60a06..58f642884 100644 --- a/code/MDLDefaultColorMap.h +++ b/code/MDL/MDLDefaultColorMap.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/MDLFileData.h b/code/MDL/MDLFileData.h similarity index 99% rename from code/MDLFileData.h rename to code/MDL/MDLFileData.h index f9be6761b..f33a57731 100644 --- a/code/MDLFileData.h +++ b/code/MDL/MDLFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/MDLLoader.cpp b/code/MDL/MDLLoader.cpp similarity index 99% rename from code/MDLLoader.cpp rename to code/MDL/MDLLoader.cpp index eb067a1c9..d71057d55 100644 --- a/code/MDLLoader.cpp +++ b/code/MDL/MDLLoader.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -50,11 +48,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_MDL_IMPORTER -#include "MDLLoader.h" -#include +#include "MDL/MDLLoader.h" +#include "MDL/MDLDefaultColorMap.h" +#include "MD2/MD2FileData.h" + #include -#include "MDLDefaultColorMap.h" -#include "MD2FileData.h" #include #include #include @@ -93,23 +91,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 @@ -403,23 +402,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)); diff --git a/code/MDLLoader.h b/code/MDL/MDLLoader.h similarity index 99% rename from code/MDLLoader.h rename to code/MDL/MDLLoader.h index f1504beea..c5ebac024 100644 --- a/code/MDLLoader.h +++ b/code/MDL/MDLLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -50,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "MDLFileData.h" -#include "HalfLifeFileData.h" +#include "HMP/HalfLifeFileData.h" struct aiNode; struct aiTexture; @@ -89,16 +89,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 +103,6 @@ public: void SetupProperties(const Importer* pImp); protected: - - // ------------------------------------------------------------------- /** Return importer meta information. * See #BaseImporter::GetInfo for the details @@ -122,8 +116,6 @@ protected: void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); -protected: - // ------------------------------------------------------------------- /** Import a quake 1 MDL file (IDPO) */ @@ -154,7 +146,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 +158,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 +169,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 +184,6 @@ protected: unsigned int iType, unsigned int* piSkip); - // ------------------------------------------------------------------- /** Used to load textures from MDL5 * \param szData Input data @@ -206,7 +194,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 +205,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 +230,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 diff --git a/code/MDLMaterialLoader.cpp b/code/MDL/MDLMaterialLoader.cpp similarity index 99% rename from code/MDLMaterialLoader.cpp rename to code/MDL/MDLMaterialLoader.cpp index 2c21b188b..0a196761f 100644 --- a/code/MDLMaterialLoader.cpp +++ b/code/MDL/MDLMaterialLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/MMDCpp14.h b/code/MMD/MMDCpp14.h similarity index 98% rename from code/MMDCpp14.h rename to code/MMD/MMDCpp14.h index 5ec2fd975..638b0bfd2 100644 --- a/code/MMDCpp14.h +++ b/code/MMD/MMDCpp14.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/MMDImporter.cpp b/code/MMD/MMDImporter.cpp similarity index 98% rename from code/MMDImporter.cpp rename to code/MMD/MMDImporter.cpp index 84b9e35a6..e7744e4cd 100644 --- a/code/MMDImporter.cpp +++ b/code/MMD/MMDImporter.cpp @@ -41,15 +41,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_MMD_IMPORTER -#include "MMDImporter.h" -#include "MMDPmdParser.h" -#include "MMDPmxParser.h" -#include "MMDVmdParser.h" -#include "ConvertToLHProcess.h" +#include "MMD/MMDImporter.h" +#include "MMD/MMDPmdParser.h" +#include "MMD/MMDPmxParser.h" +#include "MMD/MMDVmdParser.h" +#include "PostProcessing/ConvertToLHProcess.h" + #include #include #include #include + #include #include #include diff --git a/code/MMDImporter.h b/code/MMD/MMDImporter.h similarity index 100% rename from code/MMDImporter.h rename to code/MMD/MMDImporter.h diff --git a/code/MMDPmdParser.h b/code/MMD/MMDPmdParser.h similarity index 99% rename from code/MMDPmdParser.h rename to code/MMD/MMDPmdParser.h index d61a355fb..d2f2224aa 100644 --- a/code/MMDPmdParser.h +++ b/code/MMD/MMDPmdParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/MMDPmxParser.cpp b/code/MMD/MMDPmxParser.cpp similarity index 99% rename from code/MMDPmxParser.cpp rename to code/MMD/MMDPmxParser.cpp index 2c5bd9a8d..80f0986dd 100644 --- a/code/MMDPmxParser.cpp +++ b/code/MMD/MMDPmxParser.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -42,7 +42,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "MMDPmxParser.h" #include -#include "../contrib/utf8cpp/source/utf8.h" +#ifdef ASSIMP_USE_HUNTER +# include +#else +# include "../contrib/utf8cpp/source/utf8.h" +#endif #include namespace pmx diff --git a/code/MMDPmxParser.h b/code/MMD/MMDPmxParser.h similarity index 99% rename from code/MMDPmxParser.h rename to code/MMD/MMDPmxParser.h index 43cad5899..cf523a129 100644 --- a/code/MMDPmxParser.h +++ b/code/MMD/MMDPmxParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/MMDVmdParser.h b/code/MMD/MMDVmdParser.h similarity index 99% rename from code/MMDVmdParser.h rename to code/MMD/MMDVmdParser.h index 600959e94..947c3a242 100644 --- a/code/MMDVmdParser.h +++ b/code/MMD/MMDVmdParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/MS3DLoader.cpp b/code/MS3D/MS3DLoader.cpp similarity index 99% rename from code/MS3DLoader.cpp rename to code/MS3D/MS3DLoader.cpp index c659d2ec7..c0d0eddbe 100644 --- a/code/MS3DLoader.cpp +++ b/code/MS3D/MS3DLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/MS3DLoader.h b/code/MS3D/MS3DLoader.h similarity index 99% rename from code/MS3DLoader.h rename to code/MS3D/MS3DLoader.h index 2efa3be5f..3e39dc79f 100644 --- a/code/MS3DLoader.h +++ b/code/MS3D/MS3DLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/MaterialSystem.cpp b/code/Material/MaterialSystem.cpp similarity index 95% rename from code/MaterialSystem.cpp rename to code/Material/MaterialSystem.cpp index e9ca475fb..0be6e9f7b 100644 --- a/code/MaterialSystem.cpp +++ b/code/Material/MaterialSystem.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -51,7 +51,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include using namespace Assimp; @@ -96,12 +95,12 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat, ai_real* pOut, unsigned int* pMax) { - ai_assert( pOut != NULL ); - ai_assert( pMat != NULL ); + ai_assert( pOut != nullptr ); + ai_assert( pMat != nullptr ); const aiMaterialProperty* prop; aiGetMaterialProperty(pMat,pKey,type,index, (const aiMaterialProperty**) &prop); - if (!prop) { + if ( nullptr == prop) { return AI_FAILURE; } @@ -112,9 +111,11 @@ aiReturn aiGetMaterialFloatArray(const aiMaterial* pMat, if (pMax) { iWrite = std::min(*pMax,iWrite); ; } - for (unsigned int a = 0; a < iWrite;++a) { - pOut[a] = static_cast ( reinterpret_cast(prop->mData)[a] ); + + for (unsigned int a = 0; a < iWrite; ++a) { + pOut[ a ] = static_cast ( reinterpret_cast(prop->mData)[a] ); } + if (pMax) { *pMax = iWrite; } @@ -543,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(©.length); - s[1] = static_cast(pInput->length); - - return AddBinaryProperty(s+1, - static_cast(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(pInput->length+1+4), pKey, diff --git a/code/MaterialSystem.h b/code/Material/MaterialSystem.h similarity index 98% rename from code/MaterialSystem.h rename to code/Material/MaterialSystem.h index d6f2cea46..67d53578c 100644 --- a/code/MaterialSystem.h +++ b/code/Material/MaterialSystem.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/NDOLoader.cpp b/code/NDO/NDOLoader.cpp similarity index 99% rename from code/NDOLoader.cpp rename to code/NDO/NDOLoader.cpp index 17c9e135b..d33f40c75 100644 --- a/code/NDOLoader.cpp +++ b/code/NDO/NDOLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/NDOLoader.h b/code/NDO/NDOLoader.h similarity index 100% rename from code/NDOLoader.h rename to code/NDO/NDOLoader.h diff --git a/code/NFFLoader.cpp b/code/NFF/NFFLoader.cpp similarity index 99% rename from code/NFFLoader.cpp rename to code/NFF/NFFLoader.cpp index 1c7283db6..10a7d1aff 100644 --- a/code/NFFLoader.cpp +++ b/code/NFF/NFFLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/NFFLoader.h b/code/NFF/NFFLoader.h similarity index 99% rename from code/NFFLoader.h rename to code/NFF/NFFLoader.h index 1e3f0bd26..bc4840e14 100644 --- a/code/NFFLoader.h +++ b/code/NFF/NFFLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/OFFLoader.cpp b/code/OFF/OFFLoader.cpp similarity index 99% rename from code/OFFLoader.cpp rename to code/OFF/OFFLoader.cpp index a72e6d9d4..afd44a539 100644 --- a/code/OFFLoader.cpp +++ b/code/OFF/OFFLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/OFFLoader.h b/code/OFF/OFFLoader.h similarity index 98% rename from code/OFFLoader.h rename to code/OFF/OFFLoader.h index ed1ed98c1..3fca77e1b 100644 --- a/code/OFFLoader.h +++ b/code/OFF/OFFLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/ObjExporter.cpp b/code/Obj/ObjExporter.cpp similarity index 99% rename from code/ObjExporter.cpp rename to code/Obj/ObjExporter.cpp index 1542efebf..0a0dbd62c 100644 --- a/code/ObjExporter.cpp +++ b/code/Obj/ObjExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -126,9 +126,9 @@ ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene, bool noMt // make sure that all formatting happens using the standard, C locale and not the user's current locale const std::locale& l = std::locale("C"); mOutput.imbue(l); - mOutput.precision(16); + mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION); mOutputMat.imbue(l); - mOutputMat.precision(16); + mOutputMat.precision(ASSIMP_AI_REAL_TEXT_PRECISION); WriteGeometryFile(noMtl); if ( !noMtl ) { diff --git a/code/ObjExporter.h b/code/Obj/ObjExporter.h similarity index 99% rename from code/ObjExporter.h rename to code/Obj/ObjExporter.h index bd745b593..0d2b48d6b 100644 --- a/code/ObjExporter.h +++ b/code/Obj/ObjExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/ObjFileData.h b/code/Obj/ObjFileData.h similarity index 98% rename from code/ObjFileData.h rename to code/Obj/ObjFileData.h index 38786e6f4..a2d9f2cc7 100644 --- a/code/ObjFileData.h +++ b/code/Obj/ObjFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -281,6 +281,8 @@ struct Model { std::string m_strActiveGroup; //! Vector with generated texture coordinates std::vector m_TextureCoord; + //! Maximum dimension of texture coordinates + unsigned int m_TextureCoordDim; //! Current mesh instance Mesh *m_pCurrentMesh; //! Vector with stored meshes @@ -296,6 +298,7 @@ struct Model { m_pDefaultMaterial(NULL), m_pGroupFaceIDs(NULL), m_strActiveGroup(""), + m_TextureCoordDim(0), m_pCurrentMesh(NULL) { // empty diff --git a/code/ObjFileImporter.cpp b/code/Obj/ObjFileImporter.cpp similarity index 93% rename from code/ObjFileImporter.cpp rename to code/Obj/ObjFileImporter.cpp index 6fd48cfa1..26cc6d1f9 100644 --- a/code/ObjFileImporter.cpp +++ b/code/Obj/ObjFileImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -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. @@ -144,38 +141,6 @@ void ObjFileImporter::InternReadFile( const std::string &file, aiScene* pScene, modelName = file; } - // This next stage takes ~ 1/3th of the total readFile task - // so should amount for 1/3th of the progress - // only update every 100KB or it'll be too slow - /*unsigned int progress = 0; - unsigned int progressCounter = 0; - const unsigned int updateProgressEveryBytes = 100 * 1024; - const unsigned int progressTotal = static_cast(3*m_Buffer.size()/updateProgressEveryBytes);*/ - // process all '\' - /*std::vector ::iterator iter = m_Buffer.begin(); - while (iter != m_Buffer.end()) - { - if (*iter == '\\') - { - // remove '\' - iter = m_Buffer.erase(iter); - // remove next character - while (*iter == '\r' || *iter == '\n') - iter = m_Buffer.erase(iter); - } - else - ++iter; - - if (++progressCounter >= updateProgressEveryBytes) - { - m_progress->UpdateFileRead(++progress, progressTotal); - progressCounter = 0; - } - }*/ - - // 1/3rd progress - m_progress->UpdateFileRead(1, 3); - // parse the file into a temporary representation ObjFileParser parser( streamedBuffer, modelName, pIOHandler, m_progress, file); @@ -474,11 +439,12 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel, // Allocate buffer for texture coordinates if ( !pModel->m_TextureCoord.empty() && pObjMesh->m_uiUVCoordinates[0] ) { - pMesh->mNumUVComponents[ 0 ] = 2; + pMesh->mNumUVComponents[ 0 ] = pModel->m_TextureCoordDim; pMesh->mTextureCoords[ 0 ] = new aiVector3D[ pMesh->mNumVertices ]; } // Copy vertices, normals and textures into aiMesh instance + bool normalsok = true, uvok = true; unsigned int newIndex = 0, outIndex = 0; for ( size_t index=0; index < pObjMesh->m_Faces.size(); index++ ) { // Get source face @@ -498,12 +464,16 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel, pMesh->mVertices[ newIndex ] = pModel->m_Vertices[ vertex ]; // Copy all normals - if ( !pModel->m_Normals.empty() && vertexIndex < pSourceFace->m_normals.size()) { + if ( normalsok && !pModel->m_Normals.empty() && vertexIndex < pSourceFace->m_normals.size()) { const unsigned int normal = pSourceFace->m_normals.at( vertexIndex ); - if ( normal >= pModel->m_Normals.size() ) { - throw DeadlyImportError( "OBJ: vertex normal index out of range" ); + if ( normal >= pModel->m_Normals.size() ) + { + normalsok = false; + } + else + { + pMesh->mNormals[ newIndex ] = pModel->m_Normals[ normal ]; } - pMesh->mNormals[ newIndex ] = pModel->m_Normals[ normal ]; } // Copy all vertex colors @@ -514,15 +484,19 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel, } // Copy all texture coordinates - if ( !pModel->m_TextureCoord.empty() && vertexIndex < pSourceFace->m_texturCoords.size()) + if ( uvok && !pModel->m_TextureCoord.empty() && vertexIndex < pSourceFace->m_texturCoords.size()) { const unsigned int tex = pSourceFace->m_texturCoords.at( vertexIndex ); if ( tex >= pModel->m_TextureCoord.size() ) - throw DeadlyImportError("OBJ: texture coordinate index out of range"); - - const aiVector3D &coord3d = pModel->m_TextureCoord[ tex ]; - pMesh->mTextureCoords[ 0 ][ newIndex ] = aiVector3D( coord3d.x, coord3d.y, coord3d.z ); + { + uvok = false; + } + else + { + const aiVector3D &coord3d = pModel->m_TextureCoord[ tex ]; + pMesh->mTextureCoords[ 0 ][ newIndex ] = aiVector3D( coord3d.x, coord3d.y, coord3d.z ); + } } // Get destination face @@ -566,6 +540,18 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model* pModel, ++newIndex; } } + + if (!normalsok) + { + delete [] pMesh->mNormals; + pMesh->mNormals = nullptr; + } + + if (!uvok) + { + delete [] pMesh->mTextureCoords[0]; + pMesh->mTextureCoords[0] = nullptr; + } } // ------------------------------------------------------------------------------------------------ diff --git a/code/ObjFileImporter.h b/code/Obj/ObjFileImporter.h similarity index 99% rename from code/ObjFileImporter.h rename to code/Obj/ObjFileImporter.h index f564fe22b..0df2ef731 100644 --- a/code/ObjFileImporter.h +++ b/code/Obj/ObjFileImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/ObjFileMtlImporter.cpp b/code/Obj/ObjFileMtlImporter.cpp similarity index 99% rename from code/ObjFileMtlImporter.cpp rename to code/Obj/ObjFileMtlImporter.cpp index 16bde1b43..dd9cc3ce2 100644 --- a/code/ObjFileMtlImporter.cpp +++ b/code/Obj/ObjFileMtlImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/ObjFileMtlImporter.h b/code/Obj/ObjFileMtlImporter.h similarity index 99% rename from code/ObjFileMtlImporter.h rename to code/Obj/ObjFileMtlImporter.h index d6a7b1f1a..731952359 100644 --- a/code/ObjFileMtlImporter.h +++ b/code/Obj/ObjFileMtlImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/ObjFileParser.cpp b/code/Obj/ObjFileParser.cpp similarity index 95% rename from code/ObjFileParser.cpp rename to code/Obj/ObjFileParser.cpp index 7630127fa..699aafe6a 100644 --- a/code/ObjFileParser.cpp +++ b/code/Obj/ObjFileParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -113,8 +113,7 @@ void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { //const unsigned int updateProgressEveryBytes = 100 * 1024; unsigned int progressCounter = 0; const unsigned int bytesToProcess = static_cast(streamBuffer.size()); - const unsigned int progressTotal = 3 * bytesToProcess; - const unsigned int progressOffset = bytesToProcess; + const unsigned int progressTotal = bytesToProcess; unsigned int processed = 0; size_t lastFilePos( 0 ); @@ -126,10 +125,10 @@ void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { // Handle progress reporting const size_t filePos( streamBuffer.getFilePos() ); if ( lastFilePos < filePos ) { - processed += static_cast(filePos); + processed = static_cast(filePos); lastFilePos = filePos; progressCounter++; - m_progress->UpdateFileRead( progressOffset + processed * 2, progressTotal ); + m_progress->UpdateFileRead( processed, progressTotal ); } // parse line @@ -152,7 +151,8 @@ void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { } else if (*m_DataIt == 't') { // read in texture coordinate ( 2D or 3D ) ++m_DataIt; - getVector( m_pModel->m_TextureCoord ); + size_t dim = getTexCoordVector(m_pModel->m_TextureCoord); + m_pModel->m_TextureCoordDim = std::max(m_pModel->m_TextureCoordDim, (unsigned int)dim); } else if (*m_DataIt == 'n') { // Read in normal vector definition ++m_DataIt; @@ -244,8 +244,8 @@ void ObjFileParser::copyNextWord(char *pBuffer, size_t length) { size_t index = 0; m_DataIt = getNextWord(m_DataIt, m_DataItEnd); if ( *m_DataIt == '\\' ) { - m_DataIt++; - m_DataIt++; + ++m_DataIt; + ++m_DataIt; m_DataIt = getNextWord( m_DataIt, m_DataItEnd ); } while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) { @@ -272,6 +272,17 @@ static bool isDataDefinitionEnd( const char *tmp ) { return false; } +static bool isNanOrInf(const char * in) { + // Look for "nan" or "inf", case insensitive + if ((in[0] == 'N' || in[0] == 'n') && ASSIMP_strincmp(in, "nan", 3) == 0) { + return true; + } + else if ((in[0] == 'I' || in[0] == 'i') && ASSIMP_strincmp(in, "inf", 3) == 0) { + return true; + } + return false; +} + size_t ObjFileParser::getNumComponentsInDataDefinition() { size_t numComponents( 0 ); const char* tmp( &m_DataIt[0] ); @@ -285,7 +296,7 @@ size_t ObjFileParser::getNumComponentsInDataDefinition() { if ( !SkipSpaces( &tmp ) ) { break; } - const bool isNum( IsNumeric( *tmp ) ); + const bool isNum( IsNumeric( *tmp ) || isNanOrInf(tmp)); SkipToken( tmp ); if ( isNum ) { ++numComponents; @@ -297,7 +308,7 @@ size_t ObjFileParser::getNumComponentsInDataDefinition() { return numComponents; } -void ObjFileParser::getVector( std::vector &point3d_array ) { +size_t ObjFileParser::getTexCoordVector( std::vector &point3d_array ) { size_t numComponents = getNumComponentsInDataDefinition(); ai_real x, y, z; if( 2 == numComponents ) { @@ -319,8 +330,20 @@ void ObjFileParser::getVector( std::vector &point3d_array ) { } else { throw DeadlyImportError( "OBJ: Invalid number of components" ); } + + // Coerce nan and inf to 0 as is the OBJ default value + if (!std::isfinite(x)) + x = 0; + + if (!std::isfinite(y)) + y = 0; + + if (!std::isfinite(z)) + z = 0; + point3d_array.push_back( aiVector3D( x, y, z ) ); m_DataIt = skipLine( m_DataIt, m_DataItEnd, m_uiLine ); + return numComponents; } void ObjFileParser::getVector3( std::vector &point3d_array ) { @@ -428,13 +451,6 @@ void ObjFileParser::getFace( aiPrimitiveType type ) { if (type == aiPrimitiveType_POINT) { ASSIMP_LOG_ERROR("Obj: Separator unexpected in point statement"); } - if (iPos == 0) { - //if there are no texture coordinates in the file, but normals - if (!vt && vn) { - iPos = 1; - iStep++; - } - } iPos++; } else if( IsSpaceOrNewLine( *m_DataIt ) ) { iPos = 0; @@ -451,6 +467,9 @@ void ObjFileParser::getFace( aiPrimitiveType type ) { ++iStep; } + if (iPos == 1 && !vt && vn) + iPos = 2; // skip texture coords for normals if there are no tex coords + if ( iVal > 0 ) { // Store parsed index if ( 0 == iPos ) { diff --git a/code/ObjFileParser.h b/code/Obj/ObjFileParser.h similarity index 98% rename from code/ObjFileParser.h rename to code/Obj/ObjFileParser.h index 7cf06ae05..7d1b806ce 100644 --- a/code/ObjFileParser.h +++ b/code/Obj/ObjFileParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -96,7 +96,7 @@ protected: /// Get the number of components in a line. size_t getNumComponentsInDataDefinition(); /// Stores the vector - void getVector( std::vector &point3d_array ); + size_t getTexCoordVector( std::vector &point3d_array ); /// Stores the following 3d vector. void getVector3( std::vector &point3d_array ); /// Stores the following homogeneous vector as a 3D vector diff --git a/code/ObjTools.h b/code/Obj/ObjTools.h similarity index 99% rename from code/ObjTools.h rename to code/Obj/ObjTools.h index 842efd749..3f4c41033 100644 --- a/code/ObjTools.h +++ b/code/Obj/ObjTools.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/OgreBinarySerializer.cpp b/code/Ogre/OgreBinarySerializer.cpp similarity index 99% rename from code/OgreBinarySerializer.cpp rename to code/Ogre/OgreBinarySerializer.cpp index 8948844d0..589e69c7e 100644 --- a/code/OgreBinarySerializer.cpp +++ b/code/Ogre/OgreBinarySerializer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -864,6 +864,8 @@ bool OgreBinarySerializer::ImportSkeleton(Assimp::IOSystem *pIOHandler, Mesh *me } MemoryStreamReaderPtr reader = OpenReader(pIOHandler, mesh->skeletonRef); + if (!reader) + return false; Skeleton *skeleton = new Skeleton(); OgreBinarySerializer serializer(reader.get(), OgreBinarySerializer::AM_Skeleton); diff --git a/code/OgreBinarySerializer.h b/code/Ogre/OgreBinarySerializer.h similarity index 99% rename from code/OgreBinarySerializer.h rename to code/Ogre/OgreBinarySerializer.h index a31047c70..8bab00ce9 100644 --- a/code/OgreBinarySerializer.h +++ b/code/Ogre/OgreBinarySerializer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/OgreImporter.cpp b/code/Ogre/OgreImporter.cpp similarity index 99% rename from code/OgreImporter.cpp rename to code/Ogre/OgreImporter.cpp index e77654d7b..c2c328a47 100644 --- a/code/OgreImporter.cpp +++ b/code/Ogre/OgreImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/OgreImporter.h b/code/Ogre/OgreImporter.h similarity index 99% rename from code/OgreImporter.h rename to code/Ogre/OgreImporter.h index 8f088a3cc..321d58763 100644 --- a/code/OgreImporter.h +++ b/code/Ogre/OgreImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/OgreMaterial.cpp b/code/Ogre/OgreMaterial.cpp similarity index 99% rename from code/OgreMaterial.cpp rename to code/Ogre/OgreMaterial.cpp index ceca04da1..47cb17eb0 100644 --- a/code/OgreMaterial.cpp +++ b/code/Ogre/OgreMaterial.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/OgreParsingUtils.h b/code/Ogre/OgreParsingUtils.h similarity index 99% rename from code/OgreParsingUtils.h rename to code/Ogre/OgreParsingUtils.h index c6b6e0caf..8786521e4 100644 --- a/code/OgreParsingUtils.h +++ b/code/Ogre/OgreParsingUtils.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/OgreStructs.cpp b/code/Ogre/OgreStructs.cpp similarity index 99% rename from code/OgreStructs.cpp rename to code/Ogre/OgreStructs.cpp index b2ad8e089..7962202c1 100644 --- a/code/OgreStructs.cpp +++ b/code/Ogre/OgreStructs.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/OgreStructs.h b/code/Ogre/OgreStructs.h similarity index 99% rename from code/OgreStructs.h rename to code/Ogre/OgreStructs.h index dfe0346dc..6ea211e10 100644 --- a/code/OgreStructs.h +++ b/code/Ogre/OgreStructs.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/OgreXmlSerializer.cpp b/code/Ogre/OgreXmlSerializer.cpp similarity index 99% rename from code/OgreXmlSerializer.cpp rename to code/Ogre/OgreXmlSerializer.cpp index 5805a528d..19fd3ad61 100644 --- a/code/OgreXmlSerializer.cpp +++ b/code/Ogre/OgreXmlSerializer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/OgreXmlSerializer.h b/code/Ogre/OgreXmlSerializer.h similarity index 99% rename from code/OgreXmlSerializer.h rename to code/Ogre/OgreXmlSerializer.h index c0f09096c..7e5e83fec 100644 --- a/code/OgreXmlSerializer.h +++ b/code/Ogre/OgreXmlSerializer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/OpenGEXExporter.cpp b/code/OpenGEX/OpenGEXExporter.cpp similarity index 98% rename from code/OpenGEXExporter.cpp rename to code/OpenGEX/OpenGEXExporter.cpp index ea2f64e8f..635174185 100644 --- a/code/OpenGEXExporter.cpp +++ b/code/OpenGEX/OpenGEXExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/OpenGEXExporter.h b/code/OpenGEX/OpenGEXExporter.h similarity index 98% rename from code/OpenGEXExporter.h rename to code/OpenGEX/OpenGEXExporter.h index 76d2418a4..b9b54c208 100644 --- a/code/OpenGEXExporter.h +++ b/code/OpenGEX/OpenGEXExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/OpenGEXImporter.cpp b/code/OpenGEX/OpenGEXImporter.cpp similarity index 99% rename from code/OpenGEXImporter.cpp rename to code/OpenGEX/OpenGEXImporter.cpp index 2de0aabc0..07d3efd5e 100644 --- a/code/OpenGEXImporter.cpp +++ b/code/OpenGEX/OpenGEXImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -41,10 +41,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef ASSIMP_BUILD_NO_OPENGEX_IMPORTER -#include "OpenGEXImporter.h" +#include "OpenGEX/OpenGEXImporter.h" +#include "PostProcessing/MakeVerboseFormat.h" + #include #include -#include "MakeVerboseFormat.h" #include #include @@ -212,7 +213,11 @@ static void propId2StdString( Property *prop, std::string &name, std::string &ke } if ( nullptr != prop->m_key ) { +#ifdef ASSIMP_USE_HUNTER + name = prop->m_key->m_text.m_buffer; +#else name = prop->m_key->m_buffer; +#endif if ( Value::ddl_string == prop->m_value->m_type ) { key = prop->m_value->getString(); } @@ -497,7 +502,11 @@ static void getRefNames( DDLNode *node, std::vector &names ) { for( size_t i = 0; i < ref->m_numRefs; i++ ) { Name *currentName( ref->m_referencedName[ i ] ); if( nullptr != currentName && nullptr != currentName->m_id ) { +#ifdef ASSIMP_USE_HUNTER + const std::string name( currentName->m_id->m_text.m_buffer ); +#else const std::string name( currentName->m_id->m_buffer ); +#endif if( !name.empty() ) { names.push_back( name ); } @@ -1038,7 +1047,11 @@ void OpenGEXImporter::handleColorNode( ODDLParser::DDLNode *node, aiScene * /*pS col.g = col4.g; col.b = col4.b; } +#ifdef ASSIMP_USE_HUNTER + const ColorType colType( getColorType( &prop->m_key->m_text ) ); +#else const ColorType colType( getColorType( prop->m_key ) ); +#endif if( DiffuseColor == colType ) { m_currentMaterial->AddProperty( &col, 1, AI_MATKEY_COLOR_DIFFUSE ); } else if( SpecularColor == colType ) { diff --git a/code/OpenGEXImporter.h b/code/OpenGEX/OpenGEXImporter.h similarity index 99% rename from code/OpenGEXImporter.h rename to code/OpenGEX/OpenGEXImporter.h index 8e86a4aa8..22b5cabef 100644 --- a/code/OpenGEXImporter.h +++ b/code/OpenGEX/OpenGEXImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/OpenGEXStructs.h b/code/OpenGEX/OpenGEXStructs.h similarity index 99% rename from code/OpenGEXStructs.h rename to code/OpenGEX/OpenGEXStructs.h index 6cd7488e9..2c83e8660 100644 --- a/code/OpenGEXStructs.h +++ b/code/OpenGEX/OpenGEXStructs.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/PlyExporter.cpp b/code/Ply/PlyExporter.cpp similarity index 99% rename from code/PlyExporter.cpp rename to code/Ply/PlyExporter.cpp index 31c64a4d1..5e21a88ac 100644 --- a/code/PlyExporter.cpp +++ b/code/Ply/PlyExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -111,7 +111,7 @@ PlyExporter::PlyExporter(const char* _filename, const aiScene* pScene, bool bina // make sure that all formatting happens using the standard, C locale and not the user's current locale const std::locale& l = std::locale("C"); mOutput.imbue(l); - mOutput.precision(16); + mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION); unsigned int faces = 0u, vertices = 0u, components = 0u; for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { diff --git a/code/PlyExporter.h b/code/Ply/PlyExporter.h similarity index 98% rename from code/PlyExporter.h rename to code/Ply/PlyExporter.h index 060aa7ceb..b82498cbd 100644 --- a/code/PlyExporter.h +++ b/code/Ply/PlyExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/PlyLoader.cpp b/code/Ply/PlyLoader.cpp similarity index 99% rename from code/PlyLoader.cpp rename to code/Ply/PlyLoader.cpp index 7e55e6c3e..ca1ec22f8 100644 --- a/code/PlyLoader.cpp +++ b/code/Ply/PlyLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -49,7 +49,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers #include "PlyLoader.h" #include -#include #include #include #include diff --git a/code/PlyLoader.h b/code/Ply/PlyLoader.h similarity index 99% rename from code/PlyLoader.h rename to code/Ply/PlyLoader.h index 9199e17d7..201c463b2 100644 --- a/code/PlyLoader.h +++ b/code/Ply/PlyLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/PlyParser.cpp b/code/Ply/PlyParser.cpp similarity index 99% rename from code/PlyParser.cpp rename to code/Ply/PlyParser.cpp index b51b6ac71..2a6f00ad6 100644 --- a/code/PlyParser.cpp +++ b/code/Ply/PlyParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/PlyParser.h b/code/Ply/PlyParser.h similarity index 99% rename from code/PlyParser.h rename to code/Ply/PlyParser.h index b544c3b04..a11b411d1 100644 --- a/code/PlyParser.h +++ b/code/Ply/PlyParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/CalcTangentsProcess.cpp b/code/PostProcessing/CalcTangentsProcess.cpp similarity index 98% rename from code/CalcTangentsProcess.cpp rename to code/PostProcessing/CalcTangentsProcess.cpp index 54e55fc5a..a3f7dd255 100644 --- a/code/CalcTangentsProcess.cpp +++ b/code/PostProcessing/CalcTangentsProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -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(); } } diff --git a/code/CalcTangentsProcess.h b/code/PostProcessing/CalcTangentsProcess.h similarity index 97% rename from code/CalcTangentsProcess.h rename to code/PostProcessing/CalcTangentsProcess.h index 4cac2ed9f..3568a624f 100644 --- a/code/CalcTangentsProcess.h +++ b/code/PostProcessing/CalcTangentsProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -42,11 +42,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Defines a post processing step to calculate tangents and - bitangents on all imported meshes.*/ + bi-tangents on all imported meshes.*/ #ifndef AI_CALCTANGENTSPROCESS_H_INC #define AI_CALCTANGENTSPROCESS_H_INC -#include "BaseProcess.h" +#include "Common/BaseProcess.h" struct aiMesh; diff --git a/code/ComputeUVMappingProcess.cpp b/code/PostProcessing/ComputeUVMappingProcess.cpp similarity index 99% rename from code/ComputeUVMappingProcess.cpp rename to code/PostProcessing/ComputeUVMappingProcess.cpp index 3b0577b2d..df4d44337 100644 --- a/code/ComputeUVMappingProcess.cpp +++ b/code/PostProcessing/ComputeUVMappingProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -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 diff --git a/code/ComputeUVMappingProcess.h b/code/PostProcessing/ComputeUVMappingProcess.h similarity index 98% rename from code/ComputeUVMappingProcess.h rename to code/PostProcessing/ComputeUVMappingProcess.h index 41e25f99f..a6d36e06e 100644 --- a/code/ComputeUVMappingProcess.h +++ b/code/PostProcessing/ComputeUVMappingProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,7 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_COMPUTEUVMAPPING_H_INC #define AI_COMPUTEUVMAPPING_H_INC -#include "BaseProcess.h" +#include "Common/BaseProcess.h" + #include #include #include diff --git a/code/ConvertToLHProcess.cpp b/code/PostProcessing/ConvertToLHProcess.cpp similarity index 83% rename from code/ConvertToLHProcess.cpp rename to code/PostProcessing/ConvertToLHProcess.cpp index 9cb45cc69..b7cd4f0bc 100644 --- a/code/ConvertToLHProcess.cpp +++ b/code/PostProcessing/ConvertToLHProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -166,8 +166,9 @@ void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) { for( size_t a = 0; a < pMesh->mNumVertices; ++a) { pMesh->mVertices[a].z *= -1.0f; - if( pMesh->HasNormals()) + if (pMesh->HasNormals()) { pMesh->mNormals[a].z *= -1.0f; + } if( pMesh->HasTangentsAndBitangents()) { pMesh->mTangents[a].z *= -1.0f; @@ -175,6 +176,23 @@ void MakeLeftHandedProcess::ProcessMesh( aiMesh* pMesh) { } } + // mirror anim meshes positions, normals and stuff along the Z axis + for (size_t m = 0; m < pMesh->mNumAnimMeshes; ++m) + { + for (size_t a = 0; a < pMesh->mAnimMeshes[m]->mNumVertices; ++a) + { + pMesh->mAnimMeshes[m]->mVertices[a].z *= -1.0f; + if (pMesh->mAnimMeshes[m]->HasNormals()) { + pMesh->mAnimMeshes[m]->mNormals[a].z *= -1.0f; + } + if (pMesh->mAnimMeshes[m]->HasTangentsAndBitangents()) + { + pMesh->mAnimMeshes[m]->mTangents[a].z *= -1.0f; + pMesh->mAnimMeshes[m]->mBitangents[a].z *= -1.0f; + } + } + } + // mirror offset matrices of all bones for( size_t a = 0; a < pMesh->mNumBones; ++a) { @@ -346,8 +364,50 @@ void FlipWindingOrderProcess::ProcessMesh( aiMesh* pMesh) for( unsigned int a = 0; a < pMesh->mNumFaces; a++) { aiFace& face = pMesh->mFaces[a]; - for( unsigned int b = 0; b < face.mNumIndices / 2; b++) - std::swap( face.mIndices[b], face.mIndices[ face.mNumIndices - 1 - b]); + for (unsigned int b = 0; b < face.mNumIndices / 2; b++) { + std::swap(face.mIndices[b], face.mIndices[face.mNumIndices - 1 - b]); + } + } + + // invert the order of all components in this mesh anim meshes + for (unsigned int m = 0; m < pMesh->mNumAnimMeshes; m++) { + aiAnimMesh* animMesh = pMesh->mAnimMeshes[m]; + unsigned int numVertices = animMesh->mNumVertices; + if (animMesh->HasPositions()) { + for (unsigned int a = 0; a < numVertices; a++) + { + std::swap(animMesh->mVertices[a], animMesh->mVertices[numVertices - 1 - a]); + } + } + if (animMesh->HasNormals()) { + for (unsigned int a = 0; a < numVertices; a++) + { + std::swap(animMesh->mNormals[a], animMesh->mNormals[numVertices - 1 - a]); + } + } + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; i++) { + if (animMesh->HasTextureCoords(i)) { + for (unsigned int a = 0; a < numVertices; a++) + { + std::swap(animMesh->mTextureCoords[i][a], animMesh->mTextureCoords[i][numVertices - 1 - a]); + } + } + } + if (animMesh->HasTangentsAndBitangents()) { + for (unsigned int a = 0; a < numVertices; a++) + { + std::swap(animMesh->mTangents[a], animMesh->mTangents[numVertices - 1 - a]); + std::swap(animMesh->mBitangents[a], animMesh->mBitangents[numVertices - 1 - a]); + } + } + for (unsigned int v = 0; v < AI_MAX_NUMBER_OF_COLOR_SETS; v++) { + if (animMesh->HasVertexColors(v)) { + for (unsigned int a = 0; a < numVertices; a++) + { + std::swap(animMesh->mColors[v][a], animMesh->mColors[v][numVertices - 1 - a]); + } + } + } } } diff --git a/code/ConvertToLHProcess.h b/code/PostProcessing/ConvertToLHProcess.h similarity index 98% rename from code/ConvertToLHProcess.h rename to code/PostProcessing/ConvertToLHProcess.h index f219d6ca2..f32b91fc3 100644 --- a/code/ConvertToLHProcess.h +++ b/code/PostProcessing/ConvertToLHProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -52,7 +52,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_CONVERTTOLHPROCESS_H_INC #include -#include "BaseProcess.h" + +#include "Common/BaseProcess.h" struct aiMesh; struct aiNodeAnim; diff --git a/code/DeboneProcess.cpp b/code/PostProcessing/DeboneProcess.cpp similarity index 99% rename from code/DeboneProcess.cpp rename to code/PostProcessing/DeboneProcess.cpp index bc6afa36e..83b8336bc 100644 --- a/code/DeboneProcess.cpp +++ b/code/PostProcessing/DeboneProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/DeboneProcess.h b/code/PostProcessing/DeboneProcess.h similarity index 96% rename from code/DeboneProcess.h rename to code/PostProcessing/DeboneProcess.h index 3da861362..8b64c2acc 100644 --- a/code/DeboneProcess.h +++ b/code/PostProcessing/DeboneProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -44,17 +44,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_DEBONEPROCESS_H_INC #define AI_DEBONEPROCESS_H_INC -#include -#include -#include "BaseProcess.h" +#include "Common/BaseProcess.h" #include #include +#include +#include + +#// Forward declarations class DeboneTest; -namespace Assimp -{ +namespace Assimp { #if (!defined AI_DEBONE_THRESHOLD) # define AI_DEBONE_THRESHOLD 1.0f @@ -66,14 +67,11 @@ namespace Assimp * the bone are split from the mesh. The split off (new) mesh is boneless. At any * point in time, bones without affect upon a given mesh are to be removed. */ -class DeboneProcess : public BaseProcess -{ +class DeboneProcess : public BaseProcess { public: - DeboneProcess(); ~DeboneProcess(); -public: // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag. * @param pFlags The processing flags the importer was called with. @@ -91,7 +89,6 @@ public: void SetupProperties(const Importer* pImp); protected: - // ------------------------------------------------------------------- /** Executes the post processing step on the given imported data. * At the moment a process is not supposed to fail. diff --git a/code/DropFaceNormalsProcess.cpp b/code/PostProcessing/DropFaceNormalsProcess.cpp similarity index 99% rename from code/DropFaceNormalsProcess.cpp rename to code/PostProcessing/DropFaceNormalsProcess.cpp index 57e8b972b..b11615bb8 100644 --- a/code/DropFaceNormalsProcess.cpp +++ b/code/PostProcessing/DropFaceNormalsProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/DropFaceNormalsProcess.h b/code/PostProcessing/DropFaceNormalsProcess.h similarity index 96% rename from code/DropFaceNormalsProcess.h rename to code/PostProcessing/DropFaceNormalsProcess.h index 6dbfe0397..c710c5a5e 100644 --- a/code/DropFaceNormalsProcess.h +++ b/code/PostProcessing/DropFaceNormalsProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -44,23 +44,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_DROPFACENORMALPROCESS_H_INC #define AI_DROPFACENORMALPROCESS_H_INC -#include "BaseProcess.h" +#include "Common/BaseProcess.h" + #include -namespace Assimp -{ +namespace Assimp { // --------------------------------------------------------------------------- /** The DropFaceNormalsProcess computes face normals for all faces of all meshes */ -class ASSIMP_API_WINONLY DropFaceNormalsProcess : public BaseProcess -{ +class ASSIMP_API_WINONLY DropFaceNormalsProcess : public BaseProcess { public: - DropFaceNormalsProcess(); ~DropFaceNormalsProcess(); -public: // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag field. * @param pFlags The processing flags the importer was called with. A bitwise diff --git a/code/EmbedTexturesProcess.cpp b/code/PostProcessing/EmbedTexturesProcess.cpp similarity index 91% rename from code/EmbedTexturesProcess.cpp rename to code/PostProcessing/EmbedTexturesProcess.cpp index ebe7a0897..739382a05 100644 --- a/code/EmbedTexturesProcess.cpp +++ b/code/PostProcessing/EmbedTexturesProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -124,22 +124,28 @@ bool EmbedTexturesProcess::addTexture(aiScene* pScene, std::string path) const { file.read(reinterpret_cast(imageContent), imageSize); // Enlarging the textures table - auto textureId = pScene->mNumTextures++; + unsigned int textureId = pScene->mNumTextures++; auto oldTextures = pScene->mTextures; pScene->mTextures = new aiTexture*[pScene->mNumTextures]; - memmove(pScene->mTextures, oldTextures, sizeof(aiTexture*) * (pScene->mNumTextures - 1u)); + ::memmove(pScene->mTextures, oldTextures, sizeof(aiTexture*) * (pScene->mNumTextures - 1u)); // Add the new texture - auto pTexture = new aiTexture(); + auto pTexture = new aiTexture; pTexture->mHeight = 0; // Means that this is still compressed pTexture->mWidth = static_cast(imageSize); pTexture->pcData = imageContent; auto extension = path.substr(path.find_last_of('.') + 1u); std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - if (extension == "jpeg") extension = "jpg"; - strcpy(pTexture->achFormatHint, extension.c_str()); + if (extension == "jpeg") { + extension = "jpg"; + } + size_t len = extension.size(); + if (len > HINTMAXTEXTURELEN -1 ) { + len = HINTMAXTEXTURELEN - 1; + } + ::strncpy(pTexture->achFormatHint, extension.c_str(), len); pScene->mTextures[textureId] = pTexture; return true; diff --git a/code/EmbedTexturesProcess.h b/code/PostProcessing/EmbedTexturesProcess.h similarity index 97% rename from code/EmbedTexturesProcess.h rename to code/PostProcessing/EmbedTexturesProcess.h index ce9821652..3c4b2eab4 100644 --- a/code/EmbedTexturesProcess.h +++ b/code/PostProcessing/EmbedTexturesProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -42,7 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #pragma once -#include "BaseProcess.h" +#include "Common/BaseProcess.h" #include diff --git a/code/FindDegenerates.cpp b/code/PostProcessing/FindDegenerates.cpp similarity index 99% rename from code/FindDegenerates.cpp rename to code/PostProcessing/FindDegenerates.cpp index c0c0de08b..50fac46db 100644 --- a/code/FindDegenerates.cpp +++ b/code/PostProcessing/FindDegenerates.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -228,6 +228,7 @@ bool FindDegeneratesProcess::ExecuteOnMesh( aiMesh* mesh) { if ( area < 1e-6 ) { if ( mConfigRemoveDegenerates ) { remove_me[ a ] = true; + ++deg; goto evil_jump_outside; } diff --git a/code/FindDegenerates.h b/code/PostProcessing/FindDegenerates.h similarity index 98% rename from code/FindDegenerates.h rename to code/PostProcessing/FindDegenerates.h index c234c57f5..7a15e77cf 100644 --- a/code/FindDegenerates.h +++ b/code/PostProcessing/FindDegenerates.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,7 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_FINDDEGENERATESPROCESS_H_INC #define AI_FINDDEGENERATESPROCESS_H_INC -#include "BaseProcess.h" +#include "Common/BaseProcess.h" + #include class FindDegeneratesProcessTest; diff --git a/code/FindInstancesProcess.cpp b/code/PostProcessing/FindInstancesProcess.cpp similarity index 92% rename from code/FindInstancesProcess.cpp rename to code/PostProcessing/FindInstancesProcess.cpp index 25dcc51e8..64907458a 100644 --- a/code/FindInstancesProcess.cpp +++ b/code/PostProcessing/FindInstancesProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -137,6 +137,11 @@ void FindInstancesProcess::Execute( aiScene* pScene) aiMesh* inst = pScene->mMeshes[i]; hashes[i] = GetMeshHash(inst); + // Find an appropriate epsilon + // to compare position differences against + float epsilon = ComputePositionEpsilon(inst); + epsilon *= epsilon; + for (int a = i-1; a >= 0; --a) { if (hashes[i] == hashes[a]) { @@ -154,12 +159,7 @@ void FindInstancesProcess::Execute( aiScene* pScene) orig->mPrimitiveTypes != inst->mPrimitiveTypes) continue; - // up to now the meshes are equal. find an appropriate - // epsilon to compare position differences against - float epsilon = ComputePositionEpsilon(inst); - epsilon *= epsilon; - - // now compare vertex positions, normals, + // up to now the meshes are equal. Now compare vertex positions, normals, // tangents and bitangents using this epsilon. if (orig->HasPositions()) { if(!CompareArrays(orig->mVertices,inst->mVertices,orig->mNumVertices,epsilon)) @@ -178,30 +178,30 @@ void FindInstancesProcess::Execute( aiScene* pScene) // use a constant epsilon for colors and UV coordinates static const float uvEpsilon = 10e-4f; { - unsigned int i, end = orig->GetNumUVChannels(); - for(i = 0; i < end; ++i) { - if (!orig->mTextureCoords[i]) { + unsigned int j, end = orig->GetNumUVChannels(); + for(j = 0; j < end; ++j) { + if (!orig->mTextureCoords[j]) { continue; } - if(!CompareArrays(orig->mTextureCoords[i],inst->mTextureCoords[i],orig->mNumVertices,uvEpsilon)) { + if(!CompareArrays(orig->mTextureCoords[j],inst->mTextureCoords[j],orig->mNumVertices,uvEpsilon)) { break; } } - if (i != end) { + if (j != end) { continue; } } { - unsigned int i, end = orig->GetNumColorChannels(); - for(i = 0; i < end; ++i) { - if (!orig->mColors[i]) { + unsigned int j, end = orig->GetNumColorChannels(); + for(j = 0; j < end; ++j) { + if (!orig->mColors[j]) { continue; } - if(!CompareArrays(orig->mColors[i],inst->mColors[i],orig->mNumVertices,uvEpsilon)) { + if(!CompareArrays(orig->mColors[j],inst->mColors[j],orig->mNumVertices,uvEpsilon)) { break; } } - if (i != end) { + if (j != end) { continue; } } diff --git a/code/FindInstancesProcess.h b/code/PostProcessing/FindInstancesProcess.h similarity index 97% rename from code/FindInstancesProcess.h rename to code/PostProcessing/FindInstancesProcess.h index fb2ac6eb6..64b838d7c 100644 --- a/code/FindInstancesProcess.h +++ b/code/PostProcessing/FindInstancesProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -46,8 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_FINDINSTANCES_H_INC #define AI_FINDINSTANCES_H_INC -#include "BaseProcess.h" -#include "ProcessHelper.h" +#include "Common/BaseProcess.h" +#include "PostProcessing/ProcessHelper.h" class FindInstancesProcessTest; namespace Assimp { diff --git a/code/FindInvalidDataProcess.cpp b/code/PostProcessing/FindInvalidDataProcess.cpp similarity index 85% rename from code/FindInvalidDataProcess.cpp rename to code/PostProcessing/FindInvalidDataProcess.cpp index b1a296a54..016884c6e 100644 --- a/code/FindInvalidDataProcess.cpp +++ b/code/PostProcessing/FindInvalidDataProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers #include "FindInvalidDataProcess.h" #include "ProcessHelper.h" -#include + #include #include @@ -60,37 +60,34 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer FindInvalidDataProcess::FindInvalidDataProcess() - : configEpsilon(0.0) -{ +: configEpsilon(0.0) +, mIgnoreTexCoods( false ){ // nothing to do here } // ------------------------------------------------------------------------------------------------ // Destructor, private as well -FindInvalidDataProcess::~FindInvalidDataProcess() -{ +FindInvalidDataProcess::~FindInvalidDataProcess() { // nothing to do here } // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. -bool FindInvalidDataProcess::IsActive( unsigned int pFlags) const -{ +bool FindInvalidDataProcess::IsActive( unsigned int pFlags) const { return 0 != (pFlags & aiProcess_FindInvalidData); } // ------------------------------------------------------------------------------------------------ // Setup import configuration -void FindInvalidDataProcess::SetupProperties(const Importer* pImp) -{ +void FindInvalidDataProcess::SetupProperties(const Importer* pImp) { // Get the current value of AI_CONFIG_PP_FID_ANIM_ACCURACY configEpsilon = (0 != pImp->GetPropertyFloat(AI_CONFIG_PP_FID_ANIM_ACCURACY,0.f)); + mIgnoreTexCoods = pImp->GetPropertyBool(AI_CONFIG_PP_FID_IGNORE_TEXTURECOORDS, false); } // ------------------------------------------------------------------------------------------------ // Update mesh references in the node graph -void UpdateMeshReferences(aiNode* node, const std::vector& meshMapping) -{ +void UpdateMeshReferences(aiNode* node, const std::vector& meshMapping) { if (node->mNumMeshes) { unsigned int out = 0; for (unsigned int a = 0; a < node->mNumMeshes;++a) { @@ -116,8 +113,7 @@ void UpdateMeshReferences(aiNode* node, const std::vector& meshMap // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -void FindInvalidDataProcess::Execute( aiScene* pScene) -{ +void FindInvalidDataProcess::Execute( aiScene* pScene) { ASSIMP_LOG_DEBUG("FindInvalidDataProcess begin"); bool out = false; @@ -171,17 +167,18 @@ void FindInvalidDataProcess::Execute( aiScene* pScene) // ------------------------------------------------------------------------------------------------ template -inline const char* ValidateArrayContents(const T* /*arr*/, unsigned int /*size*/, - const std::vector& /*dirtyMask*/, bool /*mayBeIdentical = false*/, bool /*mayBeZero = true*/) +inline +const char* ValidateArrayContents(const T* /*arr*/, unsigned int /*size*/, + const std::vector& /*dirtyMask*/, bool /*mayBeIdentical = false*/, bool /*mayBeZero = true*/) { - return NULL; + return nullptr; } // ------------------------------------------------------------------------------------------------ template <> -inline const char* ValidateArrayContents(const aiVector3D* arr, unsigned int size, - const std::vector& dirtyMask, bool mayBeIdentical , bool mayBeZero ) -{ +inline +const char* ValidateArrayContents(const aiVector3D* arr, unsigned int size, + const std::vector& dirtyMask, bool mayBeIdentical , bool mayBeZero ) { bool b = false; unsigned int cnt = 0; for (unsigned int i = 0; i < size;++i) { @@ -203,14 +200,14 @@ inline const char* ValidateArrayContents(const aiVector3D* arr, unsi if (cnt > 1 && !b && !mayBeIdentical) { return "All vectors are identical"; } - return NULL; + return nullptr; } // ------------------------------------------------------------------------------------------------ template -inline bool ProcessArray(T*& in, unsigned int num,const char* name, - const std::vector& dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true) -{ +inline +bool ProcessArray(T*& in, unsigned int num,const char* name, + const std::vector& dirtyMask, bool mayBeIdentical = false, bool mayBeZero = true) { const char* err = ValidateArrayContents(in,num,dirtyMask,mayBeIdentical,mayBeZero); if (err) { ASSIMP_LOG_ERROR_F( "FindInvalidDataProcess fails on mesh ", name, ": ", err); @@ -251,23 +248,20 @@ bool EpsilonCompare(const aiQuatKey& n, const aiQuatKey& s, ai_real e // ------------------------------------------------------------------------------------------------ template -inline bool AllIdentical(T* in, unsigned int num, ai_real epsilon) -{ +inline +bool AllIdentical(T* in, unsigned int num, ai_real epsilon) { if (num <= 1) { return true; } - if (epsilon > 0.f) { + if (fabs(epsilon) > 0.f) { for (unsigned int i = 0; i < num-1;++i) { - if (!EpsilonCompare(in[i],in[i+1],epsilon)) { return false; } } - } - else { + } else { for (unsigned int i = 0; i < num-1;++i) { - if (in[i] != in[i+1]) { return false; } @@ -278,27 +272,26 @@ inline bool AllIdentical(T* in, unsigned int num, ai_real epsilon) // ------------------------------------------------------------------------------------------------ // Search an animation for invalid content -void FindInvalidDataProcess::ProcessAnimation (aiAnimation* anim) -{ +void FindInvalidDataProcess::ProcessAnimation (aiAnimation* anim) { // Process all animation channels - for (unsigned int a = 0; a < anim->mNumChannels;++a) { + for ( unsigned int a = 0; a < anim->mNumChannels; ++a ) { ProcessAnimationChannel( anim->mChannels[a]); } } // ------------------------------------------------------------------------------------------------ -void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim) -{ - int i = 0; - - // ScenePreprocessor's work ... - ai_assert((0 != anim->mPositionKeys && 0 != anim->mRotationKeys && 0 != anim->mScalingKeys)); +void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim) { + ai_assert( nullptr != anim ); + if (anim->mNumPositionKeys == 0 && anim->mNumRotationKeys == 0 && anim->mNumScalingKeys == 0) { + ai_assert_entry(); + return; + } // Check whether all values in a tracks are identical - in this case // we can remove al keys except one. // POSITIONS - if (anim->mNumPositionKeys > 1 && AllIdentical(anim->mPositionKeys,anim->mNumPositionKeys,configEpsilon)) - { + int i = 0; + if (anim->mNumPositionKeys > 1 && AllIdentical(anim->mPositionKeys,anim->mNumPositionKeys,configEpsilon)) { aiVectorKey v = anim->mPositionKeys[0]; // Reallocate ... we need just ONE element, it makes no sense to reuse the array @@ -309,8 +302,7 @@ void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim) } // ROTATIONS - if (anim->mNumRotationKeys > 1 && AllIdentical(anim->mRotationKeys,anim->mNumRotationKeys,configEpsilon)) - { + if (anim->mNumRotationKeys > 1 && AllIdentical(anim->mRotationKeys,anim->mNumRotationKeys,configEpsilon)) { aiQuatKey v = anim->mRotationKeys[0]; // Reallocate ... we need just ONE element, it makes no sense to reuse the array @@ -321,8 +313,7 @@ void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim) } // SCALINGS - if (anim->mNumScalingKeys > 1 && AllIdentical(anim->mScalingKeys,anim->mNumScalingKeys,configEpsilon)) - { + if (anim->mNumScalingKeys > 1 && AllIdentical(anim->mScalingKeys,anim->mNumScalingKeys,configEpsilon)) { aiVectorKey v = anim->mScalingKeys[0]; // Reallocate ... we need just ONE element, it makes no sense to reuse the array @@ -331,13 +322,14 @@ void FindInvalidDataProcess::ProcessAnimationChannel (aiNodeAnim* anim) anim->mScalingKeys[0] = v; i = 1; } - if (1 == i) + if ( 1 == i ) { ASSIMP_LOG_WARN("Simplified dummy tracks with just one key"); + } } // ------------------------------------------------------------------------------------------------ // Search a mesh for invalid contents -int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh) +int FindInvalidDataProcess::ProcessMesh(aiMesh* pMesh) { bool ret = false; std::vector dirtyMask(pMesh->mNumVertices, pMesh->mNumFaces != 0); @@ -360,18 +352,20 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh) } // process texture coordinates - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS && pMesh->mTextureCoords[i]; ++i) { - if (ProcessArray(pMesh->mTextureCoords[i], pMesh->mNumVertices, "uvcoords", dirtyMask)) { - pMesh->mNumUVComponents[i] = 0; + if (!mIgnoreTexCoods) { + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS && pMesh->mTextureCoords[i]; ++i) { + if (ProcessArray(pMesh->mTextureCoords[i], pMesh->mNumVertices, "uvcoords", dirtyMask)) { + pMesh->mNumUVComponents[i] = 0; - // delete all subsequent texture coordinate sets. - for (unsigned int a = i + 1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { - delete[] pMesh->mTextureCoords[a]; - pMesh->mTextureCoords[a] = NULL; - pMesh->mNumUVComponents[a] = 0; + // delete all subsequent texture coordinate sets. + for (unsigned int a = i + 1; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) { + delete[] pMesh->mTextureCoords[a]; + pMesh->mTextureCoords[a] = NULL; + pMesh->mNumUVComponents[a] = 0; + } + + ret = true; } - - ret = true; } } @@ -388,13 +382,11 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh) aiPrimitiveType_POLYGON & pMesh->mPrimitiveTypes) { // We need to update the lookup-table - for (unsigned int m = 0; m < pMesh->mNumFaces;++m) - { - const aiFace& f = pMesh->mFaces[m]; + for (unsigned int m = 0; m < pMesh->mNumFaces;++m) { + const aiFace& f = pMesh->mFaces[ m ]; if (f.mNumIndices < 3) { dirtyMask[f.mIndices[0]] = true; - if (f.mNumIndices == 2) { dirtyMask[f.mIndices[1]] = true; } @@ -403,7 +395,9 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh) } // Normals, tangents and bitangents are undefined for // the whole mesh (and should not even be there) - else return ret; + else { + return ret; + } } // Process mesh normals @@ -426,5 +420,4 @@ int FindInvalidDataProcess::ProcessMesh (aiMesh* pMesh) return ret ? 1 : 0; } - #endif // !! ASSIMP_BUILD_NO_FINDINVALIDDATA_PROCESS diff --git a/code/FindInvalidDataProcess.h b/code/PostProcessing/FindInvalidDataProcess.h similarity index 89% rename from code/FindInvalidDataProcess.h rename to code/PostProcessing/FindInvalidDataProcess.h index 00dfef145..ce7375f34 100644 --- a/code/FindInvalidDataProcess.h +++ b/code/PostProcessing/FindInvalidDataProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -41,16 +41,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file Defines a post processing step to search an importer's output - for data that is obviously invalid */ + * for data that is obviously invalid + */ #ifndef AI_FINDINVALIDDATA_H_INC #define AI_FINDINVALIDDATA_H_INC -#include "BaseProcess.h" +#include "Common/BaseProcess.h" + #include #include struct aiMesh; + class FindInvalidDataProcessTest; + namespace Assimp { // --------------------------------------------------------------------------- @@ -59,15 +63,11 @@ namespace Assimp { * * Originally this was a workaround for some models written by Blender * which have zero normal vectors. */ -class ASSIMP_API FindInvalidDataProcess : public BaseProcess -{ +class ASSIMP_API FindInvalidDataProcess : public BaseProcess { public: - FindInvalidDataProcess(); ~FindInvalidDataProcess(); -public: - // ------------------------------------------------------------------- // bool IsActive( unsigned int pFlags) const; @@ -80,26 +80,25 @@ public: // Run the step void Execute( aiScene* pScene); -public: - // ------------------------------------------------------------------- - /** Executes the postprocessing step on the given mesh + /** Executes the post-processing step on the given mesh * @param pMesh The mesh to process. * @return 0 - nothing, 1 - removed sth, 2 - please delete me */ int ProcessMesh( aiMesh* pMesh); // ------------------------------------------------------------------- - /** Executes the postprocessing step on the given animation + /** Executes the post-processing step on the given animation * @param anim The animation to process. */ void ProcessAnimation (aiAnimation* anim); // ------------------------------------------------------------------- - /** Executes the postprocessing step on the given anim channel + /** Executes the post-processing step on the given anim channel * @param anim The animation channel to process.*/ void ProcessAnimationChannel (aiNodeAnim* anim); private: ai_real configEpsilon; + bool mIgnoreTexCoods; }; } // end of namespace Assimp diff --git a/code/FixNormalsStep.cpp b/code/PostProcessing/FixNormalsStep.cpp similarity index 99% rename from code/FixNormalsStep.cpp rename to code/PostProcessing/FixNormalsStep.cpp index 668b50c24..bbbe6899b 100644 --- a/code/FixNormalsStep.cpp +++ b/code/PostProcessing/FixNormalsStep.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/FixNormalsStep.h b/code/PostProcessing/FixNormalsStep.h similarity index 97% rename from code/FixNormalsStep.h rename to code/PostProcessing/FixNormalsStep.h index 389e6e1a6..f60ce596a 100644 --- a/code/FixNormalsStep.h +++ b/code/PostProcessing/FixNormalsStep.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,7 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_FIXNORMALSPROCESS_H_INC #define AI_FIXNORMALSPROCESS_H_INC -#include "BaseProcess.h" +#include "Common/BaseProcess.h" struct aiMesh; diff --git a/code/PostProcessing/GenBoundingBoxesProcess.cpp b/code/PostProcessing/GenBoundingBoxesProcess.cpp new file mode 100644 index 000000000..c013454fc --- /dev/null +++ b/code/PostProcessing/GenBoundingBoxesProcess.cpp @@ -0,0 +1,115 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2019, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the following +conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +--------------------------------------------------------------------------- +*/ + +#ifndef ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS + +#include "PostProcessing/GenBoundingBoxesProcess.h" + +#include +#include + +namespace Assimp { + +GenBoundingBoxesProcess::GenBoundingBoxesProcess() +: BaseProcess() { + +} + +GenBoundingBoxesProcess::~GenBoundingBoxesProcess() { + // empty +} + +bool GenBoundingBoxesProcess::IsActive(unsigned int pFlags) const { + return 0 != ( pFlags & aiProcess_GenBoundingBoxes ); +} + +void checkMesh(aiMesh* mesh, aiVector3D& min, aiVector3D& max) { + ai_assert(nullptr != mesh); + + if (0 == mesh->mNumVertices) { + return; + } + + for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { + const aiVector3D &pos = mesh->mVertices[i]; + if (pos.x < min.x) { + min.x = pos.x; + } + if (pos.y < min.y) { + min.y = pos.y; + } + if (pos.z < min.z) { + min.z = pos.z; + } + + if (pos.x > max.x) { + max.x = pos.x; + } + if (pos.y > max.y) { + max.y = pos.y; + } + if (pos.z > max.z) { + max.z = pos.z; + } + } +} + +void GenBoundingBoxesProcess::Execute(aiScene* pScene) { + if (nullptr == pScene) { + return; + } + + for (unsigned int i = 0; i < pScene->mNumMeshes; ++i) { + aiMesh* mesh = pScene->mMeshes[i]; + if (nullptr == mesh) { + continue; + } + + aiVector3D min(999999, 999999, 999999), max(-999999, -999999, -999999); + checkMesh(mesh, min, max); + mesh->mAABB.mMin = min; + mesh->mAABB.mMax = max; + } +} + +} // Namespace Assimp + +#endif // ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS diff --git a/code/PostProcessing/GenBoundingBoxesProcess.h b/code/PostProcessing/GenBoundingBoxesProcess.h new file mode 100644 index 000000000..4b43c82a4 --- /dev/null +++ b/code/PostProcessing/GenBoundingBoxesProcess.h @@ -0,0 +1,76 @@ +/* +--------------------------------------------------------------------------- +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 Defines a post-processing step to generate Axis-aligned bounding + * volumes for all meshes. + */ + +#pragma once + +#ifndef AI_GENBOUNDINGBOXESPROCESS_H_INC +#define AI_GENBOUNDINGBOXESPROCESS_H_INC + +#ifndef ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS + +#include "Common/BaseProcess.h" + +namespace Assimp { + +/** Post-processing process to find axis-aligned bounding volumes for amm meshes + * used in a scene + */ +class ASSIMP_API GenBoundingBoxesProcess : public BaseProcess { +public: + /// The class constructor. + GenBoundingBoxesProcess(); + /// The class destructor. + ~GenBoundingBoxesProcess(); + /// Will return true, if aiProcess_GenBoundingBoxes is defined. + bool IsActive(unsigned int pFlags) const override; + /// The execution callback. + void Execute(aiScene* pScene) override; +}; + +} // Namespace Assimp + +#endif // #ifndef ASSIMP_BUILD_NO_GENBOUNDINGBOXES_PROCESS + +#endif // AI_GENBOUNDINGBOXESPROCESS_H_INC diff --git a/code/GenFaceNormalsProcess.cpp b/code/PostProcessing/GenFaceNormalsProcess.cpp similarity index 99% rename from code/GenFaceNormalsProcess.cpp rename to code/PostProcessing/GenFaceNormalsProcess.cpp index 43960ac3b..028334dec 100644 --- a/code/GenFaceNormalsProcess.cpp +++ b/code/PostProcessing/GenFaceNormalsProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/GenFaceNormalsProcess.h b/code/PostProcessing/GenFaceNormalsProcess.h similarity index 97% rename from code/GenFaceNormalsProcess.h rename to code/PostProcessing/GenFaceNormalsProcess.h index e2f41e07f..c641fd635 100644 --- a/code/GenFaceNormalsProcess.h +++ b/code/PostProcessing/GenFaceNormalsProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -44,7 +44,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_GENFACENORMALPROCESS_H_INC #define AI_GENFACENORMALPROCESS_H_INC -#include "BaseProcess.h" +#include "Common/BaseProcess.h" #include namespace Assimp diff --git a/code/GenVertexNormalsProcess.cpp b/code/PostProcessing/GenVertexNormalsProcess.cpp similarity index 99% rename from code/GenVertexNormalsProcess.cpp rename to code/PostProcessing/GenVertexNormalsProcess.cpp index 1778ef513..3f6c2f86b 100644 --- a/code/GenVertexNormalsProcess.cpp +++ b/code/PostProcessing/GenVertexNormalsProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/GenVertexNormalsProcess.h b/code/PostProcessing/GenVertexNormalsProcess.h similarity index 93% rename from code/GenVertexNormalsProcess.h rename to code/PostProcessing/GenVertexNormalsProcess.h index 2efafa302..2ceee17e8 100644 --- a/code/GenVertexNormalsProcess.h +++ b/code/PostProcessing/GenVertexNormalsProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,24 +45,24 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_GENVERTEXNORMALPROCESS_H_INC #define AI_GENVERTEXNORMALPROCESS_H_INC -#include "BaseProcess.h" +#include "Common/assbin_chunks.h" +#include "Common/BaseProcess.h" + #include +// Forward declarations class GenNormalsTest; namespace Assimp { // --------------------------------------------------------------------------- -/** The GenFaceNormalsProcess computes vertex normals for all vertizes +/** The GenFaceNormalsProcess computes vertex normals for all vertices */ -class ASSIMP_API GenVertexNormalsProcess : public BaseProcess -{ +class ASSIMP_API GenVertexNormalsProcess : public BaseProcess { public: - GenVertexNormalsProcess(); ~GenVertexNormalsProcess(); -public: // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag. * @param pFlags The processing flags the importer was called with. @@ -88,13 +88,10 @@ public: // setter for configMaxAngle - inline void SetMaxSmoothAngle(ai_real f) - { + inline void SetMaxSmoothAngle(ai_real f) { configMaxAngle =f; } -public: - // ------------------------------------------------------------------- /** Computes normals for a specific mesh * @param pcMesh Mesh @@ -104,7 +101,6 @@ public: bool GenMeshVertexNormals (aiMesh* pcMesh, unsigned int meshIndex); private: - /** Configuration option: maximum smoothing angle, in radians*/ ai_real configMaxAngle; mutable bool force_ = false; diff --git a/code/ImproveCacheLocality.cpp b/code/PostProcessing/ImproveCacheLocality.cpp similarity index 89% rename from code/ImproveCacheLocality.cpp rename to code/PostProcessing/ImproveCacheLocality.cpp index adcbc92fe..d0a016fa4 100644 --- a/code/ImproveCacheLocality.cpp +++ b/code/PostProcessing/ImproveCacheLocality.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -45,14 +45,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
* The algorithm is roughly basing on this paper: * http://www.cs.princeton.edu/gfx/pubs/Sander_2007_%3ETR/tipsy.pdf - * .. although overdraw rduction isn't implemented yet ... + * .. although overdraw reduction isn't implemented yet ... */ - - // internal headers -#include "ImproveCacheLocality.h" -#include "VertexTriangleAdjacency.h" +#include "PostProcessing/ImproveCacheLocality.h" +#include "Common/VertexTriangleAdjacency.h" + #include #include #include @@ -64,36 +63,33 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer -ImproveCacheLocalityProcess::ImproveCacheLocalityProcess() { - configCacheDepth = PP_ICL_PTCACHE_SIZE; +ImproveCacheLocalityProcess::ImproveCacheLocalityProcess() +: mConfigCacheDepth(PP_ICL_PTCACHE_SIZE) { + // empty } // ------------------------------------------------------------------------------------------------ // Destructor, private as well -ImproveCacheLocalityProcess::~ImproveCacheLocalityProcess() -{ +ImproveCacheLocalityProcess::~ImproveCacheLocalityProcess() { // nothing to do here } // ------------------------------------------------------------------------------------------------ // Returns whether the processing step is present in the given flag field. -bool ImproveCacheLocalityProcess::IsActive( unsigned int pFlags) const -{ +bool ImproveCacheLocalityProcess::IsActive( unsigned int pFlags) const { return (pFlags & aiProcess_ImproveCacheLocality) != 0; } // ------------------------------------------------------------------------------------------------ // Setup configuration -void ImproveCacheLocalityProcess::SetupProperties(const Importer* pImp) -{ +void ImproveCacheLocalityProcess::SetupProperties(const Importer* pImp) { // AI_CONFIG_PP_ICL_PTCACHE_SIZE controls the target cache size for the optimizer - configCacheDepth = pImp->GetPropertyInteger(AI_CONFIG_PP_ICL_PTCACHE_SIZE,PP_ICL_PTCACHE_SIZE); + mConfigCacheDepth = pImp->GetPropertyInteger(AI_CONFIG_PP_ICL_PTCACHE_SIZE,PP_ICL_PTCACHE_SIZE); } // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -void ImproveCacheLocalityProcess::Execute( aiScene* pScene) -{ +void ImproveCacheLocalityProcess::Execute( aiScene* pScene) { if (!pScene->mNumMeshes) { ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess skipped; there are no meshes"); return; @@ -103,7 +99,7 @@ void ImproveCacheLocalityProcess::Execute( aiScene* pScene) float out = 0.f; unsigned int numf = 0, numm = 0; - for( unsigned int a = 0; a < pScene->mNumMeshes; a++){ + for( unsigned int a = 0; a < pScene->mNumMeshes; ++a ){ const float res = ProcessMesh( pScene->mMeshes[a],a); if (res) { numf += pScene->mMeshes[a]->mNumFaces; @@ -112,51 +108,50 @@ void ImproveCacheLocalityProcess::Execute( aiScene* pScene) } } if (!DefaultLogger::isNullLogger()) { - ASSIMP_LOG_INFO_F("Cache relevant are ", numm, " meshes (", numf," faces). Average output ACMR is ", out / numf ); + if (numf > 0) { + ASSIMP_LOG_INFO_F("Cache relevant are ", numm, " meshes (", numf, " faces). Average output ACMR is ", out / numf); + } ASSIMP_LOG_DEBUG("ImproveCacheLocalityProcess finished. "); } } // ------------------------------------------------------------------------------------------------ // Improves the cache coherency of a specific mesh -float ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshNum) -{ +ai_real ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshNum) { // TODO: rewrite this to use std::vector or boost::shared_array - ai_assert(NULL != pMesh); + ai_assert(nullptr != pMesh); // Check whether the input data is valid // - there must be vertices and faces // - all faces must be triangulated or we can't operate on them if (!pMesh->HasFaces() || !pMesh->HasPositions()) - return 0.f; + return static_cast(0.f); if (pMesh->mPrimitiveTypes != aiPrimitiveType_TRIANGLE) { ASSIMP_LOG_ERROR("This algorithm works on triangle meshes only"); - return 0.f; + return static_cast(0.f); } - if(pMesh->mNumVertices <= configCacheDepth) { - return 0.f; + if(pMesh->mNumVertices <= mConfigCacheDepth) { + return static_cast(0.f); } - float fACMR = 3.f; + ai_real fACMR = 3.f; const aiFace* const pcEnd = pMesh->mFaces+pMesh->mNumFaces; // Input ACMR is for logging purposes only if (!DefaultLogger::isNullLogger()) { - unsigned int* piFIFOStack = new unsigned int[configCacheDepth]; - memset(piFIFOStack,0xff,configCacheDepth*sizeof(unsigned int)); + unsigned int* piFIFOStack = new unsigned int[mConfigCacheDepth]; + memset(piFIFOStack,0xff,mConfigCacheDepth*sizeof(unsigned int)); unsigned int* piCur = piFIFOStack; - const unsigned int* const piCurEnd = piFIFOStack + configCacheDepth; + const unsigned int* const piCurEnd = piFIFOStack + mConfigCacheDepth; // count the number of cache misses unsigned int iCacheMisses = 0; for (const aiFace* pcFace = pMesh->mFaces;pcFace != pcEnd;++pcFace) { - for (unsigned int qq = 0; qq < 3;++qq) { bool bInCache = false; - for (unsigned int* pp = piFIFOStack;pp < piCurEnd;++pp) { if (*pp == pcFace->mIndices[qq]) { // the vertex is in cache @@ -174,7 +169,7 @@ float ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int mesh } } delete[] piFIFOStack; - fACMR = (float)iCacheMisses / pMesh->mNumFaces; + fACMR = (ai_real) iCacheMisses / pMesh->mNumFaces; if (3.0 == fACMR) { char szBuff[128]; // should be sufficiently large in every case @@ -183,7 +178,7 @@ float ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int mesh // smaller than 3.0 ... ai_snprintf(szBuff,128,"Mesh %u: Not suitable for vcache optimization",meshNum); ASSIMP_LOG_WARN(szBuff); - return 0.f; + return static_cast(0.f); } } @@ -256,7 +251,7 @@ float ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int mesh int ivdx = 0; int ics = 1; - int iStampCnt = configCacheDepth+1; + int iStampCnt = mConfigCacheDepth+1; while (ivdx >= 0) { unsigned int icnt = piNumTriPtrNoModify[ivdx]; @@ -292,7 +287,7 @@ float ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int mesh *piCSIter++ = dp; // if the vertex is not yet in cache, set its cache count - if (iStampCnt-piCachingStamps[dp] > configCacheDepth) { + if (iStampCnt-piCachingStamps[dp] > mConfigCacheDepth) { piCachingStamps[dp] = iStampCnt++; ++iCacheMisses; } @@ -317,7 +312,7 @@ float ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int mesh // will the vertex be in cache, even after fanning occurs? unsigned int tmp; - if ((tmp = iStampCnt-piCachingStamps[dp]) + 2*piNumTriPtr[dp] <= configCacheDepth) { + if ((tmp = iStampCnt-piCachingStamps[dp]) + 2*piNumTriPtr[dp] <= mConfigCacheDepth) { priority = tmp; } @@ -354,7 +349,7 @@ float ImproveCacheLocalityProcess::ProcessMesh( aiMesh* pMesh, unsigned int mesh } } } - float fACMR2 = 0.0f; + ai_real fACMR2 = 0.0f; if (!DefaultLogger::isNullLogger()) { fACMR2 = (float)iCacheMisses / pMesh->mNumFaces; diff --git a/code/ImproveCacheLocality.h b/code/PostProcessing/ImproveCacheLocality.h similarity index 95% rename from code/ImproveCacheLocality.h rename to code/PostProcessing/ImproveCacheLocality.h index 18eb5e460..de25ecd9f 100644 --- a/code/ImproveCacheLocality.h +++ b/code/PostProcessing/ImproveCacheLocality.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,7 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_IMPROVECACHELOCALITY_H_INC #define AI_IMPROVECACHELOCALITY_H_INC -#include "BaseProcess.h" +#include "Common/BaseProcess.h" + #include struct aiMesh; @@ -87,12 +88,12 @@ protected: * @param pMesh The mesh to process. * @param meshNum Index of the mesh to process */ - float ProcessMesh( aiMesh* pMesh, unsigned int meshNum); + ai_real ProcessMesh( aiMesh* pMesh, unsigned int meshNum); private: //! Configuration parameter: specifies the size of the cache to //! optimize the vertex data for. - unsigned int configCacheDepth; + unsigned int mConfigCacheDepth; }; } // end of namespace Assimp diff --git a/code/JoinVerticesProcess.cpp b/code/PostProcessing/JoinVerticesProcess.cpp similarity index 93% rename from code/JoinVerticesProcess.cpp rename to code/PostProcessing/JoinVerticesProcess.cpp index b91f44048..f121fc60d 100644 --- a/code/JoinVerticesProcess.cpp +++ b/code/PostProcessing/JoinVerticesProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -431,31 +431,6 @@ int JoinVerticesProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) bone->mWeights = new aiVertexWeight[bone->mNumWeights]; memcpy( bone->mWeights, &newWeights[0], bone->mNumWeights * sizeof( aiVertexWeight)); } - else { - - /* NOTE: - * - * In the algorithm above we're assuming that there are no vertices - * with a different bone weight setup at the same position. That wouldn't - * make sense, but it is not absolutely impossible. SkeletonMeshBuilder - * for example generates such input data if two skeleton points - * share the same position. Again this doesn't make sense but is - * reality for some model formats (MD5 for example uses these special - * nodes as attachment tags for its weapons). - * - * Then it is possible that a bone has no weights anymore .... as a quick - * workaround, we're just removing these bones. If they're animated, - * model geometry might be modified but at least there's no risk of a crash. - */ - delete bone; - --pMesh->mNumBones; - for (unsigned int n = a; n < pMesh->mNumBones; ++n) { - pMesh->mBones[n] = pMesh->mBones[n+1]; - } - - --a; - ASSIMP_LOG_WARN("Removing bone -> no weights remaining"); - } } return pMesh->mNumVertices; } diff --git a/code/JoinVerticesProcess.h b/code/PostProcessing/JoinVerticesProcess.h similarity index 96% rename from code/JoinVerticesProcess.h rename to code/PostProcessing/JoinVerticesProcess.h index a7366efbe..e017ae62d 100644 --- a/code/JoinVerticesProcess.h +++ b/code/PostProcessing/JoinVerticesProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,7 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_JOINVERTICESPROCESS_H_INC #define AI_JOINVERTICESPROCESS_H_INC -#include "BaseProcess.h" +#include "Common/BaseProcess.h" + #include struct aiMesh; @@ -61,13 +62,11 @@ namespace Assimp * erases all but one of the copies. This usually reduces the number of vertices * in a mesh by a serious amount and is the standard form to render a mesh. */ -class ASSIMP_API JoinVerticesProcess : public BaseProcess -{ +class ASSIMP_API JoinVerticesProcess : public BaseProcess { public: JoinVerticesProcess(); ~JoinVerticesProcess(); -public: // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag field. * @param pFlags The processing flags the importer was called with. A bitwise @@ -83,15 +82,12 @@ public: */ void Execute( aiScene* pScene); -public: // ------------------------------------------------------------------- /** Unites identical vertices in the given mesh. * @param pMesh The mesh to process. * @param meshIndex Index of the mesh to process */ int ProcessMesh( aiMesh* pMesh, unsigned int meshIndex); - -private: }; } // end of namespace Assimp diff --git a/code/LimitBoneWeightsProcess.cpp b/code/PostProcessing/LimitBoneWeightsProcess.cpp similarity index 99% rename from code/LimitBoneWeightsProcess.cpp rename to code/PostProcessing/LimitBoneWeightsProcess.cpp index cc87e407c..d560f1928 100644 --- a/code/LimitBoneWeightsProcess.cpp +++ b/code/PostProcessing/LimitBoneWeightsProcess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/LimitBoneWeightsProcess.h b/code/PostProcessing/LimitBoneWeightsProcess.h similarity index 92% rename from code/LimitBoneWeightsProcess.h rename to code/PostProcessing/LimitBoneWeightsProcess.h index 2161b89a8..73c2a68d5 100644 --- a/code/LimitBoneWeightsProcess.h +++ b/code/PostProcessing/LimitBoneWeightsProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -44,14 +44,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_LIMITBONEWEIGHTSPROCESS_H_INC #define AI_LIMITBONEWEIGHTSPROCESS_H_INC -#include "BaseProcess.h" +#include "Common/BaseProcess.h" +// Forward declarations struct aiMesh; class LimitBoneWeightsTest; -namespace Assimp -{ +namespace Assimp { // NOTE: If you change these limits, don't forget to change the // corresponding values in all Assimp ports @@ -72,14 +72,11 @@ namespace Assimp * The other weights on this bone are then renormalized to assure the sum weight * to be 1. */ -class ASSIMP_API LimitBoneWeightsProcess : public BaseProcess -{ +class ASSIMP_API LimitBoneWeightsProcess : public BaseProcess { public: - LimitBoneWeightsProcess(); ~LimitBoneWeightsProcess(); -public: // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag. * @param pFlags The processing flags the importer was called with. @@ -96,8 +93,6 @@ public: */ void SetupProperties(const Importer* pImp); -public: - // ------------------------------------------------------------------- /** Limits the bone weight count for all vertices in the given mesh. * @param pMesh The mesh to process. @@ -111,34 +106,29 @@ public: */ void Execute( aiScene* pScene); - -public: - // ------------------------------------------------------------------- /** Describes a bone weight on a vertex */ - struct Weight - { + struct Weight { unsigned int mBone; ///< Index of the bone float mWeight; ///< Weight of that bone on this vertex Weight() AI_NO_EXCEPT : mBone(0) - , mWeight(0.0f) - { } + , mWeight(0.0f) { + // empty + } Weight( unsigned int pBone, float pWeight) - { - mBone = pBone; - mWeight = pWeight; + : mBone(pBone) + , mWeight(pWeight) { + // empty } /** Comparison operator to sort bone weights by descending weight */ - bool operator < (const Weight& pWeight) const - { + bool operator < (const Weight& pWeight) const { return mWeight > pWeight.mWeight; } }; -public: /** Maximum number of bones influencing any single vertex. */ unsigned int mMaxWeights; }; diff --git a/code/MakeVerboseFormat.cpp b/code/PostProcessing/MakeVerboseFormat.cpp similarity index 88% rename from code/MakeVerboseFormat.cpp rename to code/PostProcessing/MakeVerboseFormat.cpp index b6f5cabd9..41f50a5ba 100644 --- a/code/MakeVerboseFormat.cpp +++ b/code/PostProcessing/MakeVerboseFormat.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -224,3 +224,32 @@ bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh* pcMesh) } return (pcMesh->mNumVertices != iOldNumVertices); } + + +// ------------------------------------------------------------------------------------------------ +bool IsMeshInVerboseFormat(const aiMesh* mesh) { + // avoid slow vector specialization + std::vector seen(mesh->mNumVertices,0); + for(unsigned int i = 0; i < mesh->mNumFaces; ++i) { + const aiFace& f = mesh->mFaces[i]; + for(unsigned int j = 0; j < f.mNumIndices; ++j) { + if(++seen[f.mIndices[j]] == 2) { + // found a duplicate index + return false; + } + } + } + + return true; +} + +// ------------------------------------------------------------------------------------------------ +bool MakeVerboseFormatProcess::IsVerboseFormat(const aiScene* pScene) { + for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) { + if(!IsMeshInVerboseFormat(pScene->mMeshes[i])) { + return false; + } + } + + return true; +} diff --git a/code/MakeVerboseFormat.h b/code/PostProcessing/MakeVerboseFormat.h similarity index 91% rename from code/MakeVerboseFormat.h rename to code/PostProcessing/MakeVerboseFormat.h index 292d9bea6..8565d5933 100644 --- a/code/MakeVerboseFormat.h +++ b/code/PostProcessing/MakeVerboseFormat.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -46,7 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_MAKEVERBOSEFORMAT_H_INC #define AI_MAKEVERBOSEFORMAT_H_INC -#include "BaseProcess.h" +#include "Common/BaseProcess.h" + struct aiMesh; namespace Assimp { @@ -93,6 +94,13 @@ public: * @param pScene The imported data to work at. */ void Execute( aiScene* pScene); +public: + + // ------------------------------------------------------------------- + /** Checks whether the scene is already in verbose format. + * @param pScene The data to check. + * @return true if the scene is already in verbose format. */ + static bool IsVerboseFormat(const aiScene* pScene); private: diff --git a/code/OptimizeGraph.cpp b/code/PostProcessing/OptimizeGraph.cpp similarity index 99% rename from code/OptimizeGraph.cpp rename to code/PostProcessing/OptimizeGraph.cpp index 59a764d5c..5db51f58b 100644 --- a/code/OptimizeGraph.cpp +++ b/code/PostProcessing/OptimizeGraph.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/OptimizeGraph.h b/code/PostProcessing/OptimizeGraph.h similarity index 92% rename from code/OptimizeGraph.h rename to code/PostProcessing/OptimizeGraph.h index 6781ec534..82cc5db3f 100644 --- a/code/OptimizeGraph.h +++ b/code/PostProcessing/OptimizeGraph.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -46,13 +46,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_OPTIMIZEGRAPHPROCESS_H_INC #define AI_OPTIMIZEGRAPHPROCESS_H_INC -#include "BaseProcess.h" -#include "ProcessHelper.h" +#include "Common/BaseProcess.h" +#include "PostProcessing/ProcessHelper.h" + #include + #include +// Forward declarations struct aiMesh; + class OptimizeGraphProcessTest; + namespace Assimp { // ----------------------------------------------------------------------------- @@ -64,14 +69,11 @@ namespace Assimp { * @see aiProcess_OptimizeGraph for a detailed description of the * algorithm being applied. */ -class OptimizeGraphProcess : public BaseProcess -{ +class OptimizeGraphProcess : public BaseProcess { public: - OptimizeGraphProcess(); ~OptimizeGraphProcess(); -public: // ------------------------------------------------------------------- bool IsActive( unsigned int pFlags) const; @@ -81,14 +83,12 @@ public: // ------------------------------------------------------------------- void SetupProperties(const Importer* pImp); - // ------------------------------------------------------------------- /** @brief Add a list of node names to be locked and not modified. * @param in List of nodes. See #AI_CONFIG_PP_OG_EXCLUDE_LIST for * format explanations. */ - inline void AddLockedNodeList(std::string& in) - { + inline void AddLockedNodeList(std::string& in) { ConvertListToStrings (in,locked_nodes); } @@ -96,8 +96,7 @@ public: /** @brief Add another node to be locked and not modified. * @param name Name to be locked */ - inline void AddLockedNode(std::string& name) - { + inline void AddLockedNode(std::string& name) { locked_nodes.push_back(name); } @@ -105,25 +104,21 @@ public: /** @brief Remove a node from the list of locked nodes. * @param name Name to be unlocked */ - inline void RemoveLockedNode(std::string& name) - { + inline void RemoveLockedNode(std::string& name) { locked_nodes.remove(name); } protected: - void CollectNewChildren(aiNode* nd, std::list& nodes); void FindInstancedMeshes (aiNode* pNode); private: - #ifdef AI_OG_USE_HASHING typedef std::set LockedSetType; #else typedef std::set LockedSetType; #endif - //! Scene we're working with aiScene* mScene; diff --git a/code/OptimizeMeshes.cpp b/code/PostProcessing/OptimizeMeshes.cpp similarity index 99% rename from code/OptimizeMeshes.cpp rename to code/PostProcessing/OptimizeMeshes.cpp index 25575b049..3f6765f6c 100644 --- a/code/OptimizeMeshes.cpp +++ b/code/PostProcessing/OptimizeMeshes.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/OptimizeMeshes.h b/code/PostProcessing/OptimizeMeshes.h similarity index 97% rename from code/OptimizeMeshes.h rename to code/PostProcessing/OptimizeMeshes.h index 3ebe60cd8..dec4ab52d 100644 --- a/code/OptimizeMeshes.h +++ b/code/PostProcessing/OptimizeMeshes.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -46,8 +46,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_OPTIMIZEMESHESPROCESS_H_INC #define AI_OPTIMIZEMESHESPROCESS_H_INC -#include "BaseProcess.h" +#include "Common/BaseProcess.h" + #include + #include struct aiMesh; @@ -64,16 +66,14 @@ namespace Assimp { * * @note Instanced meshes are currently not processed. */ -class OptimizeMeshesProcess : public BaseProcess -{ +class OptimizeMeshesProcess : public BaseProcess { public: /// @brief The class constructor. OptimizeMeshesProcess(); - /// @brief The class destcructor, + /// @brief The class destructor. ~OptimizeMeshesProcess(); - /** @brief Internal utility to store additional mesh info */ struct MeshInfo { diff --git a/code/PretransformVertices.cpp b/code/PostProcessing/PretransformVertices.cpp similarity index 99% rename from code/PretransformVertices.cpp rename to code/PostProcessing/PretransformVertices.cpp index 9745abd60..52001a057 100644 --- a/code/PretransformVertices.cpp +++ b/code/PostProcessing/PretransformVertices.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/PretransformVertices.h b/code/PostProcessing/PretransformVertices.h similarity index 96% rename from code/PretransformVertices.h rename to code/PostProcessing/PretransformVertices.h index a8196289d..b2982951e 100644 --- a/code/PretransformVertices.h +++ b/code/PostProcessing/PretransformVertices.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -47,13 +47,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_PRETRANSFORMVERTICES_H_INC #define AI_PRETRANSFORMVERTICES_H_INC -#include "BaseProcess.h" +#include "Common/BaseProcess.h" + #include + #include #include +// Forward declarations struct aiNode; + class PretransformVerticesTest; + namespace Assimp { // --------------------------------------------------------------------------- @@ -80,10 +85,10 @@ public: // ------------------------------------------------------------------- /** @brief Toggle the 'keep hierarchy' option - * @param d hm ... difficult to guess what this means, hu!? + * @param keep true for keep configuration. */ - void KeepHierarchy(bool d) { - configKeepHierarchy = d; + void KeepHierarchy(bool keep) { + configKeepHierarchy = keep; } // ------------------------------------------------------------------- @@ -148,8 +153,6 @@ private: // Build reference counters for all meshes void BuildMeshRefCountArray(aiNode* nd, unsigned int * refs); - - //! Configuration option: keep scene hierarchy as long as possible bool configKeepHierarchy; bool configNormalize; diff --git a/code/ProcessHelper.cpp b/code/PostProcessing/ProcessHelper.cpp similarity index 99% rename from code/ProcessHelper.cpp rename to code/PostProcessing/ProcessHelper.cpp index 7f3e4ba72..59869fdff 100644 --- a/code/ProcessHelper.cpp +++ b/code/PostProcessing/ProcessHelper.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/ProcessHelper.h b/code/PostProcessing/ProcessHelper.h similarity index 99% rename from code/ProcessHelper.h rename to code/PostProcessing/ProcessHelper.h index dcf71e853..0afcc4142 100644 --- a/code/ProcessHelper.h +++ b/code/PostProcessing/ProcessHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -51,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "BaseProcess.h" +#include "Common/BaseProcess.h" #include #include diff --git a/code/RemoveRedundantMaterials.cpp b/code/PostProcessing/RemoveRedundantMaterials.cpp similarity index 96% rename from code/RemoveRedundantMaterials.cpp rename to code/PostProcessing/RemoveRedundantMaterials.cpp index 7194d3c8e..49ec8f5c4 100644 --- a/code/RemoveRedundantMaterials.cpp +++ b/code/PostProcessing/RemoveRedundantMaterials.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "RemoveRedundantMaterials.h" #include #include "ProcessHelper.h" -#include "MaterialSystem.h" +#include "Material/MaterialSystem.h" #include using namespace Assimp; @@ -57,7 +57,7 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer RemoveRedundantMatsProcess::RemoveRedundantMatsProcess() -: configFixedMaterials() { +: mConfigFixedMaterials() { // nothing to do here } @@ -80,7 +80,7 @@ bool RemoveRedundantMatsProcess::IsActive( unsigned int pFlags) const void RemoveRedundantMatsProcess::SetupProperties(const Importer* pImp) { // Get value of AI_CONFIG_PP_RRM_EXCLUDE_LIST - configFixedMaterials = pImp->GetPropertyString(AI_CONFIG_PP_RRM_EXCLUDE_LIST,""); + mConfigFixedMaterials = pImp->GetPropertyString(AI_CONFIG_PP_RRM_EXCLUDE_LIST,""); } // ------------------------------------------------------------------------------------------------ @@ -100,10 +100,10 @@ void RemoveRedundantMatsProcess::Execute( aiScene* pScene) // If a list of materials to be excluded was given, match the list with // our imported materials and 'salt' all positive matches to ensure that // we get unique hashes later. - if (configFixedMaterials.length()) { + if (mConfigFixedMaterials.length()) { std::list strings; - ConvertListToStrings(configFixedMaterials,strings); + ConvertListToStrings(mConfigFixedMaterials,strings); for (unsigned int i = 0; i < pScene->mNumMaterials;++i) { aiMaterial* mat = pScene->mMaterials[i]; diff --git a/code/RemoveRedundantMaterials.h b/code/PostProcessing/RemoveRedundantMaterials.h similarity index 91% rename from code/RemoveRedundantMaterials.h rename to code/PostProcessing/RemoveRedundantMaterials.h index 314bbf345..1f32a0abf 100644 --- a/code/RemoveRedundantMaterials.h +++ b/code/PostProcessing/RemoveRedundantMaterials.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_REMOVEREDUNDANTMATERIALS_H_INC #define AI_REMOVEREDUNDANTMATERIALS_H_INC -#include "BaseProcess.h" +#include "Common/BaseProcess.h" #include class RemoveRedundantMatsTest; @@ -57,8 +57,7 @@ namespace Assimp { /** RemoveRedundantMatsProcess: Post-processing step to remove redundant * materials from the imported scene. */ -class ASSIMP_API RemoveRedundantMatsProcess : public BaseProcess -{ +class ASSIMP_API RemoveRedundantMatsProcess : public BaseProcess { public: /// The default class constructor. RemoveRedundantMatsProcess(); @@ -66,7 +65,6 @@ public: /// The class destructor. ~RemoveRedundantMatsProcess(); -public: // ------------------------------------------------------------------- // Check whether step is active bool IsActive( unsigned int pFlags) const; @@ -79,27 +77,25 @@ public: // Setup import settings void SetupProperties(const Importer* pImp); - // ------------------------------------------------------------------- - /** @brief Set list of fixed (unmutable) materials + /** @brief Set list of fixed (inmutable) materials * @param fixed See #AI_CONFIG_PP_RRM_EXCLUDE_LIST */ void SetFixedMaterialsString(const std::string& fixed = "") { - configFixedMaterials = fixed; + mConfigFixedMaterials = fixed; } // ------------------------------------------------------------------- - /** @brief Get list of fixed (unmutable) materials + /** @brief Get list of fixed (inmutable) materials * @return See #AI_CONFIG_PP_RRM_EXCLUDE_LIST */ const std::string& GetFixedMaterialsString() const { - return configFixedMaterials; + return mConfigFixedMaterials; } private: - //! Configuration option: list of all fixed materials - std::string configFixedMaterials; + std::string mConfigFixedMaterials; }; } // end of namespace Assimp diff --git a/code/RemoveVCProcess.cpp b/code/PostProcessing/RemoveVCProcess.cpp similarity index 99% rename from code/RemoveVCProcess.cpp rename to code/PostProcessing/RemoveVCProcess.cpp index 81249eab2..99fd47a3a 100644 --- a/code/RemoveVCProcess.cpp +++ b/code/PostProcessing/RemoveVCProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/RemoveVCProcess.h b/code/PostProcessing/RemoveVCProcess.h similarity index 98% rename from code/RemoveVCProcess.h rename to code/PostProcessing/RemoveVCProcess.h index 597de8584..7bb21a833 100644 --- a/code/RemoveVCProcess.h +++ b/code/PostProcessing/RemoveVCProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -44,7 +44,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_REMOVEVCPROCESS_H_INCLUDED #define AI_REMOVEVCPROCESS_H_INCLUDED -#include "BaseProcess.h" +#include "Common/BaseProcess.h" + #include class RemoveVCProcessTest; diff --git a/code/PostProcessing/ScaleProcess.cpp b/code/PostProcessing/ScaleProcess.cpp new file mode 100644 index 000000000..ac770c41f --- /dev/null +++ b/code/PostProcessing/ScaleProcess.cpp @@ -0,0 +1,208 @@ +/* +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 "ScaleProcess.h" + +#include +#include +#include + +namespace Assimp { + +ScaleProcess::ScaleProcess() +: BaseProcess() +, mScale( AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT ) { +} + +ScaleProcess::~ScaleProcess() { + // empty +} + +void ScaleProcess::setScale( ai_real scale ) { + mScale = scale; +} + +ai_real ScaleProcess::getScale() const { + return mScale; +} + +bool ScaleProcess::IsActive( unsigned int pFlags ) const { + return ( pFlags & aiProcess_GlobalScale ) != 0; +} + +void ScaleProcess::SetupProperties( const Importer* pImp ) { + // User scaling + mScale = pImp->GetPropertyFloat( AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY, 1.0f ); + + // File scaling * Application Scaling + float importerScale = pImp->GetPropertyFloat( AI_CONFIG_APP_SCALE_KEY, 1.0f ); + + // apply scale to the scale + // helps prevent bugs with backward compatibility for anyone using normal scaling. + mScale *= importerScale; +} + +void ScaleProcess::Execute( aiScene* pScene ) { + if(mScale == 1.0f) { + return; // nothing to scale + } + + ai_assert( mScale != 0 ); + ai_assert( nullptr != pScene ); + ai_assert( nullptr != pScene->mRootNode ); + + if ( nullptr == pScene ) { + return; + } + + if ( nullptr == pScene->mRootNode ) { + return; + } + + // Process animations and update position transform to new unit system + for( unsigned int animationID = 0; animationID < pScene->mNumAnimations; animationID++ ) + { + aiAnimation* animation = pScene->mAnimations[animationID]; + + for( unsigned int animationChannel = 0; animationChannel < animation->mNumChannels; animationChannel++) + { + aiNodeAnim* anim = animation->mChannels[animationChannel]; + + for( unsigned int posKey = 0; posKey < anim->mNumPositionKeys; posKey++) + { + aiVectorKey& vectorKey = anim->mPositionKeys[posKey]; + vectorKey.mValue *= mScale; + } + } + } + + for( unsigned int meshID = 0; meshID < pScene->mNumMeshes; meshID++) + { + aiMesh *mesh = pScene->mMeshes[meshID]; + + // Reconstruct mesh vertexes to the new unit system + for( unsigned int vertexID = 0; vertexID < mesh->mNumVertices; vertexID++) + { + aiVector3D& vertex = mesh->mVertices[vertexID]; + vertex *= mScale; + } + + + // bone placement / scaling + for( unsigned int boneID = 0; boneID < mesh->mNumBones; boneID++) + { + // Reconstruct matrix by transform rather than by scale + // This prevent scale values being changed which can + // be meaningful in some cases + // like when you want the modeller to see 1:1 compatibility. + aiBone* bone = mesh->mBones[boneID]; + + aiVector3D pos, scale; + aiQuaternion rotation; + + bone->mOffsetMatrix.Decompose( scale, rotation, pos); + + aiMatrix4x4 translation; + aiMatrix4x4::Translation( pos * mScale, translation ); + + aiMatrix4x4 scaling; + aiMatrix4x4::Scaling( aiVector3D(scale), scaling ); + + aiMatrix4x4 RotMatrix = aiMatrix4x4 (rotation.GetMatrix()); + + bone->mOffsetMatrix = translation * RotMatrix * scaling; + } + + + // animation mesh processing + // convert by position rather than scale. + for( unsigned int animMeshID = 0; animMeshID < mesh->mNumAnimMeshes; animMeshID++) + { + aiAnimMesh * animMesh = mesh->mAnimMeshes[animMeshID]; + + for( unsigned int vertexID = 0; vertexID < animMesh->mNumVertices; vertexID++) + { + aiVector3D& vertex = animMesh->mVertices[vertexID]; + vertex *= mScale; + } + } + } + + traverseNodes( pScene->mRootNode ); +} + +void ScaleProcess::traverseNodes( aiNode *node, unsigned int nested_node_id ) { + applyScaling( node ); + + for( size_t i = 0; i < node->mNumChildren; i++) + { + // recurse into the tree until we are done! + traverseNodes( node->mChildren[i], nested_node_id+1 ); + } +} + +void ScaleProcess::applyScaling( aiNode *currentNode ) { + if ( nullptr != currentNode ) { + // Reconstruct matrix by transform rather than by scale + // This prevent scale values being changed which can + // be meaningful in some cases + // like when you want the modeller to + // see 1:1 compatibility. + + aiVector3D pos, scale; + aiQuaternion rotation; + currentNode->mTransformation.Decompose( scale, rotation, pos); + + aiMatrix4x4 translation; + aiMatrix4x4::Translation( pos * mScale, translation ); + + aiMatrix4x4 scaling; + + // note: we do not use mScale here, this is on purpose. + aiMatrix4x4::Scaling( scale, scaling ); + + aiMatrix4x4 RotMatrix = aiMatrix4x4 (rotation.GetMatrix()); + + currentNode->mTransformation = translation * RotMatrix * scaling; + } +} + +} // Namespace Assimp diff --git a/code/ScaleProcess.h b/code/PostProcessing/ScaleProcess.h similarity index 83% rename from code/ScaleProcess.h rename to code/PostProcessing/ScaleProcess.h index 0621220a8..468a21673 100644 --- a/code/ScaleProcess.h +++ b/code/PostProcessing/ScaleProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -39,9 +39,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -#pragma once +#ifndef SCALE_PROCESS_H_ +#define SCALE_PROCESS_H_ -#include "BaseProcess.h" +#include "Common/BaseProcess.h" struct aiNode; @@ -53,6 +54,11 @@ namespace Assimp { // --------------------------------------------------------------------------- /** ScaleProcess: Class to rescale the whole model. + * Now rescales animations, bones, and blend shapes properly. + * Please note this will not write to 'scale' transform it will rewrite mesh + * and matrixes so that your scale values + * from your model package are preserved, so this is completely intentional + * bugs should be reported as soon as they are found. */ class ASSIMP_API ScaleProcess : public BaseProcess { public: @@ -78,7 +84,7 @@ public: virtual void Execute( aiScene* pScene ); private: - void traverseNodes( aiNode *currentNode ); + void traverseNodes( aiNode *currentNode, unsigned int nested_node_id = 0 ); void applyScaling( aiNode *currentNode ); private: @@ -86,3 +92,6 @@ private: }; } // Namespace Assimp + + +#endif // SCALE_PROCESS_H_ \ No newline at end of file diff --git a/code/SortByPTypeProcess.cpp b/code/PostProcessing/SortByPTypeProcess.cpp similarity index 89% rename from code/SortByPTypeProcess.cpp rename to code/PostProcessing/SortByPTypeProcess.cpp index b67da5b95..be8405a17 100644 --- a/code/SortByPTypeProcess.cpp +++ b/code/PostProcessing/SortByPTypeProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -57,8 +57,8 @@ using namespace Assimp; // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer SortByPTypeProcess::SortByPTypeProcess() -{ - configRemoveMeshes = 0; +: mConfigRemoveMeshes( 0 ) { + // empty } // ------------------------------------------------------------------------------------------------ @@ -78,7 +78,7 @@ bool SortByPTypeProcess::IsActive( unsigned int pFlags) const // ------------------------------------------------------------------------------------------------ void SortByPTypeProcess::SetupProperties(const Importer* pImp) { - configRemoveMeshes = pImp->GetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE,0); + mConfigRemoveMeshes = pImp->GetPropertyInteger(AI_CONFIG_PP_SBP_REMOVE,0); } // ------------------------------------------------------------------------------------------------ @@ -172,7 +172,7 @@ void SortByPTypeProcess::Execute( aiScene* pScene) { } if (1 == num) { - if (!(configRemoveMeshes & mesh->mPrimitiveTypes)) { + if (!(mConfigRemoveMeshes & mesh->mPrimitiveTypes)) { *meshIdx = static_cast( outMeshes.size() ); outMeshes.push_back(mesh); } else { @@ -206,7 +206,7 @@ void SortByPTypeProcess::Execute( aiScene* pScene) { VertexWeightTable* avw = ComputeVertexBoneWeightTable(mesh); for (unsigned int real = 0; real < 4; ++real,++meshIdx) { - if ( !aiNumPerPType[real] || configRemoveMeshes & (1u << real)) + if ( !aiNumPerPType[real] || mConfigRemoveMeshes & (1u << real)) { continue; } @@ -228,36 +228,37 @@ void SortByPTypeProcess::Execute( aiScene* pScene) { out->mNumVertices = (3 == real ? numPolyVerts : out->mNumFaces * (real+1)); - aiVector3D *vert(NULL), *nor(NULL), *tan(NULL), *bit(NULL); + aiVector3D *vert(nullptr), *nor(nullptr), *tan(nullptr), *bit(nullptr); aiVector3D *uv [AI_MAX_NUMBER_OF_TEXTURECOORDS]; aiColor4D *cols [AI_MAX_NUMBER_OF_COLOR_SETS]; - if (mesh->mVertices) + if (mesh->mVertices) { vert = out->mVertices = new aiVector3D[out->mNumVertices]; + } - if (mesh->mNormals) - nor = out->mNormals = new aiVector3D[out->mNumVertices]; + if (mesh->mNormals) { + nor = out->mNormals = new aiVector3D[out->mNumVertices]; + } - if (mesh->mTangents) - { + if (mesh->mTangents) { tan = out->mTangents = new aiVector3D[out->mNumVertices]; bit = out->mBitangents = new aiVector3D[out->mNumVertices]; } - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) - { - if (mesh->mTextureCoords[i]) - uv[i] = out->mTextureCoords[i] = new aiVector3D[out->mNumVertices]; - else uv[i] = NULL; + for (unsigned int j = 0; j < AI_MAX_NUMBER_OF_TEXTURECOORDS;++j) { + uv[j] = nullptr; + if (mesh->mTextureCoords[j]) { + uv[j] = out->mTextureCoords[j] = new aiVector3D[out->mNumVertices]; + } - out->mNumUVComponents[i] = mesh->mNumUVComponents[i]; + out->mNumUVComponents[j] = mesh->mNumUVComponents[j]; } - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_COLOR_SETS;++i) - { - if (mesh->mColors[i]) - cols[i] = out->mColors[i] = new aiColor4D[out->mNumVertices]; - else cols[i] = NULL; + for (unsigned int j = 0; j < AI_MAX_NUMBER_OF_COLOR_SETS;++j) { + cols[j] = nullptr; + if (mesh->mColors[j]) { + cols[j] = out->mColors[j] = new aiColor4D[out->mNumVertices]; + } } typedef std::vector< aiVertexWeight > TempBoneInfo; @@ -323,7 +324,7 @@ void SortByPTypeProcess::Execute( aiScene* pScene) { in.mIndices[q] = outIdx++; } - in.mIndices = NULL; + in.mIndices = nullptr; ++outFaces; } ai_assert(outFaces == out->mFaces + out->mNumFaces); @@ -391,10 +392,10 @@ void SortByPTypeProcess::Execute( aiScene* pScene) { { char buffer[1024]; ::ai_snprintf(buffer,1024,"Points: %u%s, Lines: %u%s, Triangles: %u%s, Polygons: %u%s (Meshes, X = removed)", - aiNumMeshesPerPType[0], ((configRemoveMeshes & aiPrimitiveType_POINT) ? "X" : ""), - aiNumMeshesPerPType[1], ((configRemoveMeshes & aiPrimitiveType_LINE) ? "X" : ""), - aiNumMeshesPerPType[2], ((configRemoveMeshes & aiPrimitiveType_TRIANGLE) ? "X" : ""), - aiNumMeshesPerPType[3], ((configRemoveMeshes & aiPrimitiveType_POLYGON) ? "X" : "")); + aiNumMeshesPerPType[0], ((mConfigRemoveMeshes & aiPrimitiveType_POINT) ? "X" : ""), + aiNumMeshesPerPType[1], ((mConfigRemoveMeshes & aiPrimitiveType_LINE) ? "X" : ""), + aiNumMeshesPerPType[2], ((mConfigRemoveMeshes & aiPrimitiveType_TRIANGLE) ? "X" : ""), + aiNumMeshesPerPType[3], ((mConfigRemoveMeshes & aiPrimitiveType_POLYGON) ? "X" : "")); ASSIMP_LOG_INFO(buffer); ASSIMP_LOG_DEBUG("SortByPTypeProcess finished"); } diff --git a/code/SortByPTypeProcess.h b/code/PostProcessing/SortByPTypeProcess.h similarity index 94% rename from code/SortByPTypeProcess.h rename to code/PostProcessing/SortByPTypeProcess.h index 27bfa2155..1d7ccfc15 100644 --- a/code/SortByPTypeProcess.h +++ b/code/PostProcessing/SortByPTypeProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,10 +45,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_SORTBYPTYPEPROCESS_H_INC #define AI_SORTBYPTYPEPROCESS_H_INC -#include "BaseProcess.h" +#include "Common/BaseProcess.h" #include class SortByPTypeProcessTest; + namespace Assimp { @@ -57,14 +58,11 @@ namespace Assimp { * A mesh with 5 lines, 3 points and 145 triangles would be split in 3 * submeshes. */ -class ASSIMP_API SortByPTypeProcess : public BaseProcess -{ +class ASSIMP_API SortByPTypeProcess : public BaseProcess { public: - SortByPTypeProcess(); ~SortByPTypeProcess(); -public: // ------------------------------------------------------------------- bool IsActive( unsigned int pFlags) const; @@ -75,8 +73,7 @@ public: void SetupProperties(const Importer* pImp); private: - - int configRemoveMeshes; + int mConfigRemoveMeshes; }; diff --git a/code/SplitLargeMeshes.cpp b/code/PostProcessing/SplitLargeMeshes.cpp similarity index 99% rename from code/SplitLargeMeshes.cpp rename to code/PostProcessing/SplitLargeMeshes.cpp index 5cd3afe48..1797b28d5 100644 --- a/code/SplitLargeMeshes.cpp +++ b/code/PostProcessing/SplitLargeMeshes.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/SplitLargeMeshes.h b/code/PostProcessing/SplitLargeMeshes.h similarity index 98% rename from code/SplitLargeMeshes.h rename to code/PostProcessing/SplitLargeMeshes.h index 7a977ff07..3f90576ea 100644 --- a/code/SplitLargeMeshes.h +++ b/code/PostProcessing/SplitLargeMeshes.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -40,21 +39,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -/** @file Defines a post processing step to split large meshes into submeshes +/** @file Defines a post processing step to split large meshes into sub-meshes */ #ifndef AI_SPLITLARGEMESHES_H_INC #define AI_SPLITLARGEMESHES_H_INC #include -#include "BaseProcess.h" +#include "Common/BaseProcess.h" #include #include +// Forward declarations class SplitLargeMeshesTest; -namespace Assimp -{ +namespace Assimp { class SplitLargeMeshesProcess_Triangle; class SplitLargeMeshesProcess_Vertex; diff --git a/code/TextureTransform.cpp b/code/PostProcessing/TextureTransform.cpp similarity index 99% rename from code/TextureTransform.cpp rename to code/PostProcessing/TextureTransform.cpp index c7adbe7a9..8ae2ba721 100644 --- a/code/TextureTransform.cpp +++ b/code/PostProcessing/TextureTransform.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/TextureTransform.h b/code/PostProcessing/TextureTransform.h similarity index 98% rename from code/TextureTransform.h rename to code/PostProcessing/TextureTransform.h index 99d5acf1e..2a5d623d7 100644 --- a/code/TextureTransform.h +++ b/code/PostProcessing/TextureTransform.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,7 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_TEXTURE_TRANSFORM_H_INCLUDED #include -#include "BaseProcess.h" +#include "Common/BaseProcess.h" #include #include diff --git a/code/TriangulateProcess.cpp b/code/PostProcessing/TriangulateProcess.cpp similarity index 99% rename from code/TriangulateProcess.cpp rename to code/PostProcessing/TriangulateProcess.cpp index b2ea46ef7..1040836bb 100644 --- a/code/TriangulateProcess.cpp +++ b/code/PostProcessing/TriangulateProcess.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -60,9 +58,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * a file */ #ifndef ASSIMP_BUILD_NO_TRIANGULATE_PROCESS -#include "TriangulateProcess.h" -#include "ProcessHelper.h" -#include "PolyTools.h" + +#include "PostProcessing/TriangulateProcess.h" +#include "PostProcessing/ProcessHelper.h" +#include "Common/PolyTools.h" + #include //#define AI_BUILD_TRIANGULATE_COLOR_FACE_WINDING diff --git a/code/TriangulateProcess.h b/code/PostProcessing/TriangulateProcess.h similarity index 95% rename from code/TriangulateProcess.h rename to code/PostProcessing/TriangulateProcess.h index e6300085d..916b5103d 100644 --- a/code/TriangulateProcess.h +++ b/code/PostProcessing/TriangulateProcess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_TRIANGULATEPROCESS_H_INC #define AI_TRIANGULATEPROCESS_H_INC -#include "BaseProcess.h" +#include "Common/BaseProcess.h" struct aiMesh; @@ -59,14 +59,11 @@ namespace Assimp { * into triangles. You usually want this to happen because the graphics cards * need their data as triangles. */ -class ASSIMP_API TriangulateProcess : public BaseProcess -{ +class ASSIMP_API TriangulateProcess : public BaseProcess { public: - TriangulateProcess(); ~TriangulateProcess(); -public: // ------------------------------------------------------------------- /** Returns whether the processing step is present in the given flag field. * @param pFlags The processing flags the importer was called with. A bitwise @@ -82,7 +79,6 @@ public: */ void Execute( aiScene* pScene); -public: // ------------------------------------------------------------------- /** Triangulates the given mesh. * @param pMesh The mesh to triangulate. diff --git a/code/ValidateDataStructure.cpp b/code/PostProcessing/ValidateDataStructure.cpp similarity index 85% rename from code/ValidateDataStructure.cpp rename to code/PostProcessing/ValidateDataStructure.cpp index 931c52822..75d1b6ef7 100644 --- a/code/ValidateDataStructure.cpp +++ b/code/PostProcessing/ValidateDataStructure.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -46,8 +46,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * the data structure returned by Assimp. */ - - // internal headers #include "ValidateDataStructure.h" #include @@ -110,8 +108,8 @@ void ValidateDSProcess::ReportWarning(const char* msg,...) } // ------------------------------------------------------------------------------------------------ -inline int HasNameMatch(const aiString& in, aiNode* node) -{ +inline +int HasNameMatch(const aiString& in, aiNode* node) { int result = (node->mName == in ? 1 : 0 ); for (unsigned int i = 0; i < node->mNumChildren;++i) { result += HasNameMatch(in,node->mChildren[i]); @@ -121,9 +119,8 @@ inline int HasNameMatch(const aiString& in, aiNode* node) // ------------------------------------------------------------------------------------------------ template -inline void ValidateDSProcess::DoValidation(T** parray, unsigned int size, - const char* firstName, const char* secondName) -{ +inline +void ValidateDSProcess::DoValidation(T** parray, unsigned int size, const char* firstName, const char* secondName) { // validate all entries if (size) { @@ -160,7 +157,7 @@ inline void ValidateDSProcess::DoValidationEx(T** parray, unsigned int size, { if (!parray[i]) { - ReportError("aiScene::%s[%i] is NULL (aiScene::%s is %i)", + ReportError("aiScene::%s[%u] is NULL (aiScene::%s is %u)", firstName,i,secondName,size); } Validate(parray[i]); @@ -170,8 +167,8 @@ inline void ValidateDSProcess::DoValidationEx(T** parray, unsigned int size, { if (parray[i]->mName == parray[a]->mName) { - this->ReportError("aiScene::%s[%i] has the same name as " - "aiScene::%s[%i]",firstName, i,secondName, a); + ReportError("aiScene::%s[%u] has the same name as " + "aiScene::%s[%u]",firstName, i,secondName, a); } } } @@ -180,32 +177,30 @@ inline void ValidateDSProcess::DoValidationEx(T** parray, unsigned int size, // ------------------------------------------------------------------------------------------------ template -inline void ValidateDSProcess::DoValidationWithNameCheck(T** array, - unsigned int size, const char* firstName, - const char* secondName) -{ +inline +void ValidateDSProcess::DoValidationWithNameCheck(T** array, unsigned int size, const char* firstName, + const char* secondName) { // validate all entries DoValidationEx(array,size,firstName,secondName); - for (unsigned int i = 0; i < size;++i) - { + for (unsigned int i = 0; i < size;++i) { int res = HasNameMatch(array[i]->mName,mScene->mRootNode); - if (!res) { + if (0 == res) { + const std::string name = static_cast(array[i]->mName.data); ReportError("aiScene::%s[%i] has no corresponding node in the scene graph (%s)", - firstName,i,array[i]->mName.data); - } - else if (1 != res) { + firstName,i, name.c_str()); + } else if (1 != res) { + const std::string name = static_cast(array[i]->mName.data); ReportError("aiScene::%s[%i]: there are more than one nodes with %s as name", - firstName,i,array[i]->mName.data); + firstName,i, name.c_str()); } } } // ------------------------------------------------------------------------------------------------ // Executes the post processing step on the given imported data. -void ValidateDSProcess::Execute( aiScene* pScene) -{ - this->mScene = pScene; +void ValidateDSProcess::Execute( aiScene* pScene) { + mScene = pScene; ASSIMP_LOG_DEBUG("ValidateDataStructureProcess begin"); // validate the node graph of the scene @@ -332,6 +327,7 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh) { case 0: ReportError("aiMesh::mFaces[%i].mNumIndices is 0",i); + break; case 1: if (0 == (pMesh->mPrimitiveTypes & aiPrimitiveType_POINT)) { @@ -424,7 +420,9 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh) if (!abRefList[i])b = true; } abRefList.clear(); - if (b)ReportWarning("There are unreferenced vertices"); + if (b) { + ReportWarning("There are unreferenced vertices"); + } // texture channel 2 may not be set if channel 1 is zero ... { @@ -515,13 +513,11 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh) } // ------------------------------------------------------------------------------------------------ -void ValidateDSProcess::Validate( const aiMesh* pMesh, - const aiBone* pBone,float* afSum) -{ +void ValidateDSProcess::Validate( const aiMesh* pMesh, const aiBone* pBone,float* afSum) { this->Validate(&pBone->mName); if (!pBone->mNumWeights) { - ReportError("aiBone::mNumWeights is zero"); + //ReportError("aiBone::mNumWeights is zero"); } // check whether all vertices affected by this bone are valid @@ -542,13 +538,17 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation) { Validate(&pAnimation->mName); - // validate all materials - if (pAnimation->mNumChannels) + // validate all animations + if (pAnimation->mNumChannels || pAnimation->mNumMorphMeshChannels) { - if (!pAnimation->mChannels) { + if (!pAnimation->mChannels && pAnimation->mNumChannels) { ReportError("aiAnimation::mChannels is NULL (aiAnimation::mNumChannels is %i)", pAnimation->mNumChannels); } + if (!pAnimation->mMorphMeshChannels && pAnimation->mNumMorphMeshChannels) { + ReportError("aiAnimation::mMorphMeshChannels is NULL (aiAnimation::mNumMorphMeshChannels is %i)", + pAnimation->mNumMorphMeshChannels); + } for (unsigned int i = 0; i < pAnimation->mNumChannels;++i) { if (!pAnimation->mChannels[i]) @@ -558,11 +558,19 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation) } Validate(pAnimation, pAnimation->mChannels[i]); } + for (unsigned int i = 0; i < pAnimation->mNumMorphMeshChannels;++i) + { + if (!pAnimation->mMorphMeshChannels[i]) + { + ReportError("aiAnimation::mMorphMeshChannels[%i] is NULL (aiAnimation::mNumMorphMeshChannels is %i)", + i, pAnimation->mNumMorphMeshChannels); + } + Validate(pAnimation, pAnimation->mMorphMeshChannels[i]); + } + } + else { + ReportError("aiAnimation::mNumChannels is 0. At least one node animation channel must be there."); } - else ReportError("aiAnimation::mNumChannels is 0. At least one node animation channel must be there."); - - // Animation duration is allowed to be zero in cases where the anim contains only a single key frame. - // if (!pAnimation->mDuration)this->ReportError("aiAnimation::mDuration is zero"); } // ------------------------------------------------------------------------------------------------ @@ -579,15 +587,16 @@ void ValidateDSProcess::SearchForInvalidTextures(const aiMaterial* pMaterial, int iNumIndices = 0; int iIndex = -1; - for (unsigned int i = 0; i < pMaterial->mNumProperties;++i) - { - aiMaterialProperty* prop = pMaterial->mProperties[i]; - if (!::strcmp(prop->mKey.data,"$tex.file") && prop->mSemantic == type) { + for (unsigned int i = 0; i < pMaterial->mNumProperties;++i) { + aiMaterialProperty* prop = pMaterial->mProperties[ i ]; + ai_assert(nullptr != prop); + if ( !::strcmp(prop->mKey.data,"$tex.file") && prop->mSemantic == static_cast(type)) { iIndex = std::max(iIndex, (int) prop->mIndex); ++iNumIndices; - if (aiPTI_String != prop->mType) - ReportError("Material property %s is expected to be a string",prop->mKey.data); + if (aiPTI_String != prop->mType) { + ReportError("Material property %s is expected to be a string", prop->mKey.data); + } } } if (iIndex +1 != iNumIndices) { @@ -699,7 +708,7 @@ void ValidateDSProcess::Validate( const aiMaterial* pMaterial) if (prop->mDataLength < 5 || prop->mDataLength < 4 + (*reinterpret_cast(prop->mData)) + 1) { ReportError("aiMaterial::mProperties[%i].mDataLength is " "too small to contain a string (%i, needed: %i)", - i,prop->mDataLength,sizeof(aiString)); + i,prop->mDataLength,static_cast(sizeof(aiString))); } if(prop->mData[prop->mDataLength-1]) { ReportError("Missing null-terminator in string material property"); @@ -710,14 +719,14 @@ void ValidateDSProcess::Validate( const aiMaterial* pMaterial) if (prop->mDataLength < sizeof(float)) { ReportError("aiMaterial::mProperties[%i].mDataLength is " "too small to contain a float (%i, needed: %i)", - i,prop->mDataLength,sizeof(float)); + i,prop->mDataLength, static_cast(sizeof(float))); } } else if (aiPTI_Integer == prop->mType) { if (prop->mDataLength < sizeof(int)) { ReportError("aiMaterial::mProperties[%i].mDataLength is " "too small to contain an integer (%i, needed: %i)", - i,prop->mDataLength,sizeof(int)); + i,prop->mDataLength, static_cast(sizeof(int))); } } // TODO: check whether there is a key with an unknown name ... @@ -742,8 +751,9 @@ void ValidateDSProcess::Validate( const aiMaterial* pMaterial) "AI_MATKEY_SHININESS_STRENGTH key is 0.0"); } break; - default: ; - }; + default: + break; + } } if (AI_SUCCESS == aiGetMaterialFloat( pMaterial,AI_MATKEY_OPACITY,&fTemp) && (!fTemp || fTemp > 1.01)) { @@ -775,8 +785,10 @@ void ValidateDSProcess::Validate( const aiTexture* pTexture) } if (pTexture->mHeight) { - if (!pTexture->mWidth)ReportError("aiTexture::mWidth is zero " - "(aiTexture::mHeight is %i, uncompressed texture)",pTexture->mHeight); + if (!pTexture->mWidth){ + ReportError("aiTexture::mWidth is zero (aiTexture::mHeight is %i, uncompressed texture)", + pTexture->mHeight); + } } else { @@ -807,15 +819,15 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation, { Validate(&pNodeAnim->mNodeName); - if (!pNodeAnim->mNumPositionKeys && !pNodeAnim->mScalingKeys && !pNodeAnim->mNumRotationKeys) + if (!pNodeAnim->mNumPositionKeys && !pNodeAnim->mScalingKeys && !pNodeAnim->mNumRotationKeys) { ReportError("Empty node animation channel"); - + } // otherwise check whether one of the keys exceeds the total duration of the animation if (pNodeAnim->mNumPositionKeys) { if (!pNodeAnim->mPositionKeys) { - this->ReportError("aiNodeAnim::mPositionKeys is NULL (aiNodeAnim::mNumPositionKeys is %i)", + ReportError("aiNodeAnim::mPositionKeys is NULL (aiNodeAnim::mNumPositionKeys is %i)", pNodeAnim->mNumPositionKeys); } double dLast = -10e10; @@ -846,7 +858,7 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation, { if (!pNodeAnim->mRotationKeys) { - this->ReportError("aiNodeAnim::mRotationKeys is NULL (aiNodeAnim::mNumRotationKeys is %i)", + ReportError("aiNodeAnim::mRotationKeys is NULL (aiNodeAnim::mNumRotationKeys is %i)", pNodeAnim->mNumRotationKeys); } double dLast = -10e10; @@ -904,22 +916,68 @@ void ValidateDSProcess::Validate( const aiAnimation* pAnimation, } } +void ValidateDSProcess::Validate( const aiAnimation* pAnimation, + const aiMeshMorphAnim* pMeshMorphAnim) +{ + Validate(&pMeshMorphAnim->mName); + + if (!pMeshMorphAnim->mNumKeys) { + ReportError("Empty mesh morph animation channel"); + } + + // otherwise check whether one of the keys exceeds the total duration of the animation + if (pMeshMorphAnim->mNumKeys) + { + if (!pMeshMorphAnim->mKeys) + { + ReportError("aiMeshMorphAnim::mKeys is NULL (aiMeshMorphAnim::mNumKeys is %i)", + pMeshMorphAnim->mNumKeys); + } + double dLast = -10e10; + for (unsigned int i = 0; i < pMeshMorphAnim->mNumKeys;++i) + { + // ScenePreprocessor will compute the duration if still the default value + // (Aramis) Add small epsilon, comparison tended to fail if max_time == duration, + // seems to be due the compilers register usage/width. + if (pAnimation->mDuration > 0. && pMeshMorphAnim->mKeys[i].mTime > pAnimation->mDuration+0.001) + { + ReportError("aiMeshMorphAnim::mKeys[%i].mTime (%.5f) is larger " + "than aiAnimation::mDuration (which is %.5f)",i, + (float)pMeshMorphAnim->mKeys[i].mTime, + (float)pAnimation->mDuration); + } + if (i && pMeshMorphAnim->mKeys[i].mTime <= dLast) + { + ReportWarning("aiMeshMorphAnim::mKeys[%i].mTime (%.5f) is smaller " + "than aiMeshMorphAnim::mKeys[%i] (which is %.5f)",i, + (float)pMeshMorphAnim->mKeys[i].mTime, + i-1, (float)dLast); + } + dLast = pMeshMorphAnim->mKeys[i].mTime; + } + } +} + // ------------------------------------------------------------------------------------------------ void ValidateDSProcess::Validate( const aiNode* pNode) { - if (!pNode)ReportError("A node of the scenegraph is NULL"); - if (pNode != mScene->mRootNode && !pNode->mParent) - this->ReportError("A node has no valid parent (aiNode::mParent is NULL)"); - + if (!pNode) { + ReportError("A node of the scenegraph is NULL"); + } + // Validate node name string first so that it's safe to use in below expressions this->Validate(&pNode->mName); + const char* nodeName = (&pNode->mName)->C_Str(); + if (pNode != mScene->mRootNode && !pNode->mParent){ + ReportError("Non-root node %s lacks a valid parent (aiNode::mParent is NULL) ", nodeName); + } // validate all meshes if (pNode->mNumMeshes) { if (!pNode->mMeshes) { - ReportError("aiNode::mMeshes is NULL (aiNode::mNumMeshes is %i)", - pNode->mNumMeshes); + ReportError("aiNode::mMeshes is NULL for node %s (aiNode::mNumMeshes is %i)", + nodeName, pNode->mNumMeshes); } std::vector abHadMesh; abHadMesh.resize(mScene->mNumMeshes,false); @@ -927,13 +985,13 @@ void ValidateDSProcess::Validate( const aiNode* pNode) { if (pNode->mMeshes[i] >= mScene->mNumMeshes) { - ReportError("aiNode::mMeshes[%i] is out of range (maximum is %i)", - pNode->mMeshes[i],mScene->mNumMeshes-1); + ReportError("aiNode::mMeshes[%i] is out of range for node %s (maximum is %i)", + pNode->mMeshes[i], nodeName, mScene->mNumMeshes-1); } if (abHadMesh[pNode->mMeshes[i]]) { - ReportError("aiNode::mMeshes[%i] is already referenced by this node (value: %i)", - i,pNode->mMeshes[i]); + ReportError("aiNode::mMeshes[%i] is already referenced by this node %s (value: %i)", + i, nodeName, pNode->mMeshes[i]); } abHadMesh[pNode->mMeshes[i]] = true; } @@ -941,8 +999,8 @@ void ValidateDSProcess::Validate( const aiNode* pNode) if (pNode->mNumChildren) { if (!pNode->mChildren) { - ReportError("aiNode::mChildren is NULL (aiNode::mNumChildren is %i)", - pNode->mNumChildren); + ReportError("aiNode::mChildren is NULL for node %s (aiNode::mNumChildren is %i)", + nodeName, pNode->mNumChildren); } for (unsigned int i = 0; i < pNode->mNumChildren;++i) { Validate(pNode->mChildren[i]); @@ -955,7 +1013,7 @@ void ValidateDSProcess::Validate( const aiString* pString) { if (pString->length > MAXLEN) { - this->ReportError("aiString::length is too large (%i, maximum is %i)", + ReportError("aiString::length is too large (%u, maximum is %lu)", pString->length,MAXLEN); } const char* sz = pString->data; @@ -963,12 +1021,14 @@ void ValidateDSProcess::Validate( const aiString* pString) { if ('\0' == *sz) { - if (pString->length != (unsigned int)(sz-pString->data)) + if (pString->length != (unsigned int)(sz-pString->data)) { ReportError("aiString::data is invalid: the terminal zero is at a wrong offset"); + } break; } - else if (sz >= &pString->data[MAXLEN]) + else if (sz >= &pString->data[MAXLEN]) { ReportError("aiString::data is invalid. There is no terminal character"); + } ++sz; } } diff --git a/code/ValidateDataStructure.h b/code/PostProcessing/ValidateDataStructure.h similarity index 94% rename from code/ValidateDataStructure.h rename to code/PostProcessing/ValidateDataStructure.h index 4e1636bfa..7b309c925 100644 --- a/code/ValidateDataStructure.h +++ b/code/PostProcessing/ValidateDataStructure.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -48,12 +48,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "BaseProcess.h" + +#include "Common/BaseProcess.h" struct aiBone; struct aiMesh; struct aiAnimation; struct aiNodeAnim; +struct aiMeshMorphAnim; struct aiTexture; struct aiMaterial; struct aiNode; @@ -149,6 +151,13 @@ protected: void Validate( const aiAnimation* pAnimation, const aiNodeAnim* pBoneAnim); + /** Validates a mesh morph animation channel. + * @param pAnimation Input animation. + * @param pMeshMorphAnim Mesh morph animation channel. + * */ + void Validate( const aiAnimation* pAnimation, + const aiMeshMorphAnim* pMeshMorphAnim); + // ------------------------------------------------------------------- /** Validates a node and all of its subnodes * @param Node Input node*/ diff --git a/code/Q3BSPFileData.h b/code/Q3BSP/Q3BSPFileData.h similarity index 99% rename from code/Q3BSPFileData.h rename to code/Q3BSP/Q3BSPFileData.h index d814837c2..4e05bebf1 100644 --- a/code/Q3BSPFileData.h +++ b/code/Q3BSP/Q3BSPFileData.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/Q3BSPFileImporter.cpp b/code/Q3BSP/Q3BSPFileImporter.cpp similarity index 97% rename from code/Q3BSPFileImporter.cpp rename to code/Q3BSP/Q3BSPFileImporter.cpp index 58fbef985..4add00a07 100644 --- a/code/Q3BSPFileImporter.cpp +++ b/code/Q3BSP/Q3BSPFileImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -43,7 +43,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER #include "Q3BSPFileImporter.h" -#include "Q3BSPZipArchive.h" #include "Q3BSPFileParser.h" #include "Q3BSPFileData.h" @@ -60,6 +59,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include #include @@ -181,7 +181,7 @@ const aiImporterDesc* Q3BSPFileImporter::GetInfo () const { // ------------------------------------------------------------------------------------------------ // Import method. void Q3BSPFileImporter::InternReadFile(const std::string &rFile, aiScene* scene, IOSystem* ioHandler) { - Q3BSPZipArchive Archive( ioHandler, rFile ); + ZipArchiveIOSystem Archive( ioHandler, rFile ); if ( !Archive.isOpen() ) { throw DeadlyImportError( "Failed to open file " + rFile + "." ); } @@ -223,10 +223,10 @@ void Q3BSPFileImporter::separateMapName( const std::string &importName, std::str // ------------------------------------------------------------------------------------------------ // Returns the first map in the map archive. -bool Q3BSPFileImporter::findFirstMapInArchive( Q3BSPZipArchive &bspArchive, std::string &mapName ) { +bool Q3BSPFileImporter::findFirstMapInArchive(ZipArchiveIOSystem &bspArchive, std::string &mapName ) { mapName = ""; std::vector fileList; - bspArchive.getFileList( fileList ); + bspArchive.getFileListExtension( fileList, "bsp" ); if (fileList.empty()) { return false; } @@ -249,7 +249,7 @@ bool Q3BSPFileImporter::findFirstMapInArchive( Q3BSPZipArchive &bspArchive, std: // ------------------------------------------------------------------------------------------------ // Creates the assimp specific data. void Q3BSPFileImporter::CreateDataFromImport( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, - Q3BSPZipArchive *pArchive ) { + ZipArchiveIOSystem *pArchive ) { if (nullptr == pModel || nullptr == pScene) { return; } @@ -400,6 +400,7 @@ void Q3BSPFileImporter::createTriangleTopology( const Q3BSP::Q3BSPModel *pModel, if (nullptr != m_pCurrentFace) { m_pCurrentFace->mNumIndices = 3; m_pCurrentFace->mIndices = new unsigned int[3]; + m_pCurrentFace->mIndices[ idx ] = vertIdx; } } @@ -409,9 +410,7 @@ void Q3BSPFileImporter::createTriangleTopology( const Q3BSP::Q3BSPModel *pModel, pMesh->mTextureCoords[ 0 ][ vertIdx ].Set( pVertex->vTexCoord.x, pVertex->vTexCoord.y, 0.0f ); pMesh->mTextureCoords[ 1 ][ vertIdx ].Set( pVertex->vLightmap.x, pVertex->vLightmap.y, 0.0f ); - m_pCurrentFace->mIndices[ idx ] = vertIdx; vertIdx++; - idx++; } } @@ -419,7 +418,7 @@ void Q3BSPFileImporter::createTriangleTopology( const Q3BSP::Q3BSPModel *pModel, // ------------------------------------------------------------------------------------------------ // Creates all referenced materials. void Q3BSPFileImporter::createMaterials( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, - Q3BSPZipArchive *pArchive ) { + ZipArchiveIOSystem *pArchive ) { if ( m_MaterialLookupMap.empty() ) { return; } @@ -565,7 +564,7 @@ aiFace *Q3BSPFileImporter::getNextFace( aiMesh *mesh, unsigned int &faceIdx ) { // ------------------------------------------------------------------------------------------------ // Imports a texture file. bool Q3BSPFileImporter::importTextureFromArchive( const Q3BSP::Q3BSPModel *model, - Q3BSP::Q3BSPZipArchive *archive, aiScene*, + ZipArchiveIOSystem *archive, aiScene*, aiMaterial *pMatHelper, int textureId ) { if (nullptr == archive || nullptr == pMatHelper ) { return false; @@ -670,7 +669,7 @@ bool Q3BSPFileImporter::importLightmap( const Q3BSP::Q3BSPModel *pModel, aiScene // ------------------------------------------------------------------------------------------------ // Will search for a supported extension. -bool Q3BSPFileImporter::expandFile( Q3BSP::Q3BSPZipArchive *pArchive, const std::string &rFilename, +bool Q3BSPFileImporter::expandFile(ZipArchiveIOSystem *pArchive, const std::string &rFilename, const std::vector &rExtList, std::string &rFile, std::string &rExt ) { diff --git a/code/Q3BSPFileImporter.h b/code/Q3BSP/Q3BSPFileImporter.h similarity index 91% rename from code/Q3BSPFileImporter.h rename to code/Q3BSP/Q3BSPFileImporter.h index 5f3e31157..ee21fa48e 100644 --- a/code/Q3BSPFileImporter.h +++ b/code/Q3BSP/Q3BSPFileImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -54,9 +54,9 @@ struct aiMaterial; struct aiTexture; namespace Assimp { + class ZipArchiveIOSystem; namespace Q3BSP { - class Q3BSPZipArchive; struct Q3BSPModel; struct sQ3BSPFace; } @@ -85,24 +85,24 @@ protected: const aiImporterDesc* GetInfo () const; void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); void separateMapName( const std::string &rImportName, std::string &rArchiveName, std::string &rMapName ); - bool findFirstMapInArchive( Q3BSP::Q3BSPZipArchive &rArchive, std::string &rMapName ); - void CreateDataFromImport( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, Q3BSP::Q3BSPZipArchive *pArchive ); + bool findFirstMapInArchive(ZipArchiveIOSystem &rArchive, std::string &rMapName ); + void CreateDataFromImport( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, ZipArchiveIOSystem *pArchive ); void CreateNodes( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, aiNode *pParent ); aiNode *CreateTopology( const Q3BSP::Q3BSPModel *pModel, unsigned int materialIdx, std::vector &rArray, aiMesh **pMesh ); void createTriangleTopology( const Q3BSP::Q3BSPModel *pModel, Q3BSP::sQ3BSPFace *pQ3BSPFace, aiMesh* pMesh, unsigned int &rFaceIdx, unsigned int &rVertIdx ); - void createMaterials( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, Q3BSP::Q3BSPZipArchive *pArchive ); + void createMaterials( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, ZipArchiveIOSystem *pArchive ); size_t countData( const std::vector &rArray ) const; size_t countFaces( const std::vector &rArray ) const; size_t countTriangles( const std::vector &rArray ) const; void createMaterialMap( const Q3BSP::Q3BSPModel *pModel); aiFace *getNextFace( aiMesh *pMesh, unsigned int &rFaceIdx ); - bool importTextureFromArchive( const Q3BSP::Q3BSPModel *pModel, Q3BSP::Q3BSPZipArchive *pArchive, aiScene* pScene, + bool importTextureFromArchive( const Q3BSP::Q3BSPModel *pModel, ZipArchiveIOSystem *pArchive, aiScene* pScene, aiMaterial *pMatHelper, int textureId ); bool importLightmap( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene, aiMaterial *pMatHelper, int lightmapId ); bool importEntities( const Q3BSP::Q3BSPModel *pModel, aiScene* pScene ); - bool expandFile( Q3BSP::Q3BSPZipArchive *pArchive, const std::string &rFilename, const std::vector &rExtList, + bool expandFile(ZipArchiveIOSystem *pArchive, const std::string &rFilename, const std::vector &rExtList, std::string &rFile, std::string &rExt ); private: diff --git a/code/Q3BSPFileParser.cpp b/code/Q3BSP/Q3BSPFileParser.cpp similarity index 97% rename from code/Q3BSPFileParser.cpp rename to code/Q3BSP/Q3BSPFileParser.cpp index f7038adeb..bed2efe53 100644 --- a/code/Q3BSPFileParser.cpp +++ b/code/Q3BSP/Q3BSPFileParser.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,9 +45,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "Q3BSPFileParser.h" #include "Q3BSPFileData.h" -#include "Q3BSPZipArchive.h" #include #include +#include #include namespace Assimp { @@ -55,7 +55,7 @@ namespace Assimp { using namespace Q3BSP; // ------------------------------------------------------------------------------------------------ -Q3BSPFileParser::Q3BSPFileParser( const std::string &mapName, Q3BSPZipArchive *pZipArchive ) : +Q3BSPFileParser::Q3BSPFileParser( const std::string &mapName, ZipArchiveIOSystem *pZipArchive ) : m_sOffset( 0 ), m_Data(), m_pModel(nullptr), @@ -101,6 +101,7 @@ bool Q3BSPFileParser::readData( const std::string &rMapName ) { const size_t readSize = pMapFile->Read( &m_Data[0], sizeof( char ), size ); if ( readSize != size ) { m_Data.clear(); + m_pZipArchive->Close(pMapFile); return false; } m_pZipArchive->Close( pMapFile ); diff --git a/code/Q3BSPFileParser.h b/code/Q3BSP/Q3BSPFileParser.h similarity index 91% rename from code/Q3BSPFileParser.h rename to code/Q3BSP/Q3BSPFileParser.h index 747d1d494..fd73f5e10 100644 --- a/code/Q3BSPFileParser.h +++ b/code/Q3BSP/Q3BSPFileParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -48,13 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { + class ZipArchiveIOSystem; + namespace Q3BSP { - -class Q3BSPZipArchive; -struct Q3BSPModel; -class ZipFile; - + struct Q3BSPModel; + class ZipFile; } // ------------------------------------------------------------------- @@ -62,7 +61,7 @@ class ZipFile; class Q3BSPFileParser { public: - Q3BSPFileParser( const std::string &rMapName, Q3BSP::Q3BSPZipArchive *pZipArchive ); + Q3BSPFileParser( const std::string &rMapName, ZipArchiveIOSystem *pZipArchive ); ~Q3BSPFileParser(); Q3BSP::Q3BSPModel *getModel() const; @@ -83,7 +82,7 @@ private: size_t m_sOffset; std::vector m_Data; Q3BSP::Q3BSPModel *m_pModel; - Q3BSP::Q3BSPZipArchive *m_pZipArchive; + ZipArchiveIOSystem *m_pZipArchive; }; } // Namespace Assimp diff --git a/code/Q3BSPZipArchive.cpp b/code/Q3BSPZipArchive.cpp deleted file mode 100644 index 3e1087b9a..000000000 --- a/code/Q3BSPZipArchive.cpp +++ /dev/null @@ -1,315 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2018, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ - -#ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER - -#include "Q3BSPZipArchive.h" -#include -#include -#include - -namespace Assimp { -namespace Q3BSP { - -voidpf IOSystem2Unzip::open(voidpf opaque, const char* filename, int mode) { - IOSystem* io_system = (IOSystem*) opaque; - - const char* mode_fopen = NULL; - if((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) { - mode_fopen = "rb"; - } else { - if(mode & ZLIB_FILEFUNC_MODE_EXISTING) { - mode_fopen = "r+b"; - } else { - if(mode & ZLIB_FILEFUNC_MODE_CREATE) { - mode_fopen = "wb"; - } - } - } - - return (voidpf) io_system->Open(filename, mode_fopen); -} - -uLong IOSystem2Unzip::read(voidpf /*opaque*/, voidpf stream, void* buf, uLong size) { - IOStream* io_stream = (IOStream*) stream; - - return static_cast(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(io_stream->Write(buf, 1, size)); -} - -long IOSystem2Unzip::tell(voidpf /*opaque*/, voidpf stream) { - IOStream* io_stream = (IOStream*) stream; - - return static_cast(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; - - 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; - mapping.opaque = (voidpf) pIOHandler; - - return mapping; -} - -ZipFile::ZipFile(size_t size) : m_Size(size) { - ai_assert(m_Size != 0); - - m_Buffer = malloc(m_Size); -} - -ZipFile::~ZipFile() { - free(m_Buffer); - m_Buffer = NULL; -} - -size_t ZipFile::Read(void* pvBuffer, size_t pSize, size_t pCount) { - const size_t size = pSize * pCount; - assert(size <= m_Size); - - std::memcpy(pvBuffer, m_Buffer, size); - - return size; -} - -size_t ZipFile::Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/) { - return 0; -} - -size_t ZipFile::FileSize() const { - return m_Size; -} - -aiReturn ZipFile::Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/) { - return aiReturn_FAILURE; -} - -size_t ZipFile::Tell() const { - return 0; -} - -void ZipFile::Flush() { - // empty -} - -// ------------------------------------------------------------------------------------------------ -// Constructor. -Q3BSPZipArchive::Q3BSPZipArchive(IOSystem* pIOHandler, const std::string& rFile) : m_ZipFileHandle(NULL), m_ArchiveMap() { - if (! rFile.empty()) { - zlib_filefunc_def mapping = IOSystem2Unzip::get(pIOHandler); - - m_ZipFileHandle = unzOpen2(rFile.c_str(), &mapping); - - if(m_ZipFileHandle != nullptr) { - mapArchive(); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Destructor. -Q3BSPZipArchive::~Q3BSPZipArchive() { - for(auto &file : m_ArchiveMap) { - delete file.second; - } - m_ArchiveMap.clear(); - - if(m_ZipFileHandle != nullptr) { - unzClose(m_ZipFileHandle); - m_ZipFileHandle = nullptr; - } -} - -// ------------------------------------------------------------------------------------------------ -// Returns true, if the archive is already open. -bool Q3BSPZipArchive::isOpen() const { - return (m_ZipFileHandle != nullptr); -} - -// ------------------------------------------------------------------------------------------------ -// Returns true, if the filename is part of the archive. -bool Q3BSPZipArchive::Exists(const char* pFile) const { - bool exist = false; - if (pFile != nullptr) { - std::string rFile(pFile); - std::map::const_iterator it = m_ArchiveMap.find(rFile); - - if(it != m_ArchiveMap.end()) { - exist = true; - } - } - - return exist; -} - -// ------------------------------------------------------------------------------------------------ -// Returns the separator delimiter. -char Q3BSPZipArchive::getOsSeparator() const { -#ifndef _WIN32 - return '/'; -#else - return '\\'; -#endif -} - -// ------------------------------------------------------------------------------------------------ -// Opens a file, which is part of the archive. -IOStream *Q3BSPZipArchive::Open(const char* pFile, const char* /*pMode*/) { - ai_assert(pFile != nullptr); - - IOStream* result = nullptr; - - std::map::iterator it = m_ArchiveMap.find(pFile); - - if(it != m_ArchiveMap.end()) { - result = (IOStream*) it->second; - } - - return result; -} - -// ------------------------------------------------------------------------------------------------ -// Close a filestream. -void Q3BSPZipArchive::Close(IOStream *pFile) { - (void)(pFile); - ai_assert(pFile != nullptr); - - // We don't do anything in case the file would be opened again in the future -} -// ------------------------------------------------------------------------------------------------ -// Returns the file-list of the archive. -void Q3BSPZipArchive::getFileList(std::vector &rFileList) { - rFileList.clear(); - - for(auto &file : m_ArchiveMap) { - rFileList.push_back(file.first); - } -} - -// ------------------------------------------------------------------------------------------------ -// Maps the archive content. -bool Q3BSPZipArchive::mapArchive() { - bool success = false; - - if(m_ZipFileHandle != nullptr) { - if(m_ArchiveMap.empty()) { - // At first ensure file is already open - if(unzGoToFirstFile(m_ZipFileHandle) == UNZ_OK) { - // Loop over all files - do { - char filename[FileNameSize]; - unz_file_info fileInfo; - - if(unzGetCurrentFileInfo(m_ZipFileHandle, &fileInfo, filename, FileNameSize, NULL, 0, NULL, 0) == UNZ_OK) { - // The file has EXACTLY the size of uncompressed_size. In C - // you need to mark the last character with '\0', so add - // another character - if(fileInfo.uncompressed_size != 0 && unzOpenCurrentFile(m_ZipFileHandle) == UNZ_OK) { - std::pair::iterator, bool> result = m_ArchiveMap.insert(std::make_pair(filename, new ZipFile(fileInfo.uncompressed_size))); - - if(unzReadCurrentFile(m_ZipFileHandle, result.first->second->m_Buffer, fileInfo.uncompressed_size) == (long int) fileInfo.uncompressed_size) { - if(unzCloseCurrentFile(m_ZipFileHandle) == UNZ_OK) { - // Nothing to do anymore... - } - } - } - } - } while(unzGoToNextFile(m_ZipFileHandle) != UNZ_END_OF_LIST_OF_FILE); - } - } - - success = true; - } - - return success; -} - -// ------------------------------------------------------------------------------------------------ - -} // Namespace Q3BSP -} // Namespace Assimp - -#endif // ASSIMP_BUILD_NO_Q3BSP_IMPORTER diff --git a/code/Q3BSPZipArchive.h b/code/Q3BSPZipArchive.h deleted file mode 100644 index 606f7b183..000000000 --- a/code/Q3BSPZipArchive.h +++ /dev/null @@ -1,131 +0,0 @@ -/* -Open Asset Import Library (assimp) ----------------------------------------------------------------------- - -Copyright (c) 2006-2018, assimp team - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - ----------------------------------------------------------------------- -*/ -#ifndef AI_Q3BSP_ZIPARCHIVE_H_INC -#define AI_Q3BSP_ZIPARCHIVE_H_INC - -#include -#include -#include -#include -#include -#include - -namespace Assimp { -namespace Q3BSP { - -// ------------------------------------------------------------------------------------------------ -/// \class IOSystem2Unzip -/// \ingroup Assimp::Q3BSP -/// -/// \brief -// ------------------------------------------------------------------------------------------------ -class IOSystem2Unzip { -public: - static voidpf open(voidpf opaque, const char* filename, int mode); - static uLong read(voidpf opaque, voidpf stream, void* buf, uLong size); - static uLong write(voidpf opaque, voidpf stream, const void* buf, uLong size); - static long tell(voidpf opaque, voidpf stream); - static long seek(voidpf opaque, voidpf stream, uLong offset, int origin); - static int close(voidpf opaque, voidpf stream); - static int testerror(voidpf opaque, voidpf stream); - static zlib_filefunc_def get(IOSystem* pIOHandler); -}; - -// ------------------------------------------------------------------------------------------------ -/// \class ZipFile -/// \ingroup Assimp::Q3BSP -/// -/// \brief -// ------------------------------------------------------------------------------------------------ -class ZipFile : public IOStream { - friend class Q3BSPZipArchive; - -public: - explicit ZipFile(size_t size); - ~ZipFile(); - size_t Read(void* pvBuffer, size_t pSize, size_t pCount ); - size_t Write(const void* /*pvBuffer*/, size_t /*pSize*/, size_t /*pCount*/); - size_t FileSize() const; - aiReturn Seek(size_t /*pOffset*/, aiOrigin /*pOrigin*/); - size_t Tell() const; - void Flush(); - -private: - void* m_Buffer; - size_t m_Size; -}; - -// ------------------------------------------------------------------------------------------------ -/// \class Q3BSPZipArchive -/// \ingroup Assimp::Q3BSP -/// -/// \brief IMplements a zip archive like the WinZip archives. Will be also used to import data -/// from a P3K archive ( Quake level format ). -// ------------------------------------------------------------------------------------------------ -class Q3BSPZipArchive : public Assimp::IOSystem { -public: - static const unsigned int FileNameSize = 256; - -public: - Q3BSPZipArchive(IOSystem* pIOHandler, const std::string & rFile); - ~Q3BSPZipArchive(); - bool Exists(const char* pFile) const; - char getOsSeparator() const; - IOStream* Open(const char* pFile, const char* pMode = "rb"); - void Close(IOStream* pFile); - bool isOpen() const; - void getFileList(std::vector &rFileList); - -private: - bool mapArchive(); - -private: - unzFile m_ZipFileHandle; - std::map m_ArchiveMap; -}; - -// ------------------------------------------------------------------------------------------------ - -} // Namespace Q3BSP -} // Namespace Assimp - -#endif // AI_Q3BSP_ZIPARCHIVE_H_INC diff --git a/code/Q3DLoader.cpp b/code/Q3D/Q3DLoader.cpp similarity index 98% rename from code/Q3DLoader.cpp rename to code/Q3D/Q3DLoader.cpp index f1165dc2c..b8c8de716 100644 --- a/code/Q3DLoader.cpp +++ b/code/Q3D/Q3DLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -302,13 +302,14 @@ void Q3DImporter::InternReadFile( const std::string& pFile, case 't': pScene->mNumTextures = numTextures; - if (!numTextures)break; - pScene->mTextures = new aiTexture*[pScene->mNumTextures]; + if (!numTextures) { + break; + } + pScene->mTextures = new aiTexture*[pScene->mNumTextures]; // to make sure we won't crash if we leave through an exception ::memset(pScene->mTextures,0,sizeof(void*)*pScene->mNumTextures); - for (unsigned int i = 0; i < pScene->mNumTextures; ++i) - { - aiTexture* tex = pScene->mTextures[i] = new aiTexture(); + for (unsigned int i = 0; i < pScene->mNumTextures; ++i) { + aiTexture* tex = pScene->mTextures[i] = new aiTexture; // skip the texture name while (stream.GetI1()); @@ -317,15 +318,16 @@ void Q3DImporter::InternReadFile( const std::string& pFile, tex->mWidth = (unsigned int)stream.GetI4(); tex->mHeight = (unsigned int)stream.GetI4(); - if (!tex->mWidth || !tex->mHeight) + if (!tex->mWidth || !tex->mHeight) { throw DeadlyImportError("Quick3D: Invalid texture. Width or height is zero"); + } unsigned int mul = tex->mWidth * tex->mHeight; aiTexel* begin = tex->pcData = new aiTexel[mul]; - aiTexel* const end = & begin [mul]; + aiTexel* const end = & begin[mul-1] +1; - for (;begin != end; ++begin) - { + + for (;begin != end; ++begin) { begin->r = stream.GetI1(); begin->g = stream.GetI1(); begin->b = stream.GetI1(); diff --git a/code/Q3DLoader.h b/code/Q3D/Q3DLoader.h similarity index 99% rename from code/Q3DLoader.h rename to code/Q3D/Q3DLoader.h index bdb104df3..954d3105c 100644 --- a/code/Q3DLoader.h +++ b/code/Q3D/Q3DLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/RawLoader.cpp b/code/Raw/RawLoader.cpp similarity index 99% rename from code/RawLoader.cpp rename to code/Raw/RawLoader.cpp index 1bc508759..d0da247e4 100644 --- a/code/RawLoader.cpp +++ b/code/Raw/RawLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/RawLoader.h b/code/Raw/RawLoader.h similarity index 98% rename from code/RawLoader.h rename to code/Raw/RawLoader.h index f6e894fdd..8bfe8ef98 100644 --- a/code/RawLoader.h +++ b/code/Raw/RawLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/SIBImporter.cpp b/code/SIB/SIBImporter.cpp similarity index 99% rename from code/SIBImporter.cpp rename to code/SIB/SIBImporter.cpp index 7a69dd175..20cdc8009 100644 --- a/code/SIBImporter.cpp +++ b/code/SIB/SIBImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -59,8 +59,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -//#include "../contrib/ConvertUTF/ConvertUTF.h" -#include "../contrib/utf8cpp/source/utf8.h" +#ifdef ASSIMP_USE_HUNTER +# include +#else +//# include "../contrib/ConvertUTF/ConvertUTF.h" +# include "../contrib/utf8cpp/source/utf8.h" +#endif #include #include #include diff --git a/code/SIBImporter.h b/code/SIB/SIBImporter.h similarity index 99% rename from code/SIBImporter.h rename to code/SIB/SIBImporter.h index 9437af588..bb88c2255 100644 --- a/code/SIBImporter.h +++ b/code/SIB/SIBImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/SMDLoader.cpp b/code/SMD/SMDLoader.cpp similarity index 99% rename from code/SMDLoader.cpp rename to code/SMD/SMDLoader.cpp index c6ec61624..4288bf9c3 100644 --- a/code/SMDLoader.cpp +++ b/code/SMD/SMDLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -486,7 +486,7 @@ void SMDImporter::CreateOutputAnimations(const std::string &pFile, IOSystem* pIO if (bLoadAnimationList) { GetAnimationFileList(pFile, pIOHandler, animFileList); } - int animCount = animFileList.size() + 1; + int animCount = static_cast( animFileList.size() + 1u ); pScene->mNumAnimations = 1; pScene->mAnimations = new aiAnimation*[animCount]; memset(pScene->mAnimations, 0, sizeof(aiAnimation*)*animCount); @@ -510,7 +510,7 @@ void SMDImporter::CreateOutputAnimation(int index, const std::string &name) { anim->mName.Set(name.c_str()); } anim->mDuration = dLengthOfAnim; - anim->mNumChannels = asBones.size(); + anim->mNumChannels = static_cast( asBones.size() ); anim->mTicksPerSecond = 25.0; // FIXME: is this correct? aiNodeAnim** pp = anim->mChannels = new aiNodeAnim*[anim->mNumChannels]; diff --git a/code/SMDLoader.h b/code/SMD/SMDLoader.h similarity index 99% rename from code/SMDLoader.h rename to code/SMD/SMDLoader.h index a791e7dde..85dac97d1 100644 --- a/code/SMDLoader.h +++ b/code/SMD/SMDLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/STLExporter.cpp b/code/STL/STLExporter.cpp similarity index 97% rename from code/STLExporter.cpp rename to code/STL/STLExporter.cpp index e4a1dbb66..43bc752ae 100644 --- a/code/STLExporter.cpp +++ b/code/STL/STLExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -111,7 +111,7 @@ STLExporter::STLExporter(const char* _filename, const aiScene* pScene, bool expo // make sure that all formatting happens using the standard, C locale and not the user's current locale const std::locale& l = std::locale("C"); mOutput.imbue(l); - mOutput.precision(16); + mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION); if (binary) { char buf[80] = {0} ; buf[0] = 'A'; buf[1] = 's'; buf[2] = 's'; buf[3] = 'i'; buf[4] = 'm'; buf[5] = 'p'; @@ -127,7 +127,7 @@ STLExporter::STLExporter(const char* _filename, const aiScene* pScene, bool expo mOutput.write((char *)&meshnum, 4); if (exportPointClouds) { - + throw DeadlyExportError("This functionality is not yet implemented for binary output."); } for(unsigned int i = 0; i < pScene->mNumMeshes; ++i) { diff --git a/code/STLExporter.h b/code/STL/STLExporter.h similarity index 98% rename from code/STLExporter.h rename to code/STL/STLExporter.h index 6e8f90915..cb5238e60 100644 --- a/code/STLExporter.h +++ b/code/STL/STLExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/STLLoader.cpp b/code/STL/STLLoader.cpp similarity index 98% rename from code/STLLoader.cpp rename to code/STL/STLLoader.cpp index fb866bb7a..199a84a44 100644 --- a/code/STLLoader.cpp +++ b/code/STL/STLLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -182,7 +182,7 @@ void STLImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS std::unique_ptr file( pIOHandler->Open( pFile, "rb")); // Check whether we can read from the file - if( file.get() == NULL) { + if( file.get() == nullptr) { throw DeadlyImportError( "Failed to open STL file " + pFile + "."); } @@ -190,11 +190,11 @@ void STLImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS // allocate storage and copy the contents of the file to a memory buffer // (terminate it with zero) - std::vector mBuffer2; - TextFileToBuffer(file.get(),mBuffer2); + std::vector buffer2; + TextFileToBuffer(file.get(),buffer2); this->pScene = pScene; - this->mBuffer = &mBuffer2[0]; + this->mBuffer = &buffer2[0]; // the default vertex color is light gray. clrColorDefault.r = clrColorDefault.g = clrColorDefault.b = clrColorDefault.a = (ai_real) 0.6; @@ -225,12 +225,14 @@ void STLImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS } pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_DIFFUSE); pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_SPECULAR); - clrDiffuse = aiColor4D( ai_real(1.0), ai_real(1.0), ai_real(1.0), ai_real(1.0)); + clrDiffuse = aiColor4D( ai_real(0.05), ai_real(0.05), ai_real(0.05), ai_real(1.0)); pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_AMBIENT); pScene->mNumMaterials = 1; pScene->mMaterials = new aiMaterial*[1]; pScene->mMaterials[0] = pcMat; + + mBuffer = nullptr; } // ------------------------------------------------------------------------------------------------ @@ -276,6 +278,7 @@ void STLImporter::LoadASCIIFile( aiNode *root ) { } std::string name( szMe, temp ); node->mName.Set( name.c_str() ); + pMesh->mName.Set( name.c_str() ); //pScene->mRootNode->mName.length = temp; //memcpy(pScene->mRootNode->mName.data,szMe,temp); //pScene->mRootNode->mName.data[temp] = '\0'; diff --git a/code/STLLoader.h b/code/STL/STLLoader.h similarity index 98% rename from code/STLLoader.h rename to code/STL/STLLoader.h index 3b87f70a3..ca1011cb8 100644 --- a/code/STLLoader.h +++ b/code/STL/STLLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/STEPFile.h b/code/Step/STEPFile.h similarity index 99% rename from code/STEPFile.h rename to code/Step/STEPFile.h index f5b56c31f..d99b34b3c 100644 --- a/code/STEPFile.h +++ b/code/Step/STEPFile.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -50,7 +50,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "FBXDocument.h" //ObjectMap::value_type +#include "FBX/FBXDocument.h" //ObjectMap::value_type + #include // diff --git a/code/StepExporter.cpp b/code/Step/StepExporter.cpp similarity index 96% rename from code/StepExporter.cpp rename to code/Step/StepExporter.cpp index 4368201b7..70035d9ea 100644 --- a/code/StepExporter.cpp +++ b/code/Step/StepExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,23 +45,25 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_STEP_EXPORTER -#include "StepExporter.h" -#include "ConvertToLHProcess.h" +#include "Step/StepExporter.h" +#include "PostProcessing/ConvertToLHProcess.h" + #include #include #include #include +#include +#include +#include +#include +#include + #include #include #include #include #include #include -#include -#include -#include -#include -#include // #if _MSC_VER > 1500 || (defined __GNUC___) @@ -141,15 +143,15 @@ namespace { // ------------------------------------------------------------------------------------------------ // Constructor for a specific scene to export StepExporter::StepExporter(const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, - const std::string& file, const ExportProperties* pProperties): - mProperties(pProperties),mIOSystem(pIOSystem),mFile(file), mPath(path), - mScene(pScene), endstr(";\n") { - CollectTrafos(pScene->mRootNode, trafos); - CollectMeshes(pScene->mRootNode, meshes); + const std::string& file, const ExportProperties* pProperties) : + mProperties(pProperties), mIOSystem(pIOSystem), mFile(file), mPath(path), + mScene(pScene), endstr(";\n") { + CollectTrafos(pScene->mRootNode, trafos); + CollectMeshes(pScene->mRootNode, meshes); // make sure that all formatting happens using the standard, C locale and not the user's current locale - mOutput.imbue( std::locale("C") ); - mOutput.precision(16); + mOutput.imbue(std::locale("C")); + mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION); // start writing WriteFile(); @@ -164,7 +166,7 @@ void StepExporter::WriteFile() mOutput.setf(std::ios::fixed); // precision for double // see http://stackoverflow.com/questions/554063/how-do-i-print-a-double-value-with-full-precision-using-cout - mOutput.precision(16); + mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION); // standard color aiColor4D fColor; diff --git a/code/StepExporter.h b/code/Step/StepExporter.h similarity index 98% rename from code/StepExporter.h rename to code/Step/StepExporter.h index f1323bee8..f96a0d2b5 100644 --- a/code/StepExporter.h +++ b/code/Step/StepExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/TerragenLoader.cpp b/code/Terragen/TerragenLoader.cpp similarity index 99% rename from code/TerragenLoader.cpp rename to code/Terragen/TerragenLoader.cpp index 0eb22cef6..9b0873c68 100644 --- a/code/TerragenLoader.cpp +++ b/code/Terragen/TerragenLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/code/TerragenLoader.h b/code/Terragen/TerragenLoader.h similarity index 98% rename from code/TerragenLoader.h rename to code/Terragen/TerragenLoader.h index a02889de1..a478c0dcd 100644 --- a/code/TerragenLoader.h +++ b/code/Terragen/TerragenLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/UnrealLoader.cpp b/code/Unreal/UnrealLoader.cpp similarity index 99% rename from code/UnrealLoader.cpp rename to code/Unreal/UnrealLoader.cpp index 64bfbb9e0..0bd4650d0 100644 --- a/code/UnrealLoader.cpp +++ b/code/Unreal/UnrealLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -52,12 +52,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_3D_IMPORTER -#include "UnrealLoader.h" +#include "Unreal/UnrealLoader.h" +#include "PostProcessing/ConvertToLHProcess.h" + #include #include #include -#include "ConvertToLHProcess.h" - #include #include #include diff --git a/code/UnrealLoader.h b/code/Unreal/UnrealLoader.h similarity index 98% rename from code/UnrealLoader.h rename to code/Unreal/UnrealLoader.h index 4095aa142..678aaa76b 100644 --- a/code/UnrealLoader.h +++ b/code/Unreal/UnrealLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -127,7 +127,8 @@ inline void CompressVertex(const aiVector3D& v, uint32_t& out) n.X = (int32_t)v.x; n.Y = (int32_t)v.y; n.Z = (int32_t)v.z; - out = t; + ::memcpy( &out, &t, sizeof(int32_t)); + //out = t; } // UNREAL vertex decompression diff --git a/code/XFileExporter.cpp b/code/X/XFileExporter.cpp similarity index 98% rename from code/XFileExporter.cpp rename to code/X/XFileExporter.cpp index 1510ae6d4..ae9fd58fc 100644 --- a/code/XFileExporter.cpp +++ b/code/X/XFileExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,21 +45,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_X_EXPORTER -#include "XFileExporter.h" -#include "ConvertToLHProcess.h" +#include "X/XFileExporter.h" +#include "PostProcessing/ConvertToLHProcess.h" + #include #include #include #include #include -#include -#include -#include #include #include #include #include +#include +#include +#include + using namespace Assimp; namespace Assimp @@ -111,7 +113,7 @@ XFileExporter::XFileExporter(const aiScene* pScene, IOSystem* pIOSystem, const s { // make sure that all formatting happens using the standard, C locale and not the user's current locale mOutput.imbue( std::locale("C") ); - mOutput.precision(16); + mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION); // start writing WriteFile(); @@ -132,7 +134,7 @@ void XFileExporter::WriteFile() { // note, that all realnumber values must be comma separated in x files mOutput.setf(std::ios::fixed); - mOutput.precision(16); // precision for double + mOutput.precision(ASSIMP_AI_REAL_TEXT_PRECISION); // precision for ai_real // entry of writing the file WriteHeader(); diff --git a/code/XFileExporter.h b/code/X/XFileExporter.h similarity index 99% rename from code/XFileExporter.h rename to code/X/XFileExporter.h index fc480f40b..322440af8 100644 --- a/code/XFileExporter.h +++ b/code/X/XFileExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/XFileHelper.h b/code/X/XFileHelper.h similarity index 99% rename from code/XFileHelper.h rename to code/X/XFileHelper.h index c51e2eba9..0365280f0 100644 --- a/code/XFileHelper.h +++ b/code/X/XFileHelper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/XFileImporter.cpp b/code/X/XFileImporter.cpp similarity index 98% rename from code/XFileImporter.cpp rename to code/X/XFileImporter.cpp index ae847eef8..be7256d5c 100644 --- a/code/XFileImporter.cpp +++ b/code/X/XFileImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -44,10 +44,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_X_IMPORTER -#include "XFileImporter.h" -#include "XFileParser.h" +#include "X/XFileImporter.h" +#include "X/XFileParser.h" +#include "PostProcessing/ConvertToLHProcess.h" + #include -#include "ConvertToLHProcess.h" #include #include #include @@ -331,7 +332,7 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec // collect vertex data for indices of this face for( unsigned int d = 0; d < df.mNumIndices; ++d ) { - df.mIndices[d] = newIndex; + df.mIndices[ d ] = newIndex; const unsigned int newIdx( pf.mIndices[ d ] ); if ( newIdx > sourceMesh->mPositions.size() ) { continue; @@ -343,7 +344,10 @@ void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vec mesh->mVertices[newIndex] = sourceMesh->mPositions[pf.mIndices[d]]; // Normal, if present if ( mesh->HasNormals() ) { - mesh->mNormals[ newIndex ] = sourceMesh->mNormals[ sourceMesh->mNormFaces[ f ].mIndices[ d ] ]; + if ( sourceMesh->mNormFaces[ f ].mIndices.size() > d ) { + const size_t idx( sourceMesh->mNormFaces[ f ].mIndices[ d ] ); + mesh->mNormals[ newIndex ] = sourceMesh->mNormals[ idx ]; + } } // texture coord sets diff --git a/code/XFileImporter.h b/code/X/XFileImporter.h similarity index 98% rename from code/XFileImporter.h rename to code/X/XFileImporter.h index b3c06eab1..7d12b6fdf 100644 --- a/code/XFileImporter.h +++ b/code/X/XFileImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -58,13 +58,13 @@ struct aiNode; namespace Assimp { namespace XFile { -struct Scene; -struct Node; + struct Scene; + struct Node; } // --------------------------------------------------------------------------- /** The XFileImporter is a worker class capable of importing a scene from a - * DirectX file .x + * DirectX file .x */ class XFileImporter : public BaseImporter { public: diff --git a/code/XFileParser.cpp b/code/X/XFileParser.cpp similarity index 98% rename from code/XFileParser.cpp rename to code/X/XFileParser.cpp index e7bf8518c..8fcf87cf6 100644 --- a/code/XFileParser.cpp +++ b/code/X/XFileParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -583,24 +583,30 @@ void XFileParser::ParseDataObjectMeshNormals( Mesh* pMesh) pMesh->mNormals.resize( numNormals); // read normal vectors - for( unsigned int a = 0; a < numNormals; a++) + for( unsigned int a = 0; a < numNormals; ++a) { pMesh->mNormals[a] = ReadVector3(); + } // read normal indices unsigned int numFaces = ReadInt(); - if( numFaces != pMesh->mPosFaces.size()) + if( numFaces != pMesh->mPosFaces.size()) { ThrowException( "Normal face count does not match vertex face count."); + } - for( unsigned int a = 0; a < numFaces; a++) - { - unsigned int numIndices = ReadInt(); - pMesh->mNormFaces.push_back( Face()); - Face& face = pMesh->mNormFaces.back(); + // do not crah when no face definitions are there + if (numFaces > 0) { + // normal face creation + pMesh->mNormFaces.resize( numFaces ); + for( unsigned int a = 0; a < numFaces; ++a ) { + unsigned int numIndices = ReadInt(); + pMesh->mNormFaces[a] = Face(); + Face& face = pMesh->mNormFaces[a]; + for( unsigned int b = 0; b < numIndices; ++b ) { + face.mIndices.push_back( ReadInt()); + } - for( unsigned int b = 0; b < numIndices; b++) - face.mIndices.push_back( ReadInt()); - - TestForSeparator(); + TestForSeparator(); + } } CheckForClosingBrace(); diff --git a/code/XFileParser.h b/code/X/XFileParser.h similarity index 99% rename from code/XFileParser.h rename to code/X/XFileParser.h index 24eb6104d..993bae6a1 100644 --- a/code/XFileParser.h +++ b/code/X/XFileParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/FIReader.cpp b/code/X3D/FIReader.cpp old mode 100755 new mode 100644 similarity index 99% rename from code/FIReader.cpp rename to code/X3D/FIReader.cpp index bdc447b34..9bb2c69f6 --- a/code/FIReader.cpp +++ b/code/X3D/FIReader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -60,7 +60,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include "../contrib/utf8cpp/source/utf8.h" +#ifdef ASSIMP_USE_HUNTER +# include +#else +# include "../contrib/utf8cpp/source/utf8.h" +#endif #include #include #include diff --git a/code/FIReader.hpp b/code/X3D/FIReader.hpp similarity index 97% rename from code/FIReader.hpp rename to code/X3D/FIReader.hpp index 9ff752d5c..2c92239ac 100644 --- a/code/FIReader.hpp +++ b/code/X3D/FIReader.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -57,7 +57,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include //#include //#include -#include +#ifdef ASSIMP_USE_HUNTER +# include +#else +# include +#endif namespace Assimp { diff --git a/code/X3DExporter.cpp b/code/X3D/X3DExporter.cpp similarity index 99% rename from code/X3DExporter.cpp rename to code/X3D/X3DExporter.cpp index 9839e6ca6..e5eeb0886 100644 --- a/code/X3DExporter.cpp +++ b/code/X3D/X3DExporter.cpp @@ -68,7 +68,7 @@ aiMatrix4x4 out_matr; } // multiplicate all matrices in reverse order - for(std::list::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); rit++) out_matr = out_matr * (*rit); + for(std::list::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); ++rit) out_matr = out_matr * (*rit); return out_matr; } diff --git a/code/X3DExporter.hpp b/code/X3D/X3DExporter.hpp similarity index 100% rename from code/X3DExporter.hpp rename to code/X3D/X3DExporter.hpp diff --git a/code/X3DImporter.cpp b/code/X3D/X3DImporter.cpp similarity index 97% rename from code/X3DImporter.cpp rename to code/X3D/X3DImporter.cpp index e6c915e90..367d84fcf 100644 --- a/code/X3DImporter.cpp +++ b/code/X3D/X3DImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -80,7 +80,13 @@ const aiImporterDesc X3DImporter::Description = { //const std::regex X3DImporter::pattern_nws(R"([^, \t\r\n]+)"); //const std::regex X3DImporter::pattern_true(R"(^\s*(?:true|1)\s*$)", std::regex::icase); -struct WordIterator: public std::iterator { +struct WordIterator { + using iterator_category = std::input_iterator_tag; + using value_type = const char*; + using difference_type = ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + static const char *whitespace; const char *start_, *end_; WordIterator(const char *start, const char *end): start_(start), end_(end) { @@ -130,8 +136,8 @@ X3DImporter::~X3DImporter() { void X3DImporter::Clear() { NodeElement_Cur = nullptr; // Delete all elements - if(NodeElement_List.size()) { - for ( std::list::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); it++ ) { + if(!NodeElement_List.empty()) { + for ( std::list::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); ++it ) { delete *it; } NodeElement_List.clear(); @@ -145,7 +151,7 @@ void X3DImporter::Clear() { bool X3DImporter::FindNodeElement_FromRoot(const std::string& pID, const CX3DImporter_NodeElement::EType pType, CX3DImporter_NodeElement** pElement) { - for(std::list::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); it++) + for(std::list::iterator it = NodeElement_List.begin(); it != NodeElement_List.end(); ++it) { if(((*it)->Type == pType) && ((*it)->ID == pID)) { @@ -176,7 +182,7 @@ bool X3DImporter::FindNodeElement_FromNode(CX3DImporter_NodeElement* pStartNode, }// if((pStartNode->Type() == pType) && (pStartNode->ID() == pID)) // Check childs of pStartNode. - for(std::list::iterator ch_it = pStartNode->Child.begin(); ch_it != pStartNode->Child.end(); ch_it++) + for(std::list::iterator ch_it = pStartNode->Child.begin(); ch_it != pStartNode->Child.end(); ++ch_it) { found = FindNodeElement_FromNode(*ch_it, pID, pType, pElement); if ( found ) @@ -608,10 +614,10 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrCol3f(const int pAttrIdx, std::ve XML_ReadNode_GetAttrVal_AsListCol3f(pAttrIdx, tlist);// read as list // and copy to array - if(tlist.size() > 0) + if(!tlist.empty()) { pValue.reserve(tlist.size()); - for(std::list::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it); + for(std::list::iterator it = tlist.begin(); it != tlist.end(); ++it) pValue.push_back(*it); } } @@ -641,10 +647,10 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrCol4f(const int pAttrIdx, std::ve XML_ReadNode_GetAttrVal_AsListCol4f(pAttrIdx, tlist);// read as list // and copy to array - if(tlist.size() > 0) + if(!tlist.empty()) { pValue.reserve(tlist.size()); - for ( std::list::iterator it = tlist.begin(); it != tlist.end(); it++ ) + for ( std::list::iterator it = tlist.begin(); it != tlist.end(); ++it ) { pValue.push_back( *it ); } @@ -678,10 +684,10 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrVec2f(const int pAttrIdx, std::ve XML_ReadNode_GetAttrVal_AsListVec2f(pAttrIdx, tlist);// read as list // and copy to array - if(tlist.size() > 0) + if(!tlist.empty()) { pValue.reserve(tlist.size()); - for ( std::list::iterator it = tlist.begin(); it != tlist.end(); it++ ) + for ( std::list::iterator it = tlist.begin(); it != tlist.end(); ++it ) { pValue.push_back( *it ); } @@ -716,10 +722,10 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrVec3f(const int pAttrIdx, std::ve XML_ReadNode_GetAttrVal_AsListVec3f(pAttrIdx, tlist);// read as list // and copy to array - if(tlist.size() > 0) + if(!tlist.empty()) { pValue.reserve(tlist.size()); - for ( std::list::iterator it = tlist.begin(); it != tlist.end(); it++ ) + for ( std::list::iterator it = tlist.begin(); it != tlist.end(); ++it ) { pValue.push_back( *it ); } @@ -817,7 +823,7 @@ void X3DImporter::GeometryHelper_Extend_PointToLine(const std::list& std::list::const_iterator pit = pPoint.begin(); std::list::const_iterator pit_last = pPoint.end(); - pit_last--; + --pit_last; if ( pPoint.size() < 2 ) { @@ -831,7 +837,7 @@ void X3DImporter::GeometryHelper_Extend_PointToLine(const std::list& { pLine.push_back(*pit);// second point of previous line pLine.push_back(*pit);// first point of next line - pit++; + ++pit; } // add last point of last line pLine.push_back(*pit); @@ -849,7 +855,7 @@ void X3DImporter::GeometryHelper_Extend_PolylineIdxToLineIdx(const std::list::const_iterator plit_next; - plit_next = plit, plit_next++; + plit_next = plit, ++plit_next; pLineCoordIdx.push_back(*plit);// second point of previous line. pLineCoordIdx.push_back(-1);// delimiter if((*plit_next == (-1)) || (plit_next == pPolylineCoordIdx.end())) break;// current polyline is finished @@ -904,7 +910,7 @@ void X3DImporter::GeometryHelper_CoordIdxStr2FacesArr(const std::vector pFaces.reserve(f_data.size() / 3); inds.reserve(4); //PrintVectorSet("build. ci", pCoordIdx); - for(std::vector::iterator it = f_data.begin(); it != f_data.end(); it++) + for(std::vector::iterator it = f_data.begin(); it != f_data.end(); ++it) { // when face is got count how many indices in it. if(*it == (-1)) @@ -951,7 +957,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list tcol; // create RGBA array from RGB. - for(std::list::const_iterator it = pColors.begin(); it != pColors.end(); it++) tcol.push_back(aiColor4D((*it).r, (*it).g, (*it).b, 1)); + for(std::list::const_iterator it = pColors.begin(); it != pColors.end(); ++it) tcol.push_back(aiColor4D((*it).r, (*it).g, (*it).b, 1)); // call existing function for adding RGBA colors MeshGeometry_AddColor(pMesh, tcol, pColorPerVertex); @@ -991,7 +997,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list tcol; // create RGBA array from RGB. - for ( std::list::const_iterator it = pColors.begin(); it != pColors.end(); it++ ) + for ( std::list::const_iterator it = pColors.begin(); it != pColors.end(); ++it ) { tcol.push_back( aiColor4D( ( *it ).r, ( *it ).g, ( *it ).b, 1 ) ); } @@ -1025,7 +1031,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::vector::const_iterator it = pColors.begin(); it != pColors.end(); it++ ) + for ( std::list::const_iterator it = pColors.begin(); it != pColors.end(); ++it ) { col_arr_copy.push_back( *it ); } @@ -1042,7 +1048,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::vector::const_iterator colidx_it = pColorIdx.begin(), coordidx_it = pCoordIdx.begin(); colidx_it != pColorIdx.end(); colidx_it++, coordidx_it++) + for(std::vector::const_iterator colidx_it = pColorIdx.begin(), coordidx_it = pCoordIdx.begin(); colidx_it != pColorIdx.end(); ++colidx_it, ++coordidx_it) { if ( *colidx_it == ( -1 ) ) { @@ -1115,7 +1121,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::vector::const_iterator it = col_tgt_arr.begin(); it != col_tgt_arr.end(); it++) col_tgt_list.push_back(*it); + for(std::vector::const_iterator it = col_tgt_arr.begin(); it != col_tgt_arr.end(); ++it) col_tgt_list.push_back(*it); // add prepared colors list to mesh. MeshGeometry_AddColor(pMesh, col_tgt_list, pColorPerVertex); } @@ -1128,7 +1134,7 @@ void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::vector::const_iterator it = pNormals.begin(); it != pNormals.end(); it++ ) + for ( std::list::const_iterator it = pNormals.begin(); it != pNormals.end(); ++it ) { norm_arr_copy.push_back( *it ); } @@ -1141,7 +1147,7 @@ void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::vector::const_iterator it = pNormalIdx.begin(); it != pNormalIdx.end(); it++) + for(std::vector::const_iterator it = pNormalIdx.begin(); it != pNormalIdx.end(); ++it) { if(*it != (-1)) tind.push_back(*it); } @@ -1221,7 +1227,7 @@ void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::list::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); it++) + for(std::list::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it) { texcoord_arr_copy.push_back(aiVector3D((*it).x, (*it).y, 0)); } @@ -1285,7 +1291,7 @@ void X3DImporter::MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); it++ ) + for ( std::list::const_iterator it = pTexCoords.begin(); it != pTexCoords.end(); ++it ) { tc_arr_copy.push_back( aiVector3D( ( *it ).x, ( *it ).y, 0 ) ); } @@ -1693,7 +1699,7 @@ void X3DImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy // create nodes tree Postprocess_BuildNode(*NodeElement_Cur, *pScene->mRootNode, mesh_list, mat_list, light_list); // copy needed data to scene - if(mesh_list.size() > 0) + if(!mesh_list.empty()) { std::list::const_iterator it = mesh_list.begin(); @@ -1702,7 +1708,7 @@ void X3DImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy for(size_t i = 0; i < pScene->mNumMeshes; i++) pScene->mMeshes[i] = *it++; } - if(mat_list.size() > 0) + if(!mat_list.empty()) { std::list::const_iterator it = mat_list.begin(); @@ -1711,7 +1717,7 @@ void X3DImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSy for(size_t i = 0; i < pScene->mNumMaterials; i++) pScene->mMaterials[i] = *it++; } - if(light_list.size() > 0) + if(!light_list.empty()) { std::list::const_iterator it = light_list.begin(); diff --git a/code/X3DImporter.hpp b/code/X3D/X3DImporter.hpp similarity index 99% rename from code/X3DImporter.hpp rename to code/X3D/X3DImporter.hpp index 1c9dc5486..a4afc1463 100644 --- a/code/X3DImporter.hpp +++ b/code/X3D/X3DImporter.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/X3DImporter_Geometry2D.cpp b/code/X3D/X3DImporter_Geometry2D.cpp similarity index 99% rename from code/X3DImporter_Geometry2D.cpp rename to code/X3D/X3DImporter_Geometry2D.cpp index 5229017b3..350fd6c40 100644 --- a/code/X3DImporter_Geometry2D.cpp +++ b/code/X3D/X3DImporter_Geometry2D.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -356,7 +356,7 @@ void X3DImporter::ParseNode_Geometry2D_Polyline2D() std::list tlist; // convert vec2 to vec3 - for(std::list::iterator it2 = lineSegments.begin(); it2 != lineSegments.end(); it2++) tlist.push_back(aiVector3D(it2->x, it2->y, 0)); + for(std::list::iterator it2 = lineSegments.begin(); it2 != lineSegments.end(); ++it2) tlist.push_back(aiVector3D(it2->x, it2->y, 0)); // convert point set to line set GeometryHelper_Extend_PointToLine(tlist, ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices); @@ -399,7 +399,7 @@ void X3DImporter::ParseNode_Geometry2D_Polypoint2D() if(!def.empty()) ne->ID = def; // convert vec2 to vec3 - for(std::list::iterator it2 = point.begin(); it2 != point.end(); it2++) + for(std::list::iterator it2 = point.begin(); it2 != point.end(); ++it2) { ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0)); } @@ -500,7 +500,7 @@ void X3DImporter::ParseNode_Geometry2D_TriangleSet2D() if(!def.empty()) ne->ID = def; // convert vec2 to vec3 - for(std::list::iterator it2 = vertices.begin(); it2 != vertices.end(); it2++) + for(std::list::iterator it2 = vertices.begin(); it2 != vertices.end(); ++it2) { ((CX3DImporter_NodeElement_Geometry2D*)ne)->Vertices.push_back(aiVector3D(it2->x, it2->y, 0)); } diff --git a/code/X3DImporter_Geometry3D.cpp b/code/X3D/X3DImporter_Geometry3D.cpp similarity index 99% rename from code/X3DImporter_Geometry3D.cpp rename to code/X3D/X3DImporter_Geometry3D.cpp index b6d130098..e12cbd3ab 100644 --- a/code/X3DImporter_Geometry3D.cpp +++ b/code/X3D/X3DImporter_Geometry3D.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -153,11 +153,11 @@ void X3DImporter::ParseNode_Geometry3D_Cone() { StandardShapes::MakeCircle(bottomRadius, tess, tvec); height = -(height / 2); - for(std::vector::iterator it = tvec.begin(); it != tvec.end(); it++) it->y = height;// y - because circle made in oXZ. + for(std::vector::iterator it = tvec.begin(); it != tvec.end(); ++it) it->y = height;// y - because circle made in oXZ. } // copy data from temp array - for(std::vector::iterator it = tvec.begin(); it != tvec.end(); it++) ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices.push_back(*it); + for(std::vector::iterator it = tvec.begin(); it != tvec.end(); ++it) ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices.push_back(*it); ((CX3DImporter_NodeElement_Geometry3D*)ne)->Solid = solid; ((CX3DImporter_NodeElement_Geometry3D*)ne)->NumIndices = 3; @@ -226,11 +226,11 @@ void X3DImporter::ParseNode_Geometry3D_Cylinder() // copy data from temp arrays std::list& vlist = ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices;// just short alias. - for(std::vector::iterator it = tside.begin(); it != tside.end(); it++) vlist.push_back(*it); + for(std::vector::iterator it = tside.begin(); it != tside.end(); ++it) vlist.push_back(*it); if(top) { - for(std::vector::iterator it = tcir.begin(); it != tcir.end(); it++) + for(std::vector::iterator it = tcir.begin(); it != tcir.end(); ++it) { (*it).y = height;// y - because circle made in oXZ. vlist.push_back(*it); @@ -239,7 +239,7 @@ void X3DImporter::ParseNode_Geometry3D_Cylinder() if(bottom) { - for(std::vector::iterator it = tcir.begin(); it != tcir.end(); it++) + for(std::vector::iterator it = tcir.begin(); it != tcir.end(); ++it) { (*it).y = -height;// y - because circle made in oXZ. vlist.push_back(*it); @@ -336,7 +336,7 @@ void X3DImporter::ParseNode_Geometry3D_ElevationGrid() aiVector3D tvec(xSpacing * xi, *he_it, zSpacing * zi); grid_alias.Vertices.push_back(tvec); - he_it++; + ++he_it; } } }// END: create grid vertices list @@ -977,7 +977,7 @@ void X3DImporter::ParseNode_Geometry3D_Sphere() StandardShapes::MakeSphere(tess, tlist); // copy data from temp array and apply scale - for(std::vector::iterator it = tlist.begin(); it != tlist.end(); it++) + for(std::vector::iterator it = tlist.begin(); it != tlist.end(); ++it) { ((CX3DImporter_NodeElement_Geometry3D*)ne)->Vertices.push_back(*it * radius); } diff --git a/code/X3DImporter_Group.cpp b/code/X3D/X3DImporter_Group.cpp similarity index 99% rename from code/X3DImporter_Group.cpp rename to code/X3D/X3DImporter_Group.cpp index 0c2e820de..de3610caf 100644 --- a/code/X3DImporter_Group.cpp +++ b/code/X3D/X3DImporter_Group.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/X3DImporter_Light.cpp b/code/X3D/X3DImporter_Light.cpp similarity index 99% rename from code/X3DImporter_Light.cpp rename to code/X3D/X3DImporter_Light.cpp index 4ffea4411..842fffc04 100644 --- a/code/X3DImporter_Light.cpp +++ b/code/X3D/X3DImporter_Light.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/X3DImporter_Macro.hpp b/code/X3D/X3DImporter_Macro.hpp similarity index 99% rename from code/X3DImporter_Macro.hpp rename to code/X3D/X3DImporter_Macro.hpp index d1172798c..a6aca33fb 100644 --- a/code/X3DImporter_Macro.hpp +++ b/code/X3D/X3DImporter_Macro.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/X3DImporter_Metadata.cpp b/code/X3D/X3DImporter_Metadata.cpp similarity index 99% rename from code/X3DImporter_Metadata.cpp rename to code/X3D/X3DImporter_Metadata.cpp index a566f0aa9..f888ac2b9 100644 --- a/code/X3DImporter_Metadata.cpp +++ b/code/X3D/X3DImporter_Metadata.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/X3DImporter_Networking.cpp b/code/X3D/X3DImporter_Networking.cpp similarity index 98% rename from code/X3DImporter_Networking.cpp rename to code/X3D/X3DImporter_Networking.cpp index 9c15c4ac4..a7a200675 100644 --- a/code/X3DImporter_Networking.cpp +++ b/code/X3D/X3DImporter_Networking.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -93,7 +93,7 @@ void X3DImporter::ParseNode_Networking_Inline() // at this place new group mode created and made current, so we can name it. if(!def.empty()) NodeElement_Cur->ID = def; - if(load && (url.size() > 0)) + if(load && !url.empty()) { std::string full_path = mpIOHandler->CurrentDirectory() + url.front(); diff --git a/code/X3DImporter_Node.hpp b/code/X3D/X3DImporter_Node.hpp similarity index 99% rename from code/X3DImporter_Node.hpp rename to code/X3D/X3DImporter_Node.hpp index cb1317582..85208223d 100644 --- a/code/X3DImporter_Node.hpp +++ b/code/X3D/X3DImporter_Node.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/X3DImporter_Postprocess.cpp b/code/X3D/X3DImporter_Postprocess.cpp similarity index 94% rename from code/X3DImporter_Postprocess.cpp rename to code/X3D/X3DImporter_Postprocess.cpp index c439a4004..539563fcf 100644 --- a/code/X3DImporter_Postprocess.cpp +++ b/code/X3D/X3DImporter_Postprocess.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -81,7 +81,7 @@ aiMatrix4x4 X3DImporter::PostprocessHelper_Matrix_GlobalToCurrent() const } // multiplicate all matrices in reverse order - for(std::list::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); rit++) out_matr = out_matr * (*rit); + for(std::list::reverse_iterator rit = matr.rbegin(); rit != matr.rend(); ++rit) out_matr = out_matr * (*rit); return out_matr; } @@ -89,7 +89,7 @@ aiMatrix4x4 X3DImporter::PostprocessHelper_Matrix_GlobalToCurrent() const void X3DImporter::PostprocessHelper_CollectMetadata(const CX3DImporter_NodeElement& pNodeElement, std::list& pList) const { // walk through childs and find for metadata. - for(std::list::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); el_it++) + for(std::list::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); ++el_it) { if(((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaBoolean) || ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaDouble) || ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaFloat) || ((*el_it)->Type == CX3DImporter_NodeElement::ENET_MetaInteger) || @@ -194,7 +194,7 @@ void X3DImporter::Postprocess_BuildMaterial(const CX3DImporter_NodeElement& pNod aiMaterial& taimat = **pMaterial;// creating alias for convenience. // at this point pNodeElement point to node. Walk through childs and add all stored data. - for(std::list::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); el_it++) + for(std::list::const_iterator el_it = pNodeElement.Child.begin(); el_it != pNodeElement.Child.end(); ++el_it) { if((*el_it)->Type == CX3DImporter_NodeElement::ENET_Material) { @@ -255,7 +255,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle std::vector tarr; tarr.reserve(tnemesh.Vertices.size()); - for(std::list::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); it++) tarr.push_back(*it); + for(std::list::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); ++it) tarr.push_back(*it); *pMesh = StandardShapes::MakeMesh(tarr, static_cast(tnemesh.NumIndices));// create mesh from vertices using Assimp help. return;// mesh is build, nothing to do anymore. @@ -273,7 +273,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle std::vector tarr; tarr.reserve(tnemesh.Vertices.size()); - for(std::list::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); it++) tarr.push_back(*it); + for(std::list::iterator it = tnemesh.Vertices.begin(); it != tnemesh.Vertices.end(); ++it) tarr.push_back(*it); *pMesh = StandardShapes::MakeMesh(tarr, static_cast(tnemesh.NumIndices));// create mesh from vertices using Assimp help. @@ -289,7 +289,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle // at first create mesh from existing vertices. *pMesh = GeometryHelper_MakeMesh(tnemesh.CoordIdx, tnemesh.Vertices); // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex); @@ -301,7 +301,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle MeshGeometry_AddTexCoord(**pMesh, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of ElevationGrid: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_ElevationGrid) @@ -313,7 +313,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience // at first search for node and create mesh. - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) { @@ -322,7 +322,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle } // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) MeshGeometry_AddColor(**pMesh, tnemesh.CoordIndex, tnemesh.ColorIndex, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value, tnemesh.ColorPerVertex); @@ -338,7 +338,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedFaceSet: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedFaceSet) @@ -348,7 +348,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience // at first search for node and create mesh. - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) { @@ -357,7 +357,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle } // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { ai_assert(*pMesh); if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) @@ -369,7 +369,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle {} // skip because already read when mesh created. else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedLineSet: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedLineSet) @@ -381,7 +381,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle CX3DImporter_NodeElement_IndexedSet& tnemesh = *((CX3DImporter_NodeElement_IndexedSet*)&pNodeElement);// create alias for convenience // at first search for node and create mesh. - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) { @@ -390,7 +390,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle } // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { ai_assert(*pMesh); if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) @@ -408,7 +408,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of IndexedTriangleSet or IndexedTriangleFanSet, or \ IndexedTriangleStripSet: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if((pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleFanSet) || (pNodeElement.Type == CX3DImporter_NodeElement::ENET_IndexedTriangleStripSet)) @@ -430,7 +430,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience // at first search for node and create mesh. - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) { @@ -438,7 +438,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle vec_copy.reserve(((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.size()); for(std::list::const_iterator it = ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.begin(); - it != ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.end(); it++) + it != ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.end(); ++it) { vec_copy.push_back(*it); } @@ -448,7 +448,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle } // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { ai_assert(*pMesh); if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) @@ -459,7 +459,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle {} // skip because already read when mesh created. else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of PointSet: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_PointSet) @@ -469,7 +469,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience // at first search for node and create mesh. - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) { @@ -478,7 +478,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle } // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { ai_assert(*pMesh); if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) @@ -489,7 +489,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle {} // skip because already read when mesh created. else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of LineSet: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_LineSet) @@ -499,7 +499,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience // at first search for node and create mesh. - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) { @@ -508,7 +508,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle } // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if ( nullptr == *pMesh ) { break; @@ -526,7 +526,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeFanSet: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleFanSet) @@ -536,7 +536,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience // at first search for node and create mesh. - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) { @@ -544,7 +544,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle vec_copy.reserve(((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.size()); for(std::list::const_iterator it = ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.begin(); - it != ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.end(); it++) + it != ((CX3DImporter_NodeElement_Coordinate*)*ch_it)->Value.end(); ++it) { vec_copy.push_back(*it); } @@ -554,7 +554,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle } // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { ai_assert(*pMesh); if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) @@ -570,7 +570,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TrianlgeSet: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleSet) @@ -580,7 +580,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle CX3DImporter_NodeElement_Set& tnemesh = *((CX3DImporter_NodeElement_Set*)&pNodeElement);// create alias for convenience // at first search for node and create mesh. - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Coordinate) { @@ -589,7 +589,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle } // copy additional information from children - for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) { ai_assert(*pMesh); if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) @@ -605,7 +605,7 @@ void X3DImporter::Postprocess_BuildMesh(const CX3DImporter_NodeElement& pNodeEle MeshGeometry_AddTexCoord(**pMesh, tnemesh.CoordIndex, tnemesh.TexCoordIndex, ((CX3DImporter_NodeElement_TextureCoordinate*)*ch_it)->Value); else throw DeadlyImportError("Postprocess_BuildMesh. Unknown child of TriangleStripSet: " + to_string((*ch_it)->Type) + "."); - }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ch_it++) + }// for(std::list::iterator ch_it = tnemesh.Child.begin(); ch_it != tnemesh.Child.end(); ++ch_it) return;// mesh is build, nothing to do anymore. }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_TriangleStripSet) @@ -639,16 +639,16 @@ void X3DImporter::Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeEle } else { - for(size_t i = 0; i < (size_t)tne_group.Choice; i++) chit_begin++;// forward iterator to chosen node. + for(size_t i = 0; i < (size_t)tne_group.Choice; i++) ++chit_begin;// forward iterator to chosen node. chit_end = chit_begin; - chit_end++;// point end iterator to next element after chosen node. + ++chit_end;// point end iterator to next element after chosen node. } }// if(tne_group.UseChoice) }// if(pNodeElement.Type == CX3DImporter_NodeElement::ENET_Group) // Reserve memory for fast access and check children. - for(std::list::const_iterator it = chit_begin; it != chit_end; it++) + for(std::list::const_iterator it = chit_begin; it != chit_end; ++it) {// in this loop we do not read metadata because it's already read at begin. if((*it)->Type == CX3DImporter_NodeElement::ENET_Group) { @@ -677,7 +677,7 @@ void X3DImporter::Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeEle }// for(std::list::const_iterator it = chit_begin; it != chit_end; it++) // copy data about children and meshes to aiNode. - if(SceneNode_Child.size() > 0) + if(!SceneNode_Child.empty()) { std::list::const_iterator it = SceneNode_Child.begin(); @@ -686,7 +686,7 @@ void X3DImporter::Postprocess_BuildNode(const CX3DImporter_NodeElement& pNodeEle for(size_t i = 0; i < pSceneNode.mNumChildren; i++) pSceneNode.mChildren[i] = *it++; } - if(SceneNode_Mesh.size() > 0) + if(!SceneNode_Mesh.empty()) { std::list::const_iterator it = SceneNode_Mesh.begin(); @@ -706,7 +706,7 @@ void X3DImporter::Postprocess_BuildShape(const CX3DImporter_NodeElement_Shape& p CX3DImporter_NodeElement::EType mesh_type = CX3DImporter_NodeElement::ENET_Invalid; unsigned int mat_ind = 0; - for(std::list::const_iterator it = pShapeNodeElement.Child.begin(); it != pShapeNodeElement.Child.end(); it++) + for(std::list::const_iterator it = pShapeNodeElement.Child.begin(); it != pShapeNodeElement.Child.end(); ++it) { if(PostprocessHelper_ElementIsMesh((*it)->Type)) { @@ -779,7 +779,7 @@ void X3DImporter::Postprocess_CollectMetadata(const CX3DImporter_NodeElement& pN // copy collected metadata to output node. pSceneNode.mMetaData = aiMetadata::Alloc( static_cast(meta_list.size()) ); meta_idx = 0; - for(std::list::const_iterator it = meta_list.begin(); it != meta_list.end(); it++, meta_idx++) + for(std::list::const_iterator it = meta_list.begin(); it != meta_list.end(); ++it, ++meta_idx) { CX3DImporter_NodeElement_Meta* cur_meta = (CX3DImporter_NodeElement_Meta*)*it; diff --git a/code/X3DImporter_Rendering.cpp b/code/X3D/X3DImporter_Rendering.cpp similarity index 99% rename from code/X3DImporter_Rendering.cpp rename to code/X3D/X3DImporter_Rendering.cpp index 1b44f8c19..6e95c9441 100644 --- a/code/X3DImporter_Rendering.cpp +++ b/code/X3D/X3DImporter_Rendering.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -295,7 +295,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleFanSet() ne_alias.CoordIndex.clear(); int counter = 0; int32_t idx[3]; - for(std::vector::const_iterator idx_it = index.begin(); idx_it != index.end(); idx_it++) + for(std::vector::const_iterator idx_it = index.begin(); idx_it != index.end(); ++idx_it) { idx[2] = *idx_it; if (idx[2] < 0) @@ -413,7 +413,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleSet() ne_alias.CoordIndex.clear(); int counter = 0; int32_t idx[3]; - for(std::vector::const_iterator idx_it = index.begin(); idx_it != index.end(); idx_it++) + for(std::vector::const_iterator idx_it = index.begin(); idx_it != index.end(); ++idx_it) { idx[counter++] = *idx_it; if (counter > 2) @@ -519,7 +519,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleStripSet() ne_alias.CoordIndex.clear(); int counter = 0; int32_t idx[3]; - for(std::vector::const_iterator idx_it = index.begin(); idx_it != index.end(); idx_it++) + for(std::vector::const_iterator idx_it = index.begin(); idx_it != index.end(); ++idx_it) { idx[2] = *idx_it; if (idx[2] < 0) @@ -617,7 +617,7 @@ void X3DImporter::ParseNode_Rendering_LineSet() size_t coord_num = 0; ne_alias.CoordIndex.clear(); - for(std::vector::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++) + for(std::vector::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); ++vc_it) { if(*vc_it < 2) throw DeadlyImportError("LineSet. vertexCount shall be greater than or equal to two."); @@ -765,7 +765,7 @@ void X3DImporter::ParseNode_Rendering_TriangleFanSet() // assign indices for first triangle coord_num_first = 0; coord_num_prev = 1; - for(std::vector::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++) + for(std::vector::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); ++vc_it) { if(*vc_it < 3) throw DeadlyImportError("TriangleFanSet. fanCount shall be greater than or equal to three."); @@ -956,7 +956,7 @@ void X3DImporter::ParseNode_Rendering_TriangleStripSet() ne_alias.CoordIndex.clear(); coord_num_sb = 0; - for(std::vector::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); vc_it++) + for(std::vector::const_iterator vc_it = ne_alias.VertexCount.begin(); vc_it != ne_alias.VertexCount.end(); ++vc_it) { if(*vc_it < 3) throw DeadlyImportError("TriangleStripSet. stripCount shall be greater than or equal to three."); diff --git a/code/X3DImporter_Shape.cpp b/code/X3D/X3DImporter_Shape.cpp similarity index 99% rename from code/X3DImporter_Shape.cpp rename to code/X3D/X3DImporter_Shape.cpp index 43089c698..126d5905a 100644 --- a/code/X3DImporter_Shape.cpp +++ b/code/X3D/X3DImporter_Shape.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/X3DImporter_Texturing.cpp b/code/X3D/X3DImporter_Texturing.cpp similarity index 99% rename from code/X3DImporter_Texturing.cpp rename to code/X3D/X3DImporter_Texturing.cpp index 807d19ff8..2eaf3e6bc 100644 --- a/code/X3DImporter_Texturing.cpp +++ b/code/X3D/X3DImporter_Texturing.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -89,7 +89,7 @@ void X3DImporter::ParseNode_Texturing_ImageTexture() ((CX3DImporter_NodeElement_ImageTexture*)ne)->RepeatS = repeatS; ((CX3DImporter_NodeElement_ImageTexture*)ne)->RepeatT = repeatT; // Attribute "url" can contain list of strings. But we need only one - first. - if(url.size() > 0) + if(!url.empty()) ((CX3DImporter_NodeElement_ImageTexture*)ne)->URL = url.front(); else ((CX3DImporter_NodeElement_ImageTexture*)ne)->URL = ""; diff --git a/code/X3DVocabulary.cpp b/code/X3D/X3DVocabulary.cpp similarity index 99% rename from code/X3DVocabulary.cpp rename to code/X3D/X3DVocabulary.cpp index dc361b7aa..c6ee113b3 100644 --- a/code/X3DVocabulary.cpp +++ b/code/X3D/X3DVocabulary.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/XGLLoader.cpp b/code/XGL/XGLLoader.cpp similarity index 98% rename from code/XGLLoader.cpp rename to code/XGL/XGLLoader.cpp index 0706ffd55..32cfd72ca 100644 --- a/code/XGLLoader.cpp +++ b/code/XGL/XGLLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -370,7 +370,7 @@ aiLight* XGLImporter::ReadDirectionalLight() // ------------------------------------------------------------------------------------------------ aiNode* XGLImporter::ReadObject(TempScope& scope, bool skipFirst, const char* closetag) { - std::unique_ptr nd(new aiNode()); + aiNode *nd = new aiNode; std::vector children; std::vector meshes; @@ -453,11 +453,11 @@ aiNode* XGLImporter::ReadObject(TempScope& scope, bool skipFirst, const char* cl nd->mChildren = new aiNode*[nd->mNumChildren](); for(unsigned int i = 0; i < nd->mNumChildren; ++i) { nd->mChildren[i] = children[i]; - children[i]->mParent = nd.get(); + children[i]->mParent = nd; } } - return nd.release(); + return nd; } // ------------------------------------------------------------------------------------------------ @@ -731,11 +731,10 @@ unsigned int XGLImporter::ResolveMaterialRef(TempScope& scope) } // ------------------------------------------------------------------------------------------------ -void XGLImporter::ReadMaterial(TempScope& scope) -{ +void XGLImporter::ReadMaterial(TempScope& scope) { const unsigned int mat_id = ReadIDAttr(); - std::unique_ptr mat(new aiMaterial()); + aiMaterial *mat(new aiMaterial ); while (ReadElementUpToClosing("mat")) { const std::string& s = GetElementName(); if (s == "amb") { @@ -764,11 +763,10 @@ void XGLImporter::ReadMaterial(TempScope& scope) } } - scope.materials[mat_id] = mat.get(); - scope.materials_linear.push_back(mat.release()); + scope.materials[mat_id] = mat; + scope.materials_linear.push_back(mat); } - // ---------------------------------------------------------------------------------------------- void XGLImporter::ReadFaceVertex(const TempMesh& t, TempFace& out) { diff --git a/code/XGLLoader.h b/code/XGL/XGLLoader.h similarity index 99% rename from code/XGLLoader.h rename to code/XGL/XGLLoader.h index 8ae05836a..bba2a643c 100644 --- a/code/XGLLoader.h +++ b/code/XGL/XGLLoader.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/glTFAsset.h b/code/glTF/glTFAsset.h similarity index 95% rename from code/glTFAsset.h rename to code/glTF/glTFAsset.h index b04692901..ddc7f086e 100644 --- a/code/glTFAsset.h +++ b/code/glTF/glTFAsset.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -52,6 +52,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER +#include + #include #include #include @@ -90,38 +92,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # endif #endif +#include "glTF/glTFCommon.h" + namespace glTF { -#ifdef ASSIMP_API - using Assimp::IOStream; - using Assimp::IOSystem; - using std::shared_ptr; -#else - using std::shared_ptr; - - typedef std::runtime_error DeadlyImportError; - typedef std::runtime_error DeadlyExportError; - - enum aiOrigin { aiOrigin_SET = 0, aiOrigin_CUR = 1, aiOrigin_END = 2 }; - class IOSystem; - class IOStream - { - FILE* f; - public: - IOStream(FILE* file) : f(file) {} - ~IOStream() { fclose(f); f = 0; } - - size_t Read(void* b, size_t sz, size_t n) { return fread(b, sz, n, f); } - size_t Write(const void* b, size_t sz, size_t n) { return fwrite(b, sz, n, f); } - int Seek(size_t off, aiOrigin orig) { return fseek(f, off, int(orig)); } - size_t Tell() const { return ftell(f); } - - size_t FileSize() { - long p = Tell(), len = (Seek(0, aiOrigin_END), Tell()); - return size_t((Seek(p, aiOrigin_SET), len)); - } - }; -#endif + using glTFCommon::shared_ptr; + using glTFCommon::IOSystem; + using glTFCommon::IOStream; using rapidjson::Value; using rapidjson::Document; @@ -134,37 +111,9 @@ namespace glTF struct Light; struct Skin; - - // Vec/matrix types, as raw float arrays - typedef float (vec3)[3]; - typedef float (vec4)[4]; - typedef float (mat4)[16]; - - - namespace Util - { - void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out); - - size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out); - - inline size_t DecodeBase64(const char* in, uint8_t*& out) - { - return DecodeBase64(in, strlen(in), out); - } - - struct DataURI - { - const char* mediaType; - const char* charset; - bool base64; - const char* data; - size_t dataLength; - }; - - //! Check if a uri is a data URI - inline bool ParseDataURI(const char* uri, size_t uriLen, DataURI& out); - } - + using glTFCommon::vec3; + using glTFCommon::vec4; + using glTFCommon::mat4; //! Magic number for GLB files #define AI_GLB_MAGIC_NUMBER "glTF" @@ -537,7 +486,7 @@ namespace glTF shared_ptr mData; //!< Pointer to the data bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer) - + size_t capacity = 0; //!< The capacity of the buffer in bytes. (default: 0) /// \var EncodedRegion_List /// List of encoded regions. std::list EncodedRegion_List; diff --git a/code/glTFAsset.inl b/code/glTF/glTFAsset.inl similarity index 88% rename from code/glTFAsset.inl rename to code/glTF/glTFAsset.inl index 267cbd4a3..f31781a3f 100644 --- a/code/glTFAsset.inl +++ b/code/glTF/glTFAsset.inl @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -52,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif using namespace Assimp; +using namespace glTFCommon; namespace glTF { @@ -95,6 +95,14 @@ namespace { return out.isPresent = ReadHelper::Read(val, out.value); }}; + template<> struct ReadHelper { static bool Read(Value& val, uint64_t& out) { + return val.IsUint64() ? out = val.GetUint64(), true : false; + }}; + + template<> struct ReadHelper { static bool Read(Value& val, int64_t& out) { + return val.IsInt64() ? out = val.GetInt64(), true : false; + }}; + template inline static bool ReadValue(Value& val, T& out) { @@ -293,7 +301,7 @@ inline void Buffer::Read(Value& obj, Asset& r) const char* uri = it->GetString(); - Util::DataURI dataURI; + glTFCommon::Util::DataURI dataURI; if (ParseDataURI(uri, it->GetStringLength(), dataURI)) { if (dataURI.base64) { uint8_t* data = 0; @@ -311,7 +319,7 @@ inline void Buffer::Read(Value& obj, Asset& r) " bytes, but found " + to_string(dataURI.dataLength)); } - this->mData.reset(new uint8_t[dataURI.dataLength]); + this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete()); memcpy( this->mData.get(), dataURI.data, dataURI.dataLength ); } } @@ -417,7 +425,7 @@ uint8_t* new_data; // Copy data which place after replacing part. memcpy(&new_data[pBufferData_Offset + pReplace_Count], &mData.get()[pBufferData_Offset + pBufferData_Count], pBufferData_Offset); // Apply new data - mData.reset(new_data); + mData.reset(new_data, std::default_delete()); byteLength = new_data_size; return true; @@ -434,9 +442,19 @@ inline size_t Buffer::AppendData(uint8_t* data, size_t length) inline void Buffer::Grow(size_t amount) { if (amount <= 0) return; - uint8_t* b = new uint8_t[byteLength + amount]; + if (capacity >= byteLength + amount) + { + byteLength += amount; + return; + } + + // Shift operation is standard way to divide integer by 2, it doesn't cast it to float back and forth, also works for odd numbers, + // originally it would look like: static_cast(capacity * 1.5f) + capacity = std::max(capacity + (capacity >> 1), byteLength + amount); + + uint8_t* b = new uint8_t[capacity]; if (mData) memcpy(b, mData.get(), byteLength); - mData.reset(b); + mData.reset(b, std::default_delete()); byteLength += amount; } @@ -636,12 +654,12 @@ inline void Image::Read(Value& obj, Asset& r) if (Value* uri = FindString(obj, "uri")) { const char* uristr = uri->GetString(); - Util::DataURI dataURI; + glTFCommon::Util::DataURI dataURI; if (ParseDataURI(uristr, uri->GetStringLength(), dataURI)) { mimeType = dataURI.mediaType; if (dataURI.base64) { uint8_t *ptr = nullptr; - mDataLength = Util::DecodeBase64(dataURI.data, dataURI.dataLength, ptr); + mDataLength = glTFCommon::Util::DecodeBase64(dataURI.data, dataURI.dataLength, ptr); mData.reset(ptr); } } @@ -1162,8 +1180,12 @@ inline void Light::SetDefaults() falloffExponent = 0.f; } -inline void Node::Read(Value& obj, Asset& r) -{ +inline +void Node::Read(Value& obj, Asset& r) { + if (name.empty()) { + name = id; + } + if (Value* children = FindArray(obj, "children")) { this->children.reserve(children->Size()); for (unsigned int i = 0; i < children->Size(); ++i) { @@ -1445,7 +1467,7 @@ inline std::string Asset::FindUniqueID(const std::string& str, const char* suffi if (it == mUsedIds.end()) return id; - char buffer[256]; + char buffer[1024]; int offset = ai_snprintf(buffer, sizeof(buffer), "%s_", id.c_str()); for (int i = 0; it != mUsedIds.end(); ++i) { ai_snprintf(buffer + offset, sizeof(buffer) - offset, "%d", i); @@ -1456,190 +1478,4 @@ inline std::string Asset::FindUniqueID(const std::string& str, const char* suffi return id; } -namespace Util { - - inline - bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out) { - if ( NULL == const_uri ) { - return false; - } - - if (const_uri[0] != 0x10) { // we already parsed this uri? - if (strncmp(const_uri, "data:", 5) != 0) // not a data uri? - return false; - } - - // set defaults - out.mediaType = "text/plain"; - out.charset = "US-ASCII"; - out.base64 = false; - - char* uri = const_cast(const_uri); - if (uri[0] != 0x10) { - uri[0] = 0x10; - uri[1] = uri[2] = uri[3] = uri[4] = 0; - - size_t i = 5, j; - if (uri[i] != ';' && uri[i] != ',') { // has media type? - uri[1] = char(i); - for (; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) { - // nothing to do! - } - } - while (uri[i] == ';' && i < uriLen) { - uri[i++] = '\0'; - for (j = i; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) { - // nothing to do! - } - - if ( strncmp( uri + j, "charset=", 8 ) == 0 ) { - uri[2] = char(j + 8); - } else if ( strncmp( uri + j, "base64", 6 ) == 0 ) { - uri[3] = char(j); - } - } - if (i < uriLen) { - uri[i++] = '\0'; - uri[4] = char(i); - } else { - uri[1] = uri[2] = uri[3] = 0; - uri[4] = 5; - } - } - - if ( uri[ 1 ] != 0 ) { - out.mediaType = uri + uri[ 1 ]; - } - if ( uri[ 2 ] != 0 ) { - out.charset = uri + uri[ 2 ]; - } - if ( uri[ 3 ] != 0 ) { - out.base64 = true; - } - out.data = uri + uri[4]; - out.dataLength = (uri + uriLen) - out.data; - - return true; - } - - template - struct DATA - { - static const uint8_t tableDecodeBase64[128]; - }; - - template - const uint8_t DATA::tableDecodeBase64[128] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 64, 0, 0, - 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, - 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0 - }; - - inline char EncodeCharBase64(uint8_t b) - { - return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="[size_t(b)]; - } - - inline uint8_t DecodeCharBase64(char c) - { - return DATA::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs? - /*if (c >= 'A' && c <= 'Z') return c - 'A'; - if (c >= 'a' && c <= 'z') return c - 'a' + 26; - if (c >= '0' && c <= '9') return c - '0' + 52; - if (c == '+') return 62; - if (c == '/') return 63; - return 64; // '-' */ - } - - inline size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out) - { - ai_assert(inLength % 4 == 0); - - if (inLength < 4) { - out = 0; - return 0; - } - - int nEquals = int(in[inLength - 1] == '=') + - int(in[inLength - 2] == '='); - - size_t outLength = (inLength * 3) / 4 - nEquals; - out = new uint8_t[outLength]; - memset(out, 0, outLength); - - size_t i, j = 0; - - for (i = 0; i + 4 < inLength; i += 4) { - uint8_t b0 = DecodeCharBase64(in[i]); - uint8_t b1 = DecodeCharBase64(in[i + 1]); - uint8_t b2 = DecodeCharBase64(in[i + 2]); - uint8_t b3 = DecodeCharBase64(in[i + 3]); - - out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4)); - out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2)); - out[j++] = (uint8_t)((b2 << 6) | b3); - } - - { - uint8_t b0 = DecodeCharBase64(in[i]); - uint8_t b1 = DecodeCharBase64(in[i + 1]); - uint8_t b2 = DecodeCharBase64(in[i + 2]); - uint8_t b3 = DecodeCharBase64(in[i + 3]); - - out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4)); - if (b2 < 64) out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2)); - if (b3 < 64) out[j++] = (uint8_t)((b2 << 6) | b3); - } - - return outLength; - } - - - - inline void EncodeBase64( - const uint8_t* in, size_t inLength, - std::string& out) - { - size_t outLength = ((inLength + 2) / 3) * 4; - - size_t j = out.size(); - out.resize(j + outLength); - - for (size_t i = 0; i < inLength; i += 3) { - uint8_t b = (in[i] & 0xFC) >> 2; - out[j++] = EncodeCharBase64(b); - - b = (in[i] & 0x03) << 4; - if (i + 1 < inLength) { - b |= (in[i + 1] & 0xF0) >> 4; - out[j++] = EncodeCharBase64(b); - - b = (in[i + 1] & 0x0F) << 2; - if (i + 2 < inLength) { - b |= (in[i + 2] & 0xC0) >> 6; - out[j++] = EncodeCharBase64(b); - - b = in[i + 2] & 0x3F; - out[j++] = EncodeCharBase64(b); - } - else { - out[j++] = EncodeCharBase64(b); - out[j++] = '='; - } - } - else { - out[j++] = EncodeCharBase64(b); - out[j++] = '='; - out[j++] = '='; - } - } - } - -} - } // ns glTF diff --git a/code/glTFAssetWriter.h b/code/glTF/glTFAssetWriter.h similarity index 98% rename from code/glTFAssetWriter.h rename to code/glTF/glTFAssetWriter.h index bbe89fc77..03aee7d4c 100644 --- a/code/glTFAssetWriter.h +++ b/code/glTF/glTFAssetWriter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/glTFAssetWriter.inl b/code/glTF/glTFAssetWriter.inl similarity index 96% rename from code/glTFAssetWriter.inl rename to code/glTF/glTFAssetWriter.inl index fd29a96b4..1bbb8fd8c 100644 --- a/code/glTFAssetWriter.inl +++ b/code/glTF/glTFAssetWriter.inl @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -55,7 +55,8 @@ namespace glTF { namespace { template - inline Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) { + inline + Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) { val.SetArray(); val.Reserve(N, al); for (decltype(N) i = 0; i < N; ++i) { @@ -64,7 +65,8 @@ namespace glTF { return val; } - inline Value& MakeValue(Value& val, const std::vector & r, MemoryPoolAllocator<>& al) { + inline + Value& MakeValue(Value& val, const std::vector & r, MemoryPoolAllocator<>& al) { val.SetArray(); val.Reserve(static_cast(r.size()), al); for (unsigned int i = 0; i < r.size(); ++i) { @@ -213,7 +215,7 @@ namespace glTF { else if (img.HasData()) { uri = "data:" + (img.mimeType.empty() ? "application/octet-stream" : img.mimeType); uri += ";base64,"; - Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri); + glTFCommon::Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri); } else { uri = img.uri; @@ -294,17 +296,17 @@ namespace glTF { // filling object "compressedData" json_comp_data.SetObject(); json_comp_data.AddMember("buffer", ptr_ext_comp->Buffer, w.mAl); - json_comp_data.AddMember("byteOffset", ptr_ext_comp->Offset, w.mAl); + json_comp_data.AddMember("byteOffset", static_cast(ptr_ext_comp->Offset), w.mAl); json_comp_data.AddMember("componentType", 5121, w.mAl); json_comp_data.AddMember("type", "SCALAR", w.mAl); - json_comp_data.AddMember("count", ptr_ext_comp->Count, w.mAl); + json_comp_data.AddMember("count", static_cast(ptr_ext_comp->Count), w.mAl); if(ptr_ext_comp->Binary) json_comp_data.AddMember("mode", "binary", w.mAl); else json_comp_data.AddMember("mode", "ascii", w.mAl); - json_comp_data.AddMember("indicesCount", ptr_ext_comp->IndicesCount, w.mAl); - json_comp_data.AddMember("verticesCount", ptr_ext_comp->VerticesCount, w.mAl); + json_comp_data.AddMember("indicesCount", static_cast(ptr_ext_comp->IndicesCount), w.mAl); + json_comp_data.AddMember("verticesCount", static_cast(ptr_ext_comp->VerticesCount), w.mAl); // filling object "Open3DGC-compression" Value json_o3dgc; diff --git a/code/glTF/glTFCommon.cpp b/code/glTF/glTFCommon.cpp new file mode 100644 index 000000000..cd03224e4 --- /dev/null +++ b/code/glTF/glTFCommon.cpp @@ -0,0 +1,193 @@ +/* +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 "glTF/glTFCommon.h" + +namespace glTFCommon { + +using namespace glTFCommon::Util; + +namespace Util { + +size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out) { + ai_assert(inLength % 4 == 0); + + if (inLength < 4) { + out = 0; + return 0; + } + + int nEquals = int(in[inLength - 1] == '=') + + int(in[inLength - 2] == '='); + + size_t outLength = (inLength * 3) / 4 - nEquals; + out = new uint8_t[outLength]; + memset(out, 0, outLength); + + size_t i, j = 0; + + for (i = 0; i + 4 < inLength; i += 4) { + uint8_t b0 = DecodeCharBase64(in[i]); + uint8_t b1 = DecodeCharBase64(in[i + 1]); + uint8_t b2 = DecodeCharBase64(in[i + 2]); + uint8_t b3 = DecodeCharBase64(in[i + 3]); + + out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4)); + out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2)); + out[j++] = (uint8_t)((b2 << 6) | b3); + } + + { + uint8_t b0 = DecodeCharBase64(in[i]); + uint8_t b1 = DecodeCharBase64(in[i + 1]); + uint8_t b2 = DecodeCharBase64(in[i + 2]); + uint8_t b3 = DecodeCharBase64(in[i + 3]); + + out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4)); + if (b2 < 64) out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2)); + if (b3 < 64) out[j++] = (uint8_t)((b2 << 6) | b3); + } + + return outLength; +} + +void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out) { + size_t outLength = ((inLength + 2) / 3) * 4; + + size_t j = out.size(); + out.resize(j + outLength); + + for (size_t i = 0; i < inLength; i += 3) { + uint8_t b = (in[i] & 0xFC) >> 2; + out[j++] = EncodeCharBase64(b); + + b = (in[i] & 0x03) << 4; + if (i + 1 < inLength) { + b |= (in[i + 1] & 0xF0) >> 4; + out[j++] = EncodeCharBase64(b); + + b = (in[i + 1] & 0x0F) << 2; + if (i + 2 < inLength) { + b |= (in[i + 2] & 0xC0) >> 6; + out[j++] = EncodeCharBase64(b); + + b = in[i + 2] & 0x3F; + out[j++] = EncodeCharBase64(b); + } + else { + out[j++] = EncodeCharBase64(b); + out[j++] = '='; + } + } + else { + out[j++] = EncodeCharBase64(b); + out[j++] = '='; + out[j++] = '='; + } + } +} + +bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out) { + if (nullptr == const_uri) { + return false; + } + + if (const_uri[0] != 0x10) { // we already parsed this uri? + if (strncmp(const_uri, "data:", 5) != 0) // not a data uri? + return false; + } + + // set defaults + out.mediaType = "text/plain"; + out.charset = "US-ASCII"; + out.base64 = false; + + char* uri = const_cast(const_uri); + if (uri[0] != 0x10) { + uri[0] = 0x10; + uri[1] = uri[2] = uri[3] = uri[4] = 0; + + size_t i = 5, j; + if (uri[i] != ';' && uri[i] != ',') { // has media type? + uri[1] = char(i); + for (; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) { + // nothing to do! + } + } + while (uri[i] == ';' && i < uriLen) { + uri[i++] = '\0'; + for (j = i; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) { + // nothing to do! + } + + if (strncmp(uri + j, "charset=", 8) == 0) { + uri[2] = char(j + 8); + } + else if (strncmp(uri + j, "base64", 6) == 0) { + uri[3] = char(j); + } + } + if (i < uriLen) { + uri[i++] = '\0'; + uri[4] = char(i); + } + else { + uri[1] = uri[2] = uri[3] = 0; + uri[4] = 5; + } + } + + if (uri[1] != 0) { + out.mediaType = uri + uri[1]; + } + if (uri[2] != 0) { + out.charset = uri + uri[2]; + } + if (uri[3] != 0) { + out.base64 = true; + } + out.data = uri + uri[4]; + out.dataLength = (uri + uriLen) - out.data; + + return true; +} + +} +} diff --git a/code/glTF/glTFCommon.h b/code/glTF/glTFCommon.h new file mode 100644 index 000000000..d9edee75e --- /dev/null +++ b/code/glTF/glTFCommon.h @@ -0,0 +1,248 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2019, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ +#ifndef AI_GLFTCOMMON_H_INC +#define AI_GLFTCOMMON_H_INC + +#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER + +#include + +#include +#include +#include +#include +#include +#include + +#define RAPIDJSON_HAS_STDSTRING 1 +#include +#include +#include + +#ifdef ASSIMP_API +# include +# include +# include +#else +# include +# define AI_SWAP4(p) +# define ai_assert +#endif + + +#if _MSC_VER > 1500 || (defined __GNUC___) +# define ASSIMP_GLTF_USE_UNORDERED_MULTIMAP +# else +# define gltf_unordered_map map +#endif + +#ifdef ASSIMP_GLTF_USE_UNORDERED_MULTIMAP +# include +# if _MSC_VER > 1600 +# define gltf_unordered_map unordered_map +# else +# define gltf_unordered_map tr1::unordered_map +# endif +#endif + +namespace glTFCommon { + +#ifdef ASSIMP_API + using Assimp::IOStream; + using Assimp::IOSystem; + using std::shared_ptr; +#else + using std::shared_ptr; + + typedef std::runtime_error DeadlyImportError; + typedef std::runtime_error DeadlyExportError; + + enum aiOrigin { + aiOrigin_SET = 0, + aiOrigin_CUR = 1, + aiOrigin_END = 2 + }; + + class IOSystem; + + class IOStream { + public: + IOStream(FILE* file) : f(file) {} + ~IOStream() { fclose(f); f = 0; } + + size_t Read(void* b, size_t sz, size_t n) { return fread(b, sz, n, f); } + size_t Write(const void* b, size_t sz, size_t n) { return fwrite(b, sz, n, f); } + int Seek(size_t off, aiOrigin orig) { return fseek(f, off, int(orig)); } + size_t Tell() const { return ftell(f); } + + size_t FileSize() { + long p = Tell(), len = (Seek(0, aiOrigin_END), Tell()); + return size_t((Seek(p, aiOrigin_SET), len)); + } + + private: + FILE* f; + }; +#endif + + // Vec/matrix types, as raw float arrays + typedef float(vec3)[3]; + typedef float(vec4)[4]; + typedef float(mat4)[16]; + + inline + void CopyValue(const glTFCommon::vec3& v, aiColor4D& out) { + out.r = v[0]; + out.g = v[1]; + out.b = v[2]; + out.a = 1.0; + } + + inline + void CopyValue(const glTFCommon::vec4& v, aiColor4D& out) { + out.r = v[0]; + out.g = v[1]; + out.b = v[2]; + out.a = v[3]; + } + + inline + void CopyValue(const glTFCommon::vec4& v, aiColor3D& out) { + out.r = v[0]; + out.g = v[1]; + out.b = v[2]; + } + + inline + void CopyValue(const glTFCommon::vec3& v, aiColor3D& out) { + out.r = v[0]; + out.g = v[1]; + out.b = v[2]; + } + + inline + void CopyValue(const glTFCommon::vec3& v, aiVector3D& out) { + out.x = v[0]; + out.y = v[1]; + out.z = v[2]; + } + + inline + void CopyValue(const glTFCommon::vec4& v, aiQuaternion& out) { + out.x = v[0]; + out.y = v[1]; + out.z = v[2]; + out.w = v[3]; + } + + inline + void CopyValue(const glTFCommon::mat4& v, aiMatrix4x4& o) { + o.a1 = v[0]; o.b1 = v[1]; o.c1 = v[2]; o.d1 = v[3]; + o.a2 = v[4]; o.b2 = v[5]; o.c2 = v[6]; o.d2 = v[7]; + o.a3 = v[8]; o.b3 = v[9]; o.c3 = v[10]; o.d3 = v[11]; + o.a4 = v[12]; o.b4 = v[13]; o.c4 = v[14]; o.d4 = v[15]; + } + + namespace Util { + + void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out); + + size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out); + + inline + size_t DecodeBase64(const char* in, uint8_t*& out) { + return DecodeBase64(in, strlen(in), out); + } + + struct DataURI { + const char* mediaType; + const char* charset; + bool base64; + const char* data; + size_t dataLength; + }; + + //! Check if a uri is a data URI + bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out); + + template + struct DATA { + static const uint8_t tableDecodeBase64[128]; + }; + + template + const uint8_t DATA::tableDecodeBase64[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 64, 0, 0, + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, + 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0 + }; + + inline + char EncodeCharBase64(uint8_t b) { + return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="[size_t(b)]; + } + + inline + uint8_t DecodeCharBase64(char c) { + return DATA::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs? + /*if (c >= 'A' && c <= 'Z') return c - 'A'; + if (c >= 'a' && c <= 'z') return c - 'a' + 26; + if (c >= '0' && c <= '9') return c - '0' + 52; + if (c == '+') return 62; + if (c == '/') return 63; + return 64; // '-' */ + } + + size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out); + + void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out); + } + +} + +#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER + +#endif // AI_GLFTCOMMON_H_INC diff --git a/code/glTFExporter.cpp b/code/glTF/glTFExporter.cpp similarity index 98% rename from code/glTFExporter.cpp rename to code/glTF/glTFExporter.cpp index 29a88af8b..034f91f3b 100644 --- a/code/glTFExporter.cpp +++ b/code/glTF/glTFExporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -42,14 +42,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER -#include "glTFExporter.h" +#include "glTF/glTFExporter.h" +#include "glTF/glTFAssetWriter.h" +#include "PostProcessing/SplitLargeMeshes.h" #include #include #include - -#include "SplitLargeMeshes.h" - #include #include #include @@ -61,8 +60,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "glTFAssetWriter.h" - #ifdef ASSIMP_IMPORTER_GLTF_USE_OPEN3DGC // Header files, Open3DGC. # include @@ -101,17 +98,17 @@ glTFExporter::glTFExporter(const char* filename, IOSystem* pIOSystem, const aiSc { aiScene* sceneCopy_tmp; SceneCombiner::CopyScene(&sceneCopy_tmp, pScene); - std::unique_ptr sceneCopy(sceneCopy_tmp); + aiScene *sceneCopy(sceneCopy_tmp); SplitLargeMeshesProcess_Triangle tri_splitter; tri_splitter.SetLimit(0xffff); - tri_splitter.Execute(sceneCopy.get()); + tri_splitter.Execute(sceneCopy); SplitLargeMeshesProcess_Vertex vert_splitter; vert_splitter.SetLimit(0xffff); - vert_splitter.Execute(sceneCopy.get()); + vert_splitter.Execute(sceneCopy); - mScene = sceneCopy.get(); + mScene = sceneCopy; mAsset.reset( new glTF::Asset( pIOSystem ) ); @@ -245,7 +242,10 @@ inline Ref ExportData(Asset& a, std::string& meshName, Ref& bu namespace { void GetMatScalar(const aiMaterial* mat, float& val, const char* propName, int type, int idx) { - if (mat->Get(propName, type, idx, val) == AI_SUCCESS) {} + ai_assert( nullptr != mat ); + if ( nullptr != mat ) { + mat->Get(propName, type, idx, val); + } } } diff --git a/code/glTFExporter.h b/code/glTF/glTFExporter.h similarity index 99% rename from code/glTFExporter.h rename to code/glTF/glTFExporter.h index 061dac5e8..d6c2e7f04 100644 --- a/code/glTFExporter.h +++ b/code/glTF/glTFExporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/glTFImporter.cpp b/code/glTF/glTFImporter.cpp old mode 100755 new mode 100644 similarity index 92% rename from code/glTFImporter.cpp rename to code/glTF/glTFImporter.cpp index c68969dc6..9ecd742f6 --- a/code/glTFImporter.cpp +++ b/code/glTF/glTFImporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -42,10 +42,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER -#include "glTFImporter.h" +#include "glTF/glTFImporter.h" +#include "glTF/glTFAsset.h" +#include "glTF/glTFAssetWriter.h" +#include "PostProcessing/MakeVerboseFormat.h" + #include #include - #include #include #include @@ -54,16 +57,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -#include "MakeVerboseFormat.h" - -#include "glTFAsset.h" -// This is included here so WriteLazyDict's definition is found. -#include "glTFAssetWriter.h" - using namespace Assimp; using namespace glTF; - // // glTFImporter // @@ -86,7 +82,7 @@ glTFImporter::glTFImporter() : BaseImporter() , meshOffsets() , embeddedTexIdxs() -, mScene( NULL ) { +, mScene( nullptr ) { // empty } @@ -94,17 +90,16 @@ glTFImporter::~glTFImporter() { // empty } -const aiImporterDesc* glTFImporter::GetInfo() const -{ +const aiImporterDesc* glTFImporter::GetInfo() const { return &desc; } -bool glTFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool /* checkSig */) const -{ +bool glTFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool /* checkSig */) const { const std::string &extension = GetExtension(pFile); - if (extension != "gltf" && extension != "glb") + if (extension != "gltf" && extension != "glb") { return false; + } if (pIOHandler) { glTF::Asset asset(pIOHandler); @@ -120,44 +115,9 @@ bool glTFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool return false; } - - -//static void CopyValue(const glTF::vec3& v, aiColor3D& out) -//{ -// out.r = v[0]; out.g = v[1]; out.b = v[2]; -//} - -static void CopyValue(const glTF::vec4& v, aiColor4D& out) -{ - out.r = v[0]; out.g = v[1]; out.b = v[2]; out.a = v[3]; -} - -static void CopyValue(const glTF::vec4& v, aiColor3D& out) -{ - out.r = v[0]; out.g = v[1]; out.b = v[2]; -} - -static void CopyValue(const glTF::vec3& v, aiVector3D& out) -{ - out.x = v[0]; out.y = v[1]; out.z = v[2]; -} - -static void CopyValue(const glTF::vec4& v, aiQuaternion& out) -{ - out.x = v[0]; out.y = v[1]; out.z = v[2]; out.w = v[3]; -} - -static void CopyValue(const glTF::mat4& v, aiMatrix4x4& o) -{ - o.a1 = v[ 0]; o.b1 = v[ 1]; o.c1 = v[ 2]; o.d1 = v[ 3]; - o.a2 = v[ 4]; o.b2 = v[ 5]; o.c2 = v[ 6]; o.d2 = v[ 7]; - o.a3 = v[ 8]; o.b3 = v[ 9]; o.c3 = v[10]; o.d3 = v[11]; - o.a4 = v[12]; o.b4 = v[13]; o.c4 = v[14]; o.d4 = v[15]; -} - -inline void SetMaterialColorProperty(std::vector& embeddedTexIdxs, Asset& /*r*/, glTF::TexProperty prop, aiMaterial* mat, - aiTextureType texType, const char* pKey, unsigned int type, unsigned int idx) -{ +inline +void SetMaterialColorProperty(std::vector& embeddedTexIdxs, Asset& /*r*/, glTF::TexProperty prop, aiMaterial* mat, + aiTextureType texType, const char* pKey, unsigned int type, unsigned int idx) { if (prop.texture) { if (prop.texture->source) { aiString uri(prop.texture->source->uri); @@ -171,16 +131,14 @@ inline void SetMaterialColorProperty(std::vector& embeddedTexIdxs, Asset& / mat->AddProperty(&uri, _AI_MATKEY_TEXTURE_BASE, texType, 0); } - } - else { + } else { aiColor4D col; CopyValue(prop.color, col); mat->AddProperty(&col, 1, pKey, type, idx); } } -void glTFImporter::ImportMaterials(glTF::Asset& r) -{ +void glTFImporter::ImportMaterials(glTF::Asset& r) { mScene->mNumMaterials = unsigned(r.materials.Size()); mScene->mMaterials = new aiMaterial*[mScene->mNumMaterials]; @@ -308,7 +266,7 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) aim->mName = mesh.id; if (mesh.primitives.size() > 1) { - size_t& len = aim->mName.length; + ai_uint32& len = aim->mName.length; aim->mName.data[len] = '-'; len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p); } @@ -503,27 +461,31 @@ void glTFImporter::ImportMeshes(glTF::Asset& r) CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes); } -void glTFImporter::ImportCameras(glTF::Asset& r) -{ - if (!r.cameras.Size()) return; +void glTFImporter::ImportCameras(glTF::Asset& r) { + if (!r.cameras.Size()) { + return; + } mScene->mNumCameras = r.cameras.Size(); mScene->mCameras = new aiCamera*[r.cameras.Size()]; - for (size_t i = 0; i < r.cameras.Size(); ++i) { Camera& cam = r.cameras[i]; aiCamera* aicam = mScene->mCameras[i] = new aiCamera(); if (cam.type == Camera::Perspective) { - aicam->mAspect = cam.perspective.aspectRatio; - aicam->mHorizontalFOV = cam.perspective.yfov * aicam->mAspect; + aicam->mHorizontalFOV = cam.perspective.yfov * ((aicam->mAspect == 0.f) ? 1.f : aicam->mAspect); aicam->mClipPlaneFar = cam.perspective.zfar; aicam->mClipPlaneNear = cam.perspective.znear; - } - else { - // assimp does not support orthographic cameras + } else { + aicam->mClipPlaneFar = cam.ortographic.zfar; + aicam->mClipPlaneNear = cam.ortographic.znear; + aicam->mHorizontalFOV = 0.0; + aicam->mAspect = 1.0f; + if (0.f != cam.ortographic.ymag) { + aicam->mAspect = cam.ortographic.xmag / cam.ortographic.ymag; + } } } } @@ -717,7 +679,11 @@ void glTFImporter::ImportEmbeddedTextures(glTF::Asset& r) } } -void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { +void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) +{ + // clean all member arrays + meshOffsets.clear(); + embeddedTexIdxs.clear(); this->mScene = pScene; diff --git a/code/glTFImporter.h b/code/glTF/glTFImporter.h similarity index 98% rename from code/glTFImporter.h rename to code/glTF/glTFImporter.h index 064d6dc1a..ce8a000dc 100644 --- a/code/glTFImporter.h +++ b/code/glTF/glTFImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/glTF2Asset.h b/code/glTF2/glTF2Asset.h similarity index 94% rename from code/glTF2Asset.h rename to code/glTF2/glTF2Asset.h index 92be82f3b..15c4c44fa 100644 --- a/code/glTF2Asset.h +++ b/code/glTF2/glTF2Asset.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -46,12 +46,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * glTF Extensions Support: * KHR_materials_pbrSpecularGlossiness full * KHR_materials_unlit full + * KHR_lights_punctual full */ #ifndef GLTF2ASSET_H_INC #define GLTF2ASSET_H_INC #ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER +#include + #include #include #include @@ -92,38 +95,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include +#include "glTF/glTFCommon.h" + namespace glTF2 { -#ifdef ASSIMP_API - using Assimp::IOStream; - using Assimp::IOSystem; - using std::shared_ptr; -#else - using std::shared_ptr; - - typedef std::runtime_error DeadlyImportError; - typedef std::runtime_error DeadlyExportError; - - enum aiOrigin { aiOrigin_SET = 0, aiOrigin_CUR = 1, aiOrigin_END = 2 }; - class IOSystem; - class IOStream - { - FILE* f; - public: - IOStream(FILE* file) : f(file) {} - ~IOStream() { fclose(f); f = 0; } - - size_t Read(void* b, size_t sz, size_t n) { return fread(b, sz, n, f); } - size_t Write(const void* b, size_t sz, size_t n) { return fwrite(b, sz, n, f); } - int Seek(size_t off, aiOrigin orig) { return fseek(f, off, int(orig)); } - size_t Tell() const { return ftell(f); } - - size_t FileSize() { - long p = Tell(), len = (Seek(0, aiOrigin_END), Tell()); - return size_t((Seek(p, aiOrigin_SET), len)); - } - }; -#endif + using glTFCommon::shared_ptr; + using glTFCommon::IOSystem; + using glTFCommon::IOStream; using rapidjson::Value; using rapidjson::Document; @@ -135,35 +113,9 @@ namespace glTF2 struct Texture; struct Skin; - // Vec/matrix types, as raw float arrays - typedef float (vec3)[3]; - typedef float (vec4)[4]; - typedef float (mat4)[16]; - - namespace Util - { - void EncodeBase64(const uint8_t* in, size_t inLength, std::string& out); - - size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out); - - inline size_t DecodeBase64(const char* in, uint8_t*& out) - { - return DecodeBase64(in, strlen(in), out); - } - - struct DataURI - { - const char* mediaType; - const char* charset; - bool base64; - const char* data; - size_t dataLength; - }; - - //! Check if a uri is a data URI - inline bool ParseDataURI(const char* uri, size_t uriLen, DataURI& out); - } - + using glTFCommon::vec3; + using glTFCommon::vec4; + using glTFCommon::mat4; //! Magic number for GLB files #define AI_GLB_MAGIC_NUMBER "glTF" @@ -223,7 +175,8 @@ namespace glTF2 ComponentType_FLOAT = 5126 }; - inline unsigned int ComponentTypeSize(ComponentType t) + inline + unsigned int ComponentTypeSize(ComponentType t) { switch (t) { case ComponentType_SHORT: @@ -250,7 +203,7 @@ namespace glTF2 }; //! Values for the Sampler::magFilter field - enum class SamplerMagFilter: unsigned int + enum class SamplerMagFilter : unsigned int { UNSET = 0, SamplerMagFilter_Nearest = 9728, @@ -258,7 +211,7 @@ namespace glTF2 }; //! Values for the Sampler::minFilter field - enum class SamplerMinFilter: unsigned int + enum class SamplerMinFilter : unsigned int { UNSET = 0, SamplerMinFilter_Nearest = 9728, @@ -430,9 +383,9 @@ namespace glTF2 struct Accessor : public Object { Ref bufferView; //!< The ID of the bufferView. (required) - unsigned int byteOffset; //!< The offset relative to the start of the bufferView in bytes. (required) + size_t byteOffset; //!< The offset relative to the start of the bufferView in bytes. (required) ComponentType componentType; //!< The datatype of components in the attribute. (required) - unsigned int count; //!< The number of attributes referenced by this accessor. (required) + size_t count; //!< The number of attributes referenced by this accessor. (required) AttribType::Value type; //!< Specifies if the attribute is a scalar, vector, or matrix. (required) std::vector max; //!< Maximum value of each component in this attribute. std::vector min; //!< Minimum value of each component in this attribute. @@ -529,6 +482,7 @@ namespace glTF2 //std::string uri; //!< The uri of the buffer. Can be a filepath, a data uri, etc. (required) size_t byteLength; //!< The length of the buffer in bytes. (default: 0) //std::string type; //!< XMLHttpRequest responseType (default: "arraybuffer") + size_t capacity = 0; //!< The capacity of the buffer in bytes. (default: 0) Type type; @@ -547,7 +501,7 @@ namespace glTF2 /// but in real life you'll get: /// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 2, byteLength: 4} /// Yes, accessor of next mesh has offset and length which mean: current mesh data is decoded, all other data is encoded. - /// And when before you start to read data of current mesh (with encoded data ofcourse) you must decode region of "bufferView", after read finished + /// And when before you start to read data of current mesh (with encoded data of course) you must decode region of "bufferView", after read finished /// delete encoding mark. And after that you can repeat process: decode data of mesh, read, delete decoded data. /// /// Remark. Encoding all data at once is good in world with computers which do not has RAM limitation. So, you must use step by step encoding in @@ -656,10 +610,36 @@ namespace glTF2 } ortographic; } cameraProperties; - Camera() {} + Camera() + : type(Perspective) + , cameraProperties() { + // empty + } void Read(Value& obj, Asset& r); }; + //! A light (from KHR_lights_punctual extension) + struct Light : public Object + { + enum Type + { + Directional, + Point, + Spot + }; + + Type type; + + vec3 color; + float intensity; + Nullable range; + + float innerConeAngle; + float outerConeAngle; + + Light() {} + void Read(Value& obj, Asset& r); + }; //! Image data used to create a texture. struct Image : public Object @@ -811,6 +791,7 @@ namespace glTF2 Nullable scale; Ref camera; + Ref light; std::vector< Ref > skeletons; //!< The ID of skeleton nodes. Each of which is the root of a node hierarchy. Ref skin; //!< The ID of the skin referenced by this node. @@ -1042,6 +1023,7 @@ namespace glTF2 { bool KHR_materials_pbrSpecularGlossiness; bool KHR_materials_unlit; + bool KHR_lights_punctual; } extensionsUsed; @@ -1055,6 +1037,7 @@ namespace glTF2 LazyDict buffers; LazyDict bufferViews; LazyDict cameras; + LazyDict lights; LazyDict images; LazyDict materials; LazyDict meshes; @@ -1075,6 +1058,7 @@ namespace glTF2 , buffers (*this, "buffers") , bufferViews (*this, "bufferViews") , cameras (*this, "cameras") + , lights (*this, "lights", "KHR_lights_punctual") , images (*this, "images") , materials (*this, "materials") , meshes (*this, "meshes") diff --git a/code/glTF2Asset.inl b/code/glTF2/glTF2Asset.inl old mode 100755 new mode 100644 similarity index 87% rename from code/glTF2Asset.inl rename to code/glTF2/glTF2Asset.inl index ed37937f4..6b47b1607 --- a/code/glTF2Asset.inl +++ b/code/glTF2/glTF2Asset.inl @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -85,6 +85,14 @@ namespace { return val.IsString() ? (out = std::string(val.GetString(), val.GetStringLength()), true) : false; }}; + template<> struct ReadHelper { static bool Read(Value& val, uint64_t& out) { + return val.IsUint64() ? out = val.GetUint64(), true : false; + }}; + + template<> struct ReadHelper { static bool Read(Value& val, int64_t& out) { + return val.IsInt64() ? out = val.GetInt64(), true : false; + }}; + template struct ReadHelper< Nullable > { static bool Read(Value& val, Nullable& out) { return out.isPresent = ReadHelper::Read(val, out.value); }}; @@ -274,9 +282,7 @@ Ref LazyDict::Retrieve(unsigned int i) template Ref LazyDict::Get(unsigned int i) { - return Ref(mObjs, i); - } template @@ -353,11 +359,11 @@ inline void Buffer::Read(Value& obj, Asset& r) const char* uri = it->GetString(); - Util::DataURI dataURI; + glTFCommon::Util::DataURI dataURI; if (ParseDataURI(uri, it->GetStringLength(), dataURI)) { if (dataURI.base64) { uint8_t* data = 0; - this->byteLength = Util::DecodeBase64(dataURI.data, dataURI.dataLength, data); + this->byteLength = glTFCommon::Util::DecodeBase64(dataURI.data, dataURI.dataLength, data); this->mData.reset(data, std::default_delete()); if (statedLength > 0 && this->byteLength != statedLength) { @@ -520,7 +526,17 @@ inline size_t Buffer::AppendData(uint8_t* data, size_t length) inline void Buffer::Grow(size_t amount) { if (amount <= 0) return; - uint8_t* b = new uint8_t[byteLength + amount]; + if (capacity >= byteLength + amount) + { + byteLength += amount; + return; + } + + // Shift operation is standard way to divide integer by 2, it doesn't cast it to float back and forth, also works for odd numbers, + // originally it would look like: static_cast(capacity * 1.5f) + capacity = std::max(capacity + (capacity >> 1), byteLength + amount); + + uint8_t* b = new uint8_t[capacity]; if (mData) memcpy(b, mData.get(), byteLength); mData.reset(b, std::default_delete()); byteLength += amount; @@ -537,8 +553,8 @@ inline void BufferView::Read(Value& obj, Asset& r) buffer = r.buffers.Retrieve(bufferVal->GetUint()); } - byteOffset = MemberOrDefault(obj, "byteOffset", 0u); - byteLength = MemberOrDefault(obj, "byteLength", 0u); + byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0)); + byteLength = MemberOrDefault(obj, "byteLength", size_t(0)); byteStride = MemberOrDefault(obj, "byteStride", 0u); } @@ -553,9 +569,9 @@ inline void Accessor::Read(Value& obj, Asset& r) bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint()); } - byteOffset = MemberOrDefault(obj, "byteOffset", 0u); + byteOffset = MemberOrDefault(obj, "byteOffset", size_t(0)); componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE); - count = MemberOrDefault(obj, "count", 0u); + count = MemberOrDefault(obj, "count", size_t(0)); const char* typestr; type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR; @@ -699,12 +715,12 @@ inline void Image::Read(Value& obj, Asset& r) if (Value* uri = FindString(obj, "uri")) { const char* uristr = uri->GetString(); - Util::DataURI dataURI; + glTFCommon::Util::DataURI dataURI; if (ParseDataURI(uristr, uri->GetStringLength(), dataURI)) { mimeType = dataURI.mediaType; if (dataURI.base64) { uint8_t *ptr = nullptr; - mDataLength = Util::DecodeBase64(dataURI.data, dataURI.dataLength, ptr); + mDataLength = glTFCommon::Util::DecodeBase64(dataURI.data, dataURI.dataLength, ptr); mData.reset(ptr); } } @@ -1049,8 +1065,44 @@ inline void Camera::Read(Value& obj, Asset& /*r*/) } } -inline void Node::Read(Value& obj, Asset& r) +inline void Light::Read(Value& obj, Asset& /*r*/) { +#ifndef M_PI + const float M_PI = 3.14159265358979323846f; +#endif + + std::string type_string; + ReadMember(obj, "type", type_string); + if (type_string == "directional") + type = Light::Directional; + else if (type_string == "point") + type = Light::Point; + else + type = Light::Spot; + + name = MemberOrDefault(obj, "name", ""); + + SetVector(color, vec3{ 1.0f, 1.0f, 1.0f }); + ReadMember(obj, "color", color); + + intensity = MemberOrDefault(obj, "intensity", 1.0f); + + ReadMember(obj, "range", range); + + if (type == Light::Spot) + { + Value* spot = FindObject(obj, "spot"); + if (!spot) throw DeadlyImportError("GLTF: Light missing its spot parameters"); + innerConeAngle = MemberOrDefault(*spot, "innerConeAngle", 0.0f); + outerConeAngle = MemberOrDefault(*spot, "outerConeAngle", M_PI / 4.0f); + } +} + +inline +void Node::Read(Value& obj, Asset& r) { + if (name.empty()) { + name = id; + } if (Value* children = FindArray(obj, "children")) { this->children.reserve(children->Size()); @@ -1092,6 +1144,19 @@ inline void Node::Read(Value& obj, Asset& r) if (this->camera) this->camera->id = this->id; } + + if (Value* extensions = FindObject(obj, "extensions")) { + if (r.extensionsUsed.KHR_lights_punctual) { + + if (Value* ext = FindObject(*extensions, "KHR_lights_punctual")) { + if (Value* light = FindUInt(*ext, "light")) { + this->light = r.lights.Retrieve(light->GetUint()); + if (this->light) + this->light->id = this->id; + } + } + } + } } inline void Scene::Read(Value& obj, Asset& r) @@ -1403,6 +1468,7 @@ inline void Asset::ReadExtensionsUsed(Document& doc) CHECK_EXT(KHR_materials_pbrSpecularGlossiness); CHECK_EXT(KHR_materials_unlit); + CHECK_EXT(KHR_lights_punctual); #undef CHECK_EXT } @@ -1450,190 +1516,4 @@ inline std::string Asset::FindUniqueID(const std::string& str, const char* suffi return id; } -namespace Util { - - inline - bool ParseDataURI(const char* const_uri, size_t uriLen, DataURI& out) { - if ( NULL == const_uri ) { - return false; - } - - if (const_uri[0] != 0x10) { // we already parsed this uri? - if (strncmp(const_uri, "data:", 5) != 0) // not a data uri? - return false; - } - - // set defaults - out.mediaType = "text/plain"; - out.charset = "US-ASCII"; - out.base64 = false; - - char* uri = const_cast(const_uri); - if (uri[0] != 0x10) { - uri[0] = 0x10; - uri[1] = uri[2] = uri[3] = uri[4] = 0; - - size_t i = 5, j; - if (uri[i] != ';' && uri[i] != ',') { // has media type? - uri[1] = char(i); - for (; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) { - // nothing to do! - } - } - while (uri[i] == ';' && i < uriLen) { - uri[i++] = '\0'; - for (j = i; uri[i] != ';' && uri[i] != ',' && i < uriLen; ++i) { - // nothing to do! - } - - if ( strncmp( uri + j, "charset=", 8 ) == 0 ) { - uri[2] = char(j + 8); - } else if ( strncmp( uri + j, "base64", 6 ) == 0 ) { - uri[3] = char(j); - } - } - if (i < uriLen) { - uri[i++] = '\0'; - uri[4] = char(i); - } else { - uri[1] = uri[2] = uri[3] = 0; - uri[4] = 5; - } - } - - if ( uri[ 1 ] != 0 ) { - out.mediaType = uri + uri[ 1 ]; - } - if ( uri[ 2 ] != 0 ) { - out.charset = uri + uri[ 2 ]; - } - if ( uri[ 3 ] != 0 ) { - out.base64 = true; - } - out.data = uri + uri[4]; - out.dataLength = (uri + uriLen) - out.data; - - return true; - } - - template - struct DATA - { - static const uint8_t tableDecodeBase64[128]; - }; - - template - const uint8_t DATA::tableDecodeBase64[128] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 64, 0, 0, - 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, - 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, 0, 0, 0 - }; - - inline char EncodeCharBase64(uint8_t b) - { - return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="[size_t(b)]; - } - - inline uint8_t DecodeCharBase64(char c) - { - return DATA::tableDecodeBase64[size_t(c)]; // TODO faster with lookup table or ifs? - /*if (c >= 'A' && c <= 'Z') return c - 'A'; - if (c >= 'a' && c <= 'z') return c - 'a' + 26; - if (c >= '0' && c <= '9') return c - '0' + 52; - if (c == '+') return 62; - if (c == '/') return 63; - return 64; // '-' */ - } - - inline size_t DecodeBase64(const char* in, size_t inLength, uint8_t*& out) - { - ai_assert(inLength % 4 == 0); - - if (inLength < 4) { - out = 0; - return 0; - } - - int nEquals = int(in[inLength - 1] == '=') + - int(in[inLength - 2] == '='); - - size_t outLength = (inLength * 3) / 4 - nEquals; - out = new uint8_t[outLength]; - memset(out, 0, outLength); - - size_t i, j = 0; - - for (i = 0; i + 4 < inLength; i += 4) { - uint8_t b0 = DecodeCharBase64(in[i]); - uint8_t b1 = DecodeCharBase64(in[i + 1]); - uint8_t b2 = DecodeCharBase64(in[i + 2]); - uint8_t b3 = DecodeCharBase64(in[i + 3]); - - out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4)); - out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2)); - out[j++] = (uint8_t)((b2 << 6) | b3); - } - - { - uint8_t b0 = DecodeCharBase64(in[i]); - uint8_t b1 = DecodeCharBase64(in[i + 1]); - uint8_t b2 = DecodeCharBase64(in[i + 2]); - uint8_t b3 = DecodeCharBase64(in[i + 3]); - - out[j++] = (uint8_t)((b0 << 2) | (b1 >> 4)); - if (b2 < 64) out[j++] = (uint8_t)((b1 << 4) | (b2 >> 2)); - if (b3 < 64) out[j++] = (uint8_t)((b2 << 6) | b3); - } - - return outLength; - } - - - - inline void EncodeBase64( - const uint8_t* in, size_t inLength, - std::string& out) - { - size_t outLength = ((inLength + 2) / 3) * 4; - - size_t j = out.size(); - out.resize(j + outLength); - - for (size_t i = 0; i < inLength; i += 3) { - uint8_t b = (in[i] & 0xFC) >> 2; - out[j++] = EncodeCharBase64(b); - - b = (in[i] & 0x03) << 4; - if (i + 1 < inLength) { - b |= (in[i + 1] & 0xF0) >> 4; - out[j++] = EncodeCharBase64(b); - - b = (in[i + 1] & 0x0F) << 2; - if (i + 2 < inLength) { - b |= (in[i + 2] & 0xC0) >> 6; - out[j++] = EncodeCharBase64(b); - - b = in[i + 2] & 0x3F; - out[j++] = EncodeCharBase64(b); - } - else { - out[j++] = EncodeCharBase64(b); - out[j++] = '='; - } - } - else { - out[j++] = EncodeCharBase64(b); - out[j++] = '='; - out[j++] = '='; - } - } - } - -} - } // ns glTF diff --git a/code/glTF2AssetWriter.h b/code/glTF2/glTF2AssetWriter.h similarity index 98% rename from code/glTF2AssetWriter.h rename to code/glTF2/glTF2AssetWriter.h index 493ca1c0a..928b6e71b 100644 --- a/code/glTF2AssetWriter.h +++ b/code/glTF2/glTF2AssetWriter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/glTF2AssetWriter.inl b/code/glTF2/glTF2AssetWriter.inl similarity index 98% rename from code/glTF2AssetWriter.inl rename to code/glTF2/glTF2AssetWriter.inl index 50d855aaa..5d1b22064 100644 --- a/code/glTF2AssetWriter.inl +++ b/code/glTF2/glTF2AssetWriter.inl @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -97,10 +97,10 @@ namespace glTF2 { inline void Write(Value& obj, Accessor& a, AssetWriter& w) { obj.AddMember("bufferView", a.bufferView->index, w.mAl); - obj.AddMember("byteOffset", a.byteOffset, w.mAl); + obj.AddMember("byteOffset", (unsigned int)a.byteOffset, w.mAl); obj.AddMember("componentType", int(a.componentType), w.mAl); - obj.AddMember("count", a.count, w.mAl); + obj.AddMember("count", (unsigned int)a.count, w.mAl); obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl); Value vTmpMax, vTmpMin; @@ -202,6 +202,11 @@ namespace glTF2 { } + inline void Write(Value& /*obj*/, Light& /*c*/, AssetWriter& /*w*/) + { + + } + inline void Write(Value& obj, Image& img, AssetWriter& w) { if (img.bufferView) { @@ -213,7 +218,7 @@ namespace glTF2 { if (img.HasData()) { uri = "data:" + (img.mimeType.empty() ? "application/octet-stream" : img.mimeType); uri += ";base64,"; - Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri); + glTFCommon::Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri); } else { uri = img.uri; @@ -744,6 +749,9 @@ namespace glTF2 { if (!(dict = FindArray(*container, d.mDictId))) { container->AddMember(StringRef(d.mDictId), Value().SetArray().Move(), mDoc.GetAllocator()); dict = FindArray(*container, d.mDictId); + if (nullptr == dict) { + return; + } } for (size_t i = 0; i < d.mObjs.size(); ++i) { diff --git a/code/glTF2Exporter.cpp b/code/glTF2/glTF2Exporter.cpp similarity index 96% rename from code/glTF2Exporter.cpp rename to code/glTF2/glTF2Exporter.cpp index 40db27264..4724c2ef4 100644 --- a/code/glTF2Exporter.cpp +++ b/code/glTF2/glTF2Exporter.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -42,14 +42,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_EXPORT #ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER -#include "glTF2Exporter.h" +#include "glTF2/glTF2Exporter.h" +#include "glTF2/glTF2AssetWriter.h" +#include "PostProcessing/SplitLargeMeshes.h" #include #include #include - -#include "SplitLargeMeshes.h" - #include #include #include @@ -61,8 +60,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "glTF2AssetWriter.h" - using namespace rapidjson; using namespace Assimp; @@ -156,7 +153,7 @@ static void IdentityMatrix4(mat4& o) { } inline Ref ExportData(Asset& a, std::string& meshName, Ref& buffer, - unsigned int count, void* data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, bool isIndices = false) + size_t count, void* data, AttribType::Value typeIn, AttribType::Value typeOut, ComponentType compType, bool isIndices = false) { if (!count || !data) { return Ref(); @@ -176,7 +173,7 @@ inline Ref ExportData(Asset& a, std::string& meshName, Ref& bu // bufferView Ref bv = a.bufferViews.Create(a.FindUniqueID(meshName, "view")); bv->buffer = buffer; - bv->byteOffset = unsigned(offset); + bv->byteOffset = offset; bv->byteLength = length; //! The target that the WebGL buffer should be bound to. bv->byteStride = 0; bv->target = isIndices ? BufferViewTarget_ELEMENT_ARRAY_BUFFER : BufferViewTarget_ARRAY_BUFFER; @@ -647,9 +644,7 @@ void ExportSkin(Asset& mAsset, const aiMesh* aimesh, Ref& meshRef, RefGetPointer()[len_p]; unsigned short c = static_cast(f_value); - uint8_t* data = new uint8_t[s_bytesPerComp]; - data = (uint8_t*)&c; - memcpy(&arrys[i*s_bytesPerComp], data, s_bytesPerComp); + memcpy(&arrys[i*s_bytesPerComp], &c, s_bytesPerComp); ++i; } buf->ReplaceData_joint(offset, bytesLen, arrys, bytesLen); @@ -657,9 +652,11 @@ void ExportSkin(Asset& mAsset, const aiMesh* aimesh, Ref& meshRef, RefbufferView->byteLength = s_bytesLen; p.attributes.joint.push_back( vertexJointAccessor ); + delete[] arrys; } - Ref vertexWeightAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices, vertexWeightData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT); + Ref vertexWeightAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices, + vertexWeightData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT); if ( vertexWeightAccessor ) { p.attributes.weight.push_back( vertexWeightAccessor ); } @@ -732,6 +729,9 @@ void glTF2Exporter::ExportMeshes() /************** Texture coordinates **************/ for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + if (!aim->HasTextureCoords(i)) + continue; + // Flip UV y coords if (aim -> mNumUVComponents[i] > 1) { for (unsigned int j = 0; j < aim->mNumVertices; ++j) { @@ -748,8 +748,7 @@ void glTF2Exporter::ExportMeshes() } /*************** Vertex colors ****************/ - for (unsigned int indexColorChannel = 0; indexColorChannel < aim->GetNumColorChannels(); ++indexColorChannel) - { + for (unsigned int indexColorChannel = 0; indexColorChannel < aim->GetNumColorChannels(); ++indexColorChannel) { Ref c = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mColors[indexColorChannel], AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT, false); if (c) p.attributes.color.push_back(c); @@ -766,7 +765,7 @@ void glTF2Exporter::ExportMeshes() } } - p.indices = ExportData(*mAsset, meshId, b, unsigned(indices.size()), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_INT, true); + p.indices = ExportData(*mAsset, meshId, b, indices.size(), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_INT, true); } switch (aim->mPrimitiveTypes) { @@ -795,8 +794,12 @@ void glTF2Exporter::ExportMeshes() CopyValue(inverseBindMatricesData[idx_joint], invBindMatrixData[idx_joint]); } - Ref invBindMatrixAccessor = ExportData(*mAsset, skinName, b, static_cast(inverseBindMatricesData.size()), invBindMatrixData, AttribType::MAT4, AttribType::MAT4, ComponentType_FLOAT); - if (invBindMatrixAccessor) skinRef->inverseBindMatrices = invBindMatrixAccessor; + Ref invBindMatrixAccessor = ExportData(*mAsset, skinName, b, + static_cast(inverseBindMatricesData.size()), + invBindMatrixData, AttribType::MAT4, AttribType::MAT4, ComponentType_FLOAT); + if (invBindMatrixAccessor) { + skinRef->inverseBindMatrices = invBindMatrixAccessor; + } // Identity Matrix =====> skinRef->bindShapeMatrix // Temporary. Hard-coded identity matrix here @@ -824,10 +827,11 @@ void glTF2Exporter::ExportMeshes() meshNode->skeletons.push_back(rootJoint); meshNode->skin = skinRef; } + delete[] invBindMatrixData; } } -//merges a node's multiple meshes (with one primitive each) into one mesh with multiple primitives +// Merges a node's multiple meshes (with one primitive each) into one mesh with multiple primitives void glTF2Exporter::MergeMeshes() { for (unsigned int n = 0; n < mAsset->nodes.Size(); ++n) { @@ -963,7 +967,7 @@ void glTF2Exporter::ExportMetadata() inline Ref GetSamplerInputRef(Asset& asset, std::string& animId, Ref& buffer, std::vector& times) { - return ExportData(asset, animId, buffer, times.size(), ×[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_FLOAT); + return ExportData(asset, animId, buffer, (unsigned int)times.size(), ×[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_FLOAT); } inline void ExtractTranslationSampler(Asset& asset, std::string& animId, Ref& buffer, const aiNodeAnim* nodeChannel, float ticksPerSecond, Animation::Sampler& sampler) diff --git a/code/glTF2Exporter.h b/code/glTF2/glTF2Exporter.h similarity index 99% rename from code/glTF2Exporter.h rename to code/glTF2/glTF2Exporter.h index 06bc5ad40..2dc083709 100644 --- a/code/glTF2Exporter.h +++ b/code/glTF2/glTF2Exporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/glTF2Importer.cpp b/code/glTF2/glTF2Importer.cpp old mode 100755 new mode 100644 similarity index 77% rename from code/glTF2Importer.cpp rename to code/glTF2/glTF2Importer.cpp index f6a664e5e..c2106e26f --- a/code/glTF2Importer.cpp +++ b/code/glTF2/glTF2Importer.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -42,10 +42,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER -#include "glTF2Importer.h" +#include "glTF2/glTF2Importer.h" +#include "glTF2/glTF2Asset.h" +#include "glTF2/glTF2AssetWriter.h" +#include "PostProcessing/MakeVerboseFormat.h" + #include #include - #include #include #include @@ -56,19 +59,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "MakeVerboseFormat.h" - -#include "glTF2Asset.h" -// This is included here so WriteLazyDict's definition is found. -#include "glTF2AssetWriter.h" #include #include using namespace Assimp; using namespace glTF2; +using namespace glTFCommon; namespace { - // generate bitangents from normals and tangents according to spec + // generate bi-tangents from normals and tangents according to spec struct Tangent { aiVector3D xyz; ai_real w; @@ -142,22 +141,23 @@ static aiTextureMapMode ConvertWrappingMode(SamplerWrap gltfWrapMode) } } -//static void CopyValue(const glTF2::vec3& v, aiColor3D& out) -//{ -// out.r = v[0]; out.g = v[1]; out.b = v[2]; -//} +/*static void CopyValue(const glTF2::vec3& v, aiColor3D& out) +{ + out.r = v[0]; out.g = v[1]; out.b = v[2]; +} + static void CopyValue(const glTF2::vec4& v, aiColor4D& out) { out.r = v[0]; out.g = v[1]; out.b = v[2]; out.a = v[3]; -} +}*/ /*static void CopyValue(const glTF2::vec4& v, aiColor3D& out) { out.r = v[0]; out.g = v[1]; out.b = v[2]; }*/ -static void CopyValue(const glTF2::vec3& v, aiColor4D& out) +/*static void CopyValue(const glTF2::vec3& v, aiColor4D& out) { out.r = v[0]; out.g = v[1]; out.b = v[2]; out.a = 1.0; } @@ -170,15 +170,15 @@ static void CopyValue(const glTF2::vec3& v, aiVector3D& out) static void CopyValue(const glTF2::vec4& v, aiQuaternion& out) { out.x = v[0]; out.y = v[1]; out.z = v[2]; out.w = v[3]; -} +}*/ -static void CopyValue(const glTF2::mat4& v, aiMatrix4x4& o) +/*static void CopyValue(const glTF2::mat4& v, aiMatrix4x4& o) { o.a1 = v[ 0]; o.b1 = v[ 1]; o.c1 = v[ 2]; o.d1 = v[ 3]; o.a2 = v[ 4]; o.b2 = v[ 5]; o.c2 = v[ 6]; o.d2 = v[ 7]; o.a3 = v[ 8]; o.b3 = v[ 9]; o.c3 = v[10]; o.d3 = v[11]; o.a4 = v[12]; o.b4 = v[13]; o.c4 = v[14]; o.d4 = v[15]; -} +}*/ inline void SetMaterialColorProperty(Asset& /*r*/, vec4& prop, aiMaterial* mat, const char* pKey, unsigned int type, unsigned int idx) { @@ -190,7 +190,7 @@ inline void SetMaterialColorProperty(Asset& /*r*/, vec4& prop, aiMaterial* mat, inline void SetMaterialColorProperty(Asset& /*r*/, vec3& prop, aiMaterial* mat, const char* pKey, unsigned int type, unsigned int idx) { aiColor4D col; - CopyValue(prop, col); + glTFCommon::CopyValue(prop, col); mat->AddProperty(&col, 1, pKey, type, idx); } @@ -385,7 +385,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) aim->mName = mesh.name.empty() ? mesh.id : mesh.name; if (mesh.primitives.size() > 1) { - size_t& len = aim->mName.length; + ai_uint32& len = aim->mName.length; aim->mName.data[len] = '-'; len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p); } @@ -412,7 +412,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) Mesh::Primitive::Attributes& attr = prim.attributes; if (attr.position.size() > 0 && attr.position[0]) { - aim->mNumVertices = attr.position[0]->count; + aim->mNumVertices = static_cast(attr.position[0]->count); attr.position[0]->ExtractData(aim->mVertices); } @@ -438,6 +438,14 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) } } + for (size_t c = 0; c < attr.color.size() && c < AI_MAX_NUMBER_OF_COLOR_SETS; ++c) { + if (attr.color[c]->count != aim->mNumVertices) { + DefaultLogger::get()->warn("Color stream size in mesh \"" + mesh.name + + "\" does not match the vertex count"); + continue; + } + attr.color[c]->ExtractData(aim->mColors[c]); + } for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) { if (attr.texcoord[tc]->count != aim->mNumVertices) { DefaultLogger::get()->warn("Texcoord stream size in mesh \"" + mesh.name + @@ -502,10 +510,10 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) aiFace* faces = 0; - unsigned int nFaces = 0; + size_t nFaces = 0; if (prim.indices) { - unsigned int count = prim.indices->count; + size_t count = prim.indices->count; Accessor::Indexer data = prim.indices->GetIndexer(); ai_assert(data.IsValid()); @@ -656,8 +664,8 @@ void glTF2Importer::ImportMeshes(glTF2::Asset& r) if (faces) { aim->mFaces = faces; - aim->mNumFaces = nFaces; - ai_assert(CheckValidFacesIndices(faces, nFaces, aim->mNumVertices)); + aim->mNumFaces = static_cast(nFaces); + ai_assert(CheckValidFacesIndices(faces, static_cast(nFaces), aim->mNumVertices)); } if (prim.material) { @@ -693,12 +701,80 @@ void glTF2Importer::ImportCameras(glTF2::Asset& r) if (cam.type == Camera::Perspective) { aicam->mAspect = cam.cameraProperties.perspective.aspectRatio; - aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * aicam->mAspect; + aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * ((aicam->mAspect == 0.f) ? 1.f : aicam->mAspect); aicam->mClipPlaneFar = cam.cameraProperties.perspective.zfar; aicam->mClipPlaneNear = cam.cameraProperties.perspective.znear; + } else { + aicam->mClipPlaneFar = cam.cameraProperties.ortographic.zfar; + aicam->mClipPlaneNear = cam.cameraProperties.ortographic.znear; + aicam->mHorizontalFOV = 0.0; + aicam->mAspect = 1.0f; + if (0.f != cam.cameraProperties.ortographic.ymag ) { + aicam->mAspect = cam.cameraProperties.ortographic.xmag / cam.cameraProperties.ortographic.ymag; + } } - else { - // assimp does not support orthographic cameras + } +} + +void glTF2Importer::ImportLights(glTF2::Asset& r) +{ + if (!r.lights.Size()) + return; + + mScene->mNumLights = r.lights.Size(); + mScene->mLights = new aiLight*[r.lights.Size()]; + + for (size_t i = 0; i < r.lights.Size(); ++i) { + Light& light = r.lights[i]; + + aiLight* ail = mScene->mLights[i] = new aiLight(); + + switch (light.type) + { + case Light::Directional: + ail->mType = aiLightSource_DIRECTIONAL; break; + case Light::Point: + ail->mType = aiLightSource_POINT; break; + case Light::Spot: + ail->mType = aiLightSource_SPOT; break; + } + + if (ail->mType != aiLightSource_POINT) + { + ail->mDirection = aiVector3D(0.0f, 0.0f, -1.0f); + ail->mUp = aiVector3D(0.0f, 1.0f, 0.0f); + } + + vec3 colorWithIntensity = { light.color[0] * light.intensity, light.color[1] * light.intensity, light.color[2] * light.intensity }; + CopyValue(colorWithIntensity, ail->mColorAmbient); + CopyValue(colorWithIntensity, ail->mColorDiffuse); + CopyValue(colorWithIntensity, ail->mColorSpecular); + + if (ail->mType == aiLightSource_DIRECTIONAL) + { + ail->mAttenuationConstant = 1.0; + ail->mAttenuationLinear = 0.0; + ail->mAttenuationQuadratic = 0.0; + } + else + { + //in PBR attenuation is calculated using inverse square law which can be expressed + //using assimps equation: 1/(att0 + att1 * d + att2 * d*d) with the following parameters + //this is correct equation for the case when range (see + //https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual) + //is not present. When range is not present it is assumed that it is infinite and so numerator is 1. + //When range is present then numerator might be any value in range [0,1] and then assimps equation + //will not suffice. In this case range is added into metadata in ImportNode function + //and its up to implementation to read it when it wants to + ail->mAttenuationConstant = 0.0; + ail->mAttenuationLinear = 0.0; + ail->mAttenuationQuadratic = 1.0; + } + + if (ail->mType == aiLightSource_SPOT) + { + ail->mAngleInnerCone = light.innerConeAngle; + ail->mAngleOuterCone = light.outerConeAngle; } } } @@ -742,7 +818,7 @@ static void BuildVertexWeightMapping(Mesh::Primitive& primitive, std::vectorcount; + size_t num_vertices = attr.weight[0]->count; struct Weights { float values[4]; }; Weights* weights = nullptr; @@ -757,14 +833,20 @@ static void BuildVertexWeightMapping(Mesh::Primitive& primitive, std::vectorExtractData(indices16); } + // + if (nullptr == indices8 && nullptr == indices16) { + // Something went completely wrong! + ai_assert(false); + return; + } - for (int i = 0; i < num_vertices; ++i) { + for (size_t i = 0; i < num_vertices; ++i) { for (int j = 0; j < 4; ++j) { const unsigned int bone = (indices8!=nullptr) ? indices8[i].values[j] : indices16[i].values[j]; const float weight = weights[i].values[j]; if (weight > 0 && bone < map.size()) { map[bone].reserve(8); - map[bone].emplace_back(i, weight); + map[bone].emplace_back(static_cast(i), weight); } } } @@ -774,13 +856,16 @@ static void BuildVertexWeightMapping(Mesh::Primitive& primitive, std::vector& meshOffsets, glTF2::Ref& ptr) { Node& node = *ptr; - std::string nameOrId = node.name.empty() ? node.id : node.name; - - aiNode* ainode = new aiNode(nameOrId); + aiNode* ainode = new aiNode(GetNodeName(node)); if (!node.children.empty()) { ainode->mNumChildren = unsigned(node.children.size()); @@ -807,7 +892,7 @@ aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector& if (node.skin) { for (int primitiveNo = 0; primitiveNo < count; ++primitiveNo) { aiMesh* mesh = pScene->mMeshes[meshOffsets[mesh_idx]+primitiveNo]; - mesh->mNumBones = node.skin->jointNames.size(); + mesh->mNumBones = static_cast(node.skin->jointNames.size()); mesh->mBones = new aiBone*[mesh->mNumBones]; // GLTF and Assimp choose to store bone weights differently. @@ -822,22 +907,45 @@ aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector& std::vector> weighting(mesh->mNumBones); BuildVertexWeightMapping(node.meshes[0]->primitives[primitiveNo], weighting); - for (size_t i = 0; i < mesh->mNumBones; ++i) { + mat4* pbindMatrices = nullptr; + node.skin->inverseBindMatrices->ExtractData(pbindMatrices); + + for (uint32_t i = 0; i < mesh->mNumBones; ++i) { aiBone* bone = new aiBone(); Ref joint = node.skin->jointNames[i]; - bone->mName = joint->name; + if (!joint->name.empty()) { + bone->mName = joint->name; + } else { + // Assimp expects each bone to have a unique name. + static const std::string kDefaultName = "bone_"; + char postfix[10] = {0}; + ASSIMP_itoa10(postfix, i); + bone->mName = (kDefaultName + postfix); + } GetNodeTransform(bone->mOffsetMatrix, *joint); + CopyValue(pbindMatrices[i], bone->mOffsetMatrix); + std::vector& weights = weighting[i]; - bone->mNumWeights = weights.size(); + bone->mNumWeights = static_cast(weights.size()); if (bone->mNumWeights > 0) { - bone->mWeights = new aiVertexWeight[bone->mNumWeights]; - memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight)); + bone->mWeights = new aiVertexWeight[bone->mNumWeights]; + memcpy(bone->mWeights, weights.data(), bone->mNumWeights * sizeof(aiVertexWeight)); + } else { + // Assimp expects all bones to have at least 1 weight. + bone->mWeights = new aiVertexWeight[1]; + bone->mNumWeights = 1; + bone->mWeights->mVertexId = 0; + bone->mWeights->mWeight = 0.f; } mesh->mBones[i] = bone; } + + if (pbindMatrices) { + delete[] pbindMatrices; + } } } @@ -851,6 +959,18 @@ aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector& pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName; } + if (node.light) { + pScene->mLights[node.light.GetIndex()]->mName = ainode->mName; + + //range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual + //it is added to meta data of parent node, because there is no other place to put it + if (node.light->range.isPresent) + { + ainode->mMetaData = aiMetadata::Alloc(1); + ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value); + } + } + return ainode; } @@ -882,17 +1002,24 @@ void glTF2Importer::ImportNodes(glTF2::Asset& r) } struct AnimationSamplers { - AnimationSamplers() : translation(nullptr), rotation(nullptr), scale(nullptr) {} + AnimationSamplers() + : translation(nullptr) + , rotation(nullptr) + , scale(nullptr) + , weight(nullptr) { + // empty + } Animation::Sampler* translation; Animation::Sampler* rotation; Animation::Sampler* scale; + Animation::Sampler* weight; }; aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& samplers) { aiNodeAnim* anim = new aiNodeAnim(); - anim->mNodeName = node.name; + anim->mNodeName = GetNodeName(node); static const float kMillisecondsFromSeconds = 1000.f; @@ -901,7 +1028,7 @@ aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& sampl samplers.translation->input->ExtractData(times); aiVector3D* values = nullptr; samplers.translation->output->ExtractData(values); - anim->mNumPositionKeys = samplers.translation->input->count; + anim->mNumPositionKeys = static_cast(samplers.translation->input->count); anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; for (unsigned int i = 0; i < anim->mNumPositionKeys; ++i) { anim->mPositionKeys[i].mTime = times[i] * kMillisecondsFromSeconds; @@ -911,7 +1038,7 @@ aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& sampl delete[] values; } else if (node.translation.isPresent) { anim->mNumPositionKeys = 1; - anim->mPositionKeys = new aiVectorKey(); + anim->mPositionKeys = new aiVectorKey[anim->mNumPositionKeys]; anim->mPositionKeys->mTime = 0.f; anim->mPositionKeys->mValue.x = node.translation.value[0]; anim->mPositionKeys->mValue.y = node.translation.value[1]; @@ -923,7 +1050,7 @@ aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& sampl samplers.rotation->input->ExtractData(times); aiQuaternion* values = nullptr; samplers.rotation->output->ExtractData(values); - anim->mNumRotationKeys = samplers.rotation->input->count; + anim->mNumRotationKeys = static_cast(samplers.rotation->input->count); anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys]; for (unsigned int i = 0; i < anim->mNumRotationKeys; ++i) { anim->mRotationKeys[i].mTime = times[i] * kMillisecondsFromSeconds; @@ -936,7 +1063,7 @@ aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& sampl delete[] values; } else if (node.rotation.isPresent) { anim->mNumRotationKeys = 1; - anim->mRotationKeys = new aiQuatKey(); + anim->mRotationKeys = new aiQuatKey[anim->mNumRotationKeys]; anim->mRotationKeys->mTime = 0.f; anim->mRotationKeys->mValue.x = node.rotation.value[0]; anim->mRotationKeys->mValue.y = node.rotation.value[1]; @@ -949,7 +1076,7 @@ aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& sampl samplers.scale->input->ExtractData(times); aiVector3D* values = nullptr; samplers.scale->output->ExtractData(values); - anim->mNumScalingKeys = samplers.scale->input->count; + anim->mNumScalingKeys = static_cast(samplers.scale->input->count); anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys]; for (unsigned int i = 0; i < anim->mNumScalingKeys; ++i) { anim->mScalingKeys[i].mTime = times[i] * kMillisecondsFromSeconds; @@ -959,7 +1086,7 @@ aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& sampl delete[] values; } else if (node.scale.isPresent) { anim->mNumScalingKeys = 1; - anim->mScalingKeys = new aiVectorKey(); + anim->mScalingKeys = new aiVectorKey[anim->mNumScalingKeys]; anim->mScalingKeys->mTime = 0.f; anim->mScalingKeys->mValue.x = node.scale.value[0]; anim->mScalingKeys->mValue.y = node.scale.value[1]; @@ -969,6 +1096,43 @@ aiNodeAnim* CreateNodeAnim(glTF2::Asset& r, Node& node, AnimationSamplers& sampl return anim; } +aiMeshMorphAnim* CreateMeshMorphAnim(glTF2::Asset& r, Node& node, AnimationSamplers& samplers) +{ + aiMeshMorphAnim* anim = new aiMeshMorphAnim(); + anim->mName = GetNodeName(node); + + static const float kMillisecondsFromSeconds = 1000.f; + + if (nullptr != samplers.weight) { + float* times = nullptr; + samplers.weight->input->ExtractData(times); + float* values = nullptr; + samplers.weight->output->ExtractData(values); + anim->mNumKeys = static_cast(samplers.weight->input->count); + + const unsigned int numMorphs = samplers.weight->output->count / anim->mNumKeys; + + anim->mKeys = new aiMeshMorphKey[anim->mNumKeys]; + unsigned int k = 0u; + for (unsigned int i = 0u; i < anim->mNumKeys; ++i) { + anim->mKeys[i].mTime = times[i] * kMillisecondsFromSeconds; + anim->mKeys[i].mNumValuesAndWeights = numMorphs; + anim->mKeys[i].mValues = new unsigned int[numMorphs]; + anim->mKeys[i].mWeights = new double[numMorphs]; + + for (unsigned int j = 0u; j < numMorphs; ++j, ++k) { + anim->mKeys[i].mValues[j] = j; + anim->mKeys[i].mWeights[j] = ( 0.f > values[k] ) ? 0.f : values[k]; + } + } + + delete[] times; + delete[] values; + } + + return anim; +} + std::unordered_map GatherSamplers(Animation& anim) { std::unordered_map samplers; @@ -987,6 +1151,8 @@ std::unordered_map GatherSamplers(Animation& an sampler.rotation = &anim.samplers[channel.sampler]; } else if (channel.target.path == AnimationPath_SCALE) { sampler.scale = &anim.samplers[channel.sampler]; + } else if (channel.target.path == AnimationPath_WEIGHTS) { + sampler.weight = &anim.samplers[channel.sampler]; } } @@ -1013,18 +1179,45 @@ void glTF2Importer::ImportAnimations(glTF2::Asset& r) std::unordered_map samplers = GatherSamplers(anim); - ai_anim->mNumChannels = r.skins[0].jointNames.size(); + uint32_t numChannels = 0u; + uint32_t numMorphMeshChannels = 0u; + + for (auto& iter : samplers) { + if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) { + ++numChannels; + } + if (nullptr != iter.second.weight) { + ++numMorphMeshChannels; + } + } + + ai_anim->mNumChannels = numChannels; if (ai_anim->mNumChannels > 0) { ai_anim->mChannels = new aiNodeAnim*[ai_anim->mNumChannels]; int j = 0; - for (auto& iter : r.skins[0].jointNames) { - ai_anim->mChannels[j] = CreateNodeAnim(r, *iter, samplers[iter.GetIndex()]); - ++j; + for (auto& iter : samplers) { + if ((nullptr != iter.second.rotation) || (nullptr != iter.second.scale) || (nullptr != iter.second.translation)) { + ai_anim->mChannels[j] = CreateNodeAnim(r, r.nodes[iter.first], iter.second); + ++j; + } } } - + + ai_anim->mNumMorphMeshChannels = numMorphMeshChannels; + if (ai_anim->mNumMorphMeshChannels > 0) { + ai_anim->mMorphMeshChannels = new aiMeshMorphAnim*[ai_anim->mNumMorphMeshChannels]; + int j = 0; + for (auto& iter : samplers) { + if (nullptr != iter.second.weight) { + ai_anim->mMorphMeshChannels[j] = CreateMeshMorphAnim(r, r.nodes[iter.first], iter.second); + ++j; + } + } + } + // Use the latest keyframe for the duration of the animation double maxDuration = 0; + unsigned int maxNumberOfKeys = 0; for (unsigned int j = 0; j < ai_anim->mNumChannels; ++j) { auto chan = ai_anim->mChannels[j]; if (chan->mNumPositionKeys) { @@ -1032,22 +1225,39 @@ void glTF2Importer::ImportAnimations(glTF2::Asset& r) if (lastPosKey.mTime > maxDuration) { maxDuration = lastPosKey.mTime; } + maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumPositionKeys); } if (chan->mNumRotationKeys) { auto lastRotKey = chan->mRotationKeys[chan->mNumRotationKeys - 1]; if (lastRotKey.mTime > maxDuration) { maxDuration = lastRotKey.mTime; } + maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumRotationKeys); } if (chan->mNumScalingKeys) { auto lastScaleKey = chan->mScalingKeys[chan->mNumScalingKeys - 1]; if (lastScaleKey.mTime > maxDuration) { maxDuration = lastScaleKey.mTime; } + maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumScalingKeys); } } + + for (unsigned int j = 0; j < ai_anim->mNumMorphMeshChannels; ++j) { + const auto* const chan = ai_anim->mMorphMeshChannels[j]; + + if (0u != chan->mNumKeys) { + const auto& lastKey = chan->mKeys[chan->mNumKeys - 1u]; + if (lastKey.mTime > maxDuration) { + maxDuration = lastKey.mTime; + } + maxNumberOfKeys = std::max(maxNumberOfKeys, chan->mNumKeys); + } + } + ai_anim->mDuration = maxDuration; - + ai_anim->mTicksPerSecond = 1000.0; + mScene->mAnimations[i] = ai_anim; } } @@ -1098,7 +1308,11 @@ void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset& r) } } -void glTF2Importer::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { +void glTF2Importer::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) +{ + // clean all member arrays + meshOffsets.clear(); + embeddedTexIdxs.clear(); this->mScene = pScene; @@ -1116,6 +1330,7 @@ void glTF2Importer::InternReadFile(const std::string& pFile, aiScene* pScene, IO ImportMeshes(asset); ImportCameras(asset); + ImportLights(asset); ImportNodes(asset); diff --git a/code/glTF2Importer.h b/code/glTF2/glTF2Importer.h similarity index 98% rename from code/glTF2Importer.h rename to code/glTF2/glTF2Importer.h index 7414e2f95..091b61ee6 100644 --- a/code/glTF2Importer.h +++ b/code/glTF2/glTF2Importer.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/code/makefile.mingw b/code/makefile.mingw deleted file mode 100644 index 711d57f57..000000000 --- a/code/makefile.mingw +++ /dev/null @@ -1,105 +0,0 @@ -### USE OF THIS MAKEFILE IS NOT RECOMMENDED. -### It is no longer maintained. Use CMAKE instead. - -# --------------------------------------------------------------------------- -# Makefile for Open Asset Import Library (MinGW32-make) -# aramis_acg@users.sourceforge.net -# - just a quick'n'dirty one, could be buggy ... -# -# Usage: mingw32-make -f makefile.mingw - -# TARGETS: -# all Build a shared so from the whole library -# clean Cleanup object files, prepare for rebuild -# static Build a static library (*.a) - -# MACROS: (make clean before you change one) -# NOBOOST=1 Build against boost workaround -# SINGLETHREADED=1 Build single-threaded library -# DEBUG=1 Build debug build of library -# -# --------------------------------------------------------------------------- - -# C++ object files -OBJECTS := $(patsubst %.cpp,%.o, $(wildcard *.cpp)) -OBJECTS += $(patsubst %.cpp,%.o, $(wildcard extra/*.cpp)) -OBJECTS += $(patsubst %.cpp,%.o, $(wildcard ./../contrib/irrXML/*.cpp)) - -# C object files -OBJECTSC := $(patsubst %.c,%.oc, $(wildcard ./../contrib/zlib/*.c)) -OBJECTSC += $(patsubst %.c,%.oc, $(wildcard ./../contrib/ConvertUTF/*.c)) -OBJECTSC += $(patsubst %.c,%.oc, $(wildcard ./../contrib/unzip/*.c)) - -# Include flags for gcc -INCLUDEFLAGS = - -# Preprocessor defines for gcc -DEFINEFLAGS = - -# Suffix for the output binary, represents build type -NAMESUFFIX = - -# Output path for binaries -BINPATH = ../bin/mingw/ - -# GCC compiler flags -CPPFLAGS=-Wall - -# Setup environment for noboost build -ifeq ($(NOBOOST),1) - SINGLETHREADED = 1 - INCLUDEFLAGS += -I./BoostWorkaround/ - DEFINEFLAGS += -DASSIMP_BUILD_BOOST_WORKAROUND -# NAMESUFFIX += -noboost -else - # adjust this manually if your boost is stored elsewhere - INCLUDEFLAGS += -I"C:/Program Files/boost/boost_1_38" - #INCLUDEFLAGS += -I"$(BOOST_DIR)" - -endif - -# Setup environment for st build -ifeq ($(SINGLETHREADED),1) - DEFINEFLAGS += -DASSIMP_BUILD_SINGLETHREADED -# NAMESUFFIX += -st -endif - -# Setup environment for debug build -ifeq ($(DEBUG),1) - DEFINEFLAGS += -D_DEBUG -DDEBUG - CPPFLAGS += -g -# NAMESUFFIX += -debug -else - CPPFLAGS += -O2 -s - DEFINEFLAGS += -DNDEBUG -D_NDEBUG -endif - -# Output name of shared library -SHARED_TARGET = $(BINPATH)/libassimp$(NAMESUFFIX).so - -# Output name of static library -STATIC = $(BINPATH)/libassimp$(NAMESUFFIX).a - -# target: all -# usage : build a shared library (*.so) -all: $(SHARED_TARGET) - -$(SHARED_TARGET): $(OBJECTS) $(OBJECTSC) - gcc -o $@ $(OBJECTS) $(OBJECTSC) -shared -lstdc++ -%.o:%.cpp - $(CXX) -c $(CPPFLAGS) $? -o $@ $(INCLUDEFLAGS) $(DEFINEFLAGS) -%.oc:%.c - $(CXX) -x c -c -ansi $(CPPFLAGS) $? -o $@ - -# target: clean -# usage : cleanup all object files, prepare for a rebuild -.PHONY: clean -clean: - -del *.o .\..\contrib\irrXML\*.o .\..\contrib\zlib\*.oc .\..\contrib\unzip\*.oc .\..\contrib\ConvertUTF\*.oc - -# target: static -# usage : build a static library (*.a) -static: $(STATIC) -$(STATIC): $(OBJECTS) $(OBJECTSC) - ar rcs $@ $(OBJECTS) $(OBJECTSC) - diff --git a/code/res/assimp.rc b/code/res/assimp.rc index 0fe98c05d..daecf9cf5 100644 --- a/code/res/assimp.rc +++ b/code/res/assimp.rc @@ -1,7 +1,7 @@ // Microsoft Visual C++ generated resource script. // #include "resource.h" -#include "..\..\revision.h" +#include "revision.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// @@ -31,8 +31,8 @@ LANGUAGE LANG_GERMAN, SUBLANG_GERMAN // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,1,SVNRevision, 0 - PRODUCTVERSION 1,1,SVNRevision,0 + FILEVERSION VER_FILEVERSION + PRODUCTVERSION VER_FILEVERSION FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -50,12 +50,12 @@ BEGIN VALUE "Comments", "Licensed under a 3-clause BSD license" VALUE "CompanyName", "assimp team" VALUE "FileDescription", "Open Asset Import Library" - VALUE "FileVersion", 1,1,SVNRevision,0 + VALUE "FileVersion", VER_FILEVERSION VALUE "InternalName", "assimp " - VALUE "LegalCopyright", "Copyright (C) 2006-2010" - VALUE "OriginalFilename", "assimpNN.dll" + VALUE "LegalCopyright", "Copyright (C) 2006-2019" + VALUE "OriginalFilename", VER_ORIGINAL_FILENAME_STR VALUE "ProductName", "Open Asset Import Library" - VALUE "ProductVersion", 1,1,SVNRevision,0 + VALUE "ProductVersion", VER_FILEVERSION_STR ,0 END END diff --git a/code/res/resource.h b/code/res/resource.h index 37d39284f..c28c05073 100644 --- a/code/res/resource.h +++ b/code/res/resource.h @@ -2,8 +2,8 @@ // Microsoft Visual C++ generated include file. // Used by assimp.rc -// Nächste Standardwerte für neue Objekte -// +// Next standard values for new objects +// #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 101 diff --git a/contrib/clipper/clipper.cpp b/contrib/clipper/clipper.cpp index 074f22b21..857cd1c3e 100644 --- a/contrib/clipper/clipper.cpp +++ b/contrib/clipper/clipper.cpp @@ -371,6 +371,9 @@ inline bool PointsEqual( const IntPoint &pt1, const IntPoint &pt2) bool Orientation(OutRec *outRec, bool UseFullInt64Range) { + if (!outRec->pts) + return 0.0; + //first make sure bottomPt is correctly assigned ... OutPt *opBottom = outRec->pts, *op = outRec->pts->next; while (op != outRec->pts) @@ -434,6 +437,9 @@ double Area(const Polygon &poly) double Area(const OutRec &outRec, bool UseFullInt64Range) { + if (!outRec.pts) + return 0.0; + OutPt *op = outRec.pts; if (UseFullInt64Range) { Int128 a(0); @@ -3085,9 +3091,9 @@ void Clipper::JoinCommonEdges(bool fixHoleLinkages) FixupOutPolygon(*outRec1); FixupOutPolygon(*outRec2); - if (Orientation(outRec1, m_UseFullRange) != (Area(*outRec1, m_UseFullRange) > 0)) + if (outRec1->pts && (Orientation(outRec1, m_UseFullRange) != (Area(*outRec1, m_UseFullRange) > 0))) DisposeBottomPt(*outRec1); - if (Orientation(outRec2, m_UseFullRange) != (Area(*outRec2, m_UseFullRange) > 0)) + if (outRec2->pts && (Orientation(outRec2, m_UseFullRange) != (Area(*outRec2, m_UseFullRange) > 0))) DisposeBottomPt(*outRec2); } else diff --git a/contrib/gtest/test/gtest-param-test_test.cc b/contrib/gtest/test/gtest-param-test_test.cc index 8b278bb94..857f6c5e5 100644 --- a/contrib/gtest/test/gtest-param-test_test.cc +++ b/contrib/gtest/test/gtest-param-test_test.cc @@ -141,7 +141,7 @@ void VerifyGenerator(const ParamGenerator& generator, << ", expected_values[i] is " << PrintValue(expected_values[i]) << ", *it is " << PrintValue(*it) << ", and 'it' is an iterator created with the copy constructor.\n"; - it++; + ++it; } EXPECT_TRUE(it == generator.end()) << "At the presumed end of sequence when accessing via an iterator " @@ -161,7 +161,7 @@ void VerifyGenerator(const ParamGenerator& generator, << ", expected_values[i] is " << PrintValue(expected_values[i]) << ", *it is " << PrintValue(*it) << ", and 'it' is an iterator created with the copy constructor.\n"; - it++; + ++it; } EXPECT_TRUE(it == generator.end()) << "At the presumed end of sequence when accessing via an iterator " @@ -196,7 +196,7 @@ TEST(IteratorTest, ParamIteratorConformsToForwardIteratorConcept) { << "element same as its source points to"; // Verifies that iterator assignment works as expected. - it++; + ++it; EXPECT_FALSE(*it == *it2); it2 = it; EXPECT_TRUE(*it == *it2) << "Assigned iterators must point to the " @@ -215,7 +215,7 @@ TEST(IteratorTest, ParamIteratorConformsToForwardIteratorConcept) { // Verifies that prefix and postfix operator++() advance an iterator // all the same. it2 = it; - it++; + ++it; ++it2; EXPECT_TRUE(*it == *it2); } diff --git a/contrib/irrXML/CMakeLists.txt b/contrib/irrXML/CMakeLists.txt index 48941970a..7f58af3d8 100644 --- a/contrib/irrXML/CMakeLists.txt +++ b/contrib/irrXML/CMakeLists.txt @@ -13,10 +13,17 @@ if ( MSVC ) ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) endif ( MSVC ) -add_library(IrrXML STATIC ${IrrXML_SRCS}) +IF(CMAKE_SYSTEM_NAME MATCHES "(Darwin|FreeBSD)") + add_library(IrrXML ${IrrXML_SRCS}) +ELSE() + add_library(IrrXML STATIC ${IrrXML_SRCS}) +ENDIF() set(IRRXML_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "IrrXML_Include" ) set(IRRXML_LIBRARY "IrrXML" CACHE INTERNAL "IrrXML" ) install(TARGETS IrrXML + LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} + FRAMEWORK DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT}) diff --git a/contrib/irrXML/CXMLReaderImpl.h b/contrib/irrXML/CXMLReaderImpl.h index 7d33b9404..6f3bec5fa 100644 --- a/contrib/irrXML/CXMLReaderImpl.h +++ b/contrib/irrXML/CXMLReaderImpl.h @@ -10,8 +10,11 @@ #include "irrArray.h" #include +#include +#include +#include +//using namespace Assimp; -using namespace Assimp; #ifdef _DEBUG #define IRR_DEBUGPRINT(x) printf((x)); @@ -162,7 +165,8 @@ public: return 0; core::stringc c = attr->Value.c_str(); - return fast_atof(c.c_str()); + return static_cast(atof(c.c_str())); + //return fast_atof(c.c_str()); } @@ -174,7 +178,8 @@ public: return 0; core::stringc c = attrvalue; - return fast_atof(c.c_str()); + return static_cast(atof(c.c_str())); + //return fast_atof(c.c_str()); } @@ -428,7 +433,7 @@ private: ++P; // remove trailing whitespace, if any - while( isspace( P[-1])) + while( std::isspace( P[-1])) --P; NodeName = core::string(pBeginClose, (int)(P - pBeginClose)); diff --git a/contrib/irrXML/irrString.h b/contrib/irrXML/irrString.h index af21b8e51..ff0097b71 100644 --- a/contrib/irrXML/irrString.h +++ b/contrib/irrXML/irrString.h @@ -19,7 +19,7 @@ so you can assign unicode to string and ascii to string Note that the conversation between both is not done using an encoding. Known bugs: -Special characters like 'Ä', 'Ü' and 'Ö' are ignored in the +Special characters like 'Ä', 'Ãœ' and 'Ö' are ignored in the methods make_upper, make_lower and equals_ignore_case. */ template diff --git a/contrib/irrXML/irrXML.cpp b/contrib/irrXML/irrXML.cpp index 532eed544..5a4b04507 100644 --- a/contrib/irrXML/irrXML.cpp +++ b/contrib/irrXML/irrXML.cpp @@ -9,7 +9,7 @@ #include "irrXML.h" #include "irrString.h" #include "irrArray.h" -#include +//#include #include "CXMLReaderImpl.h" namespace irr @@ -18,7 +18,7 @@ namespace io { //! Implementation of the file read callback for ordinary files -class CFileReadCallBack : public IFileReadCallBack +class IRRXML_API CFileReadCallBack : public IFileReadCallBack { public: diff --git a/contrib/irrXML/irrXML.h b/contrib/irrXML/irrXML.h index b51ddeb54..d724b3162 100644 --- a/contrib/irrXML/irrXML.h +++ b/contrib/irrXML/irrXML.h @@ -7,6 +7,12 @@ #include +#ifdef _WIN32 +# define IRRXML_API __declspec(dllexport) +#else +# define IRRXML_API __attribute__ ((visibility("default"))) +#endif // _WIN32 + /** \mainpage irrXML 1.2 API documentation

@@ -209,7 +215,7 @@ namespace io two methods to read your data and give a pointer to an instance of your implementation when calling createIrrXMLReader(), createIrrXMLReaderUTF16() or createIrrXMLReaderUTF32() */ - class IFileReadCallBack + class IRRXML_API IFileReadCallBack { public: @@ -409,7 +415,7 @@ namespace io \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ - IrrXMLReader* createIrrXMLReader(const char* filename); + IRRXML_API IrrXMLReader* createIrrXMLReader(const char* filename); //! Creates an instance of an UFT-8 or ASCII character xml parser. /** This means that all character data will be returned in 8 bit ASCII or UTF-8. The file to read can @@ -421,7 +427,7 @@ namespace io \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ - IrrXMLReader* createIrrXMLReader(FILE* file); + IRRXML_API IrrXMLReader* createIrrXMLReader(FILE* file); //! Creates an instance of an UFT-8 or ASCII character xml parser. /** This means that all character data will be returned in 8 bit ASCII or UTF-8. The file to read can @@ -434,7 +440,7 @@ namespace io \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ - IrrXMLReader* createIrrXMLReader(IFileReadCallBack* callback); + IRRXML_API IrrXMLReader* createIrrXMLReader(IFileReadCallBack* callback); //! Creates an instance of an UFT-16 xml parser. /** This means that @@ -446,7 +452,7 @@ namespace io \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ - IrrXMLReaderUTF16* createIrrXMLReaderUTF16(const char* filename); + IRRXML_API IrrXMLReaderUTF16* createIrrXMLReaderUTF16(const char* filename); //! Creates an instance of an UFT-16 xml parser. /** This means that all character data will be returned in UTF-16. The file to read can @@ -458,7 +464,7 @@ namespace io \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ - IrrXMLReaderUTF16* createIrrXMLReaderUTF16(FILE* file); + IRRXML_API IrrXMLReaderUTF16* createIrrXMLReaderUTF16(FILE* file); //! Creates an instance of an UFT-16 xml parser. /** This means that all character data will be returned in UTF-16. The file to read can @@ -471,7 +477,7 @@ namespace io \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ - IrrXMLReaderUTF16* createIrrXMLReaderUTF16(IFileReadCallBack* callback); + IRRXML_API IrrXMLReaderUTF16* createIrrXMLReaderUTF16(IFileReadCallBack* callback); //! Creates an instance of an UFT-32 xml parser. @@ -483,7 +489,7 @@ namespace io \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ - IrrXMLReaderUTF32* createIrrXMLReaderUTF32(const char* filename); + IRRXML_API IrrXMLReaderUTF32* createIrrXMLReaderUTF32(const char* filename); //! Creates an instance of an UFT-32 xml parser. /** This means that all character data will be returned in UTF-32. The file to read can @@ -495,7 +501,7 @@ namespace io \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ - IrrXMLReaderUTF32* createIrrXMLReaderUTF32(FILE* file); + IRRXML_API IrrXMLReaderUTF32* createIrrXMLReaderUTF32(FILE* file); //! Creates an instance of an UFT-32 xml parser. /** This means that @@ -509,7 +515,7 @@ namespace io \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ - IrrXMLReaderUTF32* createIrrXMLReaderUTF32(IFileReadCallBack* callback); + IRRXML_API IrrXMLReaderUTF32* createIrrXMLReaderUTF32(IFileReadCallBack* callback); /*! \file irrxml.h diff --git a/contrib/poly2tri/AUTHORS b/contrib/poly2tri/AUTHORS index 1736f14bb..aa390660d 100644 --- a/contrib/poly2tri/AUTHORS +++ b/contrib/poly2tri/AUTHORS @@ -1,7 +1,7 @@ Primary Contributors: Mason Green (C++, Python) - Thomas Åhlén (Java) + Thomas Ã…hlén (Java) Other Contributors: diff --git a/tools/assimp_qt_viewer/stb_image.h b/contrib/stb_image/stb_image.h similarity index 100% rename from tools/assimp_qt_viewer/stb_image.h rename to contrib/stb_image/stb_image.h diff --git a/contrib/zip/.gitignore b/contrib/zip/.gitignore index 4f9972c56..a7904a1ef 100644 --- a/contrib/zip/.gitignore +++ b/contrib/zip/.gitignore @@ -36,3 +36,21 @@ # Temporary *.swp .DS_Store + +# CMake +CMakeScripts +*.cmake + +# Xcode +*.build +*.xcodeproj +zip.sln +zip.vcxproj.filters +zip.vcxproj +ALL_BUILD.vcxproj.filters +ALL_BUILD.vcxproj +CMakeFiles/ +zip.dir/ +test/test.exe.vcxproj.filters +test/test.exe.vcxproj +test/test.exe.dir/ diff --git a/contrib/zip/.travis.sh b/contrib/zip/.travis.sh new file mode 100755 index 000000000..22974b1ff --- /dev/null +++ b/contrib/zip/.travis.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# +# Build script for travis-ci.org builds. +# +if [ $ANALYZE = "true" ] && [ "$CC" = "clang" ]; then + # scan-build -h + scan-build cmake -G "Unix Makefiles" + scan-build -enable-checker security.FloatLoopCounter \ + -enable-checker security.insecureAPI.UncheckedReturn \ + --status-bugs -v \ + make -j 8 \ + make -j 8 test +else + cmake -DCMAKE_BUILD_TYPE=Debug -DSANITIZE_ADDRESS=On -DCMAKE_INSTALL_PREFIX=_install + make -j 8 + make install + ASAN_OPTIONS=detect_leaks=0 LSAN_OPTIONS=verbosity=1:log_threads=1 ctest -V +fi \ No newline at end of file diff --git a/contrib/zip/.travis.yml b/contrib/zip/.travis.yml index d8ccb728d..86bac1cca 100644 --- a/contrib/zip/.travis.yml +++ b/contrib/zip/.travis.yml @@ -1,10 +1,22 @@ language: c +addons: + apt: + packages: &1 + - lcov # Compiler selection compiler: - clang - gcc +env: + - ANALYZE=false + - ANALYZE=true # Build steps script: - - mkdir build - - cd build - - cmake -DCMAKE_BUILD_TYPE=Debug .. && make && make test + - ./.travis.sh +after_success: + # Creating report + - cmake -DENABLE_COVERAGE=ON + - make + - make test + # Uploading report to CodeCov + - bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/contrib/zip/CMakeLists.txt b/contrib/zip/CMakeLists.txt index 450ef3a98..b46dbb1db 100644 --- a/contrib/zip/CMakeLists.txt +++ b/contrib/zip/CMakeLists.txt @@ -1,18 +1,47 @@ cmake_minimum_required(VERSION 2.8) project(zip) +enable_language(C) +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) if (MSVC) - # Use secure functions by defaualt and suppress warnings about "deprecated" functions - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1") + # Use secure functions by defaualt and suppress warnings about "deprecated" functions + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1") +elseif ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR + "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR + "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra -Werror -pedantic") endif (MSVC) # zip set(SRC src/miniz.h src/zip.h src/zip.c) -add_library(${CMAKE_PROJECT_NAME} ${SRC}) +add_library(${PROJECT_NAME} ${SRC}) +target_include_directories(${PROJECT_NAME} INTERFACE src) # test -enable_testing() -add_subdirectory(test) +if (NOT CMAKE_DISABLE_TESTING) + enable_testing() + add_subdirectory(test) + find_package(Sanitizers) + add_sanitizers(${PROJECT_NAME} test.exe) + add_sanitizers(${PROJECT_NAME} test_miniz.exe) +endif() +install(TARGETS ${PROJECT_NAME} + RUNTIME DESTINATION bin + ARCHIVE DESTINATION lib + LIBRARY DESTINATION lib + COMPONENT library) +install(FILES ${PROJECT_SOURCE_DIR}/src/zip.h DESTINATION include) + +# uninstall target (https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake) +if(NOT TARGET uninstall) + configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake" + IMMEDIATE @ONLY) + + add_custom_target(uninstall + COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake) +endif() diff --git a/contrib/zip/README.md b/contrib/zip/README.md index 24de5e61a..d5fb8cd20 100644 --- a/contrib/zip/README.md +++ b/contrib/zip/README.md @@ -1,12 +1,11 @@ ### A portable (OSX/Linux/Windows), simple zip library written in C This is done by hacking awesome [miniz](https://code.google.com/p/miniz) library and layering functions on top of the miniz v1.15 API. -[![Windows][win-badge]][win-link] [![OS X][osx-linux-badge]][osx-linux-link] +[![Windows](https://ci.appveyor.com/api/projects/status/bph8dr3jacgmjv32/branch/master?svg=true&label=windows)](https://ci.appveyor.com/project/kuba--/zip) +[![Linux](https://travis-ci.org/kuba--/zip.svg?branch=master&label=linux%2fosx)](https://travis-ci.org/kuba--/zip) +[![Version](https://badge.fury.io/gh/kuba--%2Fzip.svg)](https://github.com/kuba--/zip/releases) +[![Codecov](https://codecov.io/gh/kuba--/zip/branch/master/graph/badge.svg)](https://codecov.io/gh/kuba--/zip) -[win-badge]: https://img.shields.io/appveyor/ci/kuba--/zip/master.svg?label=windows "AppVeyor build status" -[win-link]: https://ci.appveyor.com/project/kuba--/zip "AppVeyor build status" -[osx-linux-badge]: https://img.shields.io/travis/kuba--/zip/master.svg?label=linux/osx "Travis CI build status" -[osx-linux-link]: https://travis-ci.org/kuba--/zip "Travis CI build status" # The Idea @@ -23,117 +22,288 @@ It was the reason, why I decided to write zip module on top of the miniz. It req * Create a new zip archive with default compression level. ```c - struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); +struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); +{ + zip_entry_open(zip, "foo-1.txt"); { - zip_entry_open(zip, "foo-1.txt"); - { - char *buf = "Some data here..."; - zip_entry_write(zip, buf, strlen(buf)); - } - zip_entry_close(zip); - - zip_entry_open(zip, "foo-2.txt"); - { - // merge 3 files into one entry and compress them on-the-fly. - zip_entry_fwrite(zip, "foo-2.1.txt"); - zip_entry_fwrite(zip, "foo-2.2.txt"); - zip_entry_fwrite(zip, "foo-2.3.txt"); - } - zip_entry_close(zip); + const char *buf = "Some data here...\0"; + zip_entry_write(zip, buf, strlen(buf)); } - zip_close(zip); + zip_entry_close(zip); + + zip_entry_open(zip, "foo-2.txt"); + { + // merge 3 files into one entry and compress them on-the-fly. + zip_entry_fwrite(zip, "foo-2.1.txt"); + zip_entry_fwrite(zip, "foo-2.2.txt"); + zip_entry_fwrite(zip, "foo-2.3.txt"); + } + zip_entry_close(zip); +} +zip_close(zip); ``` * Append to the existing zip archive. ```c - struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'a'); +struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'a'); +{ + zip_entry_open(zip, "foo-3.txt"); { - zip_entry_open(zip, "foo-3.txt"); - { - char *buf = "Append some data here..."; - zip_entry_write(zip, buf, strlen(buf)); - } - zip_entry_close(zip); + const char *buf = "Append some data here...\0"; + zip_entry_write(zip, buf, strlen(buf)); } - zip_close(zip); + zip_entry_close(zip); +} +zip_close(zip); ``` * Extract a zip archive into a folder. ```c - int on_extract_entry(const char *filename, void *arg) { - static int i = 0; - int n = *(int *)arg; - printf("Extracted: %s (%d of %d)\n", filename, ++i, n); +int on_extract_entry(const char *filename, void *arg) { + static int i = 0; + int n = *(int *)arg; + printf("Extracted: %s (%d of %d)\n", filename, ++i, n); - return 0; - } + return 0; +} - int arg = 2; - zip_extract("foo.zip", "/tmp", on_extract_entry, &arg); +int arg = 2; +zip_extract("foo.zip", "/tmp", on_extract_entry, &arg); ``` -* Extract a zip entry into memory. +* Extract a zip entry into memory. ```c - void *buf = NULL; - size_t bufsize; +void *buf = NULL; +size_t bufsize; - struct zip_t *zip = zip_open("foo.zip", 0, 'r'); +struct zip_t *zip = zip_open("foo.zip", 0, 'r'); +{ + zip_entry_open(zip, "foo-1.txt"); { - zip_entry_open(zip, "foo-1.txt"); - { - zip_entry_read(zip, &buf, &bufsize); - } - zip_entry_close(zip); + zip_entry_read(zip, &buf, &bufsize); } - zip_close(zip); + zip_entry_close(zip); +} +zip_close(zip); - free(buf); +free(buf); ``` -* Extract a zip entry into memory using callback. +* Extract a zip entry into memory (no internal allocation). ```c - struct buffer_t { - char *data; - size_t size; - }; +unsigned char *buf; +size_t bufsize; - static size_t on_extract(void *arg, unsigned long long offset, const void *data, size_t size) { - struct buffer_t *buf = (struct buffer_t *)arg; - buf->data = realloc(buf->data, buf->size + size + 1); - assert(NULL != buf->data); - - memcpy(&(buf->data[buf->size]), data, size); - buf->size += size; - buf->data[buf->size] = 0; - - return size; - } - - struct buffer_t buf = {0}; - struct zip_t *zip = zip_open("foo.zip", 0, 'r'); +struct zip_t *zip = zip_open("foo.zip", 0, 'r'); +{ + zip_entry_open(zip, "foo-1.txt"); { - zip_entry_open(zip, "foo-1.txt"); - { - zip_entry_extract(zip, on_extract, &buf); - } - zip_entry_close(zip); - } - zip_close(zip); + bufsize = zip_entry_size(zip); + buf = calloc(sizeof(unsigned char), bufsize); - free(buf.data); + zip_entry_noallocread(zip, (void *)buf, bufsize); + } + zip_entry_close(zip); +} +zip_close(zip); + +free(buf); ``` - -* Extract a zip entry into a file. +* Extract a zip entry into memory using callback. ```c - struct zip_t *zip = zip_open("foo.zip", 0, 'r'); +struct buffer_t { + char *data; + size_t size; +}; + +static size_t on_extract(void *arg, unsigned long long offset, const void *data, size_t size) { + struct buffer_t *buf = (struct buffer_t *)arg; + buf->data = realloc(buf->data, buf->size + size + 1); + assert(NULL != buf->data); + + memcpy(&(buf->data[buf->size]), data, size); + buf->size += size; + buf->data[buf->size] = 0; + + return size; +} + +struct buffer_t buf = {0}; +struct zip_t *zip = zip_open("foo.zip", 0, 'r'); +{ + zip_entry_open(zip, "foo-1.txt"); { - zip_entry_open(zip, "foo-2.txt"); - { - zip_entry_fread(zip, "foo-2.txt"); - } - zip_entry_close(zip); + zip_entry_extract(zip, on_extract, &buf); } - zip_close(zip); + zip_entry_close(zip); +} +zip_close(zip); + +free(buf.data); +``` + + +* Extract a zip entry into a file. +```c +struct zip_t *zip = zip_open("foo.zip", 0, 'r'); +{ + zip_entry_open(zip, "foo-2.txt"); + { + zip_entry_fread(zip, "foo-2.txt"); + } + zip_entry_close(zip); +} +zip_close(zip); +``` + +* List of all zip entries +```c +struct zip_t *zip = zip_open("foo.zip", 0, 'r'); +int i, n = zip_total_entries(zip); +for (i = 0; i < n; ++i) { + zip_entry_openbyindex(zip, i); + { + const char *name = zip_entry_name(zip); + int isdir = zip_entry_isdir(zip); + unsigned long long size = zip_entry_size(zip); + unsigned int crc32 = zip_entry_crc32(zip); + } + zip_entry_close(zip); +} +zip_close(zip); +``` + +## Bindings +Compile zip library as a dynamic library. +```shell +$ mkdir build +$ cd build +$ cmake -DBUILD_SHARED_LIBS=true .. +$ make +``` + +### Go (cgo) +```go +package main + +/* +#cgo CFLAGS: -I../src +#cgo LDFLAGS: -L. -lzip +#include +*/ +import "C" +import "unsafe" + +func main() { + path := C.CString("/tmp/go.zip") + zip := C.zip_open(path, 6, 'w') + + entryname := C.CString("test") + C.zip_entry_open(zip, entryname) + + content := "test content" + buf := unsafe.Pointer(C.CString(content)) + bufsize := C.size_t(len(content)) + C.zip_entry_write(zip, buf, bufsize) + + C.zip_entry_close(zip) + + C.zip_close(zip) +} +``` + +### Ruby (ffi) +Install _ffi_ gem. +```shell +$ gem install ffi +``` + +Bind in your module. +```ruby +require 'ffi' + +module Zip + extend FFI::Library + ffi_lib "./libzip.#{::FFI::Platform::LIBSUFFIX}" + + attach_function :zip_open, [:string, :int, :char], :pointer + attach_function :zip_close, [:pointer], :void + + attach_function :zip_entry_open, [:pointer, :string], :int + attach_function :zip_entry_close, [:pointer], :void + attach_function :zip_entry_write, [:pointer, :string, :int], :int +end + +ptr = Zip.zip_open("/tmp/ruby.zip", 6, "w".bytes()[0]) + +status = Zip.zip_entry_open(ptr, "test") + +content = "test content" +status = Zip.zip_entry_write(ptr, content, content.size()) + +Zip.zip_entry_close(ptr) +Zip.zip_close(ptr) +``` + +### Python (cffi) +Install _cffi_ package +```shell +$ pip install cffi +``` + +Bind in your package. +```python +import ctypes.util +from cffi import FFI + +ffi = FFI() +ffi.cdef(""" + struct zip_t *zip_open(const char *zipname, int level, char mode); + void zip_close(struct zip_t *zip); + + int zip_entry_open(struct zip_t *zip, const char *entryname); + int zip_entry_close(struct zip_t *zip); + int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize); +""") + +Zip = ffi.dlopen(ctypes.util.find_library("zip")) + +ptr = Zip.zip_open("/tmp/python.zip", 6, 'w') + +status = Zip.zip_entry_open(ptr, "test") + +content = "test content" +status = Zip.zip_entry_write(ptr, content, len(content)) + +Zip.zip_entry_close(ptr) +Zip.zip_close(ptr) +``` + +### Ring +The language comes with RingZip based on this library +```ring +load "ziplib.ring" + +new Zip { + setFileName("myfile.zip") + open("w") + newEntry() { + open("test.c") + writefile("test.c") + close() + } + close() +} +``` + +# Contribution Rules/Coding Standards +No need to throw away your coding style, just do your best to follow default clang-format style. +Apply `clang-format` to the source files before commit: +```sh +for file in $(git ls-files | \grep -E '\.(c|h)$' | \grep -v -- '#') +do + clang-format -i $file +done ``` diff --git a/contrib/zip/appveyor.yml b/contrib/zip/appveyor.yml index 297cad8b0..0be6373ca 100644 --- a/contrib/zip/appveyor.yml +++ b/contrib/zip/appveyor.yml @@ -1,4 +1,4 @@ -version: 1.0.{build} +version: zip-0.1.9.{build} build_script: - cmd: >- cd c:\projects\zip diff --git a/contrib/zip/cmake/asan-wrapper b/contrib/zip/cmake/asan-wrapper new file mode 100755 index 000000000..5d5410337 --- /dev/null +++ b/contrib/zip/cmake/asan-wrapper @@ -0,0 +1,55 @@ +#!/bin/sh + +# The MIT License (MIT) +# +# Copyright (c) +# 2013 Matthew Arsenault +# 2015-2016 RWTH Aachen University, Federal Republic of Germany +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +# This script is a wrapper for AddressSanitizer. In some special cases you need +# to preload AddressSanitizer to avoid error messages - e.g. if you're +# preloading another library to your application. At the moment this script will +# only do something, if we're running on a Linux platform. OSX might not be +# affected. + + +# Exit immediately, if platform is not Linux. +if [ "$(uname)" != "Linux" ] +then + exec $@ +fi + + +# Get the used libasan of the application ($1). If a libasan was found, it will +# be prepended to LD_PRELOAD. +libasan=$(ldd $1 | grep libasan | sed "s/^[[:space:]]//" | cut -d' ' -f1) +if [ -n "$libasan" ] +then + if [ -n "$LD_PRELOAD" ] + then + export LD_PRELOAD="$libasan:$LD_PRELOAD" + else + export LD_PRELOAD="$libasan" + fi +fi + +# Execute the application. +exec $@ diff --git a/contrib/zip/cmake/cmake_uninstall.cmake.in b/contrib/zip/cmake/cmake_uninstall.cmake.in new file mode 100644 index 000000000..86ea34d8f --- /dev/null +++ b/contrib/zip/cmake/cmake_uninstall.cmake.in @@ -0,0 +1,23 @@ +# copied from https://gitlab.kitware.com/cmake/community/wikis/FAQ#can-i-do-make-uninstall-with-cmake +if(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") + message(FATAL_ERROR "Cannot find install manifest: @CMAKE_BINARY_DIR@/install_manifest.txt") +endif(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt") + +file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files) +string(REGEX REPLACE "\n" ";" files "${files}") +foreach(file ${files}) + message(STATUS "Uninstalling $ENV{DESTDIR}${file}") + if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + exec_program( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + if(NOT "${rm_retval}" STREQUAL 0) + message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") + endif(NOT "${rm_retval}" STREQUAL 0) + else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") + message(STATUS "File $ENV{DESTDIR}${file} does not exist.") + endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}") +endforeach(file) + diff --git a/contrib/zip/src/miniz.h b/contrib/zip/src/miniz.h index 935f7de2e..2c27a94d8 100644 --- a/contrib/zip/src/miniz.h +++ b/contrib/zip/src/miniz.h @@ -1,160 +1,221 @@ /* - miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing - See "unlicense" statement at the end of this file. - Rich Geldreich , last updated Oct. 13, 2013 - Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt + miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP + reading/writing/appending, PNG writing See "unlicense" statement at the end + of this file. Rich Geldreich , last updated Oct. 13, + 2013 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: + http://www.ietf.org/rfc/rfc1951.txt - Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define - MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). + Most API's defined in miniz.c are optional. For example, to disable the + archive related functions just define MINIZ_NO_ARCHIVE_APIS, or to get rid of + all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). * Change History - 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major release with Zip64 support (almost there!): - - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug (thanks kahmyong.moon@hp.com) which could cause locate files to not find files. This bug - would only have occured in earlier versions if you explicitly used this flag, OR if you used mz_zip_extract_archive_file_to_heap() or mz_zip_add_mem_to_archive_file_in_place() - (which used this flag). If you can't switch to v1.15 but want to fix this bug, just remove the uses of this flag from both helper funcs (and of course don't use the flag). - - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when pUser_read_buf is not NULL and compressed size is > uncompressed size - - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract compressed data from directory entries, to account for weird zipfiles which contain zero-size compressed data on dir entries. - Hopefully this fix won't cause any issues on weird zip archives, because it assumes the low 16-bits of zip external attributes are DOS attributes (which I believe they always are in practice). - - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the internal attributes, just the filename and external attributes + 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major + release with Zip64 support (almost there!): + - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug + (thanks kahmyong.moon@hp.com) which could cause locate files to not find + files. This bug would only have occured in earlier versions if you explicitly + used this flag, OR if you used mz_zip_extract_archive_file_to_heap() or + mz_zip_add_mem_to_archive_file_in_place() (which used this flag). If you + can't switch to v1.15 but want to fix this bug, just remove the uses of this + flag from both helper funcs (and of course don't use the flag). + - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when + pUser_read_buf is not NULL and compressed size is > uncompressed size + - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract + compressed data from directory entries, to account for weird zipfiles which + contain zero-size compressed data on dir entries. Hopefully this fix won't + cause any issues on weird zip archives, because it assumes the low 16-bits of + zip external attributes are DOS attributes (which I believe they always are + in practice). + - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the + internal attributes, just the filename and external attributes - mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed - - Added cmake support for Linux builds which builds all the examples, tested with clang v3.3 and gcc v4.6. + - Added cmake support for Linux builds which builds all the examples, + tested with clang v3.3 and gcc v4.6. - Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti - Merged MZ_FORCEINLINE fix from hdeanclark - Fix include before config #ifdef, thanks emil.brink - - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping (super useful for OpenGL apps), and explicit control over the compression level (so you can - set it to 1 for real-time compression). + - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping + (super useful for OpenGL apps), and explicit control over the compression + level (so you can set it to 1 for real-time compression). - Merged in some compiler fixes from paulharris's github repro. - - Retested this build under Windows (VS 2010, including static analysis), tcc 0.9.26, gcc v4.6 and clang v3.3. - - Added example6.c, which dumps an image of the mandelbrot set to a PNG file. - - Modified example2 to help test the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more. - - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix possible src file fclose() leak if alignment bytes+local header file write faiiled -  - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader(): Was pushing the wrong central dir header offset, appears harmless in this release, but it became a problem in the zip64 branch - 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, #include (thanks fermtect). - 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit. - - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and re-ran a randomized regression test on ~500k files. + - Retested this build under Windows (VS 2010, including static analysis), + tcc 0.9.26, gcc v4.6 and clang v3.3. + - Added example6.c, which dumps an image of the mandelbrot set to a PNG + file. + - Modified example2 to help test the + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more. + - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix + possible src file fclose() leak if alignment bytes+local header file write + faiiled + - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader(): Was pushing the + wrong central dir header offset, appears harmless in this release, but it + became a problem in the zip64 branch 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 + compiler fixes: added MZ_FORCEINLINE, #include (thanks fermtect). + 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix + mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit. + - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and + re-ran a randomized regression test on ~500k files. - Eliminated a bunch of warnings when compiling with GCC 32-bit/64. - - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze (static analysis) option and fixed all warnings (except for the silly - "Use of the comma-operator in a tested expression.." analysis warning, which I purposely use to work around a MSVC compiler warning). - - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and tested Linux executables. The codeblocks workspace is compatible with Linux+Win32/x64. - - Added miniz_tester solution/project, which is a useful little app derived from LZHAM's tester app that I use as part of the regression test. - - Ran miniz.c and tinfl.c through another series of regression testing on ~500,000 files and archives. - - Modified example5.c so it purposely disables a bunch of high-level functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the MINIZ_NO_STDIO bug report.) - - Fix ftell() usage in examples so they exit with an error on files which are too large (a limitation of the examples, not miniz itself). - 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple minor level_and_flags issues in the archive API's. - level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson for the feedback/bug report. - 5/28/11 v1.11 - Added statement from unlicense.org - 5/27/11 v1.10 - Substantial compressor optimizations: - - Level 1 is now ~4x faster than before. The L1 compressor's throughput now varies between 70-110MB/sec. on a - - Core i7 (actual throughput varies depending on the type of data, and x64 vs. x86). - - Improved baseline L2-L9 compression perf. Also, greatly improved compression perf. issues on some file types. - - Refactored the compression code for better readability and maintainability. - - Added level 10 compression level (L10 has slightly better ratio than level 9, but could have a potentially large - drop in throughput on some files). - 5/15/11 v1.09 - Initial stable release. + - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze + (static analysis) option and fixed all warnings (except for the silly "Use of + the comma-operator in a tested expression.." analysis warning, which I + purposely use to work around a MSVC compiler warning). + - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and + tested Linux executables. The codeblocks workspace is compatible with + Linux+Win32/x64. + - Added miniz_tester solution/project, which is a useful little app + derived from LZHAM's tester app that I use as part of the regression test. + - Ran miniz.c and tinfl.c through another series of regression testing on + ~500,000 files and archives. + - Modified example5.c so it purposely disables a bunch of high-level + functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the + MINIZ_NO_STDIO bug report.) + - Fix ftell() usage in examples so they exit with an error on files which + are too large (a limitation of the examples, not miniz itself). 4/12/12 v1.12 + - More comments, added low-level example5.c, fixed a couple minor + level_and_flags issues in the archive API's. level_and_flags can now be set + to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson + for the feedback/bug report. 5/28/11 v1.11 - Added statement from + unlicense.org 5/27/11 v1.10 - Substantial compressor optimizations: + - Level 1 is now ~4x faster than before. The L1 compressor's throughput + now varies between 70-110MB/sec. on a + - Core i7 (actual throughput varies depending on the type of data, and x64 + vs. x86). + - Improved baseline L2-L9 compression perf. Also, greatly improved + compression perf. issues on some file types. + - Refactored the compression code for better readability and + maintainability. + - Added level 10 compression level (L10 has slightly better ratio than + level 9, but could have a potentially large drop in throughput on some + files). 5/15/11 v1.09 - Initial stable release. * Low-level Deflate/Inflate implementation notes: - Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or - greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses - approximately as well as zlib. + Compression: Use the "tdefl" API's. The compressor supports raw, static, + and dynamic blocks, lazy or greedy parsing, match length filtering, RLE-only, + and Huffman-only streams. It performs and compresses approximately as well as + zlib. - Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function - coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory - block large enough to hold the entire file. + Decompression: Use the "tinfl" API's. The entire decompressor is + implemented as a single function coroutine: see tinfl_decompress(). It + supports decompression into a 32KB (or larger power of 2) wrapping buffer, or + into a memory block large enough to hold the entire file. - The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. + The low-level tdefl/tinfl API's do not make any use of dynamic memory + allocation. * zlib-style API notes: - miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in - zlib replacement in many apps: + miniz.c implements a fairly large subset of zlib. There's enough + functionality present for it to be a drop-in zlib replacement in many apps: The z_stream struct, optional memory allocation callbacks deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound inflateInit/inflateInit2/inflate/inflateEnd compress, compress2, compressBound, uncompress - CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. - Supports raw deflate streams or standard zlib streams with adler-32 checking. + CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly + routines. Supports raw deflate streams or standard zlib streams with adler-32 + checking. Limitations: - The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. - I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but - there are no guarantees that miniz.c pulls this off perfectly. + The callback API's are not implemented yet. No support for gzip headers or + zlib static dictionaries. I've tried to closely emulate zlib's various + flavors of stream flushing and return status codes, but there are no + guarantees that miniz.c pulls this off perfectly. - * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by - Alex Evans. Supports 1-4 bytes/pixel images. + * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, + originally written by Alex Evans. Supports 1-4 bytes/pixel images. * ZIP archive API notes: - The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to - get the job done with minimal fuss. There are simple API's to retrieve file information, read files from - existing archives, create new archives, append new files to existing archives, or clone archive data from - one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), - or you can specify custom file read/write callbacks. + The ZIP archive API's where designed with simplicity and efficiency in + mind, with just enough abstraction to get the job done with minimal fuss. + There are simple API's to retrieve file information, read files from existing + archives, create new archives, append new files to existing archives, or + clone archive data from one archive to another. It supports archives located + in memory or the heap, on disk (using stdio.h), or you can specify custom + file read/write callbacks. - - Archive reading: Just call this function to read a single file from a disk archive: + - Archive reading: Just call this function to read a single file from a + disk archive: - void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, - size_t *pSize, mz_uint zip_flags); + void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const + char *pArchive_name, size_t *pSize, mz_uint zip_flags); - For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central - directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. + For more complex cases, use the "mz_zip_reader" functions. Upon opening an + archive, the entire central directory is located and read as-is into memory, + and subsequent file access only occurs when reading individual files. - - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: + - Archives file scanning: The simple way is to use this function to scan a + loaded archive for a specific file: - int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); + int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, + const char *pComment, mz_uint flags); - The locate operation can optionally check file comments too, which (as one example) can be used to identify - multiple versions of the same file in an archive. This function uses a simple linear search through the central + The locate operation can optionally check file comments too, which (as one + example) can be used to identify multiple versions of the same file in an + archive. This function uses a simple linear search through the central directory, so it's not very fast. - Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and - retrieve detailed info on each file by calling mz_zip_reader_file_stat(). + Alternately, you can iterate through all the files in an archive (using + mz_zip_reader_get_num_files()) and retrieve detailed info on each file by + calling mz_zip_reader_file_stat(). - - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data - to disk and builds an exact image of the central directory in memory. The central directory image is written - all at once at the end of the archive file when the archive is finalized. + - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer + immediately writes compressed file data to disk and builds an exact image of + the central directory in memory. The central directory image is written all + at once at the end of the archive file when the archive is finalized. - The archive writer can optionally align each file's local header and file data to any power of 2 alignment, - which can be useful when the archive will be read from optical media. Also, the writer supports placing - arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still - readable by any ZIP tool. + The archive writer can optionally align each file's local header and file + data to any power of 2 alignment, which can be useful when the archive will + be read from optical media. Also, the writer supports placing arbitrary data + blobs at the very beginning of ZIP archives. Archives written using either + feature are still readable by any ZIP tool. - - Archive appending: The simple way to add a single file to an archive is to call this function: + - Archive appending: The simple way to add a single file to an archive is + to call this function: - mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, - const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); + mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, + const char *pArchive_name, const void *pBuf, size_t buf_size, const void + *pComment, mz_uint16 comment_size, mz_uint level_and_flags); - The archive will be created if it doesn't already exist, otherwise it'll be appended to. - Note the appending is done in-place and is not an atomic operation, so if something goes wrong - during the operation it's possible the archive could be left without a central directory (although the local - file headers and file data will be fine, so the archive will be recoverable). + The archive will be created if it doesn't already exist, otherwise it'll be + appended to. Note the appending is done in-place and is not an atomic + operation, so if something goes wrong during the operation it's possible the + archive could be left without a central directory (although the local file + headers and file data will be fine, so the archive will be recoverable). For more complex archive modification scenarios: - 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to - preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the - compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and - you're done. This is safe but requires a bunch of temporary disk space or heap memory. + 1. The safest way is to use a mz_zip_reader to read the existing archive, + cloning only those bits you want to preserve into a new archive using using + the mz_zip_writer_add_from_zip_reader() function (which compiles the + compressed file data as-is). When you're done, delete the old archive and + rename the newly written archive, and you're done. This is safe but requires + a bunch of temporary disk space or heap memory. - 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), - append new files as needed, then finalize the archive which will write an updated central directory to the - original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a - possibility that the archive's central directory could be lost with this method if anything goes wrong, though. + 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using + mz_zip_writer_init_from_reader(), append new files as needed, then finalize + the archive which will write an updated central directory to the original + archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() + does.) There's a possibility that the archive's central directory could be + lost with this method if anything goes wrong, though. - ZIP archive support limitations: - No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. - Requires streams capable of seeking. + No zip64 or spanning support. Extraction functions can only handle + unencrypted, stored or deflated files. Requires streams capable of seeking. - * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the - below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. + * This is a header file library, like stb_image.c. To get only a header file, + either cut and paste the below header, or create miniz.h, #define + MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. - * Important: For best perf. be sure to customize the below macros for your target platform: - #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 - #define MINIZ_LITTLE_ENDIAN 1 - #define MINIZ_HAS_64BIT_REGISTERS 1 + * Important: For best perf. be sure to customize the below macros for your + target platform: #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 #define + MINIZ_LITTLE_ENDIAN 1 #define MINIZ_HAS_64BIT_REGISTERS 1 - * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz - uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files - (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). + * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before + including miniz.c to ensure miniz uses the 64-bit variants: fopen64(), + stat64(), etc. Otherwise you won't be able to process large files (i.e. + 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). */ #ifndef MINIZ_HEADER_INCLUDED @@ -163,60 +224,80 @@ #include // Defines to completely disable specific portions of miniz.c: -// If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. +// If all macros here are defined the only functionality remaining will be +// CRC-32, adler-32, tinfl, and tdefl. -// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. +// Define MINIZ_NO_STDIO to disable all usage and any functions which rely on +// stdio for file I/O. //#define MINIZ_NO_STDIO -// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or -// get/set file times, and the C run-time funcs that get/set times won't be called. -// The current downside is the times written to your archives will be from 1979. +// If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able +// to get the current time, or get/set file times, and the C run-time funcs that +// get/set times won't be called. The current downside is the times written to +// your archives will be from 1979. //#define MINIZ_NO_TIME // Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. //#define MINIZ_NO_ARCHIVE_APIS -// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive API's. +// Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive +// API's. //#define MINIZ_NO_ARCHIVE_WRITING_APIS -// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. +// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression +// API's. //#define MINIZ_NO_ZLIB_APIS -// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. +// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent +// conflicts against stock zlib. //#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES // Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. -// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc -// callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user -// functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. +// Note if MINIZ_NO_MALLOC is defined then the user must always provide custom +// user alloc/free/realloc callbacks to the zlib and archive API's, and a few +// stand-alone helper API's which don't provide custom user functions (such as +// tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. //#define MINIZ_NO_MALLOC #if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) - // TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux - #define MINIZ_NO_TIME +// TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc +// on Linux +#define MINIZ_NO_TIME #endif #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) - #include +#include #endif -#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) +#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || \ + defined(__i386) || defined(__i486__) || defined(__i486) || \ + defined(i386) || defined(__ia64__) || defined(__x86_64__) // MINIZ_X86_OR_X64_CPU is only used to help set the below macros. #define MINIZ_X86_OR_X64_CPU 1 #endif -#if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU // Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. #define MINIZ_LITTLE_ENDIAN 1 #endif +/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES only if not set */ +#if !defined(MINIZ_USE_UNALIGNED_LOADS_AND_STORES) #if MINIZ_X86_OR_X64_CPU -// Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. +/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */ +#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 +#define MINIZ_UNALIGNED_USE_MEMCPY +#else #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 #endif +#endif -#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) -// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). +#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || \ + defined(_LP64) || defined(__LP64__) || defined(__ia64__) || \ + defined(__x86_64__) +// Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are +// reasonably fast (and don't involve compiler generated calls to helper +// functions). #define MINIZ_HAS_64BIT_REGISTERS 1 #endif @@ -225,6 +306,18 @@ #define fseeko64 fseeko #define fopen64 fopen #define freopen64 freopen + +// Darwin OSX +#define MZ_PLATFORM 19 +#endif + +#ifndef MZ_PLATFORM +#if defined(_WIN64) || defined(_WIN32) || defined(__WIN32__) +#define MZ_PLATFORM 0 +#else +// UNIX +#define MZ_PLATFORM 3 +#endif #endif #ifdef __cplusplus @@ -233,22 +326,33 @@ extern "C" { // ------------------- zlib-style API Definitions. -// For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! +// For more compatibility with zlib, miniz.c uses unsigned long for some +// parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! typedef unsigned long mz_ulong; -// mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. +// mz_free() internally uses the MZ_FREE() macro (which by default calls free() +// unless you've modified the MZ_MALLOC macro) to release a block allocated from +// the heap. void mz_free(void *p); #define MZ_ADLER32_INIT (1) -// mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. +// mz_adler32() returns the initial adler-32 value to use when called with +// ptr==NULL. mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); #define MZ_CRC32_INIT (0) -// mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. +// mz_crc32() returns the initial CRC-32 value to use when called with +// ptr==NULL. mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); // Compression strategies. -enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; +enum { + MZ_DEFAULT_STRATEGY = 0, + MZ_FILTERED = 1, + MZ_HUFFMAN_ONLY = 2, + MZ_RLE = 3, + MZ_FIXED = 4 +}; // Method #define MZ_DEFLATED 8 @@ -256,26 +360,56 @@ enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3 #ifndef MINIZ_NO_ZLIB_APIS // Heap allocation callbacks. -// Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. +// Note that mz_alloc_func parameter types purpsosely differ from zlib's: +// items/size is size_t, not unsigned long. typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); typedef void (*mz_free_func)(void *opaque, void *address); -typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); +typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, + size_t size); -#define MZ_VERSION "9.1.15" -#define MZ_VERNUM 0x91F0 -#define MZ_VER_MAJOR 9 -#define MZ_VER_MINOR 1 -#define MZ_VER_REVISION 15 -#define MZ_VER_SUBREVISION 0 +#define MZ_VERSION "9.1.15" +#define MZ_VERNUM 0x91F0 +#define MZ_VER_MAJOR 9 +#define MZ_VER_MINOR 1 +#define MZ_VER_REVISION 15 +#define MZ_VER_SUBREVISION 0 -// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). -enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; +// Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The +// other values are for advanced use (refer to the zlib docs). +enum { + MZ_NO_FLUSH = 0, + MZ_PARTIAL_FLUSH = 1, + MZ_SYNC_FLUSH = 2, + MZ_FULL_FLUSH = 3, + MZ_FINISH = 4, + MZ_BLOCK = 5 +}; // Return status codes. MZ_PARAM_ERROR is non-standard. -enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; +enum { + MZ_OK = 0, + MZ_STREAM_END = 1, + MZ_NEED_DICT = 2, + MZ_ERRNO = -1, + MZ_STREAM_ERROR = -2, + MZ_DATA_ERROR = -3, + MZ_MEM_ERROR = -4, + MZ_BUF_ERROR = -5, + MZ_VERSION_ERROR = -6, + MZ_PARAM_ERROR = -10000 +}; -// Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. -enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 }; +// Compression levels: 0-9 are the standard zlib-style levels, 10 is best +// possible compression (not zlib compatible, and may be very slow), +// MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. +enum { + MZ_NO_COMPRESSION = 0, + MZ_BEST_SPEED = 1, + MZ_BEST_COMPRESSION = 9, + MZ_UBER_COMPRESSION = 10, + MZ_DEFAULT_LEVEL = 6, + MZ_DEFAULT_COMPRESSION = -1 +}; // Window bits #define MZ_DEFAULT_WINDOW_BITS 15 @@ -283,26 +417,26 @@ enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBE struct mz_internal_state; // Compression/decompression stream struct. -typedef struct mz_stream_s -{ - const unsigned char *next_in; // pointer to next byte to read - unsigned int avail_in; // number of bytes available at next_in - mz_ulong total_in; // total number of bytes consumed so far +typedef struct mz_stream_s { + const unsigned char *next_in; // pointer to next byte to read + unsigned int avail_in; // number of bytes available at next_in + mz_ulong total_in; // total number of bytes consumed so far - unsigned char *next_out; // pointer to next byte to write - unsigned int avail_out; // number of bytes that can be written to next_out - mz_ulong total_out; // total number of bytes produced so far + unsigned char *next_out; // pointer to next byte to write + unsigned int avail_out; // number of bytes that can be written to next_out + mz_ulong total_out; // total number of bytes produced so far - char *msg; // error msg (unused) - struct mz_internal_state *state; // internal state, allocated by zalloc/zfree + char *msg; // error msg (unused) + struct mz_internal_state *state; // internal state, allocated by zalloc/zfree - mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc) - mz_free_func zfree; // optional heap free function (defaults to free) - void *opaque; // heap alloc function user pointer + mz_alloc_func + zalloc; // optional heap allocation function (defaults to malloc) + mz_free_func zfree; // optional heap free function (defaults to free) + void *opaque; // heap alloc function user pointer - int data_type; // data_type (unused) - mz_ulong adler; // adler32 of the source or uncompressed data - mz_ulong reserved; // not used + int data_type; // data_type (unused) + mz_ulong adler; // adler32 of the source or uncompressed data + mz_ulong reserved; // not used } mz_stream; typedef mz_stream *mz_streamp; @@ -314,8 +448,10 @@ const char *mz_version(void); // Parameters: // pStream must point to an initialized mz_stream struct. // level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. -// level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. -// (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) +// level 1 enables a specially optimized compression function that's been +// optimized purely for performance, not ratio. (This special func. is +// currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and +// MINIZ_LITTLE_ENDIAN are defined.) // Return values: // MZ_OK on success. // MZ_STREAM_ERROR if the stream is bogus. @@ -326,23 +462,32 @@ int mz_deflateInit(mz_streamp pStream, int level); // mz_deflateInit2() is like mz_deflate(), except with more control: // Additional parameters: // method must be MZ_DEFLATED -// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) -// mem_level must be between [1, 9] (it's checked but ignored by miniz.c) -int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); +// window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with +// zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no +// header or footer) mem_level must be between [1, 9] (it's checked but +// ignored by miniz.c) +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, + int mem_level, int strategy); -// Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). +// Quickly resets a compressor without having to reallocate anything. Same as +// calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). int mz_deflateReset(mz_streamp pStream); -// mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. -// Parameters: -// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. -// flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. +// mz_deflate() compresses the input to output, consuming as much of the input +// and producing as much output as possible. Parameters: +// pStream is the stream to read from and write to. You must initialize/update +// the next_in, avail_in, next_out, and avail_out members. flush may be +// MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. // Return values: -// MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). -// MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. +// MZ_OK on success (when flushing, or if more input is needed but not +// available, and/or there's more output to be written but the output buffer +// is full). MZ_STREAM_END if all input has been consumed and all output bytes +// have been written. Don't call mz_deflate() on the stream anymore. // MZ_STREAM_ERROR if the stream is bogus. // MZ_PARAM_ERROR if one of the parameters is invalid. -// MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) +// MZ_BUF_ERROR if no forward progress is possible because the input and/or +// output buffers are empty. (Fill up the input buffer or free up some output +// space and try again.) int mz_deflate(mz_streamp pStream, int flush); // mz_deflateEnd() deinitializes a compressor: @@ -351,123 +496,145 @@ int mz_deflate(mz_streamp pStream, int flush); // MZ_STREAM_ERROR if the stream is bogus. int mz_deflateEnd(mz_streamp pStream); -// mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. +// mz_deflateBound() returns a (very) conservative upper bound on the amount of +// data that could be generated by deflate(), assuming flush is set to only +// MZ_NO_FLUSH or MZ_FINISH. mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); // Single-call compression functions mz_compress() and mz_compress2(): -// Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. -int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); -int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); +// Returns MZ_OK on success, or one of the error codes from mz_deflate() on +// failure. +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len); +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len, int level); -// mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). +// mz_compressBound() returns a (very) conservative upper bound on the amount of +// data that could be generated by calling mz_compress(). mz_ulong mz_compressBound(mz_ulong source_len); // Initializes a decompressor. int mz_inflateInit(mz_streamp pStream); -// mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: -// window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). +// mz_inflateInit2() is like mz_inflateInit() with an additional option that +// controls the window size and whether or not the stream has been wrapped with +// a zlib header/footer: window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse +// zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). int mz_inflateInit2(mz_streamp pStream, int window_bits); -// Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. -// Parameters: -// pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. -// flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. -// On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). -// MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. +// Decompresses the input stream to the output, consuming only as much of the +// input as needed, and writing as much to the output as possible. Parameters: +// pStream is the stream to read from and write to. You must initialize/update +// the next_in, avail_in, next_out, and avail_out members. flush may be +// MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. On the first call, if flush is +// MZ_FINISH it's assumed the input and output buffers are both sized large +// enough to decompress the entire stream in a single call (this is slightly +// faster). MZ_FINISH implies that there are no more source bytes available +// beside what's already in the input buffer, and that the output buffer is +// large enough to hold the rest of the decompressed data. // Return values: -// MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. -// MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. -// MZ_STREAM_ERROR if the stream is bogus. +// MZ_OK on success. Either more input is needed but not available, and/or +// there's more output to be written but the output buffer is full. +// MZ_STREAM_END if all needed input has been consumed and all output bytes +// have been written. For zlib streams, the adler-32 of the decompressed data +// has also been verified. MZ_STREAM_ERROR if the stream is bogus. // MZ_DATA_ERROR if the deflate stream is invalid. // MZ_PARAM_ERROR if one of the parameters is invalid. -// MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again -// with more input data, or with more room in the output buffer (except when using single call decompression, described above). +// MZ_BUF_ERROR if no forward progress is possible because the input buffer is +// empty but the inflater needs more input to continue, or if the output +// buffer is not large enough. Call mz_inflate() again with more input data, +// or with more room in the output buffer (except when using single call +// decompression, described above). int mz_inflate(mz_streamp pStream, int flush); // Deinitializes a decompressor. int mz_inflateEnd(mz_streamp pStream); // Single-call decompression. -// Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. -int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); +// Returns MZ_OK on success, or one of the error codes from mz_inflate() on +// failure. +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len); -// Returns a string description of the specified error code, or NULL if the error code is invalid. +// Returns a string description of the specified error code, or NULL if the +// error code is invalid. const char *mz_error(int err); -// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. -// Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. +// Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used +// as a drop-in replacement for the subset of zlib that miniz.c supports. Define +// MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib +// in the same project. #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES - typedef unsigned char Byte; - typedef unsigned int uInt; - typedef mz_ulong uLong; - typedef Byte Bytef; - typedef uInt uIntf; - typedef char charf; - typedef int intf; - typedef void *voidpf; - typedef uLong uLongf; - typedef void *voidp; - typedef void *const voidpc; - #define Z_NULL 0 - #define Z_NO_FLUSH MZ_NO_FLUSH - #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH - #define Z_SYNC_FLUSH MZ_SYNC_FLUSH - #define Z_FULL_FLUSH MZ_FULL_FLUSH - #define Z_FINISH MZ_FINISH - #define Z_BLOCK MZ_BLOCK - #define Z_OK MZ_OK - #define Z_STREAM_END MZ_STREAM_END - #define Z_NEED_DICT MZ_NEED_DICT - #define Z_ERRNO MZ_ERRNO - #define Z_STREAM_ERROR MZ_STREAM_ERROR - #define Z_DATA_ERROR MZ_DATA_ERROR - #define Z_MEM_ERROR MZ_MEM_ERROR - #define Z_BUF_ERROR MZ_BUF_ERROR - #define Z_VERSION_ERROR MZ_VERSION_ERROR - #define Z_PARAM_ERROR MZ_PARAM_ERROR - #define Z_NO_COMPRESSION MZ_NO_COMPRESSION - #define Z_BEST_SPEED MZ_BEST_SPEED - #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION - #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION - #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY - #define Z_FILTERED MZ_FILTERED - #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY - #define Z_RLE MZ_RLE - #define Z_FIXED MZ_FIXED - #define Z_DEFLATED MZ_DEFLATED - #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS - #define alloc_func mz_alloc_func - #define free_func mz_free_func - #define internal_state mz_internal_state - #define z_stream mz_stream - #define deflateInit mz_deflateInit - #define deflateInit2 mz_deflateInit2 - #define deflateReset mz_deflateReset - #define deflate mz_deflate - #define deflateEnd mz_deflateEnd - #define deflateBound mz_deflateBound - #define compress mz_compress - #define compress2 mz_compress2 - #define compressBound mz_compressBound - #define inflateInit mz_inflateInit - #define inflateInit2 mz_inflateInit2 - #define inflate mz_inflate - #define inflateEnd mz_inflateEnd - #define uncompress mz_uncompress - #define crc32 mz_crc32 - #define adler32 mz_adler32 - #define MAX_WBITS 15 - #define MAX_MEM_LEVEL 9 - #define zError mz_error - #define ZLIB_VERSION MZ_VERSION - #define ZLIB_VERNUM MZ_VERNUM - #define ZLIB_VER_MAJOR MZ_VER_MAJOR - #define ZLIB_VER_MINOR MZ_VER_MINOR - #define ZLIB_VER_REVISION MZ_VER_REVISION - #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION - #define zlibVersion mz_version - #define zlib_version mz_version() +typedef unsigned char Byte; +typedef unsigned int uInt; +typedef mz_ulong uLong; +typedef Byte Bytef; +typedef uInt uIntf; +typedef char charf; +typedef int intf; +typedef void *voidpf; +typedef uLong uLongf; +typedef void *voidp; +typedef void *const voidpc; +#define Z_NULL 0 +#define Z_NO_FLUSH MZ_NO_FLUSH +#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH +#define Z_SYNC_FLUSH MZ_SYNC_FLUSH +#define Z_FULL_FLUSH MZ_FULL_FLUSH +#define Z_FINISH MZ_FINISH +#define Z_BLOCK MZ_BLOCK +#define Z_OK MZ_OK +#define Z_STREAM_END MZ_STREAM_END +#define Z_NEED_DICT MZ_NEED_DICT +#define Z_ERRNO MZ_ERRNO +#define Z_STREAM_ERROR MZ_STREAM_ERROR +#define Z_DATA_ERROR MZ_DATA_ERROR +#define Z_MEM_ERROR MZ_MEM_ERROR +#define Z_BUF_ERROR MZ_BUF_ERROR +#define Z_VERSION_ERROR MZ_VERSION_ERROR +#define Z_PARAM_ERROR MZ_PARAM_ERROR +#define Z_NO_COMPRESSION MZ_NO_COMPRESSION +#define Z_BEST_SPEED MZ_BEST_SPEED +#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION +#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION +#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY +#define Z_FILTERED MZ_FILTERED +#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY +#define Z_RLE MZ_RLE +#define Z_FIXED MZ_FIXED +#define Z_DEFLATED MZ_DEFLATED +#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS +#define alloc_func mz_alloc_func +#define free_func mz_free_func +#define internal_state mz_internal_state +#define z_stream mz_stream +#define deflateInit mz_deflateInit +#define deflateInit2 mz_deflateInit2 +#define deflateReset mz_deflateReset +#define deflate mz_deflate +#define deflateEnd mz_deflateEnd +#define deflateBound mz_deflateBound +#define compress mz_compress +#define compress2 mz_compress2 +#define compressBound mz_compressBound +#define inflateInit mz_inflateInit +#define inflateInit2 mz_inflateInit2 +#define inflate mz_inflate +#define inflateEnd mz_inflateEnd +#define uncompress mz_uncompress +#define crc32 mz_crc32 +#define adler32 mz_adler32 +#define MAX_WBITS 15 +#define MAX_MEM_LEVEL 9 +#define zError mz_error +#define ZLIB_VERSION MZ_VERSION +#define ZLIB_VERNUM MZ_VERNUM +#define ZLIB_VER_MAJOR MZ_VER_MAJOR +#define ZLIB_VER_MINOR MZ_VER_MINOR +#define ZLIB_VER_REVISION MZ_VER_REVISION +#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION +#define zlibVersion mz_version +#define zlib_version mz_version() #endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES #endif // MINIZ_NO_ZLIB_APIS @@ -486,26 +653,25 @@ typedef int mz_bool; #define MZ_FALSE (0) #define MZ_TRUE (1) -// An attempt to work around MSVC's spammy "warning C4127: conditional expression is constant" message. +// An attempt to work around MSVC's spammy "warning C4127: conditional +// expression is constant" message. #ifdef _MSC_VER - #define MZ_MACRO_END while (0, 0) +#define MZ_MACRO_END while (0, 0) #else - #define MZ_MACRO_END while (0) +#define MZ_MACRO_END while (0) #endif // ------------------- ZIP archive reading/writing #ifndef MINIZ_NO_ARCHIVE_APIS -enum -{ - MZ_ZIP_MAX_IO_BUF_SIZE = 64*1024, +enum { + MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256 }; -typedef struct -{ +typedef struct { mz_uint32 m_file_index; mz_uint32 m_central_dir_ofs; mz_uint16 m_version_made_by; @@ -526,22 +692,22 @@ typedef struct char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; } mz_zip_archive_file_stat; -typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); -typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); +typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, + void *pBuf, size_t n); +typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, + const void *pBuf, size_t n); struct mz_zip_internal_state_tag; typedef struct mz_zip_internal_state_tag mz_zip_internal_state; -typedef enum -{ +typedef enum { MZ_ZIP_MODE_INVALID = 0, MZ_ZIP_MODE_READING = 1, MZ_ZIP_MODE_WRITING = 2, MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 } mz_zip_mode; -typedef struct mz_zip_archive_tag -{ +typedef struct mz_zip_archive_tag { mz_uint64 m_archive_size; mz_uint64 m_central_directory_file_ofs; mz_uint m_total_files; @@ -562,11 +728,10 @@ typedef struct mz_zip_archive_tag } mz_zip_archive; -typedef enum -{ - MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, - MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, - MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, +typedef enum { + MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, + MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, + MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800 } mz_zip_flags; @@ -574,56 +739,91 @@ typedef enum // Inits a ZIP archive reader. // These functions read and validate the archive's central directory. -mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags); -mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags); +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, + mz_uint32 flags); +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, + size_t size, mz_uint32 flags); #ifndef MINIZ_NO_STDIO -mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, + mz_uint32 flags); #endif // Returns the total number of files in the archive. mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); // Returns detailed information about an archive file entry. -mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, + mz_zip_archive_file_stat *pStat); // Determines if an archive file entry is a directory entry. -mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); -mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, + mz_uint file_index); +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, + mz_uint file_index); // Retrieves the filename of an archive file entry. -// Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. -mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); +// Returns the number of bytes written to pFilename, or if filename_buf_size is +// 0 this function returns the number of bytes needed to fully store the +// filename. +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, + char *pFilename, mz_uint filename_buf_size); // Attempts to locates a file in the archive's central directory. // Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH // Returns -1 if the file cannot be found. -int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, + const char *pComment, mz_uint flags); // Extracts a archive file to a memory buffer using no memory allocation. -mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); -mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, + mz_uint file_index, void *pBuf, + size_t buf_size, mz_uint flags, + void *pUser_read_buf, + size_t user_read_buf_size); +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc( + mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, + mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); // Extracts a archive file to a memory buffer. -mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); -mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, + void *pBuf, size_t buf_size, + mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, + const char *pFilename, void *pBuf, + size_t buf_size, mz_uint flags); // Extracts a archive file to a dynamically allocated heap buffer. -void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); -void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, + size_t *pSize, mz_uint flags); +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, + const char *pFilename, size_t *pSize, + mz_uint flags); // Extracts a archive file using a callback function to output the file's data. -mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); -mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, + mz_uint file_index, + mz_file_write_func pCallback, + void *pOpaque, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, + const char *pFilename, + mz_file_write_func pCallback, + void *pOpaque, mz_uint flags); #ifndef MINIZ_NO_STDIO -// Extracts a archive file to a disk file and sets its last accessed and modified times. -// This function only extracts files, not archive directory records. -mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); -mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); +// Extracts a archive file to a disk file and sets its last accessed and +// modified times. This function only extracts files, not archive directory +// records. +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, + const char *pDst_filename, mz_uint flags); +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, + const char *pArchive_filename, + const char *pDst_filename, + mz_uint flags); #endif -// Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. +// Ends archive reading, freeing all allocations, and closing the input archive +// file if mz_zip_reader_init_file() was used. mz_bool mz_zip_reader_end(mz_zip_archive *pZip); // ZIP archive writing @@ -632,55 +832,93 @@ mz_bool mz_zip_reader_end(mz_zip_archive *pZip); // Inits a ZIP archive writer. mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); -mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, + size_t size_to_reserve_at_beginning, + size_t initial_allocation_size); #ifndef MINIZ_NO_STDIO -mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, + mz_uint64 size_to_reserve_at_beginning); #endif -// Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. -// For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. -// For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). -// Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. -// Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before -// the archive is finalized the file's central directory will be hosed. -mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); +// Converts a ZIP archive reader object into a writer object, to allow efficient +// in-place file appends to occur on an existing archive. For archives opened +// using mz_zip_reader_init_file, pFilename must be the archive's filename so it +// can be reopened for writing. If the file can't be reopened, +// mz_zip_reader_end() will be called. For archives opened using +// mz_zip_reader_init_mem, the memory block must be growable using the realloc +// callback (which defaults to realloc unless you've overridden it). Finally, +// for archives opened using mz_zip_reader_init, the mz_zip_archive's user +// provided m_pWrite function cannot be NULL. Note: In-place archive +// modification is not recommended unless you know what you're doing, because if +// execution stops or something goes wrong before the archive is finalized the +// file's central directory will be hosed. +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, + const char *pFilename); -// Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. -// To add a directory entry, call this method with an archive name ending in a forwardslash with empty buffer. -// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. -mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); -mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); +// Adds the contents of a memory buffer to an archive. These functions record +// the current local time into the archive. To add a directory entry, call this +// method with an archive name ending in a forwardslash with empty buffer. +// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, +// MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or +// just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, + const void *pBuf, size_t buf_size, + mz_uint level_and_flags); +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, + const char *pArchive_name, const void *pBuf, + size_t buf_size, const void *pComment, + mz_uint16 comment_size, + mz_uint level_and_flags, mz_uint64 uncomp_size, + mz_uint32 uncomp_crc32); #ifndef MINIZ_NO_STDIO -// Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. -// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. -mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +// Adds the contents of a disk file to an archive. This function also records +// the disk file's modified time into the archive. level_and_flags - compression +// level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd +// with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, + const char *pSrc_filename, const void *pComment, + mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint32 ext_attributes); #endif // Adds a file to an archive by fully cloning the data from another archive. -// This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data, and comment fields. -mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index); +// This function fully clones the source file's compressed data (no +// recompression), along with its full filename, extra data, and comment fields. +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, + mz_zip_archive *pSource_zip, + mz_uint file_index); -// Finalizes the archive by writing the central directory records followed by the end of central directory record. -// After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). -// An archive must be manually finalized by calling this function for it to be valid. +// Finalizes the archive by writing the central directory records followed by +// the end of central directory record. After an archive is finalized, the only +// valid call on the mz_zip_archive struct is mz_zip_writer_end(). An archive +// must be manually finalized by calling this function for it to be valid. mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); -mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize); +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, + size_t *pSize); -// Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. -// Note for the archive to be valid, it must have been finalized before ending. +// Ends archive writing, freeing all allocations, and closing the output file if +// mz_zip_writer_init_file() was used. Note for the archive to be valid, it must +// have been finalized before ending. mz_bool mz_zip_writer_end(mz_zip_archive *pZip); // Misc. high-level helper functions: -// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. -// level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. -mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); +// mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) +// appends a memory blob to a ZIP archive. level_and_flags - compression level +// (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero +// or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. +mz_bool mz_zip_add_mem_to_archive_file_in_place( + const char *pZip_filename, const char *pArchive_name, const void *pBuf, + size_t buf_size, const void *pComment, mz_uint16 comment_size, + mz_uint level_and_flags); // Reads a single file from an archive into a heap block. // Returns NULL on failure. -void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags); +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, + const char *pArchive_name, + size_t *pSize, mz_uint zip_flags); #endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS @@ -689,12 +927,17 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char // ------------------- Low-level Decompression API Definitions // Decompression flags used by tinfl_decompress(). -// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. -// TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. -// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). -// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. -enum -{ +// TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and +// ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the +// input is a raw deflate stream. TINFL_FLAG_HAS_MORE_INPUT: If set, there are +// more input bytes available beyond the end of the supplied input buffer. If +// clear, the input buffer contains all remaining input. +// TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large +// enough to hold the entire decompressed stream. If clear, the output buffer is +// at least the size of the dictionary (typically 32KB). +// TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the +// decompressed bytes. +enum { TINFL_FLAG_PARSE_ZLIB_HEADER = 1, TINFL_FLAG_HAS_MORE_INPUT = 2, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, @@ -702,33 +945,42 @@ enum }; // High level decompression functions: -// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). -// On entry: -// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. +// tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block +// allocated via malloc(). On entry: +// pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data +// to decompress. // On return: // Function returns a pointer to the decompressed data, or NULL on failure. -// *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. -// The caller must call mz_free() on the returned block when it's no longer needed. -void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); +// *pOut_len will be set to the decompressed data's size, which could be larger +// than src_buf_len on uncompressible data. The caller must call mz_free() on +// the returned block when it's no longer needed. +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, + size_t *pOut_len, int flags); -// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. -// Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. +// tinfl_decompress_mem_to_mem() decompresses a block in memory to another block +// in memory. Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the +// number of bytes written on success. #define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) -size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags); -// tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. -// Returns 1 on success or 0 on failure. -typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); -int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); +// tinfl_decompress_mem_to_callback() decompresses a block in memory to an +// internal 32KB buffer, and a user provided callback function will be called to +// flush the buffer. Returns 1 on success or 0 on failure. +typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser); +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, + tinfl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags); -struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; +struct tinfl_decompressor_tag; +typedef struct tinfl_decompressor_tag tinfl_decompressor; // Max size of LZ dictionary. #define TINFL_LZ_DICT_SIZE 32768 // Return status. -typedef enum -{ +typedef enum { TINFL_STATUS_BAD_PARAM = -3, TINFL_STATUS_ADLER32_MISMATCH = -2, TINFL_STATUS_FAILED = -1, @@ -738,126 +990,196 @@ typedef enum } tinfl_status; // Initializes the decompressor to its initial state. -#define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END +#define tinfl_init(r) \ + do { \ + (r)->m_state = 0; \ + } \ + MZ_MACRO_END #define tinfl_get_adler32(r) (r)->m_check_adler32 -// Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. -// This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); +// Main low-level decompressor coroutine function. This is the only function +// actually needed for decompression. All the other functions are just +// high-level helpers for improved usability. This is a universal API, i.e. it +// can be used as a building block to build any desired higher level +// decompression API. In the limit case, it can be called once per every byte +// input or output. +tinfl_status tinfl_decompress(tinfl_decompressor *r, + const mz_uint8 *pIn_buf_next, + size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, + mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, + const mz_uint32 decomp_flags); // Internal/private bits follow. -enum -{ - TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, - TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS +enum { + TINFL_MAX_HUFF_TABLES = 3, + TINFL_MAX_HUFF_SYMBOLS_0 = 288, + TINFL_MAX_HUFF_SYMBOLS_1 = 32, + TINFL_MAX_HUFF_SYMBOLS_2 = 19, + TINFL_FAST_LOOKUP_BITS = 10, + TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS }; -typedef struct -{ +typedef struct { mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; - mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; + mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], + m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; } tinfl_huff_table; #if MINIZ_HAS_64BIT_REGISTERS - #define TINFL_USE_64BIT_BITBUF 1 +#define TINFL_USE_64BIT_BITBUF 1 #endif #if TINFL_USE_64BIT_BITBUF - typedef mz_uint64 tinfl_bit_buf_t; - #define TINFL_BITBUF_SIZE (64) +typedef mz_uint64 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (64) #else - typedef mz_uint32 tinfl_bit_buf_t; - #define TINFL_BITBUF_SIZE (32) +typedef mz_uint32 tinfl_bit_buf_t; +#define TINFL_BITBUF_SIZE (32) #endif -struct tinfl_decompressor_tag -{ - mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; +struct tinfl_decompressor_tag { + mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, + m_check_adler32, m_dist, m_counter, m_num_extra, + m_table_sizes[TINFL_MAX_HUFF_TABLES]; tinfl_bit_buf_t m_bit_buf; size_t m_dist_from_out_buf_start; tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; - mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; + mz_uint8 m_raw_header[4], + m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; }; // ------------------- Low-level Compression API Definitions -// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). +// Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly +// slower, and raw/dynamic blocks will be output more frequently). #define TDEFL_LESS_MEMORY 0 -// tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): -// TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). -enum -{ - TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF +// tdefl_init() compression flags logically OR'd together (low 12 bits contain +// the max. number of probes per dictionary search): TDEFL_DEFAULT_MAX_PROBES: +// The compressor defaults to 128 dictionary probes per dictionary search. +// 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ +// (slowest/best compression). +enum { + TDEFL_HUFFMAN_ONLY = 0, + TDEFL_DEFAULT_MAX_PROBES = 128, + TDEFL_MAX_PROBES_MASK = 0xFFF }; -// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. -// TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). -// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. -// TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). -// TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) -// TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. +// TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before +// the deflate data, and the Adler-32 of the source data at the end. Otherwise, +// you'll get raw deflate data. TDEFL_COMPUTE_ADLER32: Always compute the +// adler-32 of the input data (even when not writing zlib headers). +// TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more +// efficient lazy parsing. TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to +// decrease the compressor's initialization time to the minimum, but the output +// may vary from run to run given the same input (depending on the contents of +// memory). TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a +// distance of 1) TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. // TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. // TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. -// The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). -enum -{ - TDEFL_WRITE_ZLIB_HEADER = 0x01000, - TDEFL_COMPUTE_ADLER32 = 0x02000, - TDEFL_GREEDY_PARSING_FLAG = 0x04000, +// The low 12 bits are reserved to control the max # of hash probes per +// dictionary lookup (see TDEFL_MAX_PROBES_MASK). +enum { + TDEFL_WRITE_ZLIB_HEADER = 0x01000, + TDEFL_COMPUTE_ADLER32 = 0x02000, + TDEFL_GREEDY_PARSING_FLAG = 0x04000, TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, - TDEFL_RLE_MATCHES = 0x10000, - TDEFL_FILTER_MATCHES = 0x20000, - TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, - TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 + TDEFL_RLE_MATCHES = 0x10000, + TDEFL_FILTER_MATCHES = 0x20000, + TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, + TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 }; // High level compression functions: -// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). -// On entry: +// tdefl_compress_mem_to_heap() compresses a block in memory to a heap block +// allocated via malloc(). On entry: // pSrc_buf, src_buf_len: Pointer and size of source block to compress. -// flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. +// flags: The max match finder probes (default is 128) logically OR'd against +// the above flags. Higher probes are slower but improve compression. // On return: // Function returns a pointer to the compressed data, or NULL on failure. -// *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. -// The caller must free() the returned block when it's no longer needed. -void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); +// *pOut_len will be set to the compressed data's size, which could be larger +// than src_buf_len on uncompressible data. The caller must free() the returned +// block when it's no longer needed. +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, + size_t *pOut_len, int flags); -// tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. -// Returns 0 on failure. -size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); +// tdefl_compress_mem_to_mem() compresses a block in memory to another block in +// memory. Returns 0 on failure. +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags); // Compresses an image to a compressed PNG file in memory. // On entry: -// pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. -// The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. -// level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL -// If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). +// pImage, w, h, and num_chans describe the image to compress. num_chans may be +// 1, 2, 3, or 4. The image pitch in bytes per scanline will be w*num_chans. +// The leftmost pixel on the top scanline is stored first in memory. level may +// range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, +// MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL If flip is +// true, the image will be flipped on the Y axis (useful for OpenGL apps). // On return: // Function returns a pointer to the compressed data, or NULL on failure. // *pLen_out will be set to the size of the PNG image file. -// The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. -void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); -void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); +// The caller must mz_free() the returned heap block (which will typically be +// larger than *pLen_out) when it's no longer needed. +void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, + int h, int num_chans, + size_t *pLen_out, + mz_uint level, mz_bool flip); +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, + int num_chans, size_t *pLen_out); -// Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. -typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); +// Output stream interface. The compressor uses this interface to write +// compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. +typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, + void *pUser); -// tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. -mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); +// tdefl_compress_mem_to_output() compresses a block to an output stream. The +// above helpers use this function internally. +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, + tdefl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags); -enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 }; +enum { + TDEFL_MAX_HUFF_TABLES = 3, + TDEFL_MAX_HUFF_SYMBOLS_0 = 288, + TDEFL_MAX_HUFF_SYMBOLS_1 = 32, + TDEFL_MAX_HUFF_SYMBOLS_2 = 19, + TDEFL_LZ_DICT_SIZE = 32768, + TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, + TDEFL_MIN_MATCH_LEN = 3, + TDEFL_MAX_MATCH_LEN = 258 +}; -// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). +// TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed +// output block (using static/fixed Huffman codes). #if TDEFL_LESS_MEMORY -enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; +enum { + TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 12, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; #else -enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; +enum { + TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, + TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10, + TDEFL_MAX_HUFF_SYMBOLS = 288, + TDEFL_LZ_HASH_BITS = 15, + TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, + TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, + TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS +}; #endif -// The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. -typedef enum -{ +// The low-level tdefl functions below may be used directly if the above helper +// functions aren't flexible enough. The low-level functions don't make any heap +// allocations, unlike the above helper functions. +typedef enum { TDEFL_STATUS_BAD_PARAM = -2, TDEFL_STATUS_PUT_BUF_FAILED = -1, TDEFL_STATUS_OKAY = 0, @@ -865,8 +1187,7 @@ typedef enum } tdefl_status; // Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums -typedef enum -{ +typedef enum { TDEFL_NO_FLUSH = 0, TDEFL_SYNC_FLUSH = 2, TDEFL_FULL_FLUSH = 3, @@ -874,16 +1195,18 @@ typedef enum } tdefl_flush; // tdefl's compression state structure. -typedef struct -{ +typedef struct { tdefl_put_buf_func_ptr m_pPut_buf_func; void *m_pPut_buf_user; mz_uint m_flags, m_max_probes[2]; int m_greedy_parsing; mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; - mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; - mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; + mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, + m_bit_buffer; + mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, + m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, + m_wants_to_finish; tdefl_status m_prev_return_status; const void *m_pIn_buf; void *m_pOut_buf; @@ -902,29 +1225,42 @@ typedef struct } tdefl_compressor; // Initializes the compressor. -// There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. -// pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. -// If pBut_buf_func is NULL the user should always call the tdefl_compress() API. -// flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) -tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); +// There is no corresponding deinit() function because the tdefl API's do not +// dynamically allocate memory. pBut_buf_func: If NULL, output data will be +// supplied to the specified callback. In this case, the user should call the +// tdefl_compress_buffer() API for compression. If pBut_buf_func is NULL the +// user should always call the tdefl_compress() API. flags: See the above enums +// (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) +tdefl_status tdefl_init(tdefl_compressor *d, + tdefl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags); -// Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. -tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); +// Compresses a block of data, consuming as much of the specified input buffer +// as possible, and writing as much compressed data to the specified output +// buffer as possible. +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, + size_t *pIn_buf_size, void *pOut_buf, + size_t *pOut_buf_size, tdefl_flush flush); -// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. -// tdefl_compress_buffer() always consumes the entire input buffer. -tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); +// tdefl_compress_buffer() is only usable when the tdefl_init() is called with a +// non-NULL tdefl_put_buf_func_ptr. tdefl_compress_buffer() always consumes the +// entire input buffer. +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, + size_t in_buf_size, tdefl_flush flush); tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); mz_uint32 tdefl_get_adler32(tdefl_compressor *d); -// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't defined, because it uses some of its macros. +// Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't +// defined, because it uses some of its macros. #ifndef MINIZ_NO_ZLIB_APIS // Create tdefl_compress() flags given zlib-style compression parameters. -// level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) -// window_bits may be -15 (raw deflate) or 15 (zlib) -// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED -mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); +// level may range from [0,10] (where 10 is absolute max compression, but may be +// much slower on some files) window_bits may be -15 (raw deflate) or 15 (zlib) +// strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, +// MZ_RLE, or MZ_FIXED +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, + int strategy); #endif // #ifndef MINIZ_NO_ZLIB_APIS #ifdef __cplusplus @@ -933,109 +1269,145 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int #endif // MINIZ_HEADER_INCLUDED -// ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) +// ------------------- End of Header: Implementation follows. (If you only want +// the header, define MINIZ_HEADER_FILE_ONLY.) #ifndef MINIZ_HEADER_FILE_ONLY -typedef unsigned char mz_validate_uint16[sizeof(mz_uint16)==2 ? 1 : -1]; -typedef unsigned char mz_validate_uint32[sizeof(mz_uint32)==4 ? 1 : -1]; -typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1]; +typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1]; +typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1]; +typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1]; -#include #include +#include #define MZ_ASSERT(x) assert(x) #ifdef MINIZ_NO_MALLOC - #define MZ_MALLOC(x) NULL - #define MZ_FREE(x) (void)x, ((void)0) - #define MZ_REALLOC(p, x) NULL +#define MZ_MALLOC(x) NULL +#define MZ_FREE(x) (void)x, ((void)0) +#define MZ_REALLOC(p, x) NULL #else - #define MZ_MALLOC(x) malloc(x) - #define MZ_FREE(x) free(x) - #define MZ_REALLOC(p, x) realloc(p, x) +#define MZ_MALLOC(x) malloc(x) +#define MZ_FREE(x) free(x) +#define MZ_REALLOC(p, x) realloc(p, x) #endif -#define MZ_MAX(a,b) (((a)>(b))?(a):(b)) -#define MZ_MIN(a,b) (((a)<(b))?(a):(b)) +#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b)) #define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN - #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) - #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) +#define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) +#define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) #else - #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) - #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) +#define MZ_READ_LE16(p) \ + ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \ + ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) +#define MZ_READ_LE32(p) \ + ((mz_uint32)(((const mz_uint8 *)(p))[0]) | \ + ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | \ + ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | \ + ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) #endif #ifdef _MSC_VER - #define MZ_FORCEINLINE __forceinline +#define MZ_FORCEINLINE __forceinline #elif defined(__GNUC__) - #define MZ_FORCEINLINE inline __attribute__((__always_inline__)) +#define MZ_FORCEINLINE inline __attribute__((__always_inline__)) #else - #define MZ_FORCEINLINE inline +#define MZ_FORCEINLINE inline #endif #ifdef __cplusplus - extern "C" { +extern "C" { #endif // ------------------- zlib-style API's -mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) -{ - mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552; - if (!ptr) return MZ_ADLER32_INIT; +mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) { + mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); + size_t block_len = buf_len % 5552; + if (!ptr) + return MZ_ADLER32_INIT; while (buf_len) { for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { - s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; } - for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; + for (; i < block_len; ++i) + s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; } return (s2 << 16) + s1; } -// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ -mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) -{ - static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, - 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; +// Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C +// implementation that balances processor cache usage against speed": +// http://www.geocities.com/malbrain/ +mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) { + static const mz_uint32 s_crc32[16] = { + 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, + 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, + 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c}; mz_uint32 crcu32 = (mz_uint32)crc; - if (!ptr) return MZ_CRC32_INIT; - crcu32 = ~crcu32; while (buf_len--) { mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; } + if (!ptr) + return MZ_CRC32_INIT; + crcu32 = ~crcu32; + while (buf_len--) { + mz_uint8 b = *ptr++; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; + crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; + } return ~crcu32; } -void mz_free(void *p) -{ - MZ_FREE(p); -} +void mz_free(void *p) { MZ_FREE(p); } #ifndef MINIZ_NO_ZLIB_APIS -static void *def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); } -static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); } -static void *def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return MZ_REALLOC(address, items * size); } - -const char *mz_version(void) -{ - return MZ_VERSION; +static void *def_alloc_func(void *opaque, size_t items, size_t size) { + (void)opaque, (void)items, (void)size; + return MZ_MALLOC(items * size); +} +static void def_free_func(void *opaque, void *address) { + (void)opaque, (void)address; + MZ_FREE(address); +} +static void *def_realloc_func(void *opaque, void *address, size_t items, + size_t size) { + (void)opaque, (void)address, (void)items, (void)size; + return MZ_REALLOC(address, items * size); } -int mz_deflateInit(mz_streamp pStream, int level) -{ - return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); +const char *mz_version(void) { return MZ_VERSION; } + +int mz_deflateInit(mz_streamp pStream, int level) { + return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, + MZ_DEFAULT_STRATEGY); } -int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) -{ +int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, + int mem_level, int strategy) { tdefl_compressor *pComp; - mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); + mz_uint comp_flags = + TDEFL_COMPUTE_ADLER32 | + tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); - if (!pStream) return MZ_STREAM_ERROR; - if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR; + if (!pStream) + return MZ_STREAM_ERROR; + if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || + ((window_bits != MZ_DEFAULT_WINDOW_BITS) && + (-window_bits != MZ_DEFAULT_WINDOW_BITS))) + return MZ_PARAM_ERROR; pStream->data_type = 0; pStream->adler = MZ_ADLER32_INIT; @@ -1043,17 +1415,19 @@ int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, pStream->reserved = 0; pStream->total_in = 0; pStream->total_out = 0; - if (!pStream->zalloc) pStream->zalloc = def_alloc_func; - if (!pStream->zfree) pStream->zfree = def_free_func; + if (!pStream->zalloc) + pStream->zalloc = def_alloc_func; + if (!pStream->zfree) + pStream->zfree = def_free_func; - pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); + pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, + sizeof(tdefl_compressor)); if (!pComp) return MZ_MEM_ERROR; pStream->state = (struct mz_internal_state *)pComp; - if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) - { + if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) { mz_deflateEnd(pStream); return MZ_PARAM_ERROR; } @@ -1061,56 +1435,64 @@ int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, return MZ_OK; } -int mz_deflateReset(mz_streamp pStream) -{ - if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR; +int mz_deflateReset(mz_streamp pStream) { + if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || + (!pStream->zfree)) + return MZ_STREAM_ERROR; pStream->total_in = pStream->total_out = 0; - tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags); + tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, + ((tdefl_compressor *)pStream->state)->m_flags); return MZ_OK; } -int mz_deflate(mz_streamp pStream, int flush) -{ +int mz_deflate(mz_streamp pStream, int flush) { size_t in_bytes, out_bytes; mz_ulong orig_total_in, orig_total_out; int mz_status = MZ_OK; - if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR; - if (!pStream->avail_out) return MZ_BUF_ERROR; + if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || + (!pStream->next_out)) + return MZ_STREAM_ERROR; + if (!pStream->avail_out) + return MZ_BUF_ERROR; - if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; + if (flush == MZ_PARTIAL_FLUSH) + flush = MZ_SYNC_FLUSH; - if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) + if (((tdefl_compressor *)pStream->state)->m_prev_return_status == + TDEFL_STATUS_DONE) return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; - orig_total_in = pStream->total_in; orig_total_out = pStream->total_out; - for ( ; ; ) - { + orig_total_in = pStream->total_in; + orig_total_out = pStream->total_out; + for (;;) { tdefl_status defl_status; - in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; - defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); - pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state); + defl_status = tdefl_compress((tdefl_compressor *)pStream->state, + pStream->next_in, &in_bytes, pStream->next_out, + &out_bytes, (tdefl_flush)flush); + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state); - pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; - if (defl_status < 0) - { + if (defl_status < 0) { mz_status = MZ_STREAM_ERROR; break; - } - else if (defl_status == TDEFL_STATUS_DONE) - { + } else if (defl_status == TDEFL_STATUS_DONE) { mz_status = MZ_STREAM_END; break; - } - else if (!pStream->avail_out) + } else if (!pStream->avail_out) break; - else if ((!pStream->avail_in) && (flush != MZ_FINISH)) - { - if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) + else if ((!pStream->avail_in) && (flush != MZ_FINISH)) { + if ((flush) || (pStream->total_in != orig_total_in) || + (pStream->total_out != orig_total_out)) break; return MZ_BUF_ERROR; // Can't make forward progress without some input. } @@ -1118,32 +1500,33 @@ int mz_deflate(mz_streamp pStream, int flush) return mz_status; } -int mz_deflateEnd(mz_streamp pStream) -{ - if (!pStream) return MZ_STREAM_ERROR; - if (pStream->state) - { +int mz_deflateEnd(mz_streamp pStream) { + if (!pStream) + return MZ_STREAM_ERROR; + if (pStream->state) { pStream->zfree(pStream->opaque, pStream->state); pStream->state = NULL; } return MZ_OK; } -mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) -{ +mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) { (void)pStream; - // This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) - return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); + // This is really over conservative. (And lame, but it's actually pretty + // tricky to compute a true upper bound given the way tdefl's blocking works.) + return MZ_MAX(128 + (source_len * 110) / 100, + 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); } -int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) -{ +int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len, int level) { int status; mz_stream stream; memset(&stream, 0, sizeof(stream)); // In case mz_ulong is 64-bits (argh I hate longs). - if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + if ((source_len | *pDest_len) > 0xFFFFFFFFU) + return MZ_PARAM_ERROR; stream.next_in = pSource; stream.avail_in = (mz_uint32)source_len; @@ -1151,11 +1534,11 @@ int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char stream.avail_out = (mz_uint32)*pDest_len; status = mz_deflateInit(&stream, level); - if (status != MZ_OK) return status; + if (status != MZ_OK) + return status; status = mz_deflate(&stream, MZ_FINISH); - if (status != MZ_STREAM_END) - { + if (status != MZ_STREAM_END) { mz_deflateEnd(&stream); return (status == MZ_OK) ? MZ_BUF_ERROR : status; } @@ -1164,29 +1547,31 @@ int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char return mz_deflateEnd(&stream); } -int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) -{ - return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); +int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len) { + return mz_compress2(pDest, pDest_len, pSource, source_len, + MZ_DEFAULT_COMPRESSION); } -mz_ulong mz_compressBound(mz_ulong source_len) -{ +mz_ulong mz_compressBound(mz_ulong source_len) { return mz_deflateBound(NULL, source_len); } -typedef struct -{ +typedef struct { tinfl_decompressor m_decomp; - mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits; + mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; + int m_window_bits; mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; tinfl_status m_last_status; } inflate_state; -int mz_inflateInit2(mz_streamp pStream, int window_bits) -{ +int mz_inflateInit2(mz_streamp pStream, int window_bits) { inflate_state *pDecomp; - if (!pStream) return MZ_STREAM_ERROR; - if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR; + if (!pStream) + return MZ_STREAM_ERROR; + if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && + (-window_bits != MZ_DEFAULT_WINDOW_BITS)) + return MZ_PARAM_ERROR; pStream->data_type = 0; pStream->adler = 0; @@ -1194,11 +1579,15 @@ int mz_inflateInit2(mz_streamp pStream, int window_bits) pStream->total_in = 0; pStream->total_out = 0; pStream->reserved = 0; - if (!pStream->zalloc) pStream->zalloc = def_alloc_func; - if (!pStream->zfree) pStream->zfree = def_free_func; + if (!pStream->zalloc) + pStream->zalloc = def_alloc_func; + if (!pStream->zfree) + pStream->zfree = def_free_func; - pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); - if (!pDecomp) return MZ_MEM_ERROR; + pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, + sizeof(inflate_state)); + if (!pDecomp) + return MZ_MEM_ERROR; pStream->state = (struct mz_internal_state *)pDecomp; @@ -1213,122 +1602,152 @@ int mz_inflateInit2(mz_streamp pStream, int window_bits) return MZ_OK; } -int mz_inflateInit(mz_streamp pStream) -{ - return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); +int mz_inflateInit(mz_streamp pStream) { + return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); } -int mz_inflate(mz_streamp pStream, int flush) -{ - inflate_state* pState; +int mz_inflate(mz_streamp pStream, int flush) { + inflate_state *pState; mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; size_t in_bytes, out_bytes, orig_avail_in; tinfl_status status; - if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; - if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; - if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + if ((!pStream) || (!pStream->state)) + return MZ_STREAM_ERROR; + if (flush == MZ_PARTIAL_FLUSH) + flush = MZ_SYNC_FLUSH; + if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; - pState = (inflate_state*)pStream->state; - if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; + pState = (inflate_state *)pStream->state; + if (pState->m_window_bits > 0) + decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; orig_avail_in = pStream->avail_in; - first_call = pState->m_first_call; pState->m_first_call = 0; - if (pState->m_last_status < 0) return MZ_DATA_ERROR; + first_call = pState->m_first_call; + pState->m_first_call = 0; + if (pState->m_last_status < 0) + return MZ_DATA_ERROR; - if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; + if (pState->m_has_flushed && (flush != MZ_FINISH)) + return MZ_STREAM_ERROR; pState->m_has_flushed |= (flush == MZ_FINISH); - if ((flush == MZ_FINISH) && (first_call)) - { - // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. + if ((flush == MZ_FINISH) && (first_call)) { + // MZ_FINISH on the first call implies that the input and output buffers are + // large enough to hold the entire compressed/decompressed file. decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; - in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; - status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); + in_bytes = pStream->avail_in; + out_bytes = pStream->avail_out; + status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, + pStream->next_out, pStream->next_out, &out_bytes, + decomp_flags); pState->m_last_status = status; - pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); - pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; + pStream->next_out += (mz_uint)out_bytes; + pStream->avail_out -= (mz_uint)out_bytes; + pStream->total_out += (mz_uint)out_bytes; if (status < 0) return MZ_DATA_ERROR; - else if (status != TINFL_STATUS_DONE) - { + else if (status != TINFL_STATUS_DONE) { pState->m_last_status = TINFL_STATUS_FAILED; return MZ_BUF_ERROR; } return MZ_STREAM_END; } // flush != MZ_FINISH then we must assume there's more input. - if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; + if (flush != MZ_FINISH) + decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; - if (pState->m_dict_avail) - { + if (pState->m_dict_avail) { n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); - pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; - pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); - return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + return ((pState->m_last_status == TINFL_STATUS_DONE) && + (!pState->m_dict_avail)) + ? MZ_STREAM_END + : MZ_OK; } - for ( ; ; ) - { + for (;;) { in_bytes = pStream->avail_in; out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; - status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); + status = tinfl_decompress( + &pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, + pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); pState->m_last_status = status; - pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; - pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); + pStream->next_in += (mz_uint)in_bytes; + pStream->avail_in -= (mz_uint)in_bytes; + pStream->total_in += (mz_uint)in_bytes; + pStream->adler = tinfl_get_adler32(&pState->m_decomp); pState->m_dict_avail = (mz_uint)out_bytes; n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); - pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; - pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); + pStream->next_out += n; + pStream->avail_out -= n; + pStream->total_out += n; + pState->m_dict_avail -= n; + pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); if (status < 0) - return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). + return MZ_DATA_ERROR; // Stream is corrupted (there could be some + // uncompressed data left in the output dictionary - + // oh well). else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) - return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. - else if (flush == MZ_FINISH) - { - // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. - if (status == TINFL_STATUS_DONE) - return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; - // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. - else if (!pStream->avail_out) - return MZ_BUF_ERROR; - } - else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) + return MZ_BUF_ERROR; // Signal caller that we can't make forward progress + // without supplying more input or by setting flush + // to MZ_FINISH. + else if (flush == MZ_FINISH) { + // The output buffer MUST be large to hold the remaining uncompressed data + // when flush==MZ_FINISH. + if (status == TINFL_STATUS_DONE) + return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; + // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's + // at least 1 more byte on the way. If there's no more room left in the + // output buffer then something is wrong. + else if (!pStream->avail_out) + return MZ_BUF_ERROR; + } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || + (!pStream->avail_out) || (pState->m_dict_avail)) break; } - return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; + return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) + ? MZ_STREAM_END + : MZ_OK; } -int mz_inflateEnd(mz_streamp pStream) -{ +int mz_inflateEnd(mz_streamp pStream) { if (!pStream) return MZ_STREAM_ERROR; - if (pStream->state) - { + if (pStream->state) { pStream->zfree(pStream->opaque, pStream->state); pStream->state = NULL; } return MZ_OK; } -int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) -{ +int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, + const unsigned char *pSource, mz_ulong source_len) { mz_stream stream; int status; memset(&stream, 0, sizeof(stream)); // In case mz_ulong is 64-bits (argh I hate longs). - if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; + if ((source_len | *pDest_len) > 0xFFFFFFFFU) + return MZ_PARAM_ERROR; stream.next_in = pSource; stream.avail_in = (mz_uint32)source_len; @@ -1340,268 +1759,482 @@ int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char return status; status = mz_inflate(&stream, MZ_FINISH); - if (status != MZ_STREAM_END) - { + if (status != MZ_STREAM_END) { mz_inflateEnd(&stream); - return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; + return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR + : status; } *pDest_len = stream.total_out; return mz_inflateEnd(&stream); } -const char *mz_error(int err) -{ - static struct { int m_err; const char *m_pDesc; } s_error_descs[] = - { - { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, - { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } - }; - mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; +const char *mz_error(int err) { + static struct { + int m_err; + const char *m_pDesc; + } s_error_descs[] = {{MZ_OK, ""}, + {MZ_STREAM_END, "stream end"}, + {MZ_NEED_DICT, "need dictionary"}, + {MZ_ERRNO, "file error"}, + {MZ_STREAM_ERROR, "stream error"}, + {MZ_DATA_ERROR, "data error"}, + {MZ_MEM_ERROR, "out of memory"}, + {MZ_BUF_ERROR, "buf error"}, + {MZ_VERSION_ERROR, "version error"}, + {MZ_PARAM_ERROR, "parameter error"}}; + mz_uint i; + for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) + if (s_error_descs[i].m_err == err) + return s_error_descs[i].m_pDesc; return NULL; } -#endif //MINIZ_NO_ZLIB_APIS +#endif // MINIZ_NO_ZLIB_APIS -// ------------------- Low-level Decompression (completely independent from all compression API's) +// ------------------- Low-level Decompression (completely independent from all +// compression API's) #define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) #define TINFL_MEMSET(p, c, l) memset(p, c, l) -#define TINFL_CR_BEGIN switch(r->m_state) { case 0: -#define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END -#define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END +#define TINFL_CR_BEGIN \ + switch (r->m_state) { \ + case 0: +#define TINFL_CR_RETURN(state_index, result) \ + do { \ + status = result; \ + r->m_state = state_index; \ + goto common_exit; \ + case state_index:; \ + } \ + MZ_MACRO_END +#define TINFL_CR_RETURN_FOREVER(state_index, result) \ + do { \ + for (;;) { \ + TINFL_CR_RETURN(state_index, result); \ + } \ + } \ + MZ_MACRO_END #define TINFL_CR_FINISH } -// TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never -// reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. -#define TINFL_GET_BYTE(state_index, c) do { \ - if (pIn_buf_cur >= pIn_buf_end) { \ - for ( ; ; ) { \ - if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ - TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ - if (pIn_buf_cur < pIn_buf_end) { \ - c = *pIn_buf_cur++; \ - break; \ - } \ - } else { \ - c = 0; \ - break; \ - } \ - } \ - } else c = *pIn_buf_cur++; } MZ_MACRO_END +// TODO: If the caller has indicated that there's no more input, and we attempt +// to read beyond the input buf, then something is wrong with the input because +// the inflator never reads ahead more than it needs to. Currently +// TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. +#define TINFL_GET_BYTE(state_index, c) \ + do { \ + if (pIn_buf_cur >= pIn_buf_end) { \ + for (;;) { \ + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ + TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ + if (pIn_buf_cur < pIn_buf_end) { \ + c = *pIn_buf_cur++; \ + break; \ + } \ + } else { \ + c = 0; \ + break; \ + } \ + } \ + } else \ + c = *pIn_buf_cur++; \ + } \ + MZ_MACRO_END -#define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n)) -#define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END -#define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END +#define TINFL_NEED_BITS(state_index, n) \ + do { \ + mz_uint c; \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ + } while (num_bits < (mz_uint)(n)) +#define TINFL_SKIP_BITS(state_index, n) \ + do { \ + if (num_bits < (mz_uint)(n)) { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END +#define TINFL_GET_BITS(state_index, b, n) \ + do { \ + if (num_bits < (mz_uint)(n)) { \ + TINFL_NEED_BITS(state_index, n); \ + } \ + b = bit_buf & ((1 << (n)) - 1); \ + bit_buf >>= (n); \ + num_bits -= (n); \ + } \ + MZ_MACRO_END -// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. -// It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a -// Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the -// bit buffer contains >=15 bits (deflate's max. Huffman code size). -#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ - do { \ - temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ - if (temp >= 0) { \ - code_len = temp >> 9; \ - if ((code_len) && (num_bits >= code_len)) \ - break; \ - } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ - code_len = TINFL_FAST_LOOKUP_BITS; \ - do { \ - temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ - } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ - } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ +// TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes +// remaining in the input buffer falls below 2. It reads just enough bytes from +// the input stream that are needed to decode the next Huffman code (and +// absolutely no more). It works by trying to fully decode a Huffman code by +// using whatever bits are currently present in the bit buffer. If this fails, +// it reads another byte, and tries again until it succeeds or until the bit +// buffer contains >=15 bits (deflate's max. Huffman code size). +#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ + do { \ + temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ + if (temp >= 0) { \ + code_len = temp >> 9; \ + if ((code_len) && (num_bits >= code_len)) \ + break; \ + } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while ((temp < 0) && (num_bits >= (code_len + 1))); \ + if (temp >= 0) \ + break; \ + } \ + TINFL_GET_BYTE(state_index, c); \ + bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \ + num_bits += 8; \ } while (num_bits < 15); -// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read -// beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully -// decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. -// The slow path is only executed at the very end of the input buffer. -#define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ - int temp; mz_uint code_len, c; \ - if (num_bits < 15) { \ - if ((pIn_buf_end - pIn_buf_cur) < 2) { \ - TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ - } else { \ - bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ - } \ - } \ - if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ - code_len = temp >> 9, temp &= 511; \ - else { \ - code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ - } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END +// TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex +// than you would initially expect because the zlib API expects the decompressor +// to never read beyond the final byte of the deflate stream. (In other words, +// when this macro wants to read another byte from the input, it REALLY needs +// another byte in order to fully decode the next Huffman code.) Handling this +// properly is particularly important on raw deflate (non-zlib) streams, which +// aren't followed by a byte aligned adler-32. The slow path is only executed at +// the very end of the input buffer. +#define TINFL_HUFF_DECODE(state_index, sym, pHuff) \ + do { \ + int temp; \ + mz_uint code_len, c; \ + if (num_bits < 15) { \ + if ((pIn_buf_end - pIn_buf_cur) < 2) { \ + TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ + } else { \ + bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | \ + (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \ + pIn_buf_cur += 2; \ + num_bits += 16; \ + } \ + } \ + if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= \ + 0) \ + code_len = temp >> 9, temp &= 511; \ + else { \ + code_len = TINFL_FAST_LOOKUP_BITS; \ + do { \ + temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ + } while (temp < 0); \ + } \ + sym = temp; \ + bit_buf >>= code_len; \ + num_bits -= code_len; \ + } \ + MZ_MACRO_END -tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) -{ - static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; - static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; - static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; - static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; - static const int s_min_table_sizes[3] = { 257, 1, 4 }; +tinfl_status tinfl_decompress(tinfl_decompressor *r, + const mz_uint8 *pIn_buf_next, + size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, + mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, + const mz_uint32 decomp_flags) { + static const int s_length_base[31] = { + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + static const int s_length_extra[31] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, + 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, + 4, 4, 5, 5, 5, 5, 0, 0, 0}; + static const int s_dist_base[32] = { + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, + 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, + 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0}; + static const int s_dist_extra[32] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, + 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, + 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; + static const mz_uint8 s_length_dezigzag[19] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + static const int s_min_table_sizes[3] = {257, 1, 4}; - tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; - const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; - mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; - size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; + tinfl_status status = TINFL_STATUS_FAILED; + mz_uint32 num_bits, dist, counter, num_extra; + tinfl_bit_buf_t bit_buf; + const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = + pIn_buf_next + *pIn_buf_size; + mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = + pOut_buf_next + *pOut_buf_size; + size_t out_buf_size_mask = + (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) + ? (size_t)-1 + : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, + dist_from_out_buf_start; - // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). - if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } - - num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; - TINFL_CR_BEGIN - - bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); - counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); - if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); - if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } + // Ensure the output buffer's size is a power of 2, unless the output buffer + // is large enough to hold the entire output file (in which case it doesn't + // matter). + if (((out_buf_size_mask + 1) & out_buf_size_mask) || + (pOut_buf_next < pOut_buf_start)) { + *pIn_buf_size = *pOut_buf_size = 0; + return TINFL_STATUS_BAD_PARAM; } - do - { - TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; - if (r->m_type == 0) - { + num_bits = r->m_num_bits; + bit_buf = r->m_bit_buf; + dist = r->m_dist; + counter = r->m_counter; + num_extra = r->m_num_extra; + dist_from_out_buf_start = r->m_dist_from_out_buf_start; + TINFL_CR_BEGIN + + bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; + r->m_z_adler32 = r->m_check_adler32 = 1; + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { + TINFL_GET_BYTE(1, r->m_zhdr0); + TINFL_GET_BYTE(2, r->m_zhdr1); + counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || + (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); + if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) + counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || + ((out_buf_size_mask + 1) < + (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); + if (counter) { + TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); + } + } + + do { + TINFL_GET_BITS(3, r->m_final, 3); + r->m_type = r->m_final >> 1; + if (r->m_type == 0) { TINFL_SKIP_BITS(5, num_bits & 7); - for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } - if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } - while ((counter) && (num_bits)) - { + for (counter = 0; counter < 4; ++counter) { + if (num_bits) + TINFL_GET_BITS(6, r->m_raw_header[counter], 8); + else + TINFL_GET_BYTE(7, r->m_raw_header[counter]); + } + if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != + (mz_uint)(0xFFFF ^ + (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { + TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); + } + while ((counter) && (num_bits)) { TINFL_GET_BITS(51, dist, 8); - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); + } *pOut_buf_cur++ = (mz_uint8)dist; counter--; } - while (counter) - { - size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } - while (pIn_buf_cur >= pIn_buf_end) - { - if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) - { + while (counter) { + size_t n; + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); + } + while (pIn_buf_cur >= pIn_buf_end) { + if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); - } - else - { + } else { TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); } } - n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); - TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; + n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), + (size_t)(pIn_buf_end - pIn_buf_cur)), + counter); + TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); + pIn_buf_cur += n; + pOut_buf_cur += n; + counter -= (mz_uint)n; } - } - else if (r->m_type == 3) - { + } else if (r->m_type == 3) { TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); - } - else - { - if (r->m_type == 1) - { - mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; - r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); - for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; - } - else - { - for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } - MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } + } else { + if (r->m_type == 1) { + mz_uint8 *p = r->m_tables[0].m_code_size; + mz_uint i; + r->m_table_sizes[0] = 288; + r->m_table_sizes[1] = 32; + TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); + for (i = 0; i <= 143; ++i) + *p++ = 8; + for (; i <= 255; ++i) + *p++ = 9; + for (; i <= 279; ++i) + *p++ = 7; + for (; i <= 287; ++i) + *p++ = 8; + } else { + for (counter = 0; counter < 3; counter++) { + TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); + r->m_table_sizes[counter] += s_min_table_sizes[counter]; + } + MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); + for (counter = 0; counter < r->m_table_sizes[2]; counter++) { + mz_uint s; + TINFL_GET_BITS(14, s, 3); + r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; + } r->m_table_sizes[2] = 19; } - for ( ; (int)r->m_type >= 0; r->m_type--) - { - int tree_next, tree_cur; tinfl_huff_table *pTable; - mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); - for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; - used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; - for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } - if ((65536 != total) && (used_syms > 1)) - { + for (; (int)r->m_type >= 0; r->m_type--) { + int tree_next, tree_cur; + tinfl_huff_table *pTable; + mz_uint i, j, used_syms, total, sym_index, next_code[17], + total_syms[16]; + pTable = &r->m_tables[r->m_type]; + MZ_CLEAR_OBJ(total_syms); + MZ_CLEAR_OBJ(pTable->m_look_up); + MZ_CLEAR_OBJ(pTable->m_tree); + for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) + total_syms[pTable->m_code_size[i]]++; + used_syms = 0, total = 0; + next_code[0] = next_code[1] = 0; + for (i = 1; i <= 15; ++i) { + used_syms += total_syms[i]; + next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); + } + if ((65536 != total) && (used_syms > 1)) { TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); } - for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) - { - mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; - cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); - if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } - if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } - rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); - for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) - { - tree_cur -= ((rev_code >>= 1) & 1); - if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; + for (tree_next = -1, sym_index = 0; + sym_index < r->m_table_sizes[r->m_type]; ++sym_index) { + mz_uint rev_code = 0, l, cur_code, + code_size = pTable->m_code_size[sym_index]; + if (!code_size) + continue; + cur_code = next_code[code_size]++; + for (l = code_size; l > 0; l--, cur_code >>= 1) + rev_code = (rev_code << 1) | (cur_code & 1); + if (code_size <= TINFL_FAST_LOOKUP_BITS) { + mz_int16 k = (mz_int16)((code_size << 9) | sym_index); + while (rev_code < TINFL_FAST_LOOKUP_SIZE) { + pTable->m_look_up[rev_code] = k; + rev_code += (1 << code_size); + } + continue; } - tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; + if (0 == + (tree_cur = pTable->m_look_up[rev_code & + (TINFL_FAST_LOOKUP_SIZE - 1)])) { + pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = + (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } + rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); + for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) { + tree_cur -= ((rev_code >>= 1) & 1); + if (!pTable->m_tree[-tree_cur - 1]) { + pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; + tree_cur = tree_next; + tree_next -= 2; + } else + tree_cur = pTable->m_tree[-tree_cur - 1]; + } + tree_cur -= ((rev_code >>= 1) & 1); + pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; } - if (r->m_type == 2) - { - for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) - { - mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } - if ((dist == 16) && (!counter)) - { + if (r->m_type == 2) { + for (counter = 0; + counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);) { + mz_uint s; + TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); + if (dist < 16) { + r->m_len_codes[counter++] = (mz_uint8)dist; + continue; + } + if ((dist == 16) && (!counter)) { TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); } - num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; - TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; + num_extra = "\02\03\07"[dist - 16]; + TINFL_GET_BITS(18, s, num_extra); + s += "\03\03\013"[dist - 16]; + TINFL_MEMSET(r->m_len_codes + counter, + (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); + counter += s; } - if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) - { + if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) { TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); } - TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); + TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, + r->m_table_sizes[0]); + TINFL_MEMCPY(r->m_tables[1].m_code_size, + r->m_len_codes + r->m_table_sizes[0], + r->m_table_sizes[1]); } } - for ( ; ; ) - { + for (;;) { mz_uint8 *pSrc; - for ( ; ; ) - { - if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) - { + for (;;) { + if (((pIn_buf_end - pIn_buf_cur) < 4) || + ((pOut_buf_end - pOut_buf_cur) < 2)) { TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); if (counter >= 256) break; - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = (mz_uint8)counter; - } - else - { - int sym2; mz_uint code_len; -#if TINFL_USE_64BIT_BITBUF - if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } -#else - if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } - counter = sym2; bit_buf >>= code_len; num_bits -= code_len; + *pOut_buf_cur++ = (mz_uint8)counter; + } else { + int sym2; + mz_uint code_len; +#if TINFL_USE_64BIT_BITBUF + if (num_bits < 30) { + bit_buf |= + (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 4; + num_bits += 32; + } +#else + if (num_bits < 15) { + bit_buf |= + (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; + } +#endif + if ((sym2 = + r->m_tables[0] + .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= + 0) + code_len = sym2 >> 9; + else { + code_len = TINFL_FAST_LOOKUP_BITS; + do { + sym2 = r->m_tables[0] + .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + counter = sym2; + bit_buf >>= code_len; + num_bits -= code_len; if (counter & 256) break; #if !TINFL_USE_64BIT_BITBUF - if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } -#endif - if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) - code_len = sym2 >> 9; - else - { - code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); + if (num_bits < 15) { + bit_buf |= + (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); + pIn_buf_cur += 2; + num_bits += 16; } - bit_buf >>= code_len; num_bits -= code_len; +#endif + if ((sym2 = + r->m_tables[0] + .m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= + 0) + code_len = sym2 >> 9; + else { + code_len = TINFL_FAST_LOOKUP_BITS; + do { + sym2 = r->m_tables[0] + .m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; + } while (sym2 < 0); + } + bit_buf >>= code_len; + num_bits -= code_len; pOut_buf_cur[0] = (mz_uint8)counter; - if (sym2 & 256) - { + if (sym2 & 256) { pOut_buf_cur++; counter = sym2; break; @@ -1610,46 +2243,56 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_nex pOut_buf_cur += 2; } } - if ((counter &= 511) == 256) break; + if ((counter &= 511) == 256) + break; - num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; - if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } + num_extra = s_length_extra[counter - 257]; + counter = s_length_base[counter - 257]; + if (num_extra) { + mz_uint extra_bits; + TINFL_GET_BITS(25, extra_bits, num_extra); + counter += extra_bits; + } TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); - num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; - if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } + num_extra = s_dist_extra[dist]; + dist = s_dist_base[dist]; + if (num_extra) { + mz_uint extra_bits; + TINFL_GET_BITS(27, extra_bits, num_extra); + dist += extra_bits; + } dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; - if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) - { + if ((dist > dist_from_out_buf_start) && + (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) { TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); } - pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); + pSrc = pOut_buf_start + + ((dist_from_out_buf_start - dist) & out_buf_size_mask); - if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) - { - while (counter--) - { - while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } - *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; + if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) { + while (counter--) { + while (pOut_buf_cur >= pOut_buf_end) { + TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); + } + *pOut_buf_cur++ = + pOut_buf_start[(dist_from_out_buf_start++ - dist) & + out_buf_size_mask]; } continue; } #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES - else if ((counter >= 9) && (counter <= dist)) - { + else if ((counter >= 9) && (counter <= dist)) { const mz_uint8 *pSrc_end = pSrc + (counter & ~7); - do - { + do { ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; pOut_buf_cur += 8; } while ((pSrc += 8) < pSrc_end); - if ((counter &= 7) < 3) - { - if (counter) - { + if ((counter &= 7) < 3) { + if (counter) { pOut_buf_cur[0] = pSrc[0]; if (counter > 1) pOut_buf_cur[1] = pSrc[1]; @@ -1659,15 +2302,14 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_nex } } #endif - do - { + do { pOut_buf_cur[0] = pSrc[0]; pOut_buf_cur[1] = pSrc[1]; pOut_buf_cur[2] = pSrc[2]; - pOut_buf_cur += 3; pSrc += 3; + pOut_buf_cur += 3; + pSrc += 3; } while ((int)(counter -= 3) > 2); - if ((int)counter > 0) - { + if ((int)counter > 0) { pOut_buf_cur[0] = pSrc[0]; if ((int)counter > 1) pOut_buf_cur[1] = pSrc[1]; @@ -1676,89 +2318,142 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_nex } } } while (!(r->m_final & 1)); - if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) - { - TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } + if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { + TINFL_SKIP_BITS(32, num_bits & 7); + for (counter = 0; counter < 4; ++counter) { + mz_uint s; + if (num_bits) + TINFL_GET_BITS(41, s, 8); + else + TINFL_GET_BYTE(42, s); + r->m_z_adler32 = (r->m_z_adler32 << 8) | s; + } } TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); TINFL_CR_FINISH common_exit: - r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; - *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; - if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) - { - const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; - mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; - while (buf_len) - { - for (i = 0; i + 7 < block_len; i += 8, ptr += 8) - { - s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; - s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; + r->m_num_bits = num_bits; + r->m_bit_buf = bit_buf; + r->m_dist = dist; + r->m_counter = counter; + r->m_num_extra = num_extra; + r->m_dist_from_out_buf_start = dist_from_out_buf_start; + *pIn_buf_size = pIn_buf_cur - pIn_buf_next; + *pOut_buf_size = pOut_buf_cur - pOut_buf_next; + if ((decomp_flags & + (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && + (status >= 0)) { + const mz_uint8 *ptr = pOut_buf_next; + size_t buf_len = *pOut_buf_size; + mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, + s2 = r->m_check_adler32 >> 16; + size_t block_len = buf_len % 5552; + while (buf_len) { + for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { + s1 += ptr[0], s2 += s1; + s1 += ptr[1], s2 += s1; + s1 += ptr[2], s2 += s1; + s1 += ptr[3], s2 += s1; + s1 += ptr[4], s2 += s1; + s1 += ptr[5], s2 += s1; + s1 += ptr[6], s2 += s1; + s1 += ptr[7], s2 += s1; } - for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; - s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; + for (; i < block_len; ++i) + s1 += *ptr++, s2 += s1; + s1 %= 65521U, s2 %= 65521U; + buf_len -= block_len; + block_len = 5552; } - r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; + r->m_check_adler32 = (s2 << 16) + s1; + if ((status == TINFL_STATUS_DONE) && + (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && + (r->m_check_adler32 != r->m_z_adler32)) + status = TINFL_STATUS_ADLER32_MISMATCH; } return status; } // Higher level helper functions. -void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -{ - tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; +void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, + size_t *pOut_len, int flags) { + tinfl_decompressor decomp; + void *pBuf = NULL, *pNew_buf; + size_t src_buf_ofs = 0, out_buf_capacity = 0; *pOut_len = 0; tinfl_init(&decomp); - for ( ; ; ) - { - size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; - tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size, - (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) - { - MZ_FREE(pBuf); *pOut_len = 0; return NULL; + for (;;) { + size_t src_buf_size = src_buf_len - src_buf_ofs, + dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; + tinfl_status status = tinfl_decompress( + &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, + (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, + &dst_buf_size, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; } src_buf_ofs += src_buf_size; *pOut_len += dst_buf_size; - if (status == TINFL_STATUS_DONE) break; - new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; + if (status == TINFL_STATUS_DONE) + break; + new_out_buf_capacity = out_buf_capacity * 2; + if (new_out_buf_capacity < 128) + new_out_buf_capacity = 128; pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); - if (!pNew_buf) - { - MZ_FREE(pBuf); *pOut_len = 0; return NULL; + if (!pNew_buf) { + MZ_FREE(pBuf); + *pOut_len = 0; + return NULL; } - pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; + pBuf = pNew_buf; + out_buf_capacity = new_out_buf_capacity; } return pBuf; } -size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -{ - tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); - status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); - return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; +size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags) { + tinfl_decompressor decomp; + tinfl_status status; + tinfl_init(&decomp); + status = + tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, + (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, + (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); + return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED + : out_buf_len; } -int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ +int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, + tinfl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags) { int result = 0; tinfl_decompressor decomp; - mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; + mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE); + size_t in_buf_ofs = 0, dict_ofs = 0; if (!pDict) return TINFL_STATUS_FAILED; tinfl_init(&decomp); - for ( ; ; ) - { - size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; - tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, - (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); + for (;;) { + size_t in_buf_size = *pIn_buf_size - in_buf_ofs, + dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; + tinfl_status status = + tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, + &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, + (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); in_buf_ofs += in_buf_size; - if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) + if ((dst_buf_size) && + (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) break; - if (status != TINFL_STATUS_HAS_MORE_OUTPUT) - { + if (status != TINFL_STATUS_HAS_MORE_OUTPUT) { result = (status == TINFL_STATUS_DONE); break; } @@ -1769,220 +2464,390 @@ int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, return result; } -// ------------------- Low-level Compression (independent from all decompression API's) +// ------------------- Low-level Compression (independent from all decompression +// API's) // Purposely making these tables static for faster init and thread safety. static const mz_uint16 s_tdefl_len_sym[256] = { - 257,258,259,260,261,262,263,264,265,265,266,266,267,267,268,268,269,269,269,269,270,270,270,270,271,271,271,271,272,272,272,272, - 273,273,273,273,273,273,273,273,274,274,274,274,274,274,274,274,275,275,275,275,275,275,275,275,276,276,276,276,276,276,276,276, - 277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278, - 279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280, - 281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281, - 282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282, - 283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283, - 284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,285 }; + 257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, + 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, + 272, 272, 273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, + 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, + 276, 276, 276, 276, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, + 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, + 278, 278, 278, 278, 278, 278, 279, 279, 279, 279, 279, 279, 279, 279, 279, + 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, + 280, 280, 280, 280, 280, 280, 280, 280, 281, 281, 281, 281, 281, 281, 281, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, + 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 282, 282, 282, 282, 282, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, + 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, + 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, + 285}; static const mz_uint8 s_tdefl_len_extra[256] = { - 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,0 }; + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0}; static const mz_uint8 s_tdefl_small_dist_sym[512] = { - 0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11, - 11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, - 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14, - 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, - 14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, - 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, - 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, - 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 }; + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, + 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17}; static const mz_uint8 s_tdefl_small_dist_extra[512] = { - 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5, - 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, - 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 7,7,7,7,7,7,7,7 }; + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7}; static const mz_uint8 s_tdefl_large_dist_sym[128] = { - 0,0,18,19,20,20,21,21,22,22,22,22,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26, - 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, - 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 }; + 0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, + 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, + 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29}; static const mz_uint8 s_tdefl_large_dist_extra[128] = { - 0,0,8,8,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, - 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, - 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 }; + 0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13}; -// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. -typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; -static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1) -{ - mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist); - for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; } - while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; - for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) - { - const mz_uint32* pHist = &hist[pass << 8]; +// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted +// values. +typedef struct { + mz_uint16 m_key, m_sym_index; +} tdefl_sym_freq; +static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, + tdefl_sym_freq *pSyms0, + tdefl_sym_freq *pSyms1) { + mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; + tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1; + MZ_CLEAR_OBJ(hist); + for (i = 0; i < num_syms; i++) { + mz_uint freq = pSyms0[i].m_key; + hist[freq & 0xFF]++; + hist[256 + ((freq >> 8) & 0xFF)]++; + } + while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) + total_passes--; + for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) { + const mz_uint32 *pHist = &hist[pass << 8]; mz_uint offsets[256], cur_ofs = 0; - for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } - for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; - { tdefl_sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; } + for (i = 0; i < 256; i++) { + offsets[i] = cur_ofs; + cur_ofs += pHist[i]; + } + for (i = 0; i < num_syms; i++) + pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = + pCur_syms[i]; + { + tdefl_sym_freq *t = pCur_syms; + pCur_syms = pNew_syms; + pNew_syms = t; + } } return pCur_syms; } -// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. -static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) -{ +// tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, +// alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. +static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) { int root, leaf, next, avbl, used, dpth; - if (n==0) return; else if (n==1) { A[0].m_key = 1; return; } - A[0].m_key += A[1].m_key; root = 0; leaf = 2; - for (next=1; next < n-1; next++) - { - if (leaf>=n || A[root].m_key=n || (root=0; next--) A[next].m_key = A[A[next].m_key].m_key+1; - avbl = 1; used = dpth = 0; root = n-2; next = n-1; - while (avbl>0) - { - while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; } - while (avbl>used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; } - avbl = 2*used; dpth++; used = 0; + A[0].m_key += A[1].m_key; + root = 0; + leaf = 2; + for (next = 1; next < n - 1; next++) { + if (leaf >= n || A[root].m_key < A[leaf].m_key) { + A[next].m_key = A[root].m_key; + A[root++].m_key = (mz_uint16)next; + } else + A[next].m_key = A[leaf++].m_key; + if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key)) { + A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key); + A[root++].m_key = (mz_uint16)next; + } else + A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key); + } + A[n - 2].m_key = 0; + for (next = n - 3; next >= 0; next--) + A[next].m_key = A[A[next].m_key].m_key + 1; + avbl = 1; + used = dpth = 0; + root = n - 2; + next = n - 1; + while (avbl > 0) { + while (root >= 0 && (int)A[root].m_key == dpth) { + used++; + root--; + } + while (avbl > used) { + A[next--].m_key = (mz_uint16)(dpth); + avbl--; + } + avbl = 2 * used; + dpth++; + used = 0; } } // Limits canonical Huffman code table's max code size. enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; -static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) -{ - int i; mz_uint32 total = 0; if (code_list_len <= 1) return; - for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; - for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); - while (total != (1UL << max_code_size)) - { +static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, + int code_list_len, + int max_code_size) { + int i; + mz_uint32 total = 0; + if (code_list_len <= 1) + return; + for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) + pNum_codes[max_code_size] += pNum_codes[i]; + for (i = max_code_size; i > 0; i--) + total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); + while (total != (1UL << max_code_size)) { pNum_codes[max_code_size]--; - for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } + for (i = max_code_size - 1; i > 0; i--) + if (pNum_codes[i]) { + pNum_codes[i]--; + pNum_codes[i + 1] += 2; + break; + } total--; } } -static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) -{ - int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes); - if (static_table) - { - for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; - } - else - { - tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; +static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, + int table_len, int code_size_limit, + int static_table) { + int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; + mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; + MZ_CLEAR_OBJ(num_codes); + if (static_table) { + for (i = 0; i < table_len; i++) + num_codes[d->m_huff_code_sizes[table_num][i]]++; + } else { + tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], + *pSyms; int num_used_syms = 0; const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; - for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; } + for (i = 0; i < table_len; i++) + if (pSym_count[i]) { + syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; + syms0[num_used_syms++].m_sym_index = (mz_uint16)i; + } - pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); + pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); + tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); - for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; + for (i = 0; i < num_used_syms; i++) + num_codes[pSyms[i].m_key]++; - tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); + tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, + code_size_limit); - MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); + MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); + MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); for (i = 1, j = num_used_syms; i <= code_size_limit; i++) - for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); + for (l = num_codes[i]; l > 0; l--) + d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); } - next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1); + next_code[1] = 0; + for (j = 0, i = 2; i <= code_size_limit; i++) + next_code[i] = j = ((j + num_codes[i - 1]) << 1); - for (i = 0; i < table_len; i++) - { - mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; - code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1); + for (i = 0; i < table_len; i++) { + mz_uint rev_code = 0, code, code_size; + if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) + continue; + code = next_code[code_size]++; + for (l = code_size; l > 0; l--, code >>= 1) + rev_code = (rev_code << 1) | (code & 1); d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; } } -#define TDEFL_PUT_BITS(b, l) do { \ - mz_uint bits = b; mz_uint len = l; MZ_ASSERT(bits <= ((1U << len) - 1U)); \ - d->m_bit_buffer |= (bits << d->m_bits_in); d->m_bits_in += len; \ - while (d->m_bits_in >= 8) { \ - if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ - *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ - d->m_bit_buffer >>= 8; \ - d->m_bits_in -= 8; \ - } \ -} MZ_MACRO_END +#define TDEFL_PUT_BITS(b, l) \ + do { \ + mz_uint bits = b; \ + mz_uint len = l; \ + MZ_ASSERT(bits <= ((1U << len) - 1U)); \ + d->m_bit_buffer |= (bits << d->m_bits_in); \ + d->m_bits_in += len; \ + while (d->m_bits_in >= 8) { \ + if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ + *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ + d->m_bit_buffer >>= 8; \ + d->m_bits_in -= 8; \ + } \ + } \ + MZ_MACRO_END -#define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \ - if (rle_repeat_count < 3) { \ - d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ - while (rle_repeat_count--) packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ - } else { \ - d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); packed_code_sizes[num_packed_code_sizes++] = 16; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ -} rle_repeat_count = 0; } } +#define TDEFL_RLE_PREV_CODE_SIZE() \ + { \ + if (rle_repeat_count) { \ + if (rle_repeat_count < 3) { \ + d->m_huff_count[2][prev_code_size] = (mz_uint16)( \ + d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ + while (rle_repeat_count--) \ + packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ + } else { \ + d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 16; \ + packed_code_sizes[num_packed_code_sizes++] = \ + (mz_uint8)(rle_repeat_count - 3); \ + } \ + rle_repeat_count = 0; \ + } \ + } -#define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \ - if (rle_z_count < 3) { \ - d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \ - } else if (rle_z_count <= 10) { \ - d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); packed_code_sizes[num_packed_code_sizes++] = 17; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ - } else { \ - d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); packed_code_sizes[num_packed_code_sizes++] = 18; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ -} rle_z_count = 0; } } +#define TDEFL_RLE_ZERO_CODE_SIZE() \ + { \ + if (rle_z_count) { \ + if (rle_z_count < 3) { \ + d->m_huff_count[2][0] = \ + (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); \ + while (rle_z_count--) \ + packed_code_sizes[num_packed_code_sizes++] = 0; \ + } else if (rle_z_count <= 10) { \ + d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 17; \ + packed_code_sizes[num_packed_code_sizes++] = \ + (mz_uint8)(rle_z_count - 3); \ + } else { \ + d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); \ + packed_code_sizes[num_packed_code_sizes++] = 18; \ + packed_code_sizes[num_packed_code_sizes++] = \ + (mz_uint8)(rle_z_count - 11); \ + } \ + rle_z_count = 0; \ + } \ + } -static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; +static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; -static void tdefl_start_dynamic_block(tdefl_compressor *d) -{ - int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; - mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; +static void tdefl_start_dynamic_block(tdefl_compressor *d) { + int num_lit_codes, num_dist_codes, num_bit_lengths; + mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, + rle_repeat_count, packed_code_sizes_index; + mz_uint8 + code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], + packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], + prev_code_size = 0xFF; d->m_huff_count[0][256] = 1; tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); - for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; - for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; + for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) + if (d->m_huff_code_sizes[0][num_lit_codes - 1]) + break; + for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) + if (d->m_huff_code_sizes[1][num_dist_codes - 1]) + break; - memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); - memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); - total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0; + memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], + sizeof(mz_uint8) * num_lit_codes); + memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], + sizeof(mz_uint8) * num_dist_codes); + total_code_sizes_to_pack = num_lit_codes + num_dist_codes; + num_packed_code_sizes = 0; + rle_z_count = 0; + rle_repeat_count = 0; - memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); - for (i = 0; i < total_code_sizes_to_pack; i++) - { + memset(&d->m_huff_count[2][0], 0, + sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); + for (i = 0; i < total_code_sizes_to_pack; i++) { mz_uint8 code_size = code_sizes_to_pack[i]; - if (!code_size) - { + if (!code_size) { TDEFL_RLE_PREV_CODE_SIZE(); - if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); } - } - else - { - TDEFL_RLE_ZERO_CODE_SIZE(); - if (code_size != prev_code_size) - { - TDEFL_RLE_PREV_CODE_SIZE(); - d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size; + if (++rle_z_count == 138) { + TDEFL_RLE_ZERO_CODE_SIZE(); } - else if (++rle_repeat_count == 6) - { + } else { + TDEFL_RLE_ZERO_CODE_SIZE(); + if (code_size != prev_code_size) { + TDEFL_RLE_PREV_CODE_SIZE(); + d->m_huff_count[2][code_size] = + (mz_uint16)(d->m_huff_count[2][code_size] + 1); + packed_code_sizes[num_packed_code_sizes++] = code_size; + } else if (++rle_repeat_count == 6) { TDEFL_RLE_PREV_CODE_SIZE(); } } prev_code_size = code_size; } - if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); } + if (rle_repeat_count) { + TDEFL_RLE_PREV_CODE_SIZE(); + } else { + TDEFL_RLE_ZERO_CODE_SIZE(); + } tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); @@ -1991,27 +2856,39 @@ static void tdefl_start_dynamic_block(tdefl_compressor *d) TDEFL_PUT_BITS(num_lit_codes - 257, 5); TDEFL_PUT_BITS(num_dist_codes - 1, 5); - for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break; - num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4); - for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); + for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) + if (d->m_huff_code_sizes + [2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) + break; + num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); + TDEFL_PUT_BITS(num_bit_lengths - 4, 4); + for (i = 0; (int)i < num_bit_lengths; i++) + TDEFL_PUT_BITS( + d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); - for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes; ) - { - mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); + for (packed_code_sizes_index = 0; + packed_code_sizes_index < num_packed_code_sizes;) { + mz_uint code = packed_code_sizes[packed_code_sizes_index++]; + MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); - if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); + if (code >= 16) + TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], + "\02\03\07"[code - 16]); } } -static void tdefl_start_static_block(tdefl_compressor *d) -{ +static void tdefl_start_static_block(tdefl_compressor *d) { mz_uint i; mz_uint8 *p = &d->m_huff_code_sizes[0][0]; - for (i = 0; i <= 143; ++i) *p++ = 8; - for ( ; i <= 255; ++i) *p++ = 9; - for ( ; i <= 279; ++i) *p++ = 7; - for ( ; i <= 287; ++i) *p++ = 8; + for (i = 0; i <= 143; ++i) + *p++ = 8; + for (; i <= 255; ++i) + *p++ = 9; + for (; i <= 279; ++i) + *p++ = 7; + for (; i <= 287; ++i) + *p++ = 8; memset(d->m_huff_code_sizes[1], 5, 32); @@ -2021,11 +2898,13 @@ static void tdefl_start_static_block(tdefl_compressor *d) TDEFL_PUT_BITS(1, 2); } -static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; +static const mz_uint mz_bitmasks[17] = { + 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, + 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF}; -#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS -static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) -{ +#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && \ + MINIZ_HAS_64BIT_REGISTERS +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { mz_uint flags; mz_uint8 *pLZ_codes; mz_uint8 *pOutput_buf = d->m_pOutput_buf; @@ -2033,22 +2912,29 @@ static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) mz_uint64 bit_buffer = d->m_bit_buffer; mz_uint bits_in = d->m_bits_in; -#define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); } +#define TDEFL_PUT_BITS_FAST(b, l) \ + { \ + bit_buffer |= (((mz_uint64)(b)) << bits_in); \ + bits_in += (l); \ + } flags = 1; - for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) - { + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; + flags >>= 1) { if (flags == 1) flags = *pLZ_codes++ | 0x100; - if (flags & 1) - { + if (flags & 1) { mz_uint s0, s1, n0, n1, sym, num_extra_bits; - mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3; + mz_uint match_len = pLZ_codes[0], + match_dist = *(const mz_uint16 *)(pLZ_codes + 1); + pLZ_codes += 3; MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], + d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], + s_tdefl_len_extra[match_len]); // This sequence coaxes MSVC into using cmov's vs. jmp's. s0 = s_tdefl_small_dist_sym[match_dist & 511]; @@ -2059,28 +2945,29 @@ static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) num_extra_bits = (match_dist < 512) ? n0 : n1; MZ_ASSERT(d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); - TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); - } - else - { + TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], + d->m_huff_code_sizes[1][sym]); + TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], + num_extra_bits); + } else { mz_uint lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], + d->m_huff_code_sizes[0][lit]); - if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) - { + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { flags >>= 1; lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], + d->m_huff_code_sizes[0][lit]); - if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) - { + if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { flags >>= 1; lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); - TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); + TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], + d->m_huff_code_sizes[0][lit]); } } } @@ -2088,7 +2975,7 @@ static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) if (pOutput_buf >= d->m_pOutput_buf_end) return MZ_FALSE; - *(mz_uint64*)pOutput_buf = bit_buffer; + *(mz_uint64 *)pOutput_buf = bit_buffer; pOutput_buf += (bits_in >> 3); bit_buffer >>= (bits_in & ~7); bits_in &= 7; @@ -2100,8 +2987,7 @@ static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) d->m_bits_in = 0; d->m_bit_buffer = 0; - while (bits_in) - { + while (bits_in) { mz_uint32 n = MZ_MIN(bits_in, 16); TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); bit_buffer >>= n; @@ -2113,39 +2999,37 @@ static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) return (d->m_pOutput_buf < d->m_pOutput_buf_end); } #else -static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) -{ +static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { mz_uint flags; mz_uint8 *pLZ_codes; flags = 1; - for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) - { + for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; + flags >>= 1) { if (flags == 1) flags = *pLZ_codes++ | 0x100; - if (flags & 1) - { + if (flags & 1) { mz_uint sym, num_extra_bits; - mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3; + mz_uint match_len = pLZ_codes[0], + match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); + pLZ_codes += 3; MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); - TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); + TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], + d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); + TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], + s_tdefl_len_extra[match_len]); - if (match_dist < 512) - { - sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + if (match_dist < 512) { + sym = s_tdefl_small_dist_sym[match_dist]; + num_extra_bits = s_tdefl_small_dist_extra[match_dist]; + } else { + sym = s_tdefl_large_dist_sym[match_dist >> 8]; + num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; } - else - { - sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; - } - MZ_ASSERT(d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); - } - else - { + } else { mz_uint lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); @@ -2156,10 +3040,10 @@ static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) return (d->m_pOutput_buf < d->m_pOutput_buf_end); } -#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS +#endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && + // MINIZ_HAS_64BIT_REGISTERS -static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) -{ +static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) { if (static_block) tdefl_start_static_block(d); else @@ -2167,13 +3051,18 @@ static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) return tdefl_compress_lz_codes(d); } -static int tdefl_flush_block(tdefl_compressor *d, int flush) -{ +static int tdefl_flush_block(tdefl_compressor *d, int flush) { mz_uint saved_bit_buf, saved_bits_in; mz_uint8 *pSaved_output_buf; mz_bool comp_block_succeeded = MZ_FALSE; - int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; - mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; + int n, use_raw_block = + ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && + (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; + mz_uint8 *pOutput_buf_start = + ((d->m_pPut_buf_func == NULL) && + ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) + ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) + : d->m_output_buf; d->m_pOutput_buf = pOutput_buf_start; d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; @@ -2185,82 +3074,106 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); - if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) - { - TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8); + if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) { + TDEFL_PUT_BITS(0x78, 8); + TDEFL_PUT_BITS(0x01, 8); } TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); - pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in; + pSaved_output_buf = d->m_pOutput_buf; + saved_bit_buf = d->m_bit_buffer; + saved_bits_in = d->m_bits_in; if (!use_raw_block) - comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); + comp_block_succeeded = + tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || + (d->m_total_lz_bytes < 48)); - // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. - if ( ((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && - ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size) ) - { - mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + // If the block gets expanded, forget the current contents of the output + // buffer and send a raw block instead. + if (((use_raw_block) || + ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= + d->m_total_lz_bytes))) && + ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size)) { + mz_uint i; + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; TDEFL_PUT_BITS(0, 2); - if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } - for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) - { + if (d->m_bits_in) { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) { TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); } - for (i = 0; i < d->m_total_lz_bytes; ++i) - { - TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); + for (i = 0; i < d->m_total_lz_bytes; ++i) { + TDEFL_PUT_BITS( + d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], + 8); } } - // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. - else if (!comp_block_succeeded) - { - d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; + // Check for the extremely unlikely (if not impossible) case of the compressed + // block not fitting into the output buffer when using dynamic codes. + else if (!comp_block_succeeded) { + d->m_pOutput_buf = pSaved_output_buf; + d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; tdefl_compress_block(d, MZ_TRUE); } - if (flush) - { - if (flush == TDEFL_FINISH) - { - if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } - if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } } - } - else - { - mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); } + if (flush) { + if (flush == TDEFL_FINISH) { + if (d->m_bits_in) { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { + mz_uint i, a = d->m_adler32; + for (i = 0; i < 4; i++) { + TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); + a <<= 8; + } + } + } else { + mz_uint i, z = 0; + TDEFL_PUT_BITS(0, 3); + if (d->m_bits_in) { + TDEFL_PUT_BITS(0, 8 - d->m_bits_in); + } + for (i = 2; i; --i, z ^= 0xFFFF) { + TDEFL_PUT_BITS(z & 0xFFFF, 16); + } } } MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + memset(&d->m_huff_count[0][0], 0, + sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, + sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); - d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; + d->m_total_lz_bytes = 0; + d->m_block_index++; - if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) - { - if (d->m_pPut_buf_func) - { + if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) { + if (d->m_pPut_buf_func) { *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); - } - else if (pOutput_buf_start == d->m_output_buf) - { - int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); - memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); + } else if (pOutput_buf_start == d->m_output_buf) { + int bytes_to_copy = (int)MZ_MIN( + (size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, + bytes_to_copy); d->m_out_buf_ofs += bytes_to_copy; - if ((n -= bytes_to_copy) != 0) - { + if ((n -= bytes_to_copy) != 0) { d->m_output_flush_ofs = bytes_to_copy; d->m_output_flush_remaining = n; } - } - else - { + } else { d->m_out_buf_ofs += n; } } @@ -2269,133 +3182,192 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) } #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES -#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p) -static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) -{ - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; +#define TDEFL_READ_UNALIGNED_WORD(p) ((p)[0] | (p)[1] << 8) +static MZ_FORCEINLINE void +tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, + mz_uint max_match_len, mz_uint *pMatch_dist, + mz_uint *pMatch_len) { + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, + match_len = *pMatch_len, probe_pos = pos, next_probe_pos, + probe_len; mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; - const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q; - mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s); - MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; - for ( ; ; ) - { - for ( ; ; ) - { - if (--num_probes_left == 0) return; - #define TDEFL_PROBE \ - next_probe_pos = d->m_next[probe_pos]; \ - if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ - probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ - if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break; - TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; + const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q; + mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), + s01 = *s; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) + return; + for (;;) { + for (;;) { + if (--num_probes_left == 0) + return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || \ + ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; } - if (!dist) break; q = (const mz_uint16*)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; p = s; probe_len = 32; - do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && - (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); - if (!probe_len) - { - *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break; - } - else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len) - { - *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break; + if (!dist) + break; + q = (const mz_uint16 *)(d->m_dict + probe_pos); + if (*q != s01) + continue; + p = s; + probe_len = 32; + do { + } while ((*(++p) == *(++q)) && (*(++p) == *(++q)) && (*(++p) == *(++q)) && + (*(++p) == *(++q)) && (--probe_len > 0)); + if (!probe_len) { + *pMatch_dist = dist; + *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); + break; + } else if ((probe_len = ((mz_uint)(p - s) * 2) + + (mz_uint)(*(const mz_uint8 *)p == + *(const mz_uint8 *)q)) > match_len) { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == + max_match_len) + break; c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); } } } #else -static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) -{ - mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; +static MZ_FORCEINLINE void +tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, + mz_uint max_match_len, mz_uint *pMatch_dist, + mz_uint *pMatch_len) { + mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, + match_len = *pMatch_len, probe_pos = pos, next_probe_pos, + probe_len; mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; const mz_uint8 *s = d->m_dict + pos, *p, *q; mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; - MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; - for ( ; ; ) - { - for ( ; ; ) - { - if (--num_probes_left == 0) return; - #define TDEFL_PROBE \ - next_probe_pos = d->m_next[probe_pos]; \ - if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ - probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ - if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break; - TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; + MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); + if (max_match_len <= match_len) + return; + for (;;) { + for (;;) { + if (--num_probes_left == 0) + return; +#define TDEFL_PROBE \ + next_probe_pos = d->m_next[probe_pos]; \ + if ((!next_probe_pos) || \ + ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \ + return; \ + probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ + if ((d->m_dict[probe_pos + match_len] == c0) && \ + (d->m_dict[probe_pos + match_len - 1] == c1)) \ + break; + TDEFL_PROBE; + TDEFL_PROBE; + TDEFL_PROBE; } - if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break; - if (probe_len > match_len) - { - *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return; - c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1]; + if (!dist) + break; + p = s; + q = d->m_dict + probe_pos; + for (probe_len = 0; probe_len < max_match_len; probe_len++) + if (*p++ != *q++) + break; + if (probe_len > match_len) { + *pMatch_dist = dist; + if ((*pMatch_len = match_len = probe_len) == max_match_len) + return; + c0 = d->m_dict[pos + match_len]; + c1 = d->m_dict[pos + match_len - 1]; } } } #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -static mz_bool tdefl_compress_fast(tdefl_compressor *d) -{ - // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. - mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; +static mz_bool tdefl_compress_fast(tdefl_compressor *d) { + // Faster, minimally featured LZRW1-style match+parse loop with better + // register utilization. Intended for applications where raw throughput is + // valued more highly than ratio. + mz_uint lookahead_pos = d->m_lookahead_pos, + lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, + total_lz_bytes = d->m_total_lz_bytes, + num_flags_left = d->m_num_flags_left; mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) - { + while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) { const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; - mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; - mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); + mz_uint dst_pos = + (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN( + d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); d->m_src_buf_left -= num_bytes_to_process; lookahead_size += num_bytes_to_process; - while (num_bytes_to_process) - { + while (num_bytes_to_process) { mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); memcpy(d->m_dict + dst_pos, d->m_pSrc, n); if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) - memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); + memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, + MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); d->m_pSrc += n; dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; num_bytes_to_process -= n; } dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); - if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break; + if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) + break; - while (lookahead_size >= 4) - { + while (lookahead_size >= 4) { mz_uint cur_match_dist, cur_match_len = 1; mz_uint8 *pCur_dict = d->m_dict + cur_pos; mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; - mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; + mz_uint hash = + (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & + TDEFL_LEVEL1_HASH_SIZE_MASK; mz_uint probe_pos = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)lookahead_pos; - if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) - { + if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= + dict_size) && + ((mz_uint32)( + *(d->m_dict + (probe_pos & TDEFL_LZ_DICT_SIZE_MASK)) | + (*(d->m_dict + ((probe_pos & TDEFL_LZ_DICT_SIZE_MASK) + 1)) + << 8) | + (*(d->m_dict + ((probe_pos & TDEFL_LZ_DICT_SIZE_MASK) + 2)) + << 16)) == first_trigram)) { const mz_uint16 *p = (const mz_uint16 *)pCur_dict; - const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); + const mz_uint16 *q = + (const mz_uint16 *)(d->m_dict + + (probe_pos & TDEFL_LZ_DICT_SIZE_MASK)); mz_uint32 probe_len = 32; - do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && - (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); - cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); + do { + } while ((*(++p) == *(++q)) && (*(++p) == *(++q)) && + (*(++p) == *(++q)) && (*(++p) == *(++q)) && (--probe_len > 0)); + cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); if (!probe_len) cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; - if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U))) - { + if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || + ((cur_match_len == TDEFL_MIN_MATCH_LEN) && + (cur_match_dist >= 8U * 1024U))) { cur_match_len = 1; *pLZ_code_buf++ = (mz_uint8)first_trigram; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); d->m_huff_count[0][(mz_uint8)first_trigram]++; - } - else - { + } else { mz_uint32 s0, s1; cur_match_len = MZ_MIN(cur_match_len, lookahead_size); - MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); + MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && + (cur_match_dist >= 1) && + (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); cur_match_dist--; @@ -2408,17 +3380,19 @@ static mz_bool tdefl_compress_fast(tdefl_compressor *d) s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; - d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; + d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - + TDEFL_MIN_MATCH_LEN]]++; } - } - else - { + } else { *pLZ_code_buf++ = (mz_uint8)first_trigram; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); d->m_huff_count[0][(mz_uint8)first_trigram]++; } - if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } + if (--num_flags_left == 0) { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } total_lz_bytes += cur_match_len; lookahead_pos += cur_match_len; @@ -2427,25 +3401,34 @@ static mz_bool tdefl_compress_fast(tdefl_compressor *d) MZ_ASSERT(lookahead_size >= cur_match_len); lookahead_size -= cur_match_len; - if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) - { + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { int n; - d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; - total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; } } - while (lookahead_size) - { + while (lookahead_size) { mz_uint8 lit = d->m_dict[cur_pos]; total_lz_bytes++; *pLZ_code_buf++ = lit; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); - if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } + if (--num_flags_left == 0) { + num_flags_left = 8; + pLZ_flags = pLZ_code_buf++; + } d->m_huff_count[0][lit]++; @@ -2454,37 +3437,54 @@ static mz_bool tdefl_compress_fast(tdefl_compressor *d) cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; lookahead_size--; - if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) - { + if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { int n; - d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; - total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; + total_lz_bytes = d->m_total_lz_bytes; + pLZ_code_buf = d->m_pLZ_code_buf; + pLZ_flags = d->m_pLZ_flags; + num_flags_left = d->m_num_flags_left; } } } - d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; - d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; + d->m_lookahead_pos = lookahead_pos; + d->m_lookahead_size = lookahead_size; + d->m_dict_size = dict_size; + d->m_total_lz_bytes = total_lz_bytes; + d->m_pLZ_code_buf = pLZ_code_buf; + d->m_pLZ_flags = pLZ_flags; + d->m_num_flags_left = num_flags_left; return MZ_TRUE; } #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN -static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) -{ +static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, + mz_uint8 lit) { d->m_total_lz_bytes++; *d->m_pLZ_code_buf++ = lit; - *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } + *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); + if (--d->m_num_flags_left == 0) { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } d->m_huff_count[0][lit]++; } -static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) -{ +static MZ_FORCEINLINE void +tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) { mz_uint32 s0, s1; - MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); + MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && + (match_dist <= TDEFL_LZ_DICT_SIZE)); d->m_total_lz_bytes += match_len; @@ -2492,145 +3492,176 @@ static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match match_dist -= 1; d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); - d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3; + d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); + d->m_pLZ_code_buf += 3; - *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } + *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); + if (--d->m_num_flags_left == 0) { + d->m_num_flags_left = 8; + d->m_pLZ_flags = d->m_pLZ_code_buf++; + } - s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; + s0 = s_tdefl_small_dist_sym[match_dist & 511]; + s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; - if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; + if (match_len >= TDEFL_MIN_MATCH_LEN) + d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; } -static mz_bool tdefl_compress_normal(tdefl_compressor *d) -{ - const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left; +static mz_bool tdefl_compress_normal(tdefl_compressor *d) { + const mz_uint8 *pSrc = d->m_pSrc; + size_t src_buf_left = d->m_src_buf_left; tdefl_flush flush = d->m_flush; - while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) - { + while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) { mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; - // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. - if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) - { - mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; - mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; - mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); + // Update dictionary and hash chains. Keeps the lookahead size equal to + // TDEFL_MAX_MATCH_LEN. + if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) { + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & + TDEFL_LZ_DICT_SIZE_MASK, + ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; + mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] + << TDEFL_LZ_HASH_SHIFT) ^ + d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; + mz_uint num_bytes_to_process = (mz_uint)MZ_MIN( + src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; src_buf_left -= num_bytes_to_process; d->m_lookahead_size += num_bytes_to_process; - while (pSrc != pSrc_end) - { - mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; - hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); - d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); - dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++; - } - } - else - { - while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) - { + while (pSrc != pSrc_end) { mz_uint8 c = *pSrc++; - mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; + d->m_dict[dst_pos] = c; + if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) + d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; + hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); + dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; + ins_pos++; + } + } else { + while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) { + mz_uint8 c = *pSrc++; + mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & + TDEFL_LZ_DICT_SIZE_MASK; src_buf_left--; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; - if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) - { + if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) { mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; - mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); - d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); + mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] + << (TDEFL_LZ_HASH_SHIFT * 2)) ^ + (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] + << TDEFL_LZ_HASH_SHIFT) ^ + c) & + (TDEFL_LZ_HASH_SIZE - 1); + d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; + d->m_hash[hash] = (mz_uint16)(ins_pos); } } } - d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); + d->m_dict_size = + MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) break; // Simple lazy/greedy parsing state machine. - len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; - if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) - { - if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) - { + len_to_move = 1; + cur_match_dist = 0; + cur_match_len = + d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); + cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; + if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) { + if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) { mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; - cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; } - if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1; + cur_match_len = 0; + while (cur_match_len < d->m_lookahead_size) { + if (d->m_dict[cur_pos + cur_match_len] != c) + break; + cur_match_len++; + } + if (cur_match_len < TDEFL_MIN_MATCH_LEN) + cur_match_len = 0; + else + cur_match_dist = 1; } + } else { + tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, + d->m_lookahead_size, &cur_match_dist, &cur_match_len); } - else - { - tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); - } - if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) - { + if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && + (cur_match_dist >= 8U * 1024U)) || + (cur_pos == cur_match_dist) || + ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) { cur_match_dist = cur_match_len = 0; } - if (d->m_saved_match_len) - { - if (cur_match_len > d->m_saved_match_len) - { + if (d->m_saved_match_len) { + if (cur_match_len > d->m_saved_match_len) { tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); - if (cur_match_len >= 128) - { + if (cur_match_len >= 128) { tdefl_record_match(d, cur_match_len, cur_match_dist); - d->m_saved_match_len = 0; len_to_move = cur_match_len; + d->m_saved_match_len = 0; + len_to_move = cur_match_len; + } else { + d->m_saved_lit = d->m_dict[cur_pos]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; } - else - { - d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; - } - } - else - { + } else { tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); - len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0; + len_to_move = d->m_saved_match_len - 1; + d->m_saved_match_len = 0; } - } - else if (!cur_match_dist) - tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); - else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) - { + } else if (!cur_match_dist) + tdefl_record_literal(d, + d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); + else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || + (cur_match_len >= 128)) { tdefl_record_match(d, cur_match_len, cur_match_dist); len_to_move = cur_match_len; - } - else - { - d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; + } else { + d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; + d->m_saved_match_dist = cur_match_dist; + d->m_saved_match_len = cur_match_len; } // Move the lookahead forward by len_to_move bytes. d->m_lookahead_pos += len_to_move; MZ_ASSERT(d->m_lookahead_size >= len_to_move); d->m_lookahead_size -= len_to_move; d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE); - // Check if it's time to flush the current LZ codes to the internal output buffer. - if ( (d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || - ( (d->m_total_lz_bytes > 31*1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) ) - { + // Check if it's time to flush the current LZ codes to the internal output + // buffer. + if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || + ((d->m_total_lz_bytes > 31 * 1024) && + (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= + d->m_total_lz_bytes) || + (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))) { int n; - d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; } } - d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; + d->m_pSrc = pSrc; + d->m_src_buf_left = src_buf_left; return MZ_TRUE; } -static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) -{ - if (d->m_pIn_buf_size) - { +static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) { + if (d->m_pIn_buf_size) { *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; } - if (d->m_pOut_buf_size) - { - size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); - memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); + if (d->m_pOut_buf_size) { + size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, + d->m_output_flush_remaining); + memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, + d->m_output_buf + d->m_output_flush_ofs, n); d->m_output_flush_ofs += (mz_uint)n; d->m_output_flush_remaining -= (mz_uint)n; d->m_out_buf_ofs += n; @@ -2638,29 +3669,40 @@ static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) *d->m_pOut_buf_size = d->m_out_buf_ofs; } - return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; + return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE + : TDEFL_STATUS_OKAY; } -tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) -{ - if (!d) - { - if (pIn_buf_size) *pIn_buf_size = 0; - if (pOut_buf_size) *pOut_buf_size = 0; +tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, + size_t *pIn_buf_size, void *pOut_buf, + size_t *pOut_buf_size, tdefl_flush flush) { + if (!d) { + if (pIn_buf_size) + *pIn_buf_size = 0; + if (pOut_buf_size) + *pOut_buf_size = 0; return TDEFL_STATUS_BAD_PARAM; } - d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size; - d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size; - d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; + d->m_pIn_buf = pIn_buf; + d->m_pIn_buf_size = pIn_buf_size; + d->m_pOut_buf = pOut_buf; + d->m_pOut_buf_size = pOut_buf_size; + d->m_pSrc = (const mz_uint8 *)(pIn_buf); + d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; d->m_out_buf_ofs = 0; d->m_flush = flush; - if ( ((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || - (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf) ) - { - if (pIn_buf_size) *pIn_buf_size = 0; - if (pOut_buf_size) *pOut_buf_size = 0; + if (((d->m_pPut_buf_func != NULL) == + ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || + (d->m_prev_return_status != TDEFL_STATUS_OKAY) || + (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || + (pIn_buf_size && *pIn_buf_size && !pIn_buf) || + (pOut_buf_size && *pOut_buf_size && !pOut_buf)) { + if (pIn_buf_size) + *pIn_buf_size = 0; + if (pOut_buf_size) + *pOut_buf_size = 0; return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); } d->m_wants_to_finish |= (flush == TDEFL_FINISH); @@ -2671,179 +3713,329 @@ tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pI #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && - ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) - { + ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | + TDEFL_RLE_MATCHES)) == 0)) { if (!tdefl_compress_fast(d)) return d->m_prev_return_status; - } - else + } else #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN { if (!tdefl_compress_normal(d)) return d->m_prev_return_status; } - if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) - d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); + if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && + (pIn_buf)) + d->m_adler32 = + (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, + d->m_pSrc - (const mz_uint8 *)pIn_buf); - if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) - { + if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && + (!d->m_output_flush_remaining)) { if (tdefl_flush_block(d, flush) < 0) return d->m_prev_return_status; d->m_finished = (flush == TDEFL_FINISH); - if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; } + if (flush == TDEFL_FULL_FLUSH) { + MZ_CLEAR_OBJ(d->m_hash); + MZ_CLEAR_OBJ(d->m_next); + d->m_dict_size = 0; + } } return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); } -tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) -{ - MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); +tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, + size_t in_buf_size, tdefl_flush flush) { + MZ_ASSERT(d->m_pPut_buf_func); + return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); } -tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ - d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user; - d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; +tdefl_status tdefl_init(tdefl_compressor *d, + tdefl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags) { + d->m_pPut_buf_func = pPut_buf_func; + d->m_pPut_buf_user = pPut_buf_user; + d->m_flags = (mz_uint)(flags); + d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; + d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; - if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); - d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; - d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; - d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; - d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY; - d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1; - d->m_pIn_buf = NULL; d->m_pOut_buf = NULL; - d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL; - d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; - memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); - memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); + if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) + MZ_CLEAR_OBJ(d->m_hash); + d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = + d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; + d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = + d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; + d->m_pLZ_code_buf = d->m_lz_code_buf + 1; + d->m_pLZ_flags = d->m_lz_code_buf; + d->m_num_flags_left = 8; + d->m_pOutput_buf = d->m_output_buf; + d->m_pOutput_buf_end = d->m_output_buf; + d->m_prev_return_status = TDEFL_STATUS_OKAY; + d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; + d->m_adler32 = 1; + d->m_pIn_buf = NULL; + d->m_pOut_buf = NULL; + d->m_pIn_buf_size = NULL; + d->m_pOut_buf_size = NULL; + d->m_flush = TDEFL_NO_FLUSH; + d->m_pSrc = NULL; + d->m_src_buf_left = 0; + d->m_out_buf_ofs = 0; + memset(&d->m_huff_count[0][0], 0, + sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); + memset(&d->m_huff_count[1][0], 0, + sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); return TDEFL_STATUS_OKAY; } -tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) -{ +tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) { return d->m_prev_return_status; } -mz_uint32 tdefl_get_adler32(tdefl_compressor *d) -{ - return d->m_adler32; +mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { return d->m_adler32; } + +mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, + tdefl_put_buf_func_ptr pPut_buf_func, + void *pPut_buf_user, int flags) { + tdefl_compressor *pComp; + mz_bool succeeded; + if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) + return MZ_FALSE; + pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + if (!pComp) + return MZ_FALSE; + succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == + TDEFL_STATUS_OKAY); + succeeded = + succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == + TDEFL_STATUS_DONE); + MZ_FREE(pComp); + return succeeded; } -mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) -{ - tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; - pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE; - succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); - succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); - MZ_FREE(pComp); return succeeded; -} - -typedef struct -{ +typedef struct { size_t m_size, m_capacity; mz_uint8 *m_pBuf; mz_bool m_expandable; } tdefl_output_buffer; -static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) -{ +static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, + void *pUser) { tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; size_t new_size = p->m_size + len; - if (new_size > p->m_capacity) - { - size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE; - do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity); - pNew_buf = (mz_uint8*)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE; - p->m_pBuf = pNew_buf; p->m_capacity = new_capacity; + if (new_size > p->m_capacity) { + size_t new_capacity = p->m_capacity; + mz_uint8 *pNew_buf; + if (!p->m_expandable) + return MZ_FALSE; + do { + new_capacity = MZ_MAX(128U, new_capacity << 1U); + } while (new_size > new_capacity); + pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity); + if (!pNew_buf) + return MZ_FALSE; + p->m_pBuf = pNew_buf; + p->m_capacity = new_capacity; } - memcpy((mz_uint8*)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size; + memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len); + p->m_size = new_size; return MZ_TRUE; } -void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) -{ - tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); - if (!pOut_len) return MZ_FALSE; else *pOut_len = 0; +void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, + size_t *pOut_len, int flags) { + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_len) + return MZ_FALSE; + else + *pOut_len = 0; out_buf.m_expandable = MZ_TRUE; - if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL; - *pOut_len = out_buf.m_size; return out_buf.m_pBuf; + if (!tdefl_compress_mem_to_output( + pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) + return NULL; + *pOut_len = out_buf.m_size; + return out_buf.m_pBuf; } -size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) -{ - tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); - if (!pOut_buf) return 0; - out_buf.m_pBuf = (mz_uint8*)pOut_buf; out_buf.m_capacity = out_buf_len; - if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0; +size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, + const void *pSrc_buf, size_t src_buf_len, + int flags) { + tdefl_output_buffer out_buf; + MZ_CLEAR_OBJ(out_buf); + if (!pOut_buf) + return 0; + out_buf.m_pBuf = (mz_uint8 *)pOut_buf; + out_buf.m_capacity = out_buf_len; + if (!tdefl_compress_mem_to_output( + pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) + return 0; return out_buf.m_size; } #ifndef MINIZ_NO_ZLIB_APIS -static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; +static const mz_uint s_tdefl_num_probes[11] = {0, 1, 6, 32, 16, 32, + 128, 256, 512, 768, 1500}; -// level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). -mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) -{ - mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); - if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; +// level may actually range from [0,10] (10 is a "hidden" max level, where we +// want a bit more compression and it's fine if throughput to fall off a cliff +// on some files). +mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, + int strategy) { + mz_uint comp_flags = + s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | + ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); + if (window_bits > 0) + comp_flags |= TDEFL_WRITE_ZLIB_HEADER; - if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; - else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES; - else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK; - else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; - else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES; + if (!level) + comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; + else if (strategy == MZ_FILTERED) + comp_flags |= TDEFL_FILTER_MATCHES; + else if (strategy == MZ_HUFFMAN_ONLY) + comp_flags &= ~TDEFL_MAX_PROBES_MASK; + else if (strategy == MZ_FIXED) + comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; + else if (strategy == MZ_RLE) + comp_flags |= TDEFL_RLE_MATCHES; return comp_flags; } -#endif //MINIZ_NO_ZLIB_APIS +#endif // MINIZ_NO_ZLIB_APIS #ifdef _MSC_VER -#pragma warning (push) -#pragma warning (disable:4204) // nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) +#pragma warning(push) +#pragma warning(disable : 4204) // nonstandard extension used : non-constant + // aggregate initializer (also supported by GNU + // C and C99, so no big deal) #endif -// Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at +// Simple PNG writer function by Alex Evans, 2011. Released into the public +// domain: https://gist.github.com/908299, more context at // http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. -// This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. -void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) -{ - // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. - static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; - tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0; - if (!pComp) return NULL; - MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57+MZ_MAX(64, (1+bpl)*h); if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; } +// This is actually a modification of Alex's original code so PNG files +// generated by this function pass pngcheck. +void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, + int h, int num_chans, + size_t *pLen_out, + mz_uint level, mz_bool flip) { + // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was + // defined. + static const mz_uint s_tdefl_png_num_probes[11] = { + 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500}; + tdefl_compressor *pComp = + (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); + tdefl_output_buffer out_buf; + int i, bpl = w * num_chans, y, z; + mz_uint32 c; + *pLen_out = 0; + if (!pComp) + return NULL; + MZ_CLEAR_OBJ(out_buf); + out_buf.m_expandable = MZ_TRUE; + out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h); + if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity))) { + MZ_FREE(pComp); + return NULL; + } // write dummy header - for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); + for (z = 41; z; --z) + tdefl_output_buffer_putter(&z, 1, &out_buf); // compress image data - tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); - for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8*)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); } - if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } + tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, + s_tdefl_png_num_probes[MZ_MIN(10, level)] | + TDEFL_WRITE_ZLIB_HEADER); + for (y = 0; y < h; ++y) { + tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); + tdefl_compress_buffer(pComp, + (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, + bpl, TDEFL_NO_FLUSH); + } + if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != + TDEFL_STATUS_DONE) { + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } // write real header - *pLen_out = out_buf.m_size-41; + *pLen_out = out_buf.m_size - 41; { static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06}; - mz_uint8 pnghdr[41]={0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, - 0,0,(mz_uint8)(w>>8),(mz_uint8)w,0,0,(mz_uint8)(h>>8),(mz_uint8)h,8,chans[num_chans],0,0,0,0,0,0,0, - (mz_uint8)(*pLen_out>>24),(mz_uint8)(*pLen_out>>16),(mz_uint8)(*pLen_out>>8),(mz_uint8)*pLen_out,0x49,0x44,0x41,0x54}; - c=(mz_uint32)mz_crc32(MZ_CRC32_INIT,pnghdr+12,17); for (i=0; i<4; ++i, c<<=8) ((mz_uint8*)(pnghdr+29))[i]=(mz_uint8)(c>>24); + mz_uint8 pnghdr[41] = {0x89, + 0x50, + 0x4e, + 0x47, + 0x0d, + 0x0a, + 0x1a, + 0x0a, + 0x00, + 0x00, + 0x00, + 0x0d, + 0x49, + 0x48, + 0x44, + 0x52, + 0, + 0, + (mz_uint8)(w >> 8), + (mz_uint8)w, + 0, + 0, + (mz_uint8)(h >> 8), + (mz_uint8)h, + 8, + chans[num_chans], + 0, + 0, + 0, + 0, + 0, + 0, + 0, + (mz_uint8)(*pLen_out >> 24), + (mz_uint8)(*pLen_out >> 16), + (mz_uint8)(*pLen_out >> 8), + (mz_uint8)*pLen_out, + 0x49, + 0x44, + 0x41, + 0x54}; + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17); + for (i = 0; i < 4; ++i, c <<= 8) + ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24); memcpy(out_buf.m_pBuf, pnghdr, 41); } // write footer (IDAT CRC-32, followed by IEND chunk) - if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } - c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,out_buf.m_pBuf+41-4, *pLen_out+4); for (i=0; i<4; ++i, c<<=8) (out_buf.m_pBuf+out_buf.m_size-16)[i] = (mz_uint8)(c >> 24); + if (!tdefl_output_buffer_putter( + "\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { + *pLen_out = 0; + MZ_FREE(pComp); + MZ_FREE(out_buf.m_pBuf); + return NULL; + } + c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, + *pLen_out + 4); + for (i = 0; i < 4; ++i, c <<= 8) + (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24); // compute final size of file, grab compressed data buffer and return - *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf; + *pLen_out += 57; + MZ_FREE(pComp); + return out_buf.m_pBuf; } -void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) -{ - // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) - return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); +void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, + int num_chans, size_t *pLen_out) { + // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we + // can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's + // where #defined out) + return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, + pLen_out, 6, MZ_FALSE); } #ifdef _MSC_VER -#pragma warning (pop) +#pragma warning(pop) #endif // ------------------- .ZIP archive reading @@ -2851,138 +4043,171 @@ void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, #ifndef MINIZ_NO_ARCHIVE_APIS #ifdef MINIZ_NO_STDIO - #define MZ_FILE void * +#define MZ_FILE void * #else - #include - #include +#include +#include - #if defined(_MSC_VER) || defined(__MINGW64__) - static FILE *mz_fopen(const char *pFilename, const char *pMode) - { - FILE* pFile = NULL; - fopen_s(&pFile, pFilename, pMode); - return pFile; - } - static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) - { - FILE* pFile = NULL; - if (freopen_s(&pFile, pPath, pMode, pStream)) - return NULL; - return pFile; - } - #ifndef MINIZ_NO_TIME - #include - #endif - #define MZ_FILE FILE - #define MZ_FOPEN mz_fopen - #define MZ_FCLOSE fclose - #define MZ_FREAD fread - #define MZ_FWRITE fwrite - #define MZ_FTELL64 _ftelli64 - #define MZ_FSEEK64 _fseeki64 - #define MZ_FILE_STAT_STRUCT _stat - #define MZ_FILE_STAT _stat - #define MZ_FFLUSH fflush - #define MZ_FREOPEN mz_freopen - #define MZ_DELETE_FILE remove - #elif defined(__MINGW32__) - #ifndef MINIZ_NO_TIME - #include - #endif - #define MZ_FILE FILE - #define MZ_FOPEN(f, m) fopen(f, m) - #define MZ_FCLOSE fclose - #define MZ_FREAD fread - #define MZ_FWRITE fwrite - #define MZ_FTELL64 ftello64 - #define MZ_FSEEK64 fseeko64 - #define MZ_FILE_STAT_STRUCT _stat - #define MZ_FILE_STAT _stat - #define MZ_FFLUSH fflush - #define MZ_FREOPEN(f, m, s) freopen(f, m, s) - #define MZ_DELETE_FILE remove - #elif defined(__TINYC__) - #ifndef MINIZ_NO_TIME - #include - #endif - #define MZ_FILE FILE - #define MZ_FOPEN(f, m) fopen(f, m) - #define MZ_FCLOSE fclose - #define MZ_FREAD fread - #define MZ_FWRITE fwrite - #define MZ_FTELL64 ftell - #define MZ_FSEEK64 fseek - #define MZ_FILE_STAT_STRUCT stat - #define MZ_FILE_STAT stat - #define MZ_FFLUSH fflush - #define MZ_FREOPEN(f, m, s) freopen(f, m, s) - #define MZ_DELETE_FILE remove - #elif defined(__GNUC__) && _LARGEFILE64_SOURCE - #ifndef MINIZ_NO_TIME - #include - #endif - #define MZ_FILE FILE - #define MZ_FOPEN(f, m) fopen64(f, m) - #define MZ_FCLOSE fclose - #define MZ_FREAD fread - #define MZ_FWRITE fwrite - #define MZ_FTELL64 ftello64 - #define MZ_FSEEK64 fseeko64 - #define MZ_FILE_STAT_STRUCT stat64 - #define MZ_FILE_STAT stat64 - #define MZ_FFLUSH fflush - #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) - #define MZ_DELETE_FILE remove - #else - #ifndef MINIZ_NO_TIME - #include - #endif - #define MZ_FILE FILE - #define MZ_FOPEN(f, m) fopen(f, m) - #define MZ_FCLOSE fclose - #define MZ_FREAD fread - #define MZ_FWRITE fwrite - #define MZ_FTELL64 ftello - #define MZ_FSEEK64 fseeko - #define MZ_FILE_STAT_STRUCT stat - #define MZ_FILE_STAT stat - #define MZ_FFLUSH fflush - #define MZ_FREOPEN(f, m, s) freopen(f, m, s) - #define MZ_DELETE_FILE remove - #endif // #ifdef _MSC_VER +#if defined(_MSC_VER) +static FILE *mz_fopen(const char *pFilename, const char *pMode) { + FILE *pFile = NULL; + fopen_s(&pFile, pFilename, pMode); + return pFile; +} +static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { + FILE *pFile = NULL; + if (freopen_s(&pFile, pPath, pMode, pStream)) + return NULL; + return pFile; +} +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN mz_fopen +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 _ftelli64 +#define MZ_FSEEK64 _fseeki64 +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN mz_freopen +#define MZ_DELETE_FILE remove +#elif defined(__MINGW32__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftell +#define MZ_FSEEK64 fseek +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#elif defined(__TINYC__) +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftell +#define MZ_FSEEK64 fseek +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#elif defined(__GNUC__) && _LARGEFILE64_SOURCE +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen64(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#define MZ_FTELL64 ftello64 +#define MZ_FSEEK64 fseeko64 +#define MZ_FILE_STAT_STRUCT stat64 +#define MZ_FILE_STAT stat64 +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(p, m, s) freopen64(p, m, s) +#define MZ_DELETE_FILE remove +#else +#ifndef MINIZ_NO_TIME +#include +#endif +#define MZ_FILE FILE +#define MZ_FOPEN(f, m) fopen(f, m) +#define MZ_FCLOSE fclose +#define MZ_FREAD fread +#define MZ_FWRITE fwrite +#if _FILE_OFFSET_BITS == 64 || _POSIX_C_SOURCE >= 200112L +#define MZ_FTELL64 ftello +#define MZ_FSEEK64 fseeko +#else +#define MZ_FTELL64 ftell +#define MZ_FSEEK64 fseek +#endif +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#define MZ_FFLUSH fflush +#define MZ_FREOPEN(f, m, s) freopen(f, m, s) +#define MZ_DELETE_FILE remove +#endif // #ifdef _MSC_VER #endif // #ifdef MINIZ_NO_STDIO #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) -// Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. -enum -{ +// Various ZIP archive enums. To completely avoid cross platform compiler +// alignment and platform endian issues, miniz.c doesn't use structs for any of +// this stuff. +enum { // ZIP archive identifiers and record sizes - MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, - MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, + MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, // Central directory header record offsets - MZ_ZIP_CDH_SIG_OFS = 0, MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, MZ_ZIP_CDH_BIT_FLAG_OFS = 8, - MZ_ZIP_CDH_METHOD_OFS = 10, MZ_ZIP_CDH_FILE_TIME_OFS = 12, MZ_ZIP_CDH_FILE_DATE_OFS = 14, MZ_ZIP_CDH_CRC32_OFS = 16, - MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, - MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, MZ_ZIP_CDH_DISK_START_OFS = 34, MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, + MZ_ZIP_CDH_SIG_OFS = 0, + MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, + MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, + MZ_ZIP_CDH_BIT_FLAG_OFS = 8, + MZ_ZIP_CDH_METHOD_OFS = 10, + MZ_ZIP_CDH_FILE_TIME_OFS = 12, + MZ_ZIP_CDH_FILE_DATE_OFS = 14, + MZ_ZIP_CDH_CRC32_OFS = 16, + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, + MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, + MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, + MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, + MZ_ZIP_CDH_DISK_START_OFS = 34, + MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, + MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, // Local directory header offsets - MZ_ZIP_LDH_SIG_OFS = 0, MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, MZ_ZIP_LDH_BIT_FLAG_OFS = 6, MZ_ZIP_LDH_METHOD_OFS = 8, MZ_ZIP_LDH_FILE_TIME_OFS = 10, - MZ_ZIP_LDH_FILE_DATE_OFS = 12, MZ_ZIP_LDH_CRC32_OFS = 14, MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, - MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, + MZ_ZIP_LDH_SIG_OFS = 0, + MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, + MZ_ZIP_LDH_BIT_FLAG_OFS = 6, + MZ_ZIP_LDH_METHOD_OFS = 8, + MZ_ZIP_LDH_FILE_TIME_OFS = 10, + MZ_ZIP_LDH_FILE_DATE_OFS = 12, + MZ_ZIP_LDH_CRC32_OFS = 14, + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, + MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, + MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, // End of central directory offsets - MZ_ZIP_ECDH_SIG_OFS = 0, MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, - MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, + MZ_ZIP_ECDH_SIG_OFS = 0, + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, + MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, + MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, + MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, }; -typedef struct -{ +typedef struct { void *m_p; size_t m_size, m_capacity; mz_uint m_element_size; } mz_zip_array; -struct mz_zip_internal_state_tag -{ +struct mz_zip_internal_state_tag { mz_zip_array m_central_dir; mz_zip_array m_central_dir_offsets; mz_zip_array m_sorted_central_dir_offsets; @@ -2992,232 +4217,324 @@ struct mz_zip_internal_state_tag size_t m_mem_capacity; }; -#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size -#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] +#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) \ + (array_ptr)->m_element_size = element_size +#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) \ + ((element_type *)((array_ptr)->m_p))[index] -static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) -{ +static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, + mz_zip_array *pArray) { pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); memset(pArray, 0, sizeof(mz_zip_array)); } -static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) -{ - void *pNew_p; size_t new_capacity = min_new_capacity; MZ_ASSERT(pArray->m_element_size); if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; - if (growing) { new_capacity = MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; } - if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE; - pArray->m_p = pNew_p; pArray->m_capacity = new_capacity; +static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, + mz_zip_array *pArray, + size_t min_new_capacity, + mz_uint growing) { + void *pNew_p; + size_t new_capacity = min_new_capacity; + MZ_ASSERT(pArray->m_element_size); + if (pArray->m_capacity >= min_new_capacity) + return MZ_TRUE; + if (growing) { + new_capacity = MZ_MAX(1, pArray->m_capacity); + while (new_capacity < min_new_capacity) + new_capacity *= 2; + } + if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, + pArray->m_element_size, new_capacity))) + return MZ_FALSE; + pArray->m_p = pNew_p; + pArray->m_capacity = new_capacity; return MZ_TRUE; } -static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) -{ - if (new_capacity > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; } +static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, + mz_zip_array *pArray, + size_t new_capacity, + mz_uint growing) { + if (new_capacity > pArray->m_capacity) { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) + return MZ_FALSE; + } return MZ_TRUE; } -static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) -{ - if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; } +static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, + mz_zip_array *pArray, + size_t new_size, + mz_uint growing) { + if (new_size > pArray->m_capacity) { + if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) + return MZ_FALSE; + } pArray->m_size = new_size; return MZ_TRUE; } -static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) -{ +static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, + mz_zip_array *pArray, + size_t n) { return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); } -static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) -{ - if (n==0) return MZ_TRUE; - assert(NULL!=pElements); - size_t orig_size = pArray->m_size; if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE; - memcpy((mz_uint8*)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); +static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, + mz_zip_array *pArray, + const void *pElements, + size_t n) { + if (0 == n) + return MZ_TRUE; + if (!pElements) + return MZ_FALSE; + + size_t orig_size = pArray->m_size; + if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) + return MZ_FALSE; + memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, + pElements, n * pArray->m_element_size); return MZ_TRUE; } #ifndef MINIZ_NO_TIME -static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) -{ +static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) { struct tm tm; - memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1; - tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31; - tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62; + memset(&tm, 0, sizeof(tm)); + tm.tm_isdst = -1; + tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; + tm.tm_mon = ((dos_date >> 5) & 15) - 1; + tm.tm_mday = dos_date & 31; + tm.tm_hour = (dos_time >> 11) & 31; + tm.tm_min = (dos_time >> 5) & 63; + tm.tm_sec = (dos_time << 1) & 62; return mktime(&tm); } -static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) -{ +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +static void mz_zip_time_t_to_dos_time(time_t time, mz_uint16 *pDOS_time, + mz_uint16 *pDOS_date) { #ifdef _MSC_VER struct tm tm_struct; struct tm *tm = &tm_struct; errno_t err = localtime_s(tm, &time); - if (err) - { - *pDOS_date = 0; *pDOS_time = 0; + if (err) { + *pDOS_date = 0; + *pDOS_time = 0; return; } #else struct tm *tm = localtime(&time); -#endif - *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); - *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); +#endif /* #ifdef _MSC_VER */ + + *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + + ((tm->tm_sec) >> 1)); + *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + + ((tm->tm_mon + 1) << 5) + tm->tm_mday); } -#endif +#endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */ #ifndef MINIZ_NO_STDIO -static mz_bool mz_zip_get_file_modified_time(const char *pFilename, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) -{ -#ifdef MINIZ_NO_TIME - (void)pFilename; *pDOS_date = *pDOS_time = 0; -#else +#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS +static mz_bool mz_zip_get_file_modified_time(const char *pFilename, + time_t *pTime) { struct MZ_FILE_STAT_STRUCT file_stat; - // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. + + /* On Linux with x86 glibc, this call will fail on large files (I think >= + * 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */ if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE; - mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date); -#endif // #ifdef MINIZ_NO_TIME + + *pTime = file_stat.st_mtime; + return MZ_TRUE; } +#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/ + +static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, + time_t modified_time) { + struct utimbuf t; + + memset(&t, 0, sizeof(t)); + t.actime = access_time; + t.modtime = modified_time; -#ifndef MINIZ_NO_TIME -static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, time_t modified_time) -{ - struct utimbuf t; t.actime = access_time; t.modtime = modified_time; return !utime(pFilename, &t); } -#endif // #ifndef MINIZ_NO_TIME -#endif // #ifndef MINIZ_NO_STDIO +#endif /* #ifndef MINIZ_NO_STDIO */ +#endif /* #ifndef MINIZ_NO_TIME */ -static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint32 flags) -{ +static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, + mz_uint32 flags) { (void)flags; if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) return MZ_FALSE; - if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; - if (!pZip->m_pFree) pZip->m_pFree = def_free_func; - if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; + if (!pZip->m_pAlloc) + pZip->m_pAlloc = def_alloc_func; + if (!pZip->m_pFree) + pZip->m_pFree = def_free_func; + if (!pZip->m_pRealloc) + pZip->m_pRealloc = def_realloc_func; pZip->m_zip_mode = MZ_ZIP_MODE_READING; pZip->m_archive_size = 0; pZip->m_central_directory_file_ofs = 0; pZip->m_total_files = 0; - if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) return MZ_FALSE; memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, + sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, + sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, + sizeof(mz_uint32)); return MZ_TRUE; } -static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) -{ - const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; - const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); - mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); +static MZ_FORCEINLINE mz_bool +mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, + const mz_zip_array *pCentral_dir_offsets, + mz_uint l_index, mz_uint r_index) { + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT( + pCentral_dir_array, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, + l_index)), + *pE; + const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT( + pCentral_dir_array, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); + mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), + r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); mz_uint8 l = 0, r = 0; - pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pE = pL + MZ_MIN(l_len, r_len); - while (pL < pE) - { + while (pL < pE) { if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; - pL++; pR++; + pL++; + pR++; } return (pL == pE) ? (l_len < r_len) : (l < r); } -#define MZ_SWAP_UINT32(a, b) do { mz_uint32 t = a; a = b; b = t; } MZ_MACRO_END +#define MZ_SWAP_UINT32(a, b) \ + do { \ + mz_uint32 t = a; \ + a = b; \ + b = t; \ + } \ + MZ_MACRO_END -// Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) -static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) -{ +// Heap sort of lowercased filenames, used to help accelerate plain central +// directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), +// but it could allocate memory.) +static void +mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) { mz_zip_internal_state *pState = pZip->m_pState; const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; const mz_zip_array *pCentral_dir = &pState->m_central_dir; - mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT( + &pState->m_sorted_central_dir_offsets, mz_uint32, 0); const int size = pZip->m_total_files; int start = (size - 2) >> 1, end; - while (start >= 0) - { + while (start >= 0) { int child, root = start; - for ( ; ; ) - { + for (;;) { if ((child = (root << 1) + 1) >= size) break; - child += (((child + 1) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1]))); - if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + child += + (((child + 1) < size) && + (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[child], pIndices[child + 1]))); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[root], pIndices[child])) break; - MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; } start--; } end = size - 1; - while (end > 0) - { + while (end > 0) { int child, root = 0; MZ_SWAP_UINT32(pIndices[end], pIndices[0]); - for ( ; ; ) - { + for (;;) { if ((child = (root << 1) + 1) >= end) break; - child += (((child + 1) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1])); - if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) + child += + (((child + 1) < end) && + mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[child], pIndices[child + 1])); + if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, + pIndices[root], pIndices[child])) break; - MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; + MZ_SWAP_UINT32(pIndices[root], pIndices[child]); + root = child; } end--; } } -static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint32 flags) -{ +static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, + mz_uint32 flags) { mz_uint cdir_size, num_this_disk, cdir_disk_index; mz_uint64 cdir_ofs; mz_int64 cur_file_ofs; const mz_uint8 *p; - mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32; - mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); - // Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. + mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; + mz_uint8 *pBuf = (mz_uint8 *)buf_u32; + mz_bool sort_central_dir = + ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); + // Basic sanity checks - reject files which are too small, and check the first + // 4 bytes of the file to make sure a local header is there. if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return MZ_FALSE; - // Find the end of central directory record by scanning the file from the end towards the beginning. - cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); - for ( ; ; ) - { - int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); + // Find the end of central directory record by scanning the file from the end + // towards the beginning. + cur_file_ofs = + MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); + for (;;) { + int i, + n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) return MZ_FALSE; for (i = n - 4; i >= 0; --i) if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) break; - if (i >= 0) - { + if (i >= 0) { cur_file_ofs += i; break; } - if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) + if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= + (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) return MZ_FALSE; cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); } // Read and verify the end of central directory record. - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return MZ_FALSE; - if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || - ((pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) + if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || + ((pZip->m_total_files = + MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != + MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) return MZ_FALSE; num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); - if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) + if (((num_this_disk | cdir_disk_index) != 0) && + ((num_this_disk != 1) || (cdir_disk_index != 1))) return MZ_FALSE; - if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) + if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < + pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) return MZ_FALSE; cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); @@ -3226,46 +4543,66 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint32 fl pZip->m_central_directory_file_ofs = cdir_ofs; - if (pZip->m_total_files) - { - mz_uint i, n; + if (pZip->m_total_files) { + mz_uint i, n; - // Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and another to hold the sorted indices. - if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || - (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) + // Read the entire central directory into a heap block, and allocate another + // heap block to hold the unsorted central dir file record offsets, and + // another to hold the sorted indices. + if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, + MZ_FALSE)) || + (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, + pZip->m_total_files, MZ_FALSE))) return MZ_FALSE; - if (sort_central_dir) - { - if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) + if (sort_central_dir) { + if (!mz_zip_array_resize(pZip, + &pZip->m_pState->m_sorted_central_dir_offsets, + pZip->m_total_files, MZ_FALSE)) return MZ_FALSE; } - if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) + if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, + pZip->m_pState->m_central_dir.m_p, + cdir_size) != cdir_size) return MZ_FALSE; - // Now create an index into the central directory file records, do some basic sanity checking on each record, and check for zip64 entries (which are not yet supported). + // Now create an index into the central directory file records, do some + // basic sanity checking on each record, and check for zip64 entries (which + // are not yet supported). p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; - for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) - { + for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) { mz_uint total_header_size, comp_size, decomp_size, disk_index; - if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) + if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || + (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) return MZ_FALSE; - MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, + i) = + (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); if (sort_central_dir) - MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, + mz_uint32, i) = i; comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); - if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF)) + if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && + (decomp_size != comp_size)) || + (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || + (comp_size == 0xFFFFFFFF)) return MZ_FALSE; disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); if ((disk_index != num_this_disk) && (disk_index != 1)) return MZ_FALSE; - if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) + if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) return MZ_FALSE; - if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) + if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > + n) return MZ_FALSE; - n -= total_header_size; p += total_header_size; + n -= total_header_size; + p += total_header_size; } } @@ -3275,31 +4612,32 @@ static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint32 fl return MZ_TRUE; } -mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags) -{ +mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, + mz_uint32 flags) { if ((!pZip) || (!pZip->m_pRead)) return MZ_FALSE; if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; pZip->m_archive_size = size; - if (!mz_zip_reader_read_central_dir(pZip, flags)) - { + if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end(pZip); return MZ_FALSE; } return MZ_TRUE; } -static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -{ +static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, + void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; - size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); + size_t s = (file_ofs >= pZip->m_archive_size) + ? 0 + : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); return s; } -mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags) -{ +mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, + size_t size, mz_uint32 flags) { if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; pZip->m_archive_size = size; @@ -3311,8 +4649,7 @@ mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t si pZip->m_pState->m_pMem = (void *)pMem; #endif pZip->m_pState->m_mem_size = size; - if (!mz_zip_reader_read_central_dir(pZip, flags)) - { + if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end(pZip); return MZ_FALSE; } @@ -3320,29 +4657,29 @@ mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t si } #ifndef MINIZ_NO_STDIO -static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) -{ +static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, + void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + if (((mz_int64)file_ofs < 0) || + (((cur_ofs != (mz_int64)file_ofs)) && + (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) return 0; return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); } -mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) -{ +mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, + mz_uint32 flags) { mz_uint64 file_size; MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb"); if (!pFile) return MZ_FALSE; - if (MZ_FSEEK64(pFile, 0, SEEK_END)) - { + if (MZ_FSEEK64(pFile, 0, SEEK_END)) { MZ_FCLOSE(pFile); return MZ_FALSE; } file_size = MZ_FTELL64(pFile); - if (!mz_zip_reader_init_internal(pZip, flags)) - { + if (!mz_zip_reader_init_internal(pZip, flags)) { MZ_FCLOSE(pFile); return MZ_FALSE; } @@ -3350,8 +4687,7 @@ mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_ pZip->m_pIO_opaque = pZip; pZip->m_pState->m_pFile = pFile; pZip->m_archive_size = file_size; - if (!mz_zip_reader_read_central_dir(pZip, flags)) - { + if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end(pZip); return MZ_FALSE; } @@ -3359,20 +4695,23 @@ mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_ } #endif // #ifndef MINIZ_NO_STDIO -mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) -{ +mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) { return pZip ? pZip->m_total_files : 0; } -static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(mz_zip_archive *pZip, mz_uint file_index) -{ - if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) +static MZ_FORCEINLINE const mz_uint8 * +mz_zip_reader_get_cdh(mz_zip_archive *pZip, mz_uint file_index) { + if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || + (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) return NULL; - return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); + return &MZ_ZIP_ARRAY_ELEMENT( + &pZip->m_pState->m_central_dir, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, + file_index)); } -mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) -{ +mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, + mz_uint file_index) { mz_uint m_bit_flag; const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); if (!p) @@ -3381,8 +4720,8 @@ mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index return (m_bit_flag & 1); } -mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) -{ +mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, + mz_uint file_index) { mz_uint filename_len, external_attr; const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); if (!p) @@ -3390,14 +4729,15 @@ mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_ind // First see if the filename ends with a '/' character. filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - if (filename_len) - { + if (filename_len) { if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') return MZ_TRUE; } - // Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. - // Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. + // Bugfix: This code was also checking if the internal attribute was non-zero, + // which wasn't correct. Most/all zip writers (hopefully) set DOS + // file/directory attributes in the low 16-bits, so check for the DOS + // directory flag and ignore the source OS ID in the created by field. // FIXME: Remove this check? Is it necessary - we already check the filename. external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); if ((external_attr & 0x10) != 0) @@ -3406,8 +4746,8 @@ mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_ind return MZ_FALSE; } -mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) -{ +mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, + mz_zip_archive_file_stat *pStat) { mz_uint n; const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); if ((!p) || (!pStat)) @@ -3415,13 +4755,16 @@ mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip // Unpack the central directory record. pStat->m_file_index = file_index; - pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); + pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT( + &pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); #ifndef MINIZ_NO_TIME - pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); + pStat->m_time = + mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), + MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); #endif pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); @@ -3431,24 +4774,35 @@ mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); // Copy as much of the filename and comment as possible. - n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); - memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0'; + n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); + memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); + pStat->m_filename[n] = '\0'; - n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); + n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); + n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); pStat->m_comment_size = n; - memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0'; + memcpy(pStat->m_comment, + p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), + n); + pStat->m_comment[n] = '\0'; return MZ_TRUE; } -mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) -{ +mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, + char *pFilename, mz_uint filename_buf_size) { mz_uint n; const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); - if (!p) { if (filename_buf_size) pFilename[0] = '\0'; return 0; } + if (!p) { + if (filename_buf_size) + pFilename[0] = '\0'; + return 0; + } n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); - if (filename_buf_size) - { + if (filename_buf_size) { n = MZ_MIN(n, filename_buf_size - 1); memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pFilename[n] = '\0'; @@ -3456,8 +4810,10 @@ mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, cha return n + 1; } -static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) -{ +static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, + const char *pB, + mz_uint len, + mz_uint flags) { mz_uint i; if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) return 0 == memcmp(pA, pB, len); @@ -3467,34 +4823,43 @@ static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, const c return MZ_TRUE; } -static MZ_FORCEINLINE int mz_zip_reader_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) -{ - const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; +static MZ_FORCEINLINE int +mz_zip_reader_filename_compare(const mz_zip_array *pCentral_dir_array, + const mz_zip_array *pCentral_dir_offsets, + mz_uint l_index, const char *pR, mz_uint r_len) { + const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT( + pCentral_dir_array, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, + l_index)), + *pE; mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); mz_uint8 l = 0, r = 0; pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pE = pL + MZ_MIN(l_len, r_len); - while (pL < pE) - { + while (pL < pE) { if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; - pL++; pR++; + pL++; + pR++; } return (pL == pE) ? (int)(l_len - r_len) : (l - r); } -static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename) -{ +static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, + const char *pFilename) { mz_zip_internal_state *pState = pZip->m_pState; const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; const mz_zip_array *pCentral_dir = &pState->m_central_dir; - mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); + mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT( + &pState->m_sorted_central_dir_offsets, mz_uint32, 0); const int size = pZip->m_total_files; const mz_uint filename_len = (mz_uint)strlen(pFilename); int l = 0, h = size - 1; - while (l <= h) - { - int m = (l + h) >> 1, file_index = pIndices[m], comp = mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); + while (l <= h) { + int m = (l + h) >> 1, file_index = pIndices[m], + comp = + mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, + file_index, pFilename, filename_len); if (!comp) return file_index; else if (comp < 0) @@ -3505,53 +4870,74 @@ static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, const c return -1; } -int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) -{ - mz_uint file_index; size_t name_len, comment_len; - if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) +int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, + const char *pComment, mz_uint flags) { + mz_uint file_index; + size_t name_len, comment_len; + if ((!pZip) || (!pZip->m_pState) || (!pName) || + (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) return -1; - if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) + if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && + (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) return mz_zip_reader_locate_file_binary_search(pZip, pName); - name_len = strlen(pName); if (name_len > 0xFFFF) return -1; - comment_len = pComment ? strlen(pComment) : 0; if (comment_len > 0xFFFF) return -1; - for (file_index = 0; file_index < pZip->m_total_files; file_index++) - { - const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); + name_len = strlen(pName); + if (name_len > 0xFFFF) + return -1; + comment_len = pComment ? strlen(pComment) : 0; + if (comment_len > 0xFFFF) + return -1; + for (file_index = 0; file_index < pZip->m_total_files; file_index++) { + const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT( + &pZip->m_pState->m_central_dir, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, + file_index)); mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); - const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + const char *pFilename = + (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; if (filename_len < name_len) continue; - if (comment_len) - { - mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); + if (comment_len) { + mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), + file_comment_len = + MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); const char *pFile_comment = pFilename + filename_len + file_extra_len; - if ((file_comment_len != comment_len) || (!mz_zip_reader_string_equal(pComment, pFile_comment, file_comment_len, flags))) + if ((file_comment_len != comment_len) || + (!mz_zip_reader_string_equal(pComment, pFile_comment, + file_comment_len, flags))) continue; } - if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) - { + if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) { int ofs = filename_len - 1; - do - { - if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) + do { + if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || + (pFilename[ofs] == ':')) break; } while (--ofs >= 0); ofs++; - pFilename += ofs; filename_len -= ofs; + pFilename += ofs; + filename_len -= ofs; } - if ((filename_len == name_len) && (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) + if ((filename_len == name_len) && + (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) return file_index; } return -1; } -mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -{ +mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, + mz_uint file_index, void *pBuf, + size_t buf_size, mz_uint flags, + void *pUser_read_buf, + size_t user_read_buf_size) { int status = TINFL_STATUS_DONE; - mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; + mz_uint64 needed_size, cur_file_ofs, comp_remaining, + out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; mz_zip_archive_file_stat file_stat; void *pRead_buf; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint32 + local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / + sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; tinfl_decompressor inflator; if ((buf_size) && (!pBuf)) @@ -3560,12 +4946,15 @@ mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; - // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) + // Empty file, or a directory (but not always a directory - I've seen odd zips + // with directories that have compressed data which inflates to 0 bytes) if (!file_stat.m_comp_size) return MZ_TRUE; - // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). - // I'm torn how to handle this case - should it fail instead? + // Entry is a subdirectory (I've seen old zips with dir entries which have + // compressed deflate data which inflates to 0 bytes, but these entries claim + // to uncompress to 512 bytes in the headers). I'm torn how to handle this + // case - should it fail instead? if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE; @@ -3574,45 +4963,51 @@ mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file return MZ_FALSE; // This function only supports stored and deflate. - if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && + (file_stat.m_method != MZ_DEFLATED)) return MZ_FALSE; // Ensure supplied output buffer is large enough. - needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; + needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size + : file_stat.m_uncomp_size; if (buf_size < needed_size) return MZ_FALSE; // Read and parse the local directory entry. cur_file_ofs = file_stat.m_local_header_ofs; - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return MZ_FALSE; if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return MZ_FALSE; - cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) return MZ_FALSE; - if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) - { + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { // The file is stored or the caller has requested the compressed data. - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, + (size_t)needed_size) != needed_size) return MZ_FALSE; - return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); + return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || + (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, + (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); } - // Decompress the file either directly from memory or from a file input buffer. + // Decompress the file either directly from memory or from a file input + // buffer. tinfl_init(&inflator); - if (pZip->m_pState->m_pMem) - { + if (pZip->m_pState->m_pMem) { // Read directly from the archive in memory. pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; read_buf_size = read_buf_avail = file_stat.m_comp_size; comp_remaining = 0; - } - else if (pUser_read_buf) - { + } else if (pUser_read_buf) { // Use a user provided read buffer. if (!user_read_buf_size) return MZ_FALSE; @@ -3620,31 +5015,30 @@ mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file read_buf_size = user_read_buf_size; read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; - } - else - { + } else { // Temporarily allocate a read buffer. read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); #ifdef _MSC_VER - if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && + (read_buf_size > 0x7FFFFFFF)) #else if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) #endif return MZ_FALSE; - if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, + (size_t)read_buf_size))) return MZ_FALSE; read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } - do - { - size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); - if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) - { + do { + size_t in_buf_size, + out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, + (size_t)read_buf_avail) != read_buf_avail) { status = TINFL_STATUS_FAILED; break; } @@ -3653,16 +5047,21 @@ mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file read_buf_ofs = 0; } in_buf_size = (size_t)read_buf_avail; - status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); + status = tinfl_decompress( + &inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, + (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, + TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | + (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); read_buf_avail -= in_buf_size; read_buf_ofs += in_buf_size; out_buf_ofs += out_buf_size; } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); - if (status == TINFL_STATUS_DONE) - { + if (status == TINFL_STATUS_DONE) { // Make sure the entire file was decompressed, and check its CRC. - if ((out_buf_ofs != file_stat.m_uncomp_size) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) + if ((out_buf_ofs != file_stat.m_uncomp_size) || + (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, + (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) status = TINFL_STATUS_FAILED; } @@ -3672,26 +5071,33 @@ mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file return status == TINFL_STATUS_DONE; } -mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) -{ +mz_bool mz_zip_reader_extract_file_to_mem_no_alloc( + mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, + mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); if (file_index < 0) return MZ_FALSE; - return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, + flags, pUser_read_buf, + user_read_buf_size); } -mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) -{ - return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); +mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, + void *pBuf, size_t buf_size, + mz_uint flags) { + return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, + flags, NULL, 0); } -mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) -{ - return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); +mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, + const char *pFilename, void *pBuf, + size_t buf_size, mz_uint flags) { + return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, + buf_size, flags, NULL, 0); } -void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) -{ +void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, + size_t *pSize, mz_uint flags) { mz_uint64 comp_size, uncomp_size, alloc_size; const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); void *pBuf; @@ -3711,47 +5117,61 @@ void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, si if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) #endif return NULL; - if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) + if (NULL == + (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) return NULL; - if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) - { + if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, + flags)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return NULL; } - if (pSize) *pSize = (size_t)alloc_size; + if (pSize) + *pSize = (size_t)alloc_size; return pBuf; } -void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) -{ +void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, + const char *pFilename, size_t *pSize, + mz_uint flags) { int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); - if (file_index < 0) - { - if (pSize) *pSize = 0; + if (file_index < 0) { + if (pSize) + *pSize = 0; return MZ_FALSE; } return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); } -mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) -{ - int status = TINFL_STATUS_DONE; mz_uint file_crc32 = MZ_CRC32_INIT; - mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; +mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, + mz_uint file_index, + mz_file_write_func pCallback, + void *pOpaque, mz_uint flags) { + int status = TINFL_STATUS_DONE; + mz_uint file_crc32 = MZ_CRC32_INIT; + mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, + out_buf_ofs = 0, cur_file_ofs; mz_zip_archive_file_stat file_stat; - void *pRead_buf = NULL; void *pWrite_buf = NULL; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + void *pRead_buf = NULL; + void *pWrite_buf = NULL; + mz_uint32 + local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / + sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; - // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) + // Empty file, or a directory (but not always a directory - I've seen odd zips + // with directories that have compressed data which inflates to 0 bytes) if (!file_stat.m_comp_size) return MZ_TRUE; - // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). - // I'm torn how to handle this case - should it fail instead? + // Entry is a subdirectory (I've seen old zips with dir entries which have + // compressed deflate data which inflates to 0 bytes, but these entries claim + // to uncompress to 512 bytes in the headers). I'm torn how to handle this + // case - should it fail instead? if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE; @@ -3760,69 +5180,76 @@ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_ind return MZ_FALSE; // This function only supports stored and deflate. - if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) + if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && + (file_stat.m_method != MZ_DEFLATED)) return MZ_FALSE; // Read and parse the local directory entry. cur_file_ofs = file_stat.m_local_header_ofs; - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return MZ_FALSE; if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return MZ_FALSE; - cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) return MZ_FALSE; - // Decompress the file either directly from memory or from a file input buffer. - if (pZip->m_pState->m_pMem) - { + // Decompress the file either directly from memory or from a file input + // buffer. + if (pZip->m_pState->m_pMem) { pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; read_buf_size = read_buf_avail = file_stat.m_comp_size; comp_remaining = 0; - } - else - { + } else { read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); - if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) + if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, + (size_t)read_buf_size))) return MZ_FALSE; read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } - if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) - { + if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { // The file is stored or the caller has requested the compressed data. - if (pZip->m_pState->m_pMem) - { + if (pZip->m_pState->m_pMem) { #ifdef _MSC_VER - if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) + if (((0, sizeof(size_t) == sizeof(mz_uint32))) && + (file_stat.m_comp_size > 0xFFFFFFFF)) #else - if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) + if (((sizeof(size_t) == sizeof(mz_uint32))) && + (file_stat.m_comp_size > 0xFFFFFFFF)) #endif return MZ_FALSE; - if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, + (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) status = TINFL_STATUS_FAILED; else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); + file_crc32 = + (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, + (size_t)file_stat.m_comp_size); + // cur_file_ofs += file_stat.m_comp_size; out_buf_ofs += file_stat.m_comp_size; - } - else - { - while (comp_remaining) - { + // comp_remaining = 0; + } else { + while (comp_remaining) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, + (size_t)read_buf_avail) != read_buf_avail) { status = TINFL_STATUS_FAILED; break; } if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); + file_crc32 = (mz_uint32)mz_crc32( + file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); - if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { + if (pCallback(pOpaque, out_buf_ofs, pRead_buf, + (size_t)read_buf_avail) != read_buf_avail) { status = TINFL_STATUS_FAILED; break; } @@ -3831,25 +5258,24 @@ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_ind comp_remaining -= read_buf_avail; } } - } - else - { + } else { tinfl_decompressor inflator; tinfl_init(&inflator); - if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) + if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, + TINFL_LZ_DICT_SIZE))) status = TINFL_STATUS_FAILED; - else - { - do - { - mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); - if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) - { + else { + do { + mz_uint8 *pWrite_buf_cur = + (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + size_t in_buf_size, + out_buf_size = + TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); + if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); - if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) - { + if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, + (size_t)read_buf_avail) != read_buf_avail) { status = TINFL_STATUS_FAILED; break; } @@ -3859,32 +5285,36 @@ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_ind } in_buf_size = (size_t)read_buf_avail; - status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); + status = tinfl_decompress( + &inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, + (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, + comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); read_buf_avail -= in_buf_size; read_buf_ofs += in_buf_size; - if (out_buf_size) - { - if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) - { + if (out_buf_size) { + if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != + out_buf_size) { status = TINFL_STATUS_FAILED; break; } - file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); - if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) - { + file_crc32 = + (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); + if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) { status = TINFL_STATUS_FAILED; break; } } - } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); + } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || + (status == TINFL_STATUS_HAS_MORE_OUTPUT)); } } - if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) - { + if ((status == TINFL_STATUS_DONE) && + (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) { // Make sure the entire file was decompressed, and check its CRC. - if ((out_buf_ofs != file_stat.m_uncomp_size) || (file_crc32 != file_stat.m_crc32)) + if ((out_buf_ofs != file_stat.m_uncomp_size) || + (file_crc32 != file_stat.m_crc32)) status = TINFL_STATUS_FAILED; } @@ -3896,72 +5326,82 @@ mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_ind return status == TINFL_STATUS_DONE; } -mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) -{ +mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, + const char *pFilename, + mz_file_write_func pCallback, + void *pOpaque, mz_uint flags) { int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); if (file_index < 0) return MZ_FALSE; - return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); + return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, + flags); } #ifndef MINIZ_NO_STDIO -static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) -{ - (void)ofs; return MZ_FWRITE(pBuf, 1, n, (MZ_FILE*)pOpaque); +static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, + const void *pBuf, size_t n) { + (void)ofs; + return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque); } -mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) -{ +mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, + const char *pDst_filename, + mz_uint flags) { mz_bool status; mz_zip_archive_file_stat file_stat; MZ_FILE *pFile; if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; + pFile = MZ_FOPEN(pDst_filename, "wb"); if (!pFile) return MZ_FALSE; - status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); + status = mz_zip_reader_extract_to_callback( + pZip, file_index, mz_zip_file_write_callback, pFile, flags); if (MZ_FCLOSE(pFile) == EOF) return MZ_FALSE; #ifndef MINIZ_NO_TIME - if (status) + if (status) { mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); + } #endif + return status; } #endif // #ifndef MINIZ_NO_STDIO -mz_bool mz_zip_reader_end(mz_zip_archive *pZip) -{ - if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) +mz_bool mz_zip_reader_end(mz_zip_archive *pZip) { + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || + (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) return MZ_FALSE; - if (pZip->m_pState) - { - mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL; - mz_zip_array_clear(pZip, &pState->m_central_dir); - mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); - mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); + mz_zip_internal_state *pState = pZip->m_pState; + pZip->m_pState = NULL; + mz_zip_array_clear(pZip, &pState->m_central_dir); + mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); + mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); #ifndef MINIZ_NO_STDIO - if (pState->m_pFile) - { - MZ_FCLOSE(pState->m_pFile); - pState->m_pFile = NULL; - } + if (pState->m_pFile) { + MZ_FCLOSE(pState->m_pFile); + pState->m_pFile = NULL; + } #endif // #ifndef MINIZ_NO_STDIO - pZip->m_pFree(pZip->m_pAlloc_opaque, pState); - } + pZip->m_pFree(pZip->m_pAlloc_opaque, pState); + pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; return MZ_TRUE; } #ifndef MINIZ_NO_STDIO -mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) -{ - int file_index = mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags); +mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, + const char *pArchive_filename, + const char *pDst_filename, + mz_uint flags) { + int file_index = + mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags); if (file_index < 0) return MZ_FALSE; return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); @@ -3972,75 +5412,92 @@ mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pAr #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS -static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); } -static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); p[2] = (mz_uint8)(v >> 16); p[3] = (mz_uint8)(v >> 24); } +static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); +} +static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { + p[0] = (mz_uint8)v; + p[1] = (mz_uint8)(v >> 8); + p[2] = (mz_uint8)(v >> 16); + p[3] = (mz_uint8)(v >> 24); +} #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) -mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) -{ - if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) +mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) { + if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || + (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) return MZ_FALSE; - if (pZip->m_file_offset_alignment) - { + if (pZip->m_file_offset_alignment) { // Ensure user specified file offset alignment is a power of 2. if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) return MZ_FALSE; } - if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; - if (!pZip->m_pFree) pZip->m_pFree = def_free_func; - if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; + if (!pZip->m_pAlloc) + pZip->m_pAlloc = def_alloc_func; + if (!pZip->m_pFree) + pZip->m_pFree = def_free_func; + if (!pZip->m_pRealloc) + pZip->m_pRealloc = def_realloc_func; pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; pZip->m_archive_size = existing_size; pZip->m_central_directory_file_ofs = 0; pZip->m_total_files = 0; - if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) + if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) return MZ_FALSE; memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); - MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, + sizeof(mz_uint8)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, + sizeof(mz_uint32)); + MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, + sizeof(mz_uint32)); return MZ_TRUE; } -static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -{ +static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, + const void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_zip_internal_state *pState = pZip->m_pState; mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); -#ifdef _MSC_VER - if ((!n) || ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) -#else - if ((!n) || ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) -#endif + + if ((!n) || + ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) return 0; - if (new_size > pState->m_mem_capacity) - { + + if (new_size > pState->m_mem_capacity) { void *pNew_block; - size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); while (new_capacity < new_size) new_capacity *= 2; - if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) + size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); + while (new_capacity < new_size) + new_capacity *= 2; + if (NULL == (pNew_block = pZip->m_pRealloc( + pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) return 0; - pState->m_pMem = pNew_block; pState->m_mem_capacity = new_capacity; + pState->m_pMem = pNew_block; + pState->m_mem_capacity = new_capacity; } memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); pState->m_mem_size = (size_t)new_size; return n; } -mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) -{ +mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, + size_t size_to_reserve_at_beginning, + size_t initial_allocation_size) { pZip->m_pWrite = mz_zip_heap_write_func; pZip->m_pIO_opaque = pZip; if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE; - if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) - { - if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) - { + if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, + size_to_reserve_at_beginning))) { + if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, initial_allocation_size))) { mz_zip_writer_end(pZip); return MZ_FALSE; } @@ -4050,61 +5507,65 @@ mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_ } #ifndef MINIZ_NO_STDIO -static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) -{ +static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, + const void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); - if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) + if (((mz_int64)file_ofs < 0) || + (((cur_ofs != (mz_int64)file_ofs)) && + (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) return 0; return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); } -mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) -{ +mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, + mz_uint64 size_to_reserve_at_beginning) { MZ_FILE *pFile; pZip->m_pWrite = mz_zip_file_write_func; pZip->m_pIO_opaque = pZip; if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE; - if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) - { + if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) { mz_zip_writer_end(pZip); return MZ_FALSE; } pZip->m_pState->m_pFile = pFile; - if (size_to_reserve_at_beginning) - { - mz_uint64 cur_ofs = 0; char buf[4096]; MZ_CLEAR_OBJ(buf); - do - { + if (size_to_reserve_at_beginning) { + mz_uint64 cur_ofs = 0; + char buf[4096]; + MZ_CLEAR_OBJ(buf); + do { size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) - { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) { mz_zip_writer_end(pZip); return MZ_FALSE; } - cur_ofs += n; size_to_reserve_at_beginning -= n; + cur_ofs += n; + size_to_reserve_at_beginning -= n; } while (size_to_reserve_at_beginning); } return MZ_TRUE; } #endif // #ifndef MINIZ_NO_STDIO -mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) -{ +mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, + const char *pFilename) { mz_zip_internal_state *pState; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) return MZ_FALSE; - // No sense in trying to write to an archive that's already at the support max size - if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + // No sense in trying to write to an archive that's already at the support max + // size + if ((pZip->m_total_files == 0xFFFF) || + ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) return MZ_FALSE; pState = pZip->m_pState; - if (pState->m_pFile) - { + if (pState->m_pFile) { #ifdef MINIZ_NO_STDIO - pFilename; return MZ_FALSE; + pFilename; + return MZ_FALSE; #else // Archive is being read from stdio - try to reopen as writable. if (pZip->m_pIO_opaque != pZip) @@ -4112,27 +5573,29 @@ mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilena if (!pFilename) return MZ_FALSE; pZip->m_pWrite = mz_zip_file_write_func; - if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) - { - // The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. + if (NULL == + (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) { + // The mz_zip_archive is now in a bogus state because pState->m_pFile is + // NULL, so just close it. mz_zip_reader_end(pZip); return MZ_FALSE; } #endif // #ifdef MINIZ_NO_STDIO - } - else if (pState->m_pMem) - { - // Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. + } else if (pState->m_pMem) { + // Archive lives in a memory block. Assume it's from the heap that we can + // resize using the realloc callback. if (pZip->m_pIO_opaque != pZip) return MZ_FALSE; pState->m_mem_capacity = pState->m_mem_size; pZip->m_pWrite = mz_zip_heap_write_func; } - // Archive is being read via a user provided read function - make sure the user has specified a write function too. + // Archive is being read via a user provided read function - make sure the + // user has specified a write function too. else if (!pZip->m_pWrite) return MZ_FALSE; - // Start writing new files at the archive's current central directory location. + // Start writing new files at the archive's current central directory + // location. pZip->m_archive_size = pZip->m_central_directory_file_ofs; pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; pZip->m_central_directory_file_ofs = 0; @@ -4140,30 +5603,36 @@ mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilena return MZ_TRUE; } -mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) -{ - return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); +mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, + const void *pBuf, size_t buf_size, + mz_uint level_and_flags) { + return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, + level_and_flags, 0, 0); } -typedef struct -{ +typedef struct { mz_zip_archive *m_pZip; mz_uint64 m_cur_archive_file_ofs; mz_uint64 m_comp_size; } mz_zip_writer_add_state; -static mz_bool mz_zip_writer_add_put_buf_callback(const void* pBuf, int len, void *pUser) -{ +static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, + void *pUser) { mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; - if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) + if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, + pState->m_cur_archive_file_ofs, pBuf, + len) != len) return MZ_FALSE; pState->m_cur_archive_file_ofs += len; pState->m_comp_size += len; return MZ_TRUE; } -static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) -{ +static mz_bool mz_zip_writer_create_local_dir_header( + mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, + mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, + mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, + mz_uint16 dos_time, mz_uint16 dos_date) { (void)pZip; memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); @@ -4180,11 +5649,19 @@ static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_ui return MZ_TRUE; } -static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) -{ +static mz_bool mz_zip_writer_create_central_dir_header( + mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, + mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, + mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, + mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, + mz_uint64 local_header_ofs, mz_uint32 ext_attributes) { (void)pZip; + mz_uint16 version_made_by = 10 * MZ_VER_MAJOR + MZ_VER_MINOR; + version_made_by |= (MZ_PLATFORM << 8); + memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_MADE_BY_OFS, version_made_by); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); @@ -4201,41 +5678,57 @@ static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_ return MZ_TRUE; } -static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) -{ +static mz_bool mz_zip_writer_add_to_central_dir( + mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, + const void *pExtra, mz_uint16 extra_size, const void *pComment, + mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, + mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, + mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, + mz_uint32 ext_attributes) { mz_zip_internal_state *pState = pZip->m_pState; mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; size_t orig_central_dir_size = pState->m_central_dir.m_size; mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; // No zip64 support yet - if ((local_header_ofs > 0xFFFFFFFF) || (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + comment_size) > 0xFFFFFFFF)) + if ((local_header_ofs > 0xFFFFFFFF) || + (((mz_uint64)pState->m_central_dir.m_size + + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + + comment_size) > 0xFFFFFFFF)) return MZ_FALSE; - if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) + if (!mz_zip_writer_create_central_dir_header( + pZip, central_dir_header, filename_size, extra_size, comment_size, + uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, + dos_date, local_header_ofs, ext_attributes)) return MZ_FALSE; - if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || - (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) - { + if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, + filename_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, + extra_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, + comment_size)) || + (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, + ¢ral_dir_ofs, 1))) { // Try to push the central directory array back into its original state. - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, + MZ_FALSE); return MZ_FALSE; } return MZ_TRUE; } -static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) -{ - // Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. +static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) { + // Basic ZIP archive filename validity checks: Valid filenames cannot start + // with a forward slash, cannot contain a drive letter, and cannot use + // DOS-style backward slashes. if (*pArchive_name == '/') return MZ_FALSE; - while (*pArchive_name) - { + while (*pArchive_name) { if ((*pArchive_name == '\\') || (*pArchive_name == ':')) return MZ_FALSE; pArchive_name++; @@ -4243,33 +5736,39 @@ static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) return MZ_TRUE; } -static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) -{ +static mz_uint +mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) { mz_uint32 n; if (!pZip->m_file_offset_alignment) return 0; n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); - return (pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1); + return (pZip->m_file_offset_alignment - n) & + (pZip->m_file_offset_alignment - 1); } -static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) -{ +static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, + mz_uint64 cur_file_ofs, mz_uint32 n) { char buf[4096]; memset(buf, 0, MZ_MIN(sizeof(buf), n)); - while (n) - { + while (n) { mz_uint32 s = MZ_MIN(sizeof(buf), n); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) return MZ_FALSE; - cur_file_ofs += s; n -= s; + cur_file_ofs += s; + n -= s; } return MZ_TRUE; } -mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) -{ +mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, + const char *pArchive_name, const void *pBuf, + size_t buf_size, const void *pComment, + mz_uint16 comment_size, + mz_uint level_and_flags, mz_uint64 uncomp_size, + mz_uint32 uncomp_crc32) { + mz_uint32 ext_attributes = 0; mz_uint16 method = 0, dos_time = 0, dos_date = 0; - mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; + mz_uint level, num_alignment_padding_bytes; mz_uint64 local_dir_header_ofs, cur_archive_file_ofs, comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; @@ -4280,9 +5779,13 @@ mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; level = level_and_flags & 0xF; - store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); + store_data_uncompressed = + ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION)) + if ((!pZip) || (!pZip->m_pState) || + (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || + (!pArchive_name) || ((comment_size) && (!pComment)) || + (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION)) return MZ_FALSE; local_dir_header_ofs = cur_archive_file_ofs = pZip->m_archive_size; @@ -4298,8 +5801,9 @@ mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name #ifndef MINIZ_NO_TIME { - time_t cur_time; time(&cur_time); - mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date); + time_t cur_time; + time(&cur_time); + mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date); } #endif // #ifndef MINIZ_NO_TIME @@ -4307,14 +5811,17 @@ mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name if (archive_name_size > 0xFFFF) return MZ_FALSE; - num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + num_alignment_padding_bytes = + mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); // no zip64 support yet - if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) + if ((pZip->m_total_files == 0xFFFF) || + ((pZip->m_archive_size + num_alignment_padding_bytes + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + comment_size + archive_name_size) > 0xFFFFFFFF)) return MZ_FALSE; - if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) - { + if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) { // Set DOS Subdirectory attribute bit. ext_attributes |= 0x10; // Subdirectories cannot contain data. @@ -4322,48 +5829,56 @@ mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name return MZ_FALSE; } - // Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) - if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) + // Try to do any allocations before writing to the archive, so if an + // allocation fails the file remains unmodified. (A good idea if we're doing + // an in-place modification.) + if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + archive_name_size + comment_size)) || + (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) return MZ_FALSE; - if ((!store_data_uncompressed) && (buf_size)) - { - if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) + if ((!store_data_uncompressed) && (buf_size)) { + if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) return MZ_FALSE; } - if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) - { + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, + num_alignment_padding_bytes + + sizeof(local_dir_header))) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return MZ_FALSE; } local_dir_header_ofs += num_alignment_padding_bytes; - if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } - cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); + if (pZip->m_file_offset_alignment) { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == + 0); + } + cur_archive_file_ofs += + num_alignment_padding_bytes + sizeof(local_dir_header); MZ_CLEAR_OBJ(local_dir_header); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) - { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, + archive_name_size) != archive_name_size) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return MZ_FALSE; } cur_archive_file_ofs += archive_name_size; - if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) - { - uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8*)pBuf, buf_size); + if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { + uncomp_crc32 = + (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size); uncomp_size = buf_size; - if (uncomp_size <= 3) - { + if (uncomp_size <= 3) { level = 0; store_data_uncompressed = MZ_TRUE; } } - if (store_data_uncompressed) - { - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) - { + if (store_data_uncompressed) { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, + buf_size) != buf_size) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return MZ_FALSE; } @@ -4373,18 +5888,19 @@ mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) method = MZ_DEFLATED; - } - else if (buf_size) - { + } else if (buf_size) { mz_zip_writer_add_state state; state.m_pZip = pZip; state.m_cur_archive_file_ofs = cur_archive_file_ofs; state.m_comp_size = 0; - if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || - (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) - { + if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, + tdefl_create_comp_flags_from_zip_params( + level, -15, MZ_DEFAULT_STRATEGY)) != + TDEFL_STATUS_OKAY) || + (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != + TDEFL_STATUS_DONE)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return MZ_FALSE; } @@ -4402,13 +5918,19 @@ mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) return MZ_FALSE; - if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) + if (!mz_zip_writer_create_local_dir_header( + pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, + comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) return MZ_FALSE; - if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, + sizeof(local_dir_header)) != sizeof(local_dir_header)) return MZ_FALSE; - if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) + if (!mz_zip_writer_add_to_central_dir( + pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, + comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, + dos_time, dos_date, local_dir_header_ofs, ext_attributes)) return MZ_FALSE; pZip->m_total_files++; @@ -4418,24 +5940,30 @@ mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name } #ifndef MINIZ_NO_STDIO -mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) -{ +mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, + const char *pSrc_filename, const void *pComment, + mz_uint16 comment_size, mz_uint level_and_flags, + mz_uint32 ext_attributes) { mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; - mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; - mz_uint64 local_dir_header_ofs, cur_archive_file_ofs, uncomp_size = 0, comp_size = 0; + mz_uint16 method = 0, dos_time = 0, dos_date = 0; + time_t file_modified_time; + mz_uint64 local_dir_header_ofs, cur_archive_file_ofs, uncomp_size = 0, + comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; MZ_FILE *pSrc_file = NULL; - if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || ( level_and_flags > MZ_UBER_COMPRESSION)) - return MZ_FALSE; - - local_dir_header_ofs = cur_archive_file_ofs = pZip->m_archive_size; - if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; level = level_and_flags & 0xF; + if ((!pZip) || (!pZip->m_pState) || + (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || + ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) + return MZ_FALSE; + + local_dir_header_ofs = cur_archive_file_ofs = pZip->m_archive_size; + if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) return MZ_FALSE; if (!mz_zip_writer_validate_archive_name(pArchive_name)) @@ -4445,14 +5973,20 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, if (archive_name_size > 0xFFFF) return MZ_FALSE; - num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + num_alignment_padding_bytes = + mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); // no zip64 support yet - if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) + if ((pZip->m_total_files == 0xFFFF) || + ((pZip->m_archive_size + num_alignment_padding_bytes + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + comment_size + archive_name_size) > 0xFFFFFFFF)) return MZ_FALSE; - if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date)) + memset(&file_modified_time, 0, sizeof(file_modified_time)); + if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time)) return MZ_FALSE; + mz_zip_time_t_to_dos_time(file_modified_time, &dos_time, &dos_date); pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); if (!pSrc_file) @@ -4461,8 +5995,7 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, uncomp_size = MZ_FTELL64(pSrc_file); MZ_FSEEK64(pSrc_file, 0, SEEK_SET); - if (uncomp_size > 0xFFFFFFFF) - { + if (uncomp_size > 0xFFFFFFFF) { // No zip64 support yet MZ_FCLOSE(pSrc_file); return MZ_FALSE; @@ -4470,57 +6003,59 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, if (uncomp_size <= 3) level = 0; - if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) - { + if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, + num_alignment_padding_bytes + + sizeof(local_dir_header))) { MZ_FCLOSE(pSrc_file); return MZ_FALSE; } local_dir_header_ofs += num_alignment_padding_bytes; - if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } - cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); + if (pZip->m_file_offset_alignment) { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == + 0); + } + cur_archive_file_ofs += + num_alignment_padding_bytes + sizeof(local_dir_header); MZ_CLEAR_OBJ(local_dir_header); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) - { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, + archive_name_size) != archive_name_size) { MZ_FCLOSE(pSrc_file); return MZ_FALSE; } cur_archive_file_ofs += archive_name_size; - if (uncomp_size) - { + if (uncomp_size) { mz_uint64 uncomp_remaining = uncomp_size; - void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); - if (!pRead_buf) - { + void *pRead_buf = + pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); + if (!pRead_buf) { MZ_FCLOSE(pSrc_file); return MZ_FALSE; } - if (!level) - { - while (uncomp_remaining) - { + if (!level) { + while (uncomp_remaining) { mz_uint n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); - if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) - { + if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || + (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, + n) != n)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); MZ_FCLOSE(pSrc_file); return MZ_FALSE; } - uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); + uncomp_crc32 = + (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); uncomp_remaining -= n; cur_archive_file_ofs += n; } comp_size = uncomp_size; - } - else - { + } else { mz_bool result = MZ_FALSE; mz_zip_writer_add_state state; - tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); - if (!pComp) - { + tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc( + pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); + if (!pComp) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); MZ_FCLOSE(pSrc_file); return MZ_FALSE; @@ -4530,39 +6065,41 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, state.m_cur_archive_file_ofs = cur_archive_file_ofs; state.m_comp_size = 0; - if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) - { + if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, + tdefl_create_comp_flags_from_zip_params( + level, -15, MZ_DEFAULT_STRATEGY)) != + TDEFL_STATUS_OKAY) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); MZ_FCLOSE(pSrc_file); return MZ_FALSE; } - for ( ; ; ) - { - size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE); + for (;;) { + size_t in_buf_size = + (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE); tdefl_status status; if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) break; - uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); + uncomp_crc32 = (mz_uint32)mz_crc32( + uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); uncomp_remaining -= in_buf_size; - status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH); - if (status == TDEFL_STATUS_DONE) - { + status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, + uncomp_remaining ? TDEFL_NO_FLUSH + : TDEFL_FINISH); + if (status == TDEFL_STATUS_DONE) { result = MZ_TRUE; break; - } - else if (status != TDEFL_STATUS_OKAY) + } else if (status != TDEFL_STATUS_OKAY) break; } pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); - if (!result) - { + if (!result) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); MZ_FCLOSE(pSrc_file); return MZ_FALSE; @@ -4577,19 +6114,26 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); } - MZ_FCLOSE(pSrc_file); pSrc_file = NULL; + MZ_FCLOSE(pSrc_file); + pSrc_file = NULL; // no zip64 support yet if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) return MZ_FALSE; - if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) + if (!mz_zip_writer_create_local_dir_header( + pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, + comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) return MZ_FALSE; - if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) + if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, + sizeof(local_dir_header)) != sizeof(local_dir_header)) return MZ_FALSE; - if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) + if (!mz_zip_writer_add_to_central_dir( + pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, + comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, + dos_time, dos_date, local_dir_header_ofs, ext_attributes)) return MZ_FALSE; pZip->m_total_files++; @@ -4599,66 +6143,89 @@ mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, } #endif // #ifndef MINIZ_NO_STDIO -mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index) -{ +mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, + mz_zip_archive *pSource_zip, + mz_uint file_index) { mz_uint n, bit_flags, num_alignment_padding_bytes; mz_uint64 comp_bytes_remaining, local_dir_header_ofs; mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; - mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; + mz_uint32 + local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / + sizeof(mz_uint32)]; + mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; size_t orig_central_dir_size; mz_zip_internal_state *pState; - void *pBuf; const mz_uint8 *pSrc_central_header; + void *pBuf; + const mz_uint8 *pSrc_central_header; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) return MZ_FALSE; - if (NULL == (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index))) + if (NULL == + (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index))) return MZ_FALSE; pState = pZip->m_pState; - num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); + num_alignment_padding_bytes = + mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); // no zip64 support yet - if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + if ((pZip->m_total_files == 0xFFFF) || + ((pZip->m_archive_size + num_alignment_padding_bytes + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > + 0xFFFFFFFF)) return MZ_FALSE; - cur_src_file_ofs = MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); + cur_src_file_ofs = + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); cur_dst_file_ofs = pZip->m_archive_size; - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, + pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return MZ_FALSE; if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return MZ_FALSE; cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; - if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) + if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, + num_alignment_padding_bytes)) return MZ_FALSE; cur_dst_file_ofs += num_alignment_padding_bytes; local_dir_header_ofs = cur_dst_file_ofs; - if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } + if (pZip->m_file_offset_alignment) { + MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == + 0); + } - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return MZ_FALSE; cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; - n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); - comp_bytes_remaining = n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); + n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); + comp_bytes_remaining = + n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); - if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(sizeof(mz_uint32) * 4, MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining))))) + if (NULL == + (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, + (size_t)MZ_MAX(sizeof(mz_uint32) * 4, + MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, + comp_bytes_remaining))))) return MZ_FALSE; - while (comp_bytes_remaining) - { + while (comp_bytes_remaining) { n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining); - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) - { + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, + n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return MZ_FALSE; } cur_src_file_ofs += n; - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) - { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return MZ_FALSE; } @@ -4668,22 +6235,21 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * } bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); - if (bit_flags & 8) - { + if (bit_flags & 8) { // Copy data descriptor - if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) - { + if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, + sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return MZ_FALSE; } n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3); - if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) - { + if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return MZ_FALSE; } + // cur_src_file_ofs += n; cur_dst_file_ofs += n; } pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); @@ -4695,23 +6261,29 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * orig_central_dir_size = pState->m_central_dir.m_size; memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); - MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) + MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, + local_dir_header_ofs); + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) return MZ_FALSE; - n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) - { - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); + if (!mz_zip_array_push_back( + pZip, &pState->m_central_dir, + pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, + MZ_FALSE); return MZ_FALSE; } if (pState->m_central_dir.m_size > 0xFFFFFFFF) return MZ_FALSE; n = (mz_uint32)orig_central_dir_size; - if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) - { - mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); + if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) { + mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, + MZ_FALSE); return MZ_FALSE; } @@ -4721,8 +6293,7 @@ mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive * return MZ_TRUE; } -mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) -{ +mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) { mz_zip_internal_state *pState; mz_uint64 central_dir_ofs, central_dir_size; mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE]; @@ -4733,31 +6304,37 @@ mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) pState = pZip->m_pState; // no zip64 support yet - if ((pZip->m_total_files > 0xFFFF) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) + if ((pZip->m_total_files > 0xFFFF) || + ((pZip->m_archive_size + pState->m_central_dir.m_size + + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) return MZ_FALSE; central_dir_ofs = 0; central_dir_size = 0; - if (pZip->m_total_files) - { + if (pZip->m_total_files) { // Write central directory central_dir_ofs = pZip->m_archive_size; central_dir_size = pState->m_central_dir.m_size; pZip->m_central_directory_file_ofs = central_dir_ofs; - if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) + if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, + pState->m_central_dir.m_p, + (size_t)central_dir_size) != central_dir_size) return MZ_FALSE; pZip->m_archive_size += central_dir_size; } // Write end of central directory record MZ_CLEAR_OBJ(hdr); - MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); - MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); + MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); + MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, + pZip->m_total_files); MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs); - if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, sizeof(hdr)) != sizeof(hdr)) + if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, + sizeof(hdr)) != sizeof(hdr)) return MZ_FALSE; #ifndef MINIZ_NO_STDIO if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) @@ -4770,8 +6347,8 @@ mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) return MZ_TRUE; } -mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize) -{ +mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, + size_t *pSize) { if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) return MZ_FALSE; if (pZip->m_pWrite != mz_zip_heap_write_func) @@ -4786,11 +6363,12 @@ mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, s return MZ_TRUE; } -mz_bool mz_zip_writer_end(mz_zip_archive *pZip) -{ +mz_bool mz_zip_writer_end(mz_zip_archive *pZip) { mz_zip_internal_state *pState; mz_bool status = MZ_TRUE; - if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) + if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || + ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && + (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) return MZ_FALSE; pState = pZip->m_pState; @@ -4800,15 +6378,13 @@ mz_bool mz_zip_writer_end(mz_zip_archive *pZip) mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); #ifndef MINIZ_NO_STDIO - if (pState->m_pFile) - { + if (pState->m_pFile) { MZ_FCLOSE(pState->m_pFile); pState->m_pFile = NULL; } #endif // #ifndef MINIZ_NO_STDIO - if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) - { + if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); pState->m_pMem = NULL; } @@ -4819,44 +6395,48 @@ mz_bool mz_zip_writer_end(mz_zip_archive *pZip) } #ifndef MINIZ_NO_STDIO -mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) -{ +mz_bool mz_zip_add_mem_to_archive_file_in_place( + const char *pZip_filename, const char *pArchive_name, const void *pBuf, + size_t buf_size, const void *pComment, mz_uint16 comment_size, + mz_uint level_and_flags) { mz_bool status, created_new_archive = MZ_FALSE; mz_zip_archive zip_archive; struct MZ_FILE_STAT_STRUCT file_stat; MZ_CLEAR_OBJ(zip_archive); if ((int)level_and_flags < 0) - level_and_flags = MZ_DEFAULT_LEVEL; - if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) + level_and_flags = MZ_DEFAULT_LEVEL; + if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || + ((comment_size) && (!pComment)) || + ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) return MZ_FALSE; if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; - if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) - { + if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) { // Create a new archive. if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0)) return MZ_FALSE; created_new_archive = MZ_TRUE; - } - else - { + } else { // Append to an existing archive. - if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) + if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, + level_and_flags | + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) return MZ_FALSE; - if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) - { + if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) { mz_zip_reader_end(&zip_archive); return MZ_FALSE; } } - status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); - // Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) + status = + mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, + pComment, comment_size, level_and_flags, 0, 0); + // Always finalize, even if adding failed for some reason, so we have a valid + // central directory. (This may not always succeed, but we can try.) if (!mz_zip_writer_finalize_archive(&zip_archive)) status = MZ_FALSE; if (!mz_zip_writer_end(&zip_archive)) status = MZ_FALSE; - if ((!status) && (created_new_archive)) - { + if ((!status) && (created_new_archive)) { // It's a new archive and something went wrong, so just delete it. int ignoredStatus = MZ_DELETE_FILE(pZip_filename); (void)ignoredStatus; @@ -4864,8 +6444,9 @@ mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const return status; } -void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) -{ +void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, + const char *pArchive_name, + size_t *pSize, mz_uint flags) { int file_index; mz_zip_archive zip_archive; void *p = NULL; @@ -4877,10 +6458,13 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char return NULL; MZ_CLEAR_OBJ(zip_archive); - if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) + if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, + flags | + MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) return NULL; - if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, flags)) >= 0) + if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, + flags)) >= 0) p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); mz_zip_reader_end(&zip_archive); diff --git a/contrib/zip/src/zip.c b/contrib/zip/src/zip.c index 80573096b..ff3a8fe1e 100644 --- a/contrib/zip/src/zip.c +++ b/contrib/zip/src/zip.c @@ -7,29 +7,40 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ - -#include "zip.h" -#include "miniz.h" +#define __STDC_WANT_LIB_EXT1__ 1 #include #include #include -#if defined _WIN32 || defined __WIN32__ -/* Win32, DOS */ +#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ + defined(__MINGW32__) +/* Win32, DOS, MSVC, MSVS */ #include #define MKDIR(DIRNAME) _mkdir(DIRNAME) #define STRCLONE(STR) ((STR) ? _strdup(STR) : NULL) #define HAS_DEVICE(P) \ - ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) && \ - (P)[1] == ':') + ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) && \ + (P)[1] == ':') #define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE(P) ? 2 : 0) #define ISSLASH(C) ((C) == '/' || (C) == '\\') #else + +#include // needed for symlink() on BSD +int symlink(const char *target, const char *linkpath); // needed on Linux + #define MKDIR(DIRNAME) mkdir(DIRNAME, 0755) #define STRCLONE(STR) ((STR) ? strdup(STR) : NULL) + +#endif + +#include "miniz.h" +#include "zip.h" + +#ifndef HAS_DEVICE +#define HAS_DEVICE(P) 0 #endif #ifndef FILESYSTEM_PREFIX_LEN @@ -40,601 +51,876 @@ #define ISSLASH(C) ((C) == '/') #endif -#define CLEANUP(ptr) \ - do { \ - if (ptr) { \ - free((void *)ptr); \ - ptr = NULL; \ - } \ - } while (0) +#define CLEANUP(ptr) \ + do { \ + if (ptr) { \ + free((void *)ptr); \ + ptr = NULL; \ + } \ + } while (0) -static char *basename(const char *name) { - char const *p; - char const *base = name += FILESYSTEM_PREFIX_LEN(name); - int all_slashes = 1; +static const char *base_name(const char *name) { + char const *p; + char const *base = name += FILESYSTEM_PREFIX_LEN(name); + int all_slashes = 1; - for (p = name; *p; p++) { - if (ISSLASH(*p)) - base = p + 1; - else - all_slashes = 0; - } + for (p = name; *p; p++) { + if (ISSLASH(*p)) + base = p + 1; + else + all_slashes = 0; + } - /* If NAME is all slashes, arrange to return `/'. */ - if (*base == '\0' && ISSLASH(*name) && all_slashes) --base; + /* If NAME is all slashes, arrange to return `/'. */ + if (*base == '\0' && ISSLASH(*name) && all_slashes) + --base; - return (char *)base; + return base; } static int mkpath(const char *path) { - char const *p; - char npath[MAX_PATH + 1] = {0}; - int len = 0; + char const *p; + char npath[MAX_PATH + 1]; + int len = 0; + int has_device = HAS_DEVICE(path); - for (p = path; *p && len < MAX_PATH; p++) { - if (ISSLASH(*p) && len > 0) { - if (MKDIR(npath) == -1) - if (errno != EEXIST) return -1; - } - npath[len++] = *p; + memset(npath, 0, MAX_PATH + 1); + +#ifdef _WIN32 + // only on windows fix the path + npath[0] = path[0]; + npath[1] = path[1]; + len = 2; +#endif // _WIN32 + + for (p = path + len; *p && len < MAX_PATH; p++) { + if (ISSLASH(*p) && ((!has_device && len > 0) || (has_device && len > 2))) { + if (MKDIR(npath) == -1) + if (errno != EEXIST) + return -1; } + npath[len++] = *p; + } - return 0; + return 0; } -static char *strrpl(const char *str, char oldchar, char newchar) { - char *rpl = (char *)malloc(sizeof(char) * (1 + strlen(str))); - char *begin = rpl; - char c; - while((c = *str++)) { - if (c == oldchar) { - c = newchar; - } - *rpl++ = c; - } - *rpl = '\0'; +static char *strrpl(const char *str, size_t n, char oldchar, char newchar) { + char c; + size_t i; + char *rpl = (char *)calloc((1 + n), sizeof(char)); + char *begin = rpl; + if (!rpl) { + return NULL; + } - return begin; + for (i = 0; (i < n) && (c = *str++); ++i) { + if (c == oldchar) { + c = newchar; + } + *rpl++ = c; + } + + return begin; } struct zip_entry_t { - int index; - const char *name; - mz_uint64 uncomp_size; - mz_uint64 comp_size; - mz_uint32 uncomp_crc32; - mz_uint64 offset; - mz_uint8 header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; - mz_uint64 header_offset; - mz_uint16 method; - mz_zip_writer_add_state state; - tdefl_compressor comp; + int index; + char *name; + mz_uint64 uncomp_size; + mz_uint64 comp_size; + mz_uint32 uncomp_crc32; + mz_uint64 offset; + mz_uint8 header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; + mz_uint64 header_offset; + mz_uint16 method; + mz_zip_writer_add_state state; + tdefl_compressor comp; + mz_uint32 external_attr; + time_t m_time; }; struct zip_t { - mz_zip_archive archive; - mz_uint level; - struct zip_entry_t entry; - char mode; + mz_zip_archive archive; + mz_uint level; + struct zip_entry_t entry; }; struct zip_t *zip_open(const char *zipname, int level, char mode) { - struct zip_t *zip = NULL; + struct zip_t *zip = NULL; - if (!zipname || strlen(zipname) < 1) { - // zip_t archive name is empty or NULL - goto cleanup; + if (!zipname || strlen(zipname) < 1) { + // zip_t archive name is empty or NULL + goto cleanup; + } + + if (level < 0) + level = MZ_DEFAULT_LEVEL; + if ((level & 0xF) > MZ_UBER_COMPRESSION) { + // Wrong compression level + goto cleanup; + } + + zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t)); + if (!zip) + goto cleanup; + + zip->level = (mz_uint)level; + switch (mode) { + case 'w': + // Create a new archive. + if (!mz_zip_writer_init_file(&(zip->archive), zipname, 0)) { + // Cannot initialize zip_archive writer + goto cleanup; } + break; - if (level < 0) level = MZ_DEFAULT_LEVEL; - if ((level & 0xF) > MZ_UBER_COMPRESSION) { - // Wrong compression level - goto cleanup; + case 'r': + case 'a': + if (!mz_zip_reader_init_file( + &(zip->archive), zipname, + zip->level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { + // An archive file does not exist or cannot initialize + // zip_archive reader + goto cleanup; } - - zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t)); - if (!zip) goto cleanup; - - zip->level = level; - zip->mode = mode; - switch (mode) { - case 'w': - // Create a new archive. - if (!mz_zip_writer_init_file(&(zip->archive), zipname, 0)) { - // Cannot initialize zip_archive writer - goto cleanup; - } - break; - - case 'r': - case 'a': - if (!mz_zip_reader_init_file( - &(zip->archive), zipname, - level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { - // An archive file does not exist or cannot initialize - // zip_archive reader - goto cleanup; - } - - if (mode == 'a' && - !mz_zip_writer_init_from_reader(&(zip->archive), zipname)) { - mz_zip_reader_end(&(zip->archive)); - goto cleanup; - } - - break; - - default: - goto cleanup; + if (mode == 'a' && + !mz_zip_writer_init_from_reader(&(zip->archive), zipname)) { + mz_zip_reader_end(&(zip->archive)); + goto cleanup; } + break; - return zip; + default: + goto cleanup; + } + + return zip; cleanup: - CLEANUP(zip); - return NULL; + CLEANUP(zip); + return NULL; } void zip_close(struct zip_t *zip) { - if (zip) { - // Always finalize, even if adding failed for some reason, so we have a - // valid central directory. - mz_zip_writer_finalize_archive(&(zip->archive)); + if (zip) { + // Always finalize, even if adding failed for some reason, so we have a + // valid central directory. + mz_zip_writer_finalize_archive(&(zip->archive)); - mz_zip_writer_end(&(zip->archive)); - mz_zip_reader_end(&(zip->archive)); + mz_zip_writer_end(&(zip->archive)); + mz_zip_reader_end(&(zip->archive)); - CLEANUP(zip); - } + CLEANUP(zip); + } } int zip_entry_open(struct zip_t *zip, const char *entryname) { - char *locname = NULL; - size_t entrylen = 0; - mz_zip_archive *pzip = NULL; - mz_uint num_alignment_padding_bytes, level; + size_t entrylen = 0; + mz_zip_archive *pzip = NULL; + mz_uint num_alignment_padding_bytes, level; + mz_zip_archive_file_stat stats; - if (!zip || !entryname) { - return -1; + if (!zip || !entryname) { + return -1; + } + + entrylen = strlen(entryname); + if (entrylen < 1) { + return -1; + } + + /* + .ZIP File Format Specification Version: 6.3.3 + + 4.4.17.1 The name of the file, with optional relative path. + The path stored MUST not contain a drive or + device letter, or a leading slash. All slashes + MUST be forward slashes '/' as opposed to + backwards slashes '\' for compatibility with Amiga + and UNIX file systems etc. If input came from standard + input, there is no file name field. + */ + zip->entry.name = strrpl(entryname, entrylen, '\\', '/'); + if (!zip->entry.name) { + // Cannot parse zip entry name + return -1; + } + + pzip = &(zip->archive); + if (pzip->m_zip_mode == MZ_ZIP_MODE_READING) { + zip->entry.index = + mz_zip_reader_locate_file(pzip, zip->entry.name, NULL, 0); + if (zip->entry.index < 0) { + goto cleanup; } - entrylen = strlen(entryname); - if (entrylen < 1) { - return -1; + if (!mz_zip_reader_file_stat(pzip, (mz_uint)zip->entry.index, &stats)) { + goto cleanup; } - pzip = &(zip->archive); - /* - .ZIP File Format Specification Version: 6.3.3 - - 4.4.17.1 The name of the file, with optional relative path. - The path stored MUST not contain a drive or - device letter, or a leading slash. All slashes - MUST be forward slashes '/' as opposed to - backwards slashes '\' for compatibility with Amiga - and UNIX file systems etc. If input came from standard - input, there is no file name field. - */ - locname = strrpl(entryname, '\\', '/'); - - if (zip->mode == 'r') { - zip->entry.index = mz_zip_reader_locate_file(pzip, locname, NULL, 0); - CLEANUP(locname); - return (zip->entry.index < 0) ? -1 : 0; - } - - zip->entry.index = zip->archive.m_total_files; - zip->entry.name = locname; - if (!zip->entry.name) { - // Cannot parse zip entry name - return -1; - } - - zip->entry.comp_size = 0; - zip->entry.uncomp_size = 0; - zip->entry.uncomp_crc32 = MZ_CRC32_INIT; - zip->entry.offset = zip->archive.m_archive_size; - zip->entry.header_offset = zip->archive.m_archive_size; - memset(zip->entry.header, 0, - MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8)); - zip->entry.method = 0; - - num_alignment_padding_bytes = - mz_zip_writer_compute_padding_needed_for_file_alignment(pzip); - - if (!pzip->m_pState || (pzip->m_zip_mode != MZ_ZIP_MODE_WRITING)) { - // Wrong zip mode - return -1; - } - if (zip->level & MZ_ZIP_FLAG_COMPRESSED_DATA) { - // Wrong zip compression level - return -1; - } - // no zip64 support yet - if ((pzip->m_total_files == 0xFFFF) || - ((pzip->m_archive_size + num_alignment_padding_bytes + - MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + - entrylen) > 0xFFFFFFFF)) { - // No zip64 support yet - return -1; - } - if (!mz_zip_writer_write_zeros( - pzip, zip->entry.offset, - num_alignment_padding_bytes + sizeof(zip->entry.header))) { - // Cannot memset zip entry header - return -1; - } - - zip->entry.header_offset += num_alignment_padding_bytes; - if (pzip->m_file_offset_alignment) { - MZ_ASSERT((zip->entry.header_offset & - (pzip->m_file_offset_alignment - 1)) == 0); - } - zip->entry.offset += - num_alignment_padding_bytes + sizeof(zip->entry.header); - - if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, zip->entry.name, - entrylen) != entrylen) { - // Cannot write data to zip entry - return -1; - } - - zip->entry.offset += entrylen; - level = zip->level & 0xF; - if (level) { - zip->entry.state.m_pZip = pzip; - zip->entry.state.m_cur_archive_file_ofs = zip->entry.offset; - zip->entry.state.m_comp_size = 0; - - if (tdefl_init(&(zip->entry.comp), mz_zip_writer_add_put_buf_callback, - &(zip->entry.state), - tdefl_create_comp_flags_from_zip_params( - level, -15, MZ_DEFAULT_STRATEGY)) != - TDEFL_STATUS_OKAY) { - // Cannot initialize the zip compressor - return -1; - } - } + zip->entry.comp_size = stats.m_comp_size; + zip->entry.uncomp_size = stats.m_uncomp_size; + zip->entry.uncomp_crc32 = stats.m_crc32; + zip->entry.offset = stats.m_central_dir_ofs; + zip->entry.header_offset = stats.m_local_header_ofs; + zip->entry.method = stats.m_method; + zip->entry.external_attr = stats.m_external_attr; + zip->entry.m_time = stats.m_time; return 0; + } + + zip->entry.index = (int)zip->archive.m_total_files; + zip->entry.comp_size = 0; + zip->entry.uncomp_size = 0; + zip->entry.uncomp_crc32 = MZ_CRC32_INIT; + zip->entry.offset = zip->archive.m_archive_size; + zip->entry.header_offset = zip->archive.m_archive_size; + memset(zip->entry.header, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8)); + zip->entry.method = 0; + zip->entry.external_attr = 0; + + num_alignment_padding_bytes = + mz_zip_writer_compute_padding_needed_for_file_alignment(pzip); + + if (!pzip->m_pState || (pzip->m_zip_mode != MZ_ZIP_MODE_WRITING)) { + // Wrong zip mode + goto cleanup; + } + if (zip->level & MZ_ZIP_FLAG_COMPRESSED_DATA) { + // Wrong zip compression level + goto cleanup; + } + // no zip64 support yet + if ((pzip->m_total_files == 0xFFFF) || + ((pzip->m_archive_size + num_alignment_padding_bytes + + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + + entrylen) > 0xFFFFFFFF)) { + // No zip64 support yet + goto cleanup; + } + if (!mz_zip_writer_write_zeros(pzip, zip->entry.offset, + num_alignment_padding_bytes + + sizeof(zip->entry.header))) { + // Cannot memset zip entry header + goto cleanup; + } + + zip->entry.header_offset += num_alignment_padding_bytes; + if (pzip->m_file_offset_alignment) { + MZ_ASSERT( + (zip->entry.header_offset & (pzip->m_file_offset_alignment - 1)) == 0); + } + zip->entry.offset += num_alignment_padding_bytes + sizeof(zip->entry.header); + + if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, zip->entry.name, + entrylen) != entrylen) { + // Cannot write data to zip entry + goto cleanup; + } + + zip->entry.offset += entrylen; + level = zip->level & 0xF; + if (level) { + zip->entry.state.m_pZip = pzip; + zip->entry.state.m_cur_archive_file_ofs = zip->entry.offset; + zip->entry.state.m_comp_size = 0; + + if (tdefl_init(&(zip->entry.comp), mz_zip_writer_add_put_buf_callback, + &(zip->entry.state), + (int)tdefl_create_comp_flags_from_zip_params( + (int)level, -15, MZ_DEFAULT_STRATEGY)) != + TDEFL_STATUS_OKAY) { + // Cannot initialize the zip compressor + goto cleanup; + } + } + + zip->entry.m_time = time(NULL); + + return 0; + +cleanup: + CLEANUP(zip->entry.name); + return -1; +} + +int zip_entry_openbyindex(struct zip_t *zip, int index) { + mz_zip_archive *pZip = NULL; + mz_zip_archive_file_stat stats; + mz_uint namelen; + const mz_uint8 *pHeader; + const char *pFilename; + + if (!zip) { + // zip_t handler is not initialized + return -1; + } + + pZip = &(zip->archive); + if (pZip->m_zip_mode != MZ_ZIP_MODE_READING) { + // open by index requires readonly mode + return -1; + } + + if (index < 0 || (mz_uint)index >= pZip->m_total_files) { + // index out of range + return -1; + } + + if (!(pHeader = &MZ_ZIP_ARRAY_ELEMENT( + &pZip->m_pState->m_central_dir, mz_uint8, + MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, + mz_uint32, index)))) { + // cannot find header in central directory + return -1; + } + + namelen = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); + pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; + + /* + .ZIP File Format Specification Version: 6.3.3 + + 4.4.17.1 The name of the file, with optional relative path. + The path stored MUST not contain a drive or + device letter, or a leading slash. All slashes + MUST be forward slashes '/' as opposed to + backwards slashes '\' for compatibility with Amiga + and UNIX file systems etc. If input came from standard + input, there is no file name field. + */ + zip->entry.name = strrpl(pFilename, namelen, '\\', '/'); + if (!zip->entry.name) { + // local entry name is NULL + return -1; + } + + if (!mz_zip_reader_file_stat(pZip, (mz_uint)index, &stats)) { + return -1; + } + + zip->entry.index = index; + zip->entry.comp_size = stats.m_comp_size; + zip->entry.uncomp_size = stats.m_uncomp_size; + zip->entry.uncomp_crc32 = stats.m_crc32; + zip->entry.offset = stats.m_central_dir_ofs; + zip->entry.header_offset = stats.m_local_header_ofs; + zip->entry.method = stats.m_method; + zip->entry.external_attr = stats.m_external_attr; + zip->entry.m_time = stats.m_time; + + return 0; } int zip_entry_close(struct zip_t *zip) { - mz_zip_archive *pzip = NULL; - mz_uint level; - tdefl_status done; - mz_uint16 entrylen; - time_t t; - struct tm *tm; - mz_uint16 dos_time, dos_date; - int status = -1; + mz_zip_archive *pzip = NULL; + mz_uint level; + tdefl_status done; + mz_uint16 entrylen; + mz_uint16 dos_time, dos_date; + int status = -1; - if (!zip) { - // zip_t handler is not initialized - return -1; - } + if (!zip) { + // zip_t handler is not initialized + goto cleanup; + } - if (zip->mode == 'r') { - return 0; - } - - pzip = &(zip->archive); - level = zip->level & 0xF; - if (level) { - done = tdefl_compress_buffer(&(zip->entry.comp), "", 0, TDEFL_FINISH); - if (done != TDEFL_STATUS_DONE && done != TDEFL_STATUS_OKAY) { - // Cannot flush compressed buffer - goto cleanup; - } - zip->entry.comp_size = zip->entry.state.m_comp_size; - zip->entry.offset = zip->entry.state.m_cur_archive_file_ofs; - zip->entry.method = MZ_DEFLATED; - } - - entrylen = (mz_uint16)strlen(zip->entry.name); - t = time(NULL); - tm = localtime(&t); - dos_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + - ((tm->tm_sec) >> 1)); - dos_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + - ((tm->tm_mon + 1) << 5) + tm->tm_mday); - - // no zip64 support yet - if ((zip->entry.comp_size > 0xFFFFFFFF) || - (zip->entry.offset > 0xFFFFFFFF)) { - // No zip64 support, yet - goto cleanup; - } - - if (!mz_zip_writer_create_local_dir_header( - pzip, zip->entry.header, entrylen, 0, zip->entry.uncomp_size, - zip->entry.comp_size, zip->entry.uncomp_crc32, zip->entry.method, 0, - dos_time, dos_date)) { - // Cannot create zip entry header - goto cleanup; - } - - if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.header_offset, - zip->entry.header, sizeof(zip->entry.header)) != - sizeof(zip->entry.header)) { - // Cannot write zip entry header - goto cleanup; - } - - if (!mz_zip_writer_add_to_central_dir( - pzip, zip->entry.name, entrylen, NULL, 0, "", 0, - zip->entry.uncomp_size, zip->entry.comp_size, - zip->entry.uncomp_crc32, zip->entry.method, 0, dos_time, dos_date, - zip->entry.header_offset, 0)) { - // Cannot write to zip central dir - goto cleanup; - } - - pzip->m_total_files++; - pzip->m_archive_size = zip->entry.offset; + pzip = &(zip->archive); + if (pzip->m_zip_mode == MZ_ZIP_MODE_READING) { status = 0; + goto cleanup; + } + + level = zip->level & 0xF; + if (level) { + done = tdefl_compress_buffer(&(zip->entry.comp), "", 0, TDEFL_FINISH); + if (done != TDEFL_STATUS_DONE && done != TDEFL_STATUS_OKAY) { + // Cannot flush compressed buffer + goto cleanup; + } + zip->entry.comp_size = zip->entry.state.m_comp_size; + zip->entry.offset = zip->entry.state.m_cur_archive_file_ofs; + zip->entry.method = MZ_DEFLATED; + } + + entrylen = (mz_uint16)strlen(zip->entry.name); + // no zip64 support yet + if ((zip->entry.comp_size > 0xFFFFFFFF) || (zip->entry.offset > 0xFFFFFFFF)) { + // No zip64 support, yet + goto cleanup; + } + + mz_zip_time_t_to_dos_time(zip->entry.m_time, &dos_time, &dos_date); + if (!mz_zip_writer_create_local_dir_header( + pzip, zip->entry.header, entrylen, 0, zip->entry.uncomp_size, + zip->entry.comp_size, zip->entry.uncomp_crc32, zip->entry.method, 0, + dos_time, dos_date)) { + // Cannot create zip entry header + goto cleanup; + } + + if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.header_offset, + zip->entry.header, + sizeof(zip->entry.header)) != sizeof(zip->entry.header)) { + // Cannot write zip entry header + goto cleanup; + } + + if (!mz_zip_writer_add_to_central_dir( + pzip, zip->entry.name, entrylen, NULL, 0, "", 0, + zip->entry.uncomp_size, zip->entry.comp_size, zip->entry.uncomp_crc32, + zip->entry.method, 0, dos_time, dos_date, zip->entry.header_offset, + zip->entry.external_attr)) { + // Cannot write to zip central dir + goto cleanup; + } + + pzip->m_total_files++; + pzip->m_archive_size = zip->entry.offset; + status = 0; cleanup: + if (zip) { + zip->entry.m_time = 0; CLEANUP(zip->entry.name); - return status; + } + return status; +} + +const char *zip_entry_name(struct zip_t *zip) { + if (!zip) { + // zip_t handler is not initialized + return NULL; + } + + return zip->entry.name; +} + +int zip_entry_index(struct zip_t *zip) { + if (!zip) { + // zip_t handler is not initialized + return -1; + } + + return zip->entry.index; +} + +int zip_entry_isdir(struct zip_t *zip) { + if (!zip) { + // zip_t handler is not initialized + return -1; + } + + if (zip->entry.index < 0) { + // zip entry is not opened + return -1; + } + + return (int)mz_zip_reader_is_file_a_directory(&zip->archive, + (mz_uint)zip->entry.index); +} + +unsigned long long zip_entry_size(struct zip_t *zip) { + return zip ? zip->entry.uncomp_size : 0; +} + +unsigned int zip_entry_crc32(struct zip_t *zip) { + return zip ? zip->entry.uncomp_crc32 : 0; } int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) { - mz_uint level; - mz_zip_archive *pzip = NULL; - tdefl_status status; + mz_uint level; + mz_zip_archive *pzip = NULL; + tdefl_status status; - if (!zip) { - // zip_t handler is not initialized + if (!zip) { + // zip_t handler is not initialized + return -1; + } + + pzip = &(zip->archive); + if (buf && bufsize > 0) { + zip->entry.uncomp_size += bufsize; + zip->entry.uncomp_crc32 = (mz_uint32)mz_crc32( + zip->entry.uncomp_crc32, (const mz_uint8 *)buf, bufsize); + + level = zip->level & 0xF; + if (!level) { + if ((pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, buf, + bufsize) != bufsize)) { + // Cannot write buffer return -1; + } + zip->entry.offset += bufsize; + zip->entry.comp_size += bufsize; + } else { + status = tdefl_compress_buffer(&(zip->entry.comp), buf, bufsize, + TDEFL_NO_FLUSH); + if (status != TDEFL_STATUS_DONE && status != TDEFL_STATUS_OKAY) { + // Cannot compress buffer + return -1; + } } + } - pzip = &(zip->archive); - if (buf && bufsize > 0) { - zip->entry.uncomp_size += bufsize; - zip->entry.uncomp_crc32 = (mz_uint32)mz_crc32( - zip->entry.uncomp_crc32, (const mz_uint8 *)buf, bufsize); - - level = zip->level & 0xF; - if (!level) { - if ((pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, buf, - bufsize) != bufsize)) { - // Cannot write buffer - return -1; - } - zip->entry.offset += bufsize; - zip->entry.comp_size += bufsize; - } else { - status = tdefl_compress_buffer(&(zip->entry.comp), buf, bufsize, - TDEFL_NO_FLUSH); - if (status != TDEFL_STATUS_DONE && status != TDEFL_STATUS_OKAY) { - // Cannot compress buffer - return -1; - } - } - } - - return 0; + return 0; } int zip_entry_fwrite(struct zip_t *zip, const char *filename) { - int status = 0; - size_t n = 0; - FILE *stream = NULL; - mz_uint8 buf[MZ_ZIP_MAX_IO_BUF_SIZE] = {0}; + int status = 0; + size_t n = 0; + FILE *stream = NULL; + mz_uint8 buf[MZ_ZIP_MAX_IO_BUF_SIZE]; + struct MZ_FILE_STAT_STRUCT file_stat; - if (!zip) { - // zip_t handler is not initialized - return -1; + if (!zip) { + // zip_t handler is not initialized + return -1; + } + + memset(buf, 0, MZ_ZIP_MAX_IO_BUF_SIZE); + memset((void *)&file_stat, 0, sizeof(struct MZ_FILE_STAT_STRUCT)); + if (MZ_FILE_STAT(filename, &file_stat) != 0) { + // problem getting information - check errno + return -1; + } + + if ((file_stat.st_mode & 0200) == 0) { + // MS-DOS read-only attribute + zip->entry.external_attr |= 0x01; + } + zip->entry.external_attr |= (mz_uint32)((file_stat.st_mode & 0xFFFF) << 16); + zip->entry.m_time = file_stat.st_mtime; + +#if defined(_MSC_VER) + if (fopen_s(&stream, filename, "rb")) +#else + if (!(stream = fopen(filename, "rb"))) +#endif + { + // Cannot open filename + return -1; + } + + while ((n = fread(buf, sizeof(mz_uint8), MZ_ZIP_MAX_IO_BUF_SIZE, stream)) > + 0) { + if (zip_entry_write(zip, buf, n) < 0) { + status = -1; + break; } + } + fclose(stream); - stream = fopen(filename, "rb"); - if (!stream) { - // Cannot open filename - return -1; - } - - while ((n = fread(buf, sizeof(mz_uint8), MZ_ZIP_MAX_IO_BUF_SIZE, stream)) > - 0) { - if (zip_entry_write(zip, buf, n) < 0) { - status = -1; - break; - } - } - fclose(stream); - - return status; + return status; } -int zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize) { - mz_zip_archive *pzip = NULL; - mz_uint idx; +ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize) { + mz_zip_archive *pzip = NULL; + mz_uint idx; + size_t size = 0; - if (!zip) { - // zip_t handler is not initialized - return -1; - } + if (!zip) { + // zip_t handler is not initialized + return -1; + } - if (zip->mode != 'r' || zip->entry.index < 0) { - // the entry is not found or we do not have read access - return -1; - } + pzip = &(zip->archive); + if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) { + // the entry is not found or we do not have read access + return -1; + } - pzip = &(zip->archive); - idx = (mz_uint)zip->entry.index; - if (mz_zip_reader_is_file_a_directory(pzip, idx)) { - // the entry is a directory - return -1; - } + idx = (mz_uint)zip->entry.index; + if (mz_zip_reader_is_file_a_directory(pzip, idx)) { + // the entry is a directory + return -1; + } - *buf = mz_zip_reader_extract_to_heap(pzip, idx, bufsize, 0); - return (*buf) ? 0 : -1; + *buf = mz_zip_reader_extract_to_heap(pzip, idx, &size, 0); + if (*buf && bufsize) { + *bufsize = size; + } + return size; +} + +ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize) { + mz_zip_archive *pzip = NULL; + + if (!zip) { + // zip_t handler is not initialized + return -1; + } + + pzip = &(zip->archive); + if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) { + // the entry is not found or we do not have read access + return -1; + } + + if (!mz_zip_reader_extract_to_mem_no_alloc(pzip, (mz_uint)zip->entry.index, + buf, bufsize, 0, NULL, 0)) { + return -1; + } + + return (ssize_t)zip->entry.uncomp_size; } int zip_entry_fread(struct zip_t *zip, const char *filename) { - mz_zip_archive *pzip = NULL; - mz_uint idx; + mz_zip_archive *pzip = NULL; + mz_uint idx; +#if defined(_MSC_VER) +#else + mz_uint32 xattr = 0; +#endif + mz_zip_archive_file_stat info; - if (!zip) { - // zip_t handler is not initialized - return -1; + if (!zip) { + // zip_t handler is not initialized + return -1; + } + + memset((void *)&info, 0, sizeof(mz_zip_archive_file_stat)); + pzip = &(zip->archive); + if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) { + // the entry is not found or we do not have read access + return -1; + } + + idx = (mz_uint)zip->entry.index; + if (mz_zip_reader_is_file_a_directory(pzip, idx)) { + // the entry is a directory + return -1; + } + + if (!mz_zip_reader_extract_to_file(pzip, idx, filename, 0)) { + return -1; + } + +#if defined(_MSC_VER) +#else + if (!mz_zip_reader_file_stat(pzip, idx, &info)) { + // Cannot get information about zip archive; + return -1; + } + + xattr = (info.m_external_attr >> 16) & 0xFFFF; + if (xattr > 0) { + if (chmod(filename, (mode_t)xattr) < 0) { + return -1; } + } +#endif - if (zip->mode != 'r' || zip->entry.index < 0) { - // the entry is not found or we do not have read access - return -1; - } - - pzip = &(zip->archive); - idx = (mz_uint)zip->entry.index; - if (mz_zip_reader_is_file_a_directory(pzip, idx)) { - // the entry is a directory - return -1; - } - - return (mz_zip_reader_extract_to_file(pzip, idx, filename, 0)) ? 0 : -1; + return 0; } int zip_entry_extract(struct zip_t *zip, size_t (*on_extract)(void *arg, unsigned long long offset, const void *buf, size_t bufsize), void *arg) { - mz_zip_archive *pzip = NULL; - mz_uint idx; + mz_zip_archive *pzip = NULL; + mz_uint idx; - if (!zip) { - // zip_t handler is not initialized - return -1; - } + if (!zip) { + // zip_t handler is not initialized + return -1; + } - if (zip->mode != 'r' || zip->entry.index < 0) { - // the entry is not found or we do not have read access - return -1; - } + pzip = &(zip->archive); + if (pzip->m_zip_mode != MZ_ZIP_MODE_READING || zip->entry.index < 0) { + // the entry is not found or we do not have read access + return -1; + } - pzip = &(zip->archive); - idx = (mz_uint)zip->entry.index; + idx = (mz_uint)zip->entry.index; + return (mz_zip_reader_extract_to_callback(pzip, idx, on_extract, arg, 0)) + ? 0 + : -1; +} - return (mz_zip_reader_extract_to_callback(pzip, idx, on_extract, arg, 0)) - ? 0 - : -1; +int zip_total_entries(struct zip_t *zip) { + if (!zip) { + // zip_t handler is not initialized + return -1; + } + + return (int)zip->archive.m_total_files; } int zip_create(const char *zipname, const char *filenames[], size_t len) { - int status = 0; - size_t i; - mz_zip_archive zip_archive; + int status = 0; + size_t i; + mz_zip_archive zip_archive; + struct MZ_FILE_STAT_STRUCT file_stat; + mz_uint32 ext_attributes = 0; - if (!zipname || strlen(zipname) < 1) { - // zip_t archive name is empty or NULL - return -1; + if (!zipname || strlen(zipname) < 1) { + // zip_t archive name is empty or NULL + return -1; + } + + // Create a new archive. + if (!memset(&(zip_archive), 0, sizeof(zip_archive))) { + // Cannot memset zip archive + return -1; + } + + if (!mz_zip_writer_init_file(&zip_archive, zipname, 0)) { + // Cannot initialize zip_archive writer + return -1; + } + + memset((void *)&file_stat, 0, sizeof(struct MZ_FILE_STAT_STRUCT)); + + for (i = 0; i < len; ++i) { + const char *name = filenames[i]; + if (!name) { + status = -1; + break; } - // Create a new archive. - if (!memset(&(zip_archive), 0, sizeof(zip_archive))) { - // Cannot memset zip archive - return -1; + if (MZ_FILE_STAT(name, &file_stat) != 0) { + // problem getting information - check errno + return -1; } - if (!mz_zip_writer_init_file(&zip_archive, zipname, 0)) { - // Cannot initialize zip_archive writer - return -1; + if ((file_stat.st_mode & 0200) == 0) { + // MS-DOS read-only attribute + ext_attributes |= 0x01; } + ext_attributes |= (mz_uint32)((file_stat.st_mode & 0xFFFF) << 16); - for (i = 0; i < len; ++i) { - const char *name = filenames[i]; - if (!name) { - status = -1; - break; - } - - if (!mz_zip_writer_add_file(&zip_archive, basename(name), name, "", 0, - ZIP_DEFAULT_COMPRESSION_LEVEL)) { - // Cannot add file to zip_archive - status = -1; - break; - } + if (!mz_zip_writer_add_file(&zip_archive, base_name(name), name, "", 0, + ZIP_DEFAULT_COMPRESSION_LEVEL, + ext_attributes)) { + // Cannot add file to zip_archive + status = -1; + break; } + } - mz_zip_writer_finalize_archive(&zip_archive); - mz_zip_writer_end(&zip_archive); - return status; + mz_zip_writer_finalize_archive(&zip_archive); + mz_zip_writer_end(&zip_archive); + return status; } int zip_extract(const char *zipname, const char *dir, int (*on_extract)(const char *filename, void *arg), void *arg) { - int status = -1; - mz_uint i, n; - char path[MAX_PATH + 1] = {0}; - mz_zip_archive zip_archive; - mz_zip_archive_file_stat info; - size_t dirlen = 0; + int status = -1; + mz_uint i, n; + char path[MAX_PATH + 1]; + char symlink_to[MAX_PATH + 1]; + mz_zip_archive zip_archive; + mz_zip_archive_file_stat info; + size_t dirlen = 0; + mz_uint32 xattr = 0; - if (!memset(&(zip_archive), 0, sizeof(zip_archive))) { - // Cannot memset zip archive - return -1; - } + memset(path, 0, sizeof(path)); + memset(symlink_to, 0, sizeof(symlink_to)); + if (!memset(&(zip_archive), 0, sizeof(zip_archive))) { + // Cannot memset zip archive + return -1; + } - if (!zipname || !dir) { - // Cannot parse zip archive name - return -1; - } + if (!zipname || !dir) { + // Cannot parse zip archive name + return -1; + } - dirlen = strlen(dir); - if (dirlen + 1 > MAX_PATH) { - return -1; - } + dirlen = strlen(dir); + if (dirlen + 1 > MAX_PATH) { + return -1; + } - // Now try to open the archive. - if (!mz_zip_reader_init_file(&zip_archive, zipname, 0)) { - // Cannot initialize zip_archive reader - return -1; - } + // Now try to open the archive. + if (!mz_zip_reader_init_file(&zip_archive, zipname, 0)) { + // Cannot initialize zip_archive reader + return -1; + } - strcpy(path, dir); - if (!ISSLASH(path[dirlen - 1])) { -#if defined _WIN32 || defined __WIN32__ - path[dirlen] = '\\'; + memset((void *)&info, 0, sizeof(mz_zip_archive_file_stat)); + +#if defined(_MSC_VER) + strcpy_s(path, MAX_PATH, dir); #else - path[dirlen] = '/'; + strcpy(path, dir); #endif - ++dirlen; + + if (!ISSLASH(path[dirlen - 1])) { +#if defined(_WIN32) || defined(__WIN32__) + path[dirlen] = '\\'; +#else + path[dirlen] = '/'; +#endif + ++dirlen; + } + + // Get and print information about each file in the archive. + n = mz_zip_reader_get_num_files(&zip_archive); + for (i = 0; i < n; ++i) { + if (!mz_zip_reader_file_stat(&zip_archive, i, &info)) { + // Cannot get information about zip archive; + goto out; + } +#if defined(_MSC_VER) + strncpy_s(&path[dirlen], MAX_PATH - dirlen, info.m_filename, + MAX_PATH - dirlen); +#else + strncpy(&path[dirlen], info.m_filename, MAX_PATH - dirlen); +#endif + if (mkpath(path) < 0) { + // Cannot make a path + goto out; } - // Get and print information about each file in the archive. - n = mz_zip_reader_get_num_files(&zip_archive); - for (i = 0; i < n; ++i) { - if (!mz_zip_reader_file_stat(&zip_archive, i, &info)) { - // Cannot get information about zip archive; - goto out; - } - strncpy(&path[dirlen], info.m_filename, MAX_PATH - dirlen); - if (mkpath(path) < 0) { - // Cannot make a path - goto out; + if ((((info.m_version_made_by >> 8) == 3) || ((info.m_version_made_by >> 8) == 19)) // if zip is produced on Unix or macOS (3 and 19 from section 4.4.2.2 of zip standard) + && info.m_external_attr & (0x20 << 24)) { // and has sym link attribute (0x80 is file, 0x40 is directory) +#if defined(_WIN32) || defined(__WIN32__) || defined(_MSC_VER) || \ + defined(__MINGW32__) +#else + if (info.m_uncomp_size > MAX_PATH || !mz_zip_reader_extract_to_mem_no_alloc(&zip_archive, i, symlink_to, MAX_PATH, 0, NULL, 0)) { + goto out; + } + symlink_to[info.m_uncomp_size] = '\0'; + if (symlink(symlink_to, path) != 0) { + goto out; + } +#endif + } else { + if (!mz_zip_reader_is_file_a_directory(&zip_archive, i)) { + if (!mz_zip_reader_extract_to_file(&zip_archive, i, path, 0)) { + // Cannot extract zip archive to file + goto out; } + } - if (!mz_zip_reader_is_file_a_directory(&zip_archive, i)) { - if (!mz_zip_reader_extract_to_file(&zip_archive, i, path, 0)) { - // Cannot extract zip archive to file - goto out; - } - } - - if (on_extract) { - if (on_extract(path, arg) < 0) { - goto out; - } +#if defined(_MSC_VER) +#else + xattr = (info.m_external_attr >> 16) & 0xFFFF; + if (xattr > 0) { + if (chmod(path, (mode_t)xattr) < 0) { + goto out; } + } +#endif } - status = 0; + + if (on_extract) { + if (on_extract(path, arg) < 0) { + goto out; + } + } + } + status = 0; out: - // Close the archive, freeing any resources it was using - if (!mz_zip_reader_end(&zip_archive)) { - // Cannot end zip reader - status = -1; - } + // Close the archive, freeing any resources it was using + if (!mz_zip_reader_end(&zip_archive)) { + // Cannot end zip reader + status = -1; + } - return status; + return status; } diff --git a/contrib/zip/src/zip.h b/contrib/zip/src/zip.h index 1611b5417..5f39df50a 100644 --- a/contrib/zip/src/zip.h +++ b/contrib/zip/src/zip.h @@ -13,11 +13,24 @@ #define ZIP_H #include +#include #ifdef __cplusplus extern "C" { #endif +#if !defined(_SSIZE_T_DEFINED) && !defined(_SSIZE_T_DEFINED_) && \ + !defined(_SSIZE_T) && !defined(_SSIZE_T_) && !defined(__ssize_t_defined) +#define _SSIZE_T +// 64-bit Windows is the only mainstream platform +// where sizeof(long) != sizeof(void*) +#ifdef _WIN64 +typedef long long ssize_t; /* byte count or error */ +#else +typedef long ssize_t; /* byte count or error */ +#endif +#endif + #ifndef MAX_PATH #define MAX_PATH 32767 /* # chars in a path name including NULL */ #endif @@ -47,7 +60,7 @@ struct zip_t; extern struct zip_t *zip_open(const char *zipname, int level, char mode); /* - Closes zip archive, releases resources - always finalize. + Closes the zip archive, releases resources - always finalize. Args: zip: zip archive handler. @@ -55,7 +68,10 @@ extern struct zip_t *zip_open(const char *zipname, int level, char mode); extern void zip_close(struct zip_t *zip); /* - Opens a new entry for writing in a zip archive. + Opens an entry by name in the zip archive. + For zip archive opened in 'w' or 'a' mode the function will append + a new entry. In readonly mode the function tries to locate the entry + in global dictionary. Args: zip: zip archive handler. @@ -66,6 +82,19 @@ extern void zip_close(struct zip_t *zip); */ extern int zip_entry_open(struct zip_t *zip, const char *entryname); +/* + Opens a new entry by index in the zip archive. + This function is only valid if zip archive was opened in 'r' (readonly) mode. + + Args: + zip: zip archive handler. + index: index in local dictionary. + + Returns: + The return code - 0 on success, negative number (< 0) on error. +*/ +extern int zip_entry_openbyindex(struct zip_t *zip, int index); + /* Closes a zip entry, flushes buffer and releases resources. @@ -77,6 +106,67 @@ extern int zip_entry_open(struct zip_t *zip, const char *entryname); */ extern int zip_entry_close(struct zip_t *zip); +/* + Returns a local name of the current zip entry. + The main difference between user's entry name and local entry name + is optional relative path. + Following .ZIP File Format Specification - the path stored MUST not contain + a drive or device letter, or a leading slash. + All slashes MUST be forward slashes '/' as opposed to backwards slashes '\' + for compatibility with Amiga and UNIX file systems etc. + + Args: + zip: zip archive handler. + + Returns: + The pointer to the current zip entry name, or NULL on error. +*/ +extern const char *zip_entry_name(struct zip_t *zip); + +/* + Returns an index of the current zip entry. + + Args: + zip: zip archive handler. + + Returns: + The index on success, negative number (< 0) on error. +*/ +extern int zip_entry_index(struct zip_t *zip); + +/* + Determines if the current zip entry is a directory entry. + + Args: + zip: zip archive handler. + + Returns: + The return code - 1 (true), 0 (false), negative number (< 0) on error. +*/ +extern int zip_entry_isdir(struct zip_t *zip); + +/* + Returns an uncompressed size of the current zip entry. + + Args: + zip: zip archive handler. + + Returns: + The uncompressed size in bytes. +*/ +extern unsigned long long zip_entry_size(struct zip_t *zip); + +/* + Returns CRC-32 checksum of the current zip entry. + + Args: + zip: zip archive handler. + + Returns: + The CRC-32 checksum. +*/ +extern unsigned int zip_entry_crc32(struct zip_t *zip); + /* Compresses an input buffer for the current zip entry. @@ -116,9 +206,31 @@ extern int zip_entry_fwrite(struct zip_t *zip, const char *filename); - for large entries, please take a look at zip_entry_extract function. Returns: - The return code - 0 on success, negative number (< 0) on error. + The return code - the number of bytes actually read on success. + Otherwise a -1 on error. */ -extern int zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize); +extern ssize_t zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize); + +/* + Extracts the current zip entry into a memory buffer using no memory + allocation. + + Args: + zip: zip archive handler. + buf: preallocated output buffer. + bufsize: output buffer size (in bytes). + + Note: + - ensure supplied output buffer is large enough. + - zip_entry_size function (returns uncompressed size for the current entry) + can be handy to estimate how big buffer is needed. + - for large entries, please take a look at zip_entry_extract function. + + Returns: + The return code - the number of bytes actually read on success. + Otherwise a -1 on error (e.g. bufsize is not large enough). +*/ +extern ssize_t zip_entry_noallocread(struct zip_t *zip, void *buf, size_t bufsize); /* Extracts the current zip entry into output file. @@ -133,9 +245,9 @@ extern int zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize); extern int zip_entry_fread(struct zip_t *zip, const char *filename); /* - Extract the current zip entry using a callback function (on_extract). + Extracts the current zip entry using a callback function (on_extract). - Args: + Args: zip: zip archive handler. on_extract: callback function. arg: opaque pointer (optional argument, @@ -144,12 +256,23 @@ extern int zip_entry_fread(struct zip_t *zip, const char *filename); Returns: The return code - 0 on success, negative number (< 0) on error. */ -extern int zip_entry_extract(struct zip_t *zip, - size_t (*on_extract)(void *arg, - unsigned long long offset, - const void *data, - size_t size), - void *arg); +extern int +zip_entry_extract(struct zip_t *zip, + size_t (*on_extract)(void *arg, unsigned long long offset, + const void *data, size_t size), + void *arg); + +/* + Returns the number of all entries (files and directories) in the zip archive. + + Args: + zip: zip archive handler. + + Returns: + The return code - the number of entries on success, + negative number (< 0) on error. +*/ +extern int zip_total_entries(struct zip_t *zip); /* Creates a new archive and puts files into a single zip archive. diff --git a/contrib/zip/test/CMakeLists.txt b/contrib/zip/test/CMakeLists.txt index 7734dcbe7..9b2a8db10 100644 --- a/contrib/zip/test/CMakeLists.txt +++ b/contrib/zip/test/CMakeLists.txt @@ -1,7 +1,19 @@ cmake_minimum_required(VERSION 2.8) +if ("${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") + if(ENABLE_COVERAGE) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g ") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ftest-coverage") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage") + endif() +endif () + # test include_directories(../src) add_executable(test.exe test.c ../src/zip.c) +add_executable(test_miniz.exe test_miniz.c) add_test(NAME test COMMAND test.exe) +add_test(NAME test_miniz COMMAND test_miniz.exe) diff --git a/contrib/zip/test/test.c b/contrib/zip/test/test.c index 0b9c9f7b6..454430533 100644 --- a/contrib/zip/test/test.c +++ b/contrib/zip/test/test.c @@ -4,102 +4,456 @@ #include #include #include +#include -#define ZIPNAME "test.zip" +#if defined(_MSC_VER) || defined(__MINGW64__) || defined(__MINGW32__) +#define MZ_FILE_STAT_STRUCT _stat +#define MZ_FILE_STAT _stat +#else +#define MZ_FILE_STAT_STRUCT stat +#define MZ_FILE_STAT stat +#endif + +#define ZIPNAME "test.zip\0" #define TESTDATA1 "Some test data 1...\0" +#define CRC32DATA1 2220805626 #define TESTDATA2 "Some test data 2...\0" +#define CRC32DATA2 2532008468 + +#define RFILE "4.txt\0" +#define RMODE 0100444 + +#define WFILE "6.txt\0" +#define WMODE 0100666 + +#define XFILE "7.txt\0" +#define XMODE 0100777 + +#define UNUSED(x) (void)x + +static int total_entries = 0; static void test_write(void) { - struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); - assert(zip != NULL); + struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + assert(zip != NULL); - assert(0 == zip_entry_open(zip, "test/test-1.txt")); - assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); - assert(0 == zip_entry_close(zip)); + assert(0 == zip_entry_open(zip, "test/test-1.txt")); + assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); + assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt")); + assert(total_entries == zip_entry_index(zip)); + assert(strlen(TESTDATA1) == zip_entry_size(zip)); + assert(CRC32DATA1 == zip_entry_crc32(zip)); + ++total_entries; + assert(0 == zip_entry_close(zip)); - zip_close(zip); + zip_close(zip); } static void test_append(void) { - struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a'); - assert(zip != NULL); + struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a'); + assert(zip != NULL); - assert(0 == zip_entry_open(zip, "test\\test-2.txt")); - assert(0 == zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2))); - assert(0 == zip_entry_close(zip)); + assert(0 == zip_entry_open(zip, "test\\test-2.txt")); + assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt")); + assert(total_entries == zip_entry_index(zip)); + assert(0 == zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2))); + assert(strlen(TESTDATA2) == zip_entry_size(zip)); + assert(CRC32DATA2 == zip_entry_crc32(zip)); - zip_close(zip); + ++total_entries; + assert(0 == zip_entry_close(zip)); + + assert(0 == zip_entry_open(zip, "test\\empty/")); + assert(0 == strcmp(zip_entry_name(zip), "test/empty/")); + assert(0 == zip_entry_size(zip)); + assert(0 == zip_entry_crc32(zip)); + + assert(total_entries == zip_entry_index(zip)); + ++total_entries; + assert(0 == zip_entry_close(zip)); + + assert(0 == zip_entry_open(zip, "empty/")); + assert(0 == strcmp(zip_entry_name(zip), "empty/")); + assert(0 == zip_entry_size(zip)); + assert(0 == zip_entry_crc32(zip)); + + assert(total_entries == zip_entry_index(zip)); + ++total_entries; + assert(0 == zip_entry_close(zip)); + + zip_close(zip); } static void test_read(void) { - char *buf = NULL; - size_t bufsize; - struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); - assert(zip != NULL); + char *buf = NULL; + ssize_t bufsize; + size_t buftmp; + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + assert(zip != NULL); - assert(0 == zip_entry_open(zip, "test\\test-1.txt")); - assert(0 == zip_entry_read(zip, (void **)&buf, &bufsize)); - assert(bufsize == strlen(TESTDATA1)); - assert(0 == strncmp(buf, TESTDATA1, bufsize)); - assert(0 == zip_entry_close(zip)); - free(buf); - buf = NULL; - bufsize = 0; + assert(0 == zip_entry_open(zip, "test\\test-1.txt")); + assert(strlen(TESTDATA1) == zip_entry_size(zip)); + assert(CRC32DATA1 == zip_entry_crc32(zip)); - assert(0 == zip_entry_open(zip, "test/test-2.txt")); - assert(0 == zip_entry_read(zip, (void **)&buf, &bufsize)); - assert(bufsize == strlen(TESTDATA2)); - assert(0 == strncmp(buf, TESTDATA2, bufsize)); - assert(0 == zip_entry_close(zip)); - free(buf); - buf = NULL; - bufsize = 0; + bufsize = zip_entry_read(zip, (void **)&buf, &buftmp); + assert(bufsize == strlen(TESTDATA1)); + assert((size_t)bufsize == buftmp); + assert(0 == strncmp(buf, TESTDATA1, bufsize)); + assert(0 == zip_entry_close(zip)); + free(buf); + buf = NULL; + + assert(0 == zip_entry_open(zip, "test/test-2.txt")); + assert(strlen(TESTDATA2) == zip_entry_size(zip)); + assert(CRC32DATA2 == zip_entry_crc32(zip)); - zip_close(zip); + bufsize = zip_entry_read(zip, (void **)&buf, NULL); + assert((size_t)bufsize == strlen(TESTDATA2)); + assert(0 == strncmp(buf, TESTDATA2, (size_t)bufsize)); + assert(0 == zip_entry_close(zip)); + free(buf); + buf = NULL; + bufsize = 0; + + assert(0 == zip_entry_open(zip, "test\\empty/")); + assert(0 == strcmp(zip_entry_name(zip), "test/empty/")); + assert(0 == zip_entry_size(zip)); + assert(0 == zip_entry_crc32(zip)); + assert(0 == zip_entry_close(zip)); + + buftmp = strlen(TESTDATA2); + buf = calloc(buftmp, sizeof(char)); + assert(0 == zip_entry_open(zip, "test/test-2.txt")); + + bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp); + assert(buftmp == (size_t)bufsize); + assert(0 == strncmp(buf, TESTDATA2, buftmp)); + assert(0 == zip_entry_close(zip)); + free(buf); + buf = NULL; + + buftmp = strlen(TESTDATA1); + buf = calloc(buftmp, sizeof(char)); + assert(0 == zip_entry_open(zip, "test/test-1.txt")); + + bufsize = zip_entry_noallocread(zip, (void *)buf, buftmp); + assert(buftmp == (size_t)bufsize); + assert(0 == strncmp(buf, TESTDATA1, buftmp)); + assert(0 == zip_entry_close(zip)); + free(buf); + buf = NULL; + bufsize = 0; + + zip_close(zip); } struct buffer_t { - char *data; - size_t size; + char *data; + size_t size; }; static size_t on_extract(void *arg, unsigned long long offset, const void *data, size_t size) { - struct buffer_t *buf = (struct buffer_t *)arg; - buf->data = realloc(buf->data, buf->size + size + 1); - assert(NULL != buf->data); + UNUSED(offset); - memcpy(&(buf->data[buf->size]), data, size); - buf->size += size; - buf->data[buf->size] = 0; + struct buffer_t *buf = (struct buffer_t *)arg; + buf->data = realloc(buf->data, buf->size + size + 1); + assert(NULL != buf->data); - return size; + memcpy(&(buf->data[buf->size]), data, size); + buf->size += size; + buf->data[buf->size] = 0; + + return size; } static void test_extract(void) { - struct buffer_t buf = {0}; + struct buffer_t buf; - struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); - assert(zip != NULL); + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + assert(zip != NULL); + memset((void *)&buf, 0, sizeof(struct buffer_t)); - assert(0 == zip_entry_open(zip, "test/test-1.txt")); - assert(0 == zip_entry_extract(zip, on_extract, &buf)); + assert(0 == zip_entry_open(zip, "test/test-1.txt")); + assert(0 == zip_entry_extract(zip, on_extract, &buf)); - assert(buf.size == strlen(TESTDATA1)); - assert(0 == strncmp(buf.data, TESTDATA1, buf.size)); + assert(buf.size == strlen(TESTDATA1)); + assert(0 == strncmp(buf.data, TESTDATA1, buf.size)); + assert(0 == zip_entry_close(zip)); + free(buf.data); + buf.data = NULL; + buf.size = 0; + + zip_close(zip); +} + +static void test_total_entries(void) { + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + assert(zip != NULL); + + int n = zip_total_entries(zip); + zip_close(zip); + + assert(n == total_entries); +} + +static void test_entry_name(void) { + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + assert(zip != NULL); + + assert(zip_entry_name(zip) == NULL); + + assert(0 == zip_entry_open(zip, "test\\test-1.txt")); + assert(NULL != zip_entry_name(zip)); + assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt")); + assert(strlen(TESTDATA1) == zip_entry_size(zip)); + assert(CRC32DATA1 == zip_entry_crc32(zip)); + assert(0 == zip_entry_index(zip)); + + assert(0 == zip_entry_close(zip)); + + assert(0 == zip_entry_open(zip, "test/test-2.txt")); + assert(NULL != zip_entry_name(zip)); + assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt")); + assert(strlen(TESTDATA2) == zip_entry_size(zip)); + assert(CRC32DATA2 == zip_entry_crc32(zip)); + assert(1 == zip_entry_index(zip)); + + assert(0 == zip_entry_close(zip)); + + zip_close(zip); +} + +static void test_entry_index(void) { + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + assert(zip != NULL); + + assert(0 == zip_entry_open(zip, "test\\test-1.txt")); + assert(0 == zip_entry_index(zip)); + assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt")); + assert(strlen(TESTDATA1) == zip_entry_size(zip)); + assert(CRC32DATA1 == zip_entry_crc32(zip)); + assert(0 == zip_entry_close(zip)); + + assert(0 == zip_entry_open(zip, "test/test-2.txt")); + assert(1 == zip_entry_index(zip)); + assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt")); + assert(strlen(TESTDATA2) == zip_entry_size(zip)); + assert(CRC32DATA2 == zip_entry_crc32(zip)); + assert(0 == zip_entry_close(zip)); + + zip_close(zip); +} + +static void test_entry_openbyindex(void) { + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + assert(zip != NULL); + + assert(0 == zip_entry_openbyindex(zip, 1)); + assert(1 == zip_entry_index(zip)); + assert(strlen(TESTDATA2) == zip_entry_size(zip)); + assert(CRC32DATA2 == zip_entry_crc32(zip)); + assert(0 == strcmp(zip_entry_name(zip), "test/test-2.txt")); + assert(0 == zip_entry_close(zip)); + + assert(0 == zip_entry_openbyindex(zip, 0)); + assert(0 == zip_entry_index(zip)); + assert(strlen(TESTDATA1) == zip_entry_size(zip)); + assert(CRC32DATA1 == zip_entry_crc32(zip)); + assert(0 == strcmp(zip_entry_name(zip), "test/test-1.txt")); + assert(0 == zip_entry_close(zip)); + + zip_close(zip); +} + +static void test_list_entries(void) { + struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); + assert(zip != NULL); + + int i = 0, n = zip_total_entries(zip); + for (; i < n; ++i) { + assert(0 == zip_entry_openbyindex(zip, i)); + fprintf(stdout, "[%d]: %s", i, zip_entry_name(zip)); + if (zip_entry_isdir(zip)) { + fprintf(stdout, " (DIR)"); + } + fprintf(stdout, "\n"); assert(0 == zip_entry_close(zip)); - free(buf.data); - buf.data = NULL; - buf.size = 0; + } - zip_close(zip); + zip_close(zip); +} + +static void test_fwrite(void) { + const char *filename = WFILE; + FILE *stream = NULL; + struct zip_t *zip = NULL; +#if defined(_MSC_VER) + if (0 != fopen_s(&stream, filename, "w+")) +#else + if (!(stream = fopen(filename, "w+"))) +#endif + { + // Cannot open filename + fprintf(stdout, "Cannot open filename\n"); + assert(0 == -1); + } + fwrite(TESTDATA1, sizeof(char), strlen(TESTDATA1), stream); + assert(0 == fclose(stream)); + + zip = zip_open(ZIPNAME, 9, 'w'); + assert(zip != NULL); + assert(0 == zip_entry_open(zip, WFILE)); + assert(0 == zip_entry_fwrite(zip, WFILE)); + assert(0 == zip_entry_close(zip)); + + zip_close(zip); + remove(WFILE); + remove(ZIPNAME); +} + +static void test_exe_permissions(void) { +#if defined(_WIN32) || defined(__WIN32__) +#else + struct MZ_FILE_STAT_STRUCT file_stats; + const char *filenames[] = {XFILE}; + FILE *f = fopen(XFILE, "w"); + fclose(f); + chmod(XFILE, XMODE); + + remove(ZIPNAME); + + assert(0 == zip_create(ZIPNAME, filenames, 1)); + + remove(XFILE); + + assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL)); + + assert(0 == MZ_FILE_STAT(XFILE, &file_stats)); + assert(XMODE == file_stats.st_mode); + + remove(XFILE); + remove(ZIPNAME); +#endif +} + +static void test_read_permissions(void) { +#if defined(_MSC_VER) +#else + + struct MZ_FILE_STAT_STRUCT file_stats; + const char *filenames[] = {RFILE}; + FILE *f = fopen(RFILE, "w"); + fclose(f); + chmod(RFILE, RMODE); + + remove(ZIPNAME); + + assert(0 == zip_create(ZIPNAME, filenames, 1)); + + // chmod from 444 to 666 to be able delete the file on windows + chmod(RFILE, WMODE); + remove(RFILE); + + assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL)); + + assert(0 == MZ_FILE_STAT(RFILE, &file_stats)); + assert(RMODE == file_stats.st_mode); + + chmod(RFILE, WMODE); + remove(RFILE); + remove(ZIPNAME); +#endif +} + +static void test_write_permissions(void) { +#if defined(_MSC_VER) +#else + + struct MZ_FILE_STAT_STRUCT file_stats; + const char *filenames[] = {WFILE}; + FILE *f = fopen(WFILE, "w"); + fclose(f); + chmod(WFILE, WMODE); + + remove(ZIPNAME); + + assert(0 == zip_create(ZIPNAME, filenames, 1)); + + remove(WFILE); + + assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL)); + + assert(0 == MZ_FILE_STAT(WFILE, &file_stats)); + assert(WMODE == file_stats.st_mode); + + remove(WFILE); + remove(ZIPNAME); +#endif +} + +static void test_mtime(void) { + struct MZ_FILE_STAT_STRUCT file_stat1, file_stat2; + + const char *filename = WFILE; + FILE *stream = NULL; + struct zip_t *zip = NULL; +#if defined(_MSC_VER) + if (0 != fopen_s(&stream, filename, "w+")) +#else + if (!(stream = fopen(filename, "w+"))) +#endif + { + // Cannot open filename + fprintf(stdout, "Cannot open filename\n"); + assert(0 == -1); + } + fwrite(TESTDATA1, sizeof(char), strlen(TESTDATA1), stream); + assert(0 == fclose(stream)); + + memset(&file_stat1, 0, sizeof(file_stat1)); + memset(&file_stat2, 0, sizeof(file_stat2)); + zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); + assert(zip != NULL); + assert(0 == zip_entry_open(zip, filename)); + assert(0 == zip_entry_fwrite(zip, filename)); + assert(0 == zip_entry_close(zip)); + zip_close(zip); + + assert(0 == MZ_FILE_STAT(filename, &file_stat1)); + + remove(filename); + assert(0 == zip_extract(ZIPNAME, ".", NULL, NULL)); + assert(0 == MZ_FILE_STAT(filename, &file_stat2)); + fprintf(stdout, "file_stat1.st_mtime: %lu\n", file_stat1.st_mtime); + fprintf(stdout, "file_stat2.st_mtime: %lu\n", file_stat2.st_mtime); + assert(labs(file_stat1.st_mtime - file_stat2.st_mtime) <= 1); + + remove(filename); + remove(ZIPNAME); } int main(int argc, char *argv[]) { - test_write(); - test_append(); - test_read(); - test_extract(); + UNUSED(argc); + UNUSED(argv); - return remove(ZIPNAME); + remove(ZIPNAME); + + test_write(); + test_append(); + test_read(); + test_extract(); + test_total_entries(); + test_entry_name(); + test_entry_index(); + test_entry_openbyindex(); + test_list_entries(); + test_fwrite(); + test_read_permissions(); + test_write_permissions(); + test_exe_permissions(); + test_mtime(); + + remove(ZIPNAME); + return 0; } diff --git a/contrib/zip/test/test_miniz.c b/contrib/zip/test/test_miniz.c new file mode 100644 index 000000000..ebc0564dc --- /dev/null +++ b/contrib/zip/test/test_miniz.c @@ -0,0 +1,104 @@ +// Demonstrates miniz.c's compress() and uncompress() functions +// (same as zlib's). Public domain, May 15 2011, Rich Geldreich, +// richgel99@gmail.com. See "unlicense" statement at the end of tinfl.c. + +#include +#include + +typedef unsigned char uint8; +typedef unsigned short uint16; +typedef unsigned int uint; + +// The string to compress. +static const char *s_pStr = + "Good morning Dr. Chandra. This is Hal. I am ready for my first lesson." + "Good morning Dr. Chandra. This is Hal. I am ready for my first lesson." + "Good morning Dr. Chandra. This is Hal. I am ready for my first lesson." + "Good morning Dr. Chandra. This is Hal. I am ready for my first lesson." + "Good morning Dr. Chandra. This is Hal. I am ready for my first lesson." + "Good morning Dr. Chandra. This is Hal. I am ready for my first lesson." + "Good morning Dr. Chandra. This is Hal. I am ready for my first lesson."; + +int main(int argc, char *argv[]) { + uint step = 0; + int cmp_status; + uLong src_len = (uLong)strlen(s_pStr); + uLong cmp_len = compressBound(src_len); + uLong uncomp_len = src_len; + uint8 *pCmp, *pUncomp; + uint total_succeeded = 0; + (void)argc, (void)argv; + + printf("miniz.c version: %s\n", MZ_VERSION); + + do { + // Allocate buffers to hold compressed and uncompressed data. + pCmp = (mz_uint8 *)malloc((size_t)cmp_len); + pUncomp = (mz_uint8 *)malloc((size_t)src_len); + if ((!pCmp) || (!pUncomp)) { + printf("Out of memory!\n"); + return EXIT_FAILURE; + } + + // Compress the string. + cmp_status = + compress(pCmp, &cmp_len, (const unsigned char *)s_pStr, src_len); + if (cmp_status != Z_OK) { + printf("compress() failed!\n"); + free(pCmp); + free(pUncomp); + return EXIT_FAILURE; + } + + printf("Compressed from %u to %u bytes\n", (mz_uint32)src_len, + (mz_uint32)cmp_len); + + if (step) { + // Purposely corrupt the compressed data if fuzzy testing (this is a + // very crude fuzzy test). + uint n = 1 + (rand() % 3); + while (n--) { + uint i = rand() % cmp_len; + pCmp[i] ^= (rand() & 0xFF); + } + } + + // Decompress. + cmp_status = uncompress(pUncomp, &uncomp_len, pCmp, cmp_len); + total_succeeded += (cmp_status == Z_OK); + + if (step) { + printf("Simple fuzzy test: step %u total_succeeded: %u\n", step, + total_succeeded); + } else { + if (cmp_status != Z_OK) { + printf("uncompress failed!\n"); + free(pCmp); + free(pUncomp); + return EXIT_FAILURE; + } + + printf("Decompressed from %u to %u bytes\n", (mz_uint32)cmp_len, + (mz_uint32)uncomp_len); + + // Ensure uncompress() returned the expected data. + if ((uncomp_len != src_len) || + (memcmp(pUncomp, s_pStr, (size_t)src_len))) { + printf("Decompression failed!\n"); + free(pCmp); + free(pUncomp); + return EXIT_FAILURE; + } + } + + free(pCmp); + free(pUncomp); + + step++; + + // Keep on fuzzy testing if there's a non-empty command line. + } while (argc >= 2); + + printf("Success.\n"); + return EXIT_SUCCESS; +} diff --git a/contrib/zlib/CMakeLists.txt b/contrib/zlib/CMakeLists.txt index 5f1368adb..9d1fcc943 100644 --- a/contrib/zlib/CMakeLists.txt +++ b/contrib/zlib/CMakeLists.txt @@ -5,12 +5,17 @@ set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON) # See http://www.cmake.org/cmake/help/v3.0/policy/CMP0048.html cmake_policy(PUSH) if(CMAKE_MAJOR_VERSION GREATER 2) - cmake_policy(SET CMP0048 OLD) + cmake_policy(SET CMP0048 NEW) endif() project(zlib C) +SET (ZLIB_VERSION_MAJOR 1) +SET (ZLIB_VERSION_MINOR 2) +SET (ZLIB_VERSION_PATCH 11) +SET (ZLIB_VERSION ${ZLIB_VERSION_MAJOR}.${ZLIB_VERSION_MINOR}.${ZLIB_VERSION_PATCH}) +SET (ZLIB_SOVERSION 1) +SET (PROJECT_VERSION "${ZLIB_VERSION}") cmake_policy(POP) -set(VERSION "1.2.11.1") option(ASM686 "Enable building i686 assembly implementation") option(AMD64 "Enable building amd64 assembly implementation") diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs b/contrib/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs index b110dae6a..cd1ef44eb 100644 --- a/contrib/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs +++ b/contrib/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs @@ -1,5 +1,5 @@ // -// © Copyright Henrik Ravn 2004 +// © Copyright Henrik Ravn 2004 // // Use, modification and distribution are subject to the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -199,4 +199,4 @@ namespace DotZLib } #endregion -} \ No newline at end of file +} diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs b/contrib/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs index 9c8d60195..e7a88b9f4 100644 --- a/contrib/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs +++ b/contrib/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs @@ -1,5 +1,5 @@ // -// © Copyright Henrik Ravn 2004 +// © Copyright Henrik Ravn 2004 // // Use, modification and distribution are subject to the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/CodecBase.cs b/contrib/zlib/contrib/dotzlib/DotZLib/CodecBase.cs index b0eb78a02..6ef6d8fab 100644 --- a/contrib/zlib/contrib/dotzlib/DotZLib/CodecBase.cs +++ b/contrib/zlib/contrib/dotzlib/DotZLib/CodecBase.cs @@ -1,5 +1,5 @@ // -// © Copyright Henrik Ravn 2004 +// © Copyright Henrik Ravn 2004 // // Use, modification and distribution are subject to the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/Deflater.cs b/contrib/zlib/contrib/dotzlib/DotZLib/Deflater.cs index 9039f41f6..778a6794d 100644 --- a/contrib/zlib/contrib/dotzlib/DotZLib/Deflater.cs +++ b/contrib/zlib/contrib/dotzlib/DotZLib/Deflater.cs @@ -1,5 +1,5 @@ // -// © Copyright Henrik Ravn 2004 +// © Copyright Henrik Ravn 2004 // // Use, modification and distribution are subject to the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/DotZLib.cs b/contrib/zlib/contrib/dotzlib/DotZLib/DotZLib.cs index 90c7c3b38..a48ed4974 100644 --- a/contrib/zlib/contrib/dotzlib/DotZLib/DotZLib.cs +++ b/contrib/zlib/contrib/dotzlib/DotZLib/DotZLib.cs @@ -1,5 +1,5 @@ // -// © Copyright Henrik Ravn 2004 +// © Copyright Henrik Ravn 2004 // // Use, modification and distribution are subject to the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/GZipStream.cs b/contrib/zlib/contrib/dotzlib/DotZLib/GZipStream.cs index f0eada1d2..07b2f7a9b 100644 --- a/contrib/zlib/contrib/dotzlib/DotZLib/GZipStream.cs +++ b/contrib/zlib/contrib/dotzlib/DotZLib/GZipStream.cs @@ -1,5 +1,5 @@ // -// © Copyright Henrik Ravn 2004 +// © Copyright Henrik Ravn 2004 // // Use, modification and distribution are subject to the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/contrib/zlib/contrib/dotzlib/DotZLib/Inflater.cs b/contrib/zlib/contrib/dotzlib/DotZLib/Inflater.cs index d295f2680..8e900ae20 100644 --- a/contrib/zlib/contrib/dotzlib/DotZLib/Inflater.cs +++ b/contrib/zlib/contrib/dotzlib/DotZLib/Inflater.cs @@ -1,5 +1,5 @@ // -// © Copyright Henrik Ravn 2004 +// © Copyright Henrik Ravn 2004 // // Use, modification and distribution are subject to the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/dox.h b/doc/dox.h index d63c8a806..910e77eae 100644 --- a/doc/dox.h +++ b/doc/dox.h @@ -1173,6 +1173,18 @@ float4 PimpMyPixel (float4 prev) @endcode +@section shdacc How to access shader-code from a texture (AI_MATKEY_GLOBAL_SHADERLANG and AI_MATKEY_SHADER_VERTEX, ...) + +You can get assigned shader sources by using the following material keys: + +
  • AI_MATKEY_GLOBAL_SHADERLANG
  • To get the used shader language. +
  • AI_MATKEY_SHADER_VERTEX
  • Assigned vertex shader code stored as a string. +
  • AI_MATKEY_SHADER_FRAGMENT
  • Assigned fragment shader code stored as a string. +
  • AI_MATKEY_SHADER_GEO
  • Assigned geometry shader code stored as a string. +
  • AI_MATKEY_SHADER_TESSELATION
  • Assigned tesselation shader code stored as a string. +
  • AI_MATKEY_SHADER_PRIMITIVE
  • Assigned primitive shader code stored as a string. +
  • AI_MATKEY_SHADER_COMPUTE
  • Assigned compute shader code stored as a string. + */ diff --git a/include/assimp/BaseImporter.h b/include/assimp/BaseImporter.h index b218d06ff..bd0451be3 100644 --- a/include/assimp/BaseImporter.h +++ b/include/assimp/BaseImporter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -41,15 +41,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file Definition of the base class for all importer worker classes. */ +#pragma once #ifndef INCLUDED_AI_BASEIMPORTER_H #define INCLUDED_AI_BASEIMPORTER_H +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include "Exceptional.h" #include #include +#include #include #include +#include struct aiScene; struct aiImporterDesc; @@ -80,6 +87,10 @@ class IOStream; class ASSIMP_API BaseImporter { friend class Importer; +private: + /* Pushes state into importer for the importer scale */ + virtual void UpdateImporterScale( Importer* pImp ); + public: /** Constructor to be privately used by #Importer */ @@ -132,7 +143,7 @@ public: * a suitable response to the caller. */ aiScene* ReadFile( - const Importer* pImp, + Importer* pImp, const std::string& pFile, IOSystem* pIOHandler ); @@ -161,14 +172,65 @@ public: * some loader features. Importers must provide this information. */ virtual const aiImporterDesc* GetInfo() const = 0; + /** + * Will be called only by scale process when scaling is requested. + */ + virtual void SetFileScale(double scale) + { + fileScale = scale; + } + + virtual double GetFileScale() const + { + return fileScale; + } + + enum ImporterUnits { + M, + MM, + CM, + INCHES, + FEET + }; + + /** + * Assimp Importer + * unit conversions available + * if you need another measurment unit add it below. + * it's currently defined in assimp that we prefer meters. + * */ + std::map importerUnits = { + {ImporterUnits::M, 1}, + {ImporterUnits::CM, 0.01}, + {ImporterUnits::MM, 0.001}, + {ImporterUnits::INCHES, 0.0254}, + {ImporterUnits::FEET, 0.3048} + }; + + virtual void SetApplicationUnits( const ImporterUnits& unit ) + { + importerScale = importerUnits[unit]; + applicationUnits = unit; + } + + virtual const ImporterUnits& GetApplicationUnits() + { + return applicationUnits; + } + // ------------------------------------------------------------------- /** Called by #Importer::GetExtensionList for each loaded importer. * Take the extension list contained in the structure returned by * #GetInfo and insert all file extensions into the given set. * @param extension set to collect file extensions in*/ void GetExtensionList(std::set& extensions); + +protected: + ImporterUnits applicationUnits = ImporterUnits::M; + double importerScale = 1.0; + double fileScale = 1.0; + -protected: // ------------------------------------------------------------------- /** Imports the given file into the given scene structure. The diff --git a/include/assimp/Bitmap.h b/include/assimp/Bitmap.h index 209116863..4c3f5a437 100644 --- a/include/assimp/Bitmap.h +++ b/include/assimp/Bitmap.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -46,10 +46,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Used for file formats which embed their textures into the model file. */ - +#pragma once #ifndef AI_BITMAP_H_INC #define AI_BITMAP_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include "defs.h" #include #include diff --git a/include/assimp/BlobIOSystem.h b/include/assimp/BlobIOSystem.h index a0ed7209f..d005e5c11 100644 --- a/include/assimp/BlobIOSystem.h +++ b/include/assimp/BlobIOSystem.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/include/assimp/ByteSwapper.h b/include/assimp/ByteSwapper.h index 322a242de..3f14c471a 100644 --- a/include/assimp/ByteSwapper.h +++ b/include/assimp/ByteSwapper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -42,9 +42,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Helper class tp perform various byte oder swappings (e.g. little to big endian) */ +#pragma once #ifndef AI_BYTESWAPPER_H_INC #define AI_BYTESWAPPER_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include #include diff --git a/include/assimp/CreateAnimMesh.h b/include/assimp/CreateAnimMesh.h index ad625cb9f..1266d1de1 100644 --- a/include/assimp/CreateAnimMesh.h +++ b/include/assimp/CreateAnimMesh.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -43,16 +43,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file CreateAnimMesh.h * Create AnimMesh from Mesh */ +#pragma once #ifndef INCLUDED_AI_CREATE_ANIM_MESH_H #define INCLUDED_AI_CREATE_ANIM_MESH_H +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include -namespace Assimp { +namespace Assimp { -/** Create aiAnimMesh from aiMesh. */ +/** + * Create aiAnimMesh from aiMesh. + * @param mesh The input mesh to create an animated mesh from. + * @return The new created animated mesh. + */ ASSIMP_API aiAnimMesh *aiCreateAnimMesh(const aiMesh *mesh); } // end of namespace Assimp + #endif // INCLUDED_AI_CREATE_ANIM_MESH_H diff --git a/include/assimp/DefaultIOStream.h b/include/assimp/DefaultIOStream.h index e0e010ecb..c6d382c1b 100644 --- a/include/assimp/DefaultIOStream.h +++ b/include/assimp/DefaultIOStream.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -41,15 +41,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file Default file I/O using fXXX()-family of functions */ +#pragma once #ifndef AI_DEFAULTIOSTREAM_H_INC #define AI_DEFAULTIOSTREAM_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include #include #include -namespace Assimp { +namespace Assimp { // ---------------------------------------------------------------------------------- //! @class DefaultIOStream @@ -57,8 +62,7 @@ namespace Assimp { //! @note An instance of this class can exist without a valid file handle //! attached to it. All calls fail, but the instance can nevertheless be //! used with no restrictions. -class ASSIMP_API DefaultIOStream : public IOStream -{ +class ASSIMP_API DefaultIOStream : public IOStream { friend class DefaultIOSystem; #if __ANDROID__ # if __ANDROID_API__ > 9 @@ -82,7 +86,6 @@ public: size_t pSize, size_t pCount); - // ------------------------------------------------------------------- /// Write to stream size_t Write(const void* pvBuffer, @@ -107,16 +110,13 @@ public: void Flush(); private: - // File data-structure, using clib FILE* mFile; - // Filename std::string mFilename; - // Cached file size mutable size_t mCachedSize; }; // ---------------------------------------------------------------------------------- -inline +AI_FORCE_INLINE DefaultIOStream::DefaultIOStream() AI_NO_EXCEPT : mFile(nullptr) , mFilename("") @@ -125,7 +125,7 @@ DefaultIOStream::DefaultIOStream() AI_NO_EXCEPT } // ---------------------------------------------------------------------------------- -inline +AI_FORCE_INLINE DefaultIOStream::DefaultIOStream (FILE* pFile, const std::string &strFilename) : mFile(pFile) , mFilename(strFilename) @@ -137,4 +137,3 @@ DefaultIOStream::DefaultIOStream (FILE* pFile, const std::string &strFilename) } // ns assimp #endif //!!AI_DEFAULTIOSTREAM_H_INC - diff --git a/include/assimp/DefaultIOSystem.h b/include/assimp/DefaultIOSystem.h index a5d45c692..46f6d447c 100644 --- a/include/assimp/DefaultIOSystem.h +++ b/include/assimp/DefaultIOSystem.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -41,9 +41,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file Default implementation of IOSystem using the standard C file functions */ +#pragma once #ifndef AI_DEFAULTIOSYSTEM_H_INC #define AI_DEFAULTIOSYSTEM_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include namespace Assimp { diff --git a/include/assimp/DefaultLogger.hpp b/include/assimp/DefaultLogger.hpp index 1f0c899be..1946e250a 100644 --- a/include/assimp/DefaultLogger.hpp +++ b/include/assimp/DefaultLogger.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/include/assimp/Defines.h b/include/assimp/Defines.h index 15e1d83c2..be3e2fafd 100644 --- a/include/assimp/Defines.h +++ b/include/assimp/Defines.h @@ -38,6 +38,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ +#pragma once +#ifndef AI_DEFINES_H_INC +#define AI_DEFINES_H_INC + +#ifdef __GNUC__ +# pragma GCC system_header +#endif + // We need those constants, workaround for any platforms where nobody defined them yet #if (!defined SIZE_MAX) # define SIZE_MAX (~((size_t)0)) @@ -47,3 +55,4 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # define UINT_MAX (~((unsigned int)0)) #endif +#endif // AI_DEINES_H_INC diff --git a/include/assimp/Exceptional.h b/include/assimp/Exceptional.h index 5109b8f07..6bb6ce1e3 100644 --- a/include/assimp/Exceptional.h +++ b/include/assimp/Exceptional.h @@ -38,11 +38,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ -#ifndef INCLUDED_EXCEPTIONAL_H -#define INCLUDED_EXCEPTIONAL_H +#pragma once +#ifndef AI_INCLUDED_EXCEPTIONAL_H +#define AI_INCLUDED_EXCEPTIONAL_H + +#ifdef __GNUC__ +# pragma GCC system_header +#endif #include #include + using std::runtime_error; #ifdef _MSC_VER @@ -53,17 +59,14 @@ using std::runtime_error; /** FOR IMPORTER PLUGINS ONLY: Simple exception class to be thrown if an * unrecoverable error occurs while importing. Loading APIs return * NULL instead of a valid aiScene then. */ -class DeadlyImportError - : public runtime_error -{ +class DeadlyImportError : public runtime_error { public: /** Constructor with arguments */ explicit DeadlyImportError( const std::string& errorText) - : runtime_error(errorText) - { + : runtime_error(errorText) { + // empty } -private: }; typedef DeadlyImportError DeadlyExportError; @@ -84,7 +87,7 @@ struct ExceptionSwallower { template struct ExceptionSwallower { T* operator ()() const { - return NULL; + return nullptr; } }; @@ -122,4 +125,4 @@ struct ExceptionSwallower { }\ } -#endif // INCLUDED_EXCEPTIONAL_H +#endif // AI_INCLUDED_EXCEPTIONAL_H diff --git a/include/assimp/Exporter.hpp b/include/assimp/Exporter.hpp index 4e0843b60..2612e1f9d 100644 --- a/include/assimp/Exporter.hpp +++ b/include/assimp/Exporter.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,6 +48,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_EXPORT_HPP_INC #define AI_EXPORT_HPP_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifndef ASSIMP_BUILD_NO_EXPORT #include "cexport.h" @@ -190,7 +194,7 @@ public: * @note Use aiCopyScene() to get a modifiable copy of a previously * imported scene. */ const aiExportDataBlob* ExportToBlob(const aiScene* pScene, const char* pFormatId, - unsigned int pPreprocessing = 0u, const ExportProperties* = nullptr); + unsigned int pPreprocessing = 0u, const ExportProperties* pProperties = nullptr); const aiExportDataBlob* ExportToBlob( const aiScene* pScene, const std::string& pFormatId, unsigned int pPreprocessing = 0u, const ExportProperties* pProperties = nullptr); diff --git a/include/assimp/GenericProperty.h b/include/assimp/GenericProperty.h index 7b75cb1c8..7796d595b 100644 --- a/include/assimp/GenericProperty.h +++ b/include/assimp/GenericProperty.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -40,12 +40,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ +#pragma once #ifndef AI_GENERIC_PROPERTY_H_INCLUDED #define AI_GENERIC_PROPERTY_H_INCLUDED +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include -#include "Hash.h" +#include #include diff --git a/include/assimp/Hash.h b/include/assimp/Hash.h index eb5df757d..905644078 100644 --- a/include/assimp/Hash.h +++ b/include/assimp/Hash.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -39,10 +39,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ - +#pragma once #ifndef AI_HASH_H_INCLUDED #define AI_HASH_H_INCLUDED +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include diff --git a/include/assimp/IOStream.hpp b/include/assimp/IOStream.hpp index 52b80cc15..39932cd94 100644 --- a/include/assimp/IOStream.hpp +++ b/include/assimp/IOStream.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,14 +48,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_IOSTREAM_H_INC #define AI_IOSTREAM_H_INC -#include "types.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include #ifndef __cplusplus # error This header requires C++ to be used. aiFileIO.h is the \ corresponding C interface. #endif -namespace Assimp { +namespace Assimp { // ---------------------------------------------------------------------------------- /** @brief CPP-API: Class to handle file I/O for C++ @@ -125,13 +129,13 @@ public: }; //! class IOStream // ---------------------------------------------------------------------------------- -inline +AI_FORCE_INLINE IOStream::IOStream() AI_NO_EXCEPT { // empty } // ---------------------------------------------------------------------------------- -inline +AI_FORCE_INLINE IOStream::~IOStream() { // empty } diff --git a/include/assimp/IOStreamBuffer.h b/include/assimp/IOStreamBuffer.h index c93a191df..97c84b23e 100644 --- a/include/assimp/IOStreamBuffer.h +++ b/include/assimp/IOStreamBuffer.h @@ -1,10 +1,8 @@ -#pragma once - /* Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -42,10 +40,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ +#pragma once +#ifndef AI_IOSTREAMBUFFER_H_INC +#define AI_IOSTREAMBUFFER_H_INC + +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include - -#include "ParsingUtils.h" +#include #include @@ -124,7 +129,7 @@ private: }; template -inline +AI_FORCE_INLINE IOStreamBuffer::IOStreamBuffer( size_t cache ) : m_stream( nullptr ) , m_filesize( 0 ) @@ -138,13 +143,13 @@ IOStreamBuffer::IOStreamBuffer( size_t cache ) } template -inline +AI_FORCE_INLINE IOStreamBuffer::~IOStreamBuffer() { // empty } template -inline +AI_FORCE_INLINE bool IOStreamBuffer::open( IOStream *stream ) { // file still opened! if ( nullptr != m_stream ) { @@ -174,7 +179,7 @@ bool IOStreamBuffer::open( IOStream *stream ) { } template -inline +AI_FORCE_INLINE bool IOStreamBuffer::close() { if ( nullptr == m_stream ) { return false; @@ -192,19 +197,19 @@ bool IOStreamBuffer::close() { } template -inline +AI_FORCE_INLINE size_t IOStreamBuffer::size() const { return m_filesize; } template -inline +AI_FORCE_INLINE size_t IOStreamBuffer::cacheSize() const { return m_cacheSize; } template -inline +AI_FORCE_INLINE bool IOStreamBuffer::readNextBlock() { m_stream->Seek( m_filePos, aiOrigin_SET ); size_t readLen = m_stream->Read( &m_cache[ 0 ], sizeof( T ), m_cacheSize ); @@ -222,28 +227,28 @@ bool IOStreamBuffer::readNextBlock() { } template -inline +AI_FORCE_INLINE size_t IOStreamBuffer::getNumBlocks() const { return m_numBlocks; } template -inline +AI_FORCE_INLINE size_t IOStreamBuffer::getCurrentBlockIndex() const { return m_blockIdx; } template -inline +AI_FORCE_INLINE size_t IOStreamBuffer::getFilePos() const { return m_filePos; } template -inline +AI_FORCE_INLINE bool IOStreamBuffer::getNextDataLine( std::vector &buffer, T continuationToken ) { buffer.resize( m_cacheSize ); - if ( m_cachePos == m_cacheSize || 0 == m_filePos ) { + if ( m_cachePos >= m_cacheSize || 0 == m_filePos ) { if ( !readNextBlock() ) { return false; } @@ -273,6 +278,9 @@ bool IOStreamBuffer::getNextDataLine( std::vector &buffer, T continuationT buffer[ i ] = m_cache[ m_cachePos ]; ++m_cachePos; ++i; + if (m_cachePos >= size()) { + break; + } if ( m_cachePos >= m_cacheSize ) { if ( !readNextBlock() ) { return false; @@ -286,13 +294,13 @@ bool IOStreamBuffer::getNextDataLine( std::vector &buffer, T continuationT return true; } -static inline +static AI_FORCE_INLINE bool isEndOfCache( size_t pos, size_t cacheSize ) { return ( pos == cacheSize ); } template -inline +AI_FORCE_INLINE bool IOStreamBuffer::getNextLine(std::vector &buffer) { buffer.resize(m_cacheSize); if ( isEndOfCache( m_cachePos, m_cacheSize ) || 0 == m_filePos) { @@ -332,7 +340,7 @@ bool IOStreamBuffer::getNextLine(std::vector &buffer) { } template -inline +AI_FORCE_INLINE bool IOStreamBuffer::getNextBlock( std::vector &buffer) { // Return the last block-value if getNextLine was used before if ( 0 != m_cachePos ) { @@ -350,3 +358,5 @@ bool IOStreamBuffer::getNextBlock( std::vector &buffer) { } } // !ns Assimp + +#endif // AI_IOSTREAMBUFFER_H_INC diff --git a/include/assimp/IOSystem.hpp b/include/assimp/IOSystem.hpp index a36e22508..f1fb3b0c2 100644 --- a/include/assimp/IOSystem.hpp +++ b/include/assimp/IOSystem.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -50,6 +50,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_IOSYSTEM_H_INC #define AI_IOSYSTEM_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifndef __cplusplus # error This header requires C++ to be used. aiFileIO.h is the \ corresponding C interface. diff --git a/include/assimp/Importer.hpp b/include/assimp/Importer.hpp index 1d1dac19f..bf449a9a2 100644 --- a/include/assimp/Importer.hpp +++ b/include/assimp/Importer.hpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,6 +48,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_ASSIMP_HPP_INC #define AI_ASSIMP_HPP_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifndef __cplusplus # error This header requires C++ to be used. Use assimp.h for plain C. #endif // __cplusplus diff --git a/include/assimp/LineSplitter.h b/include/assimp/LineSplitter.h index eb6b6e46c..6c1097bb6 100644 --- a/include/assimp/LineSplitter.h +++ b/include/assimp/LineSplitter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -48,9 +48,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef INCLUDED_LINE_SPLITTER_H #define INCLUDED_LINE_SPLITTER_H +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include -#include "StreamReader.h" -#include "ParsingUtils.h" +#include +#include namespace Assimp { @@ -140,7 +144,7 @@ private: bool mSwallow, mSkip_empty_lines, mTrim; }; -inline +AI_FORCE_INLINE LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_empty_lines, bool trim ) : mIdx(0) , mCur() @@ -153,12 +157,12 @@ LineSplitter::LineSplitter(StreamReaderLE& stream, bool skip_empty_lines, bool t mIdx = 0; } -inline +AI_FORCE_INLINE LineSplitter::~LineSplitter() { // empty } -inline +AI_FORCE_INLINE LineSplitter& LineSplitter::operator++() { if (mSwallow) { mSwallow = false; @@ -199,12 +203,12 @@ LineSplitter& LineSplitter::operator++() { return *this; } -inline +AI_FORCE_INLINE LineSplitter &LineSplitter::operator++(int) { return ++(*this); } -inline +AI_FORCE_INLINE const char *LineSplitter::operator[] (size_t idx) const { const char* s = operator->()->c_str(); @@ -222,7 +226,7 @@ const char *LineSplitter::operator[] (size_t idx) const { } template -inline +AI_FORCE_INLINE void LineSplitter::get_tokens(const char* (&tokens)[N]) const { const char* s = operator->()->c_str(); @@ -238,44 +242,44 @@ void LineSplitter::get_tokens(const char* (&tokens)[N]) const { } } -inline +AI_FORCE_INLINE const std::string* LineSplitter::operator -> () const { return &mCur; } -inline +AI_FORCE_INLINE std::string LineSplitter::operator* () const { return mCur; } -inline +AI_FORCE_INLINE LineSplitter::operator bool() const { return mStream.GetRemainingSize() > 0; } -inline +AI_FORCE_INLINE LineSplitter::operator line_idx() const { return mIdx; } -inline +AI_FORCE_INLINE LineSplitter::line_idx LineSplitter::get_index() const { return mIdx; } -inline +AI_FORCE_INLINE StreamReaderLE &LineSplitter::get_stream() { return mStream; } -inline +AI_FORCE_INLINE bool LineSplitter::match_start(const char* check) { const size_t len = ::strlen(check); return len <= mCur.length() && std::equal(check, check + len, mCur.begin()); } -inline +AI_FORCE_INLINE void LineSplitter::swallow_next_increment() { mSwallow = true; } diff --git a/include/assimp/LogAux.h b/include/assimp/LogAux.h index cf6d50014..bcead78dd 100644 --- a/include/assimp/LogAux.h +++ b/include/assimp/LogAux.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -43,9 +43,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file LogAux.h * @brief Common logging usage patterns for importer implementations */ +#pragma once #ifndef INCLUDED_AI_LOGAUX_H #define INCLUDED_AI_LOGAUX_H +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include #include diff --git a/include/assimp/LogStream.hpp b/include/assimp/LogStream.hpp index e0eb8d505..d0281e2d0 100644 --- a/include/assimp/LogStream.hpp +++ b/include/assimp/LogStream.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/include/assimp/Logger.hpp b/include/assimp/Logger.hpp index 6a9928735..89cade6c3 100644 --- a/include/assimp/Logger.hpp +++ b/include/assimp/Logger.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/include/assimp/MathFunctions.h b/include/assimp/MathFunctions.h index cb3b69607..b6c5872a7 100644 --- a/include/assimp/MathFunctions.h +++ b/include/assimp/MathFunctions.h @@ -39,22 +39,28 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ +#pragma once + +#ifdef __GNUC__ +# pragma GCC system_header +#endif + /** @file MathFunctions.h - * @brief Implementation of the math functions (gcd and lcm) +* @brief Implementation of math utility functions. * - * Copied from BoostWorkaround/math - */ +*/ + +#include namespace Assimp { namespace Math { // TODO: use binary GCD for unsigned integers .... template < typename IntegerType > -IntegerType gcd( IntegerType a, IntegerType b ) -{ +inline +IntegerType gcd( IntegerType a, IntegerType b ) { const IntegerType zero = (IntegerType)0; - while ( true ) - { + while ( true ) { if ( a == zero ) return b; b %= a; @@ -66,12 +72,19 @@ IntegerType gcd( IntegerType a, IntegerType b ) } template < typename IntegerType > -IntegerType lcm( IntegerType a, IntegerType b ) -{ +inline +IntegerType lcm( IntegerType a, IntegerType b ) { const IntegerType t = gcd (a,b); - if (!t)return t; + if (!t) + return t; return a / t * b; } +template +inline +T getEpsilon() { + return std::numeric_limits::epsilon(); +} + } } diff --git a/include/assimp/MemoryIOWrapper.h b/include/assimp/MemoryIOWrapper.h index 5260cb2b2..5598d4fc5 100644 --- a/include/assimp/MemoryIOWrapper.h +++ b/include/assimp/MemoryIOWrapper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -42,35 +42,38 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file MemoryIOWrapper.h * Handy IOStream/IOSystem implemetation to read directly from a memory buffer */ +#pragma once #ifndef AI_MEMORYIOSTREAM_H_INC #define AI_MEMORYIOSTREAM_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include #include + #include namespace Assimp { + #define AI_MEMORYIO_MAGIC_FILENAME "$$$___magic___$$$" #define AI_MEMORYIO_MAGIC_FILENAME_LENGTH 17 // ---------------------------------------------------------------------------------- /** Implementation of IOStream to read directly from a memory buffer */ // ---------------------------------------------------------------------------------- -class MemoryIOStream : public IOStream -{ - //friend class MemoryIOSystem; +class MemoryIOStream : public IOStream { public: MemoryIOStream (const uint8_t* buff, size_t len, bool own = false) - : buffer (buff) - , length(len) - , pos((size_t)0) - , own(own) - { + : buffer (buff) + , length(len) + , pos((size_t)0) + , own(own) { + // empty } -public: - ~MemoryIOStream () { if(own) { delete[] buffer; @@ -80,11 +83,13 @@ public: // ------------------------------------------------------------------- // Read from stream size_t Read(void* pvBuffer, size_t pSize, size_t pCount) { - ai_assert(pvBuffer); - ai_assert(pSize); - const size_t cnt = std::min(pCount,(length-pos)/pSize), ofs = pSize*cnt; + ai_assert(nullptr != pvBuffer); + ai_assert(0 != pSize); + + const size_t cnt = std::min( pCount, (length-pos) / pSize); + const size_t ofs = pSize * cnt; - memcpy(pvBuffer,buffer+pos,ofs); + ::memcpy(pvBuffer,buffer+pos,ofs); pos += ofs; return cnt; @@ -105,14 +110,12 @@ public: return AI_FAILURE; } pos = pOffset; - } - else if (aiOrigin_END == pOrigin) { + } else if (aiOrigin_END == pOrigin) { if (pOffset > length) { return AI_FAILURE; } pos = length-pOffset; - } - else { + } else { if (pOffset+pos > length) { return AI_FAILURE; } @@ -147,12 +150,15 @@ private: // --------------------------------------------------------------------------- /** Dummy IO system to read from a memory buffer */ -class MemoryIOSystem : public IOSystem -{ +class MemoryIOSystem : public IOSystem { public: /** Constructor. */ - MemoryIOSystem (const uint8_t* buff, size_t len) - : buffer (buff), length(len) { + MemoryIOSystem(const uint8_t* buff, size_t len, IOSystem* io) + : buffer(buff) + , length(len) + , existing_io(io) + , created_streams() { + // empty } /** Destructor. */ @@ -161,41 +167,84 @@ public: // ------------------------------------------------------------------- /** Tests for the existence of a file at the given path. */ - bool Exists( const char* pFile) const { - return !strncmp(pFile,AI_MEMORYIO_MAGIC_FILENAME,AI_MEMORYIO_MAGIC_FILENAME_LENGTH); + bool Exists(const char* pFile) const override { + if (0 == strncmp( pFile, AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH ) ) { + return true; + } + return existing_io ? existing_io->Exists(pFile) : false; } // ------------------------------------------------------------------- /** Returns the directory separator. */ - char getOsSeparator() const { - return '/'; // why not? it doesn't care + char getOsSeparator() const override { + return existing_io ? existing_io->getOsSeparator() + : '/'; // why not? it doesn't care } // ------------------------------------------------------------------- /** Open a new file with a given path. */ - IOStream* Open( const char* pFile, const char* /*pMode*/ = "rb") { - if (strncmp(pFile,AI_MEMORYIO_MAGIC_FILENAME,AI_MEMORYIO_MAGIC_FILENAME_LENGTH)) { - return NULL; + IOStream* Open(const char* pFile, const char* pMode = "rb") override { + if ( 0 == strncmp( pFile, AI_MEMORYIO_MAGIC_FILENAME, AI_MEMORYIO_MAGIC_FILENAME_LENGTH ) ) { + created_streams.emplace_back(new MemoryIOStream(buffer, length)); + return created_streams.back(); } - return new MemoryIOStream(buffer,length); + return existing_io ? existing_io->Open(pFile, pMode) : NULL; } // ------------------------------------------------------------------- /** Closes the given file and releases all resources associated with it. */ - void Close( IOStream* pFile) { - delete pFile; + void Close( IOStream* pFile) override { + auto it = std::find(created_streams.begin(), created_streams.end(), pFile); + if (it != created_streams.end()) { + delete pFile; + created_streams.erase(it); + } else if (existing_io) { + existing_io->Close(pFile); + } } // ------------------------------------------------------------------- /** Compare two paths */ - bool ComparePaths (const char* /*one*/, const char* /*second*/) const { - return false; + bool ComparePaths(const char* one, const char* second) const override { + return existing_io ? existing_io->ComparePaths(one, second) : false; + } + + bool PushDirectory( const std::string &path ) override { + return existing_io ? existing_io->PushDirectory(path) : false; + } + + const std::string &CurrentDirectory() const override { + static std::string empty; + return existing_io ? existing_io->CurrentDirectory() : empty; + } + + size_t StackSize() const override { + return existing_io ? existing_io->StackSize() : 0; + } + + bool PopDirectory() override { + return existing_io ? existing_io->PopDirectory() : false; + } + + bool CreateDirectory( const std::string &path ) override { + return existing_io ? existing_io->CreateDirectory(path) : false; + } + + bool ChangeDirectory( const std::string &path ) override { + return existing_io ? existing_io->ChangeDirectory(path) : false; + } + + bool DeleteFile( const std::string &file ) override { + return existing_io ? existing_io->DeleteFile(file) : false; } private: const uint8_t* buffer; size_t length; + IOSystem* existing_io; + std::vector created_streams; }; + } // end namespace Assimp #endif diff --git a/include/assimp/NullLogger.hpp b/include/assimp/NullLogger.hpp index 776f301ab..c45d01bd4 100644 --- a/include/assimp/NullLogger.hpp +++ b/include/assimp/NullLogger.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/include/assimp/ParsingUtils.h b/include/assimp/ParsingUtils.h index 4553072db..302560124 100644 --- a/include/assimp/ParsingUtils.h +++ b/include/assimp/ParsingUtils.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -44,11 +44,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file ParsingUtils.h * @brief Defines helper functions for text parsing */ +#pragma once #ifndef AI_PARSING_UTILS_H_INC #define AI_PARSING_UTILS_H_INC -#include "StringComparison.h" -#include "StringUtils.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include +#include #include namespace Assimp { @@ -196,8 +201,7 @@ bool GetNextLine( const char_t*& buffer, char_t out[ BufferSize ] ) { // --------------------------------------------------------------------------------- template -AI_FORCE_INLINE bool IsNumeric( char_t in) -{ +AI_FORCE_INLINE bool IsNumeric( char_t in) { return ( in >= '0' && in <= '9' ) || '-' == in || '+' == in; } diff --git a/include/assimp/Profiler.h b/include/assimp/Profiler.h index da5af2726..624029be9 100644 --- a/include/assimp/Profiler.h +++ b/include/assimp/Profiler.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -43,12 +43,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Profiler.h * @brief Utility to measure the respective runtime of each import step */ -#ifndef INCLUDED_PROFILER_H -#define INCLUDED_PROFILER_H +#pragma once +#ifndef AI_INCLUDED_PROFILER_H +#define AI_INCLUDED_PROFILER_H + +#ifdef __GNUC__ +# pragma GCC system_header +#endif #include #include -#include "TinyFormatter.h" +#include #include @@ -67,7 +72,6 @@ public: // empty } -public: /** Start a named timer */ void BeginRegion(const std::string& region) { @@ -95,5 +99,5 @@ private: } } -#endif +#endif // AI_INCLUDED_PROFILER_H diff --git a/include/assimp/ProgressHandler.hpp b/include/assimp/ProgressHandler.hpp index f295eac39..8991a6461 100644 --- a/include/assimp/ProgressHandler.hpp +++ b/include/assimp/ProgressHandler.hpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -47,9 +47,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_PROGRESSHANDLER_H_INC #define AI_PROGRESSHANDLER_H_INC -#include "types.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif -namespace Assimp { +#include + +namespace Assimp { // ------------------------------------------------------------------------------------ /** @brief CPP-API: Abstract interface for custom progress report receivers. diff --git a/include/assimp/RemoveComments.h b/include/assimp/RemoveComments.h index 08299f22b..f12942053 100644 --- a/include/assimp/RemoveComments.h +++ b/include/assimp/RemoveComments.h @@ -2,8 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -43,9 +42,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Declares a helper class, "CommentRemover", which can be * used to remove comments (single and multi line) from a text file. */ +#pragma once #ifndef AI_REMOVE_COMMENTS_H_INC #define AI_REMOVE_COMMENTS_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif #include @@ -58,8 +61,7 @@ namespace Assimp { * to those in C or C++ so this code has been moved to a separate * module. */ -class ASSIMP_API CommentRemover -{ +class ASSIMP_API CommentRemover { // class cannot be instanced CommentRemover() {} diff --git a/include/assimp/SGSpatialSort.h b/include/assimp/SGSpatialSort.h index 3c95d0b51..fdb5ce817 100644 --- a/include/assimp/SGSpatialSort.h +++ b/include/assimp/SGSpatialSort.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -42,9 +42,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** Small helper classes to optimize finding vertices close to a given location */ +#pragma once #ifndef AI_D3DSSPATIALSORT_H_INC #define AI_D3DSSPATIALSORT_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include #include diff --git a/include/assimp/SceneCombiner.h b/include/assimp/SceneCombiner.h index ec2788245..0683c1e05 100644 --- a/include/assimp/SceneCombiner.h +++ b/include/assimp/SceneCombiner.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -43,17 +43,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Declares a helper class, "SceneCombiner" providing various * utilities to merge scenes. */ +#pragma once #ifndef AI_SCENE_COMBINER_H_INC #define AI_SCENE_COMBINER_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include #include + #include #include #include #include - #include struct aiScene; @@ -65,8 +70,10 @@ struct aiLight; struct aiMetadata; struct aiBone; struct aiMesh; +struct aiAnimMesh; struct aiAnimation; struct aiNodeAnim; +struct aiMeshMorphAnim; namespace Assimp { @@ -363,6 +370,7 @@ public: static void Copy (aiMesh** dest, const aiMesh* src); // similar to Copy(): + static void Copy (aiAnimMesh** dest, const aiAnimMesh* src); static void Copy (aiMaterial** dest, const aiMaterial* src); static void Copy (aiTexture** dest, const aiTexture* src); static void Copy (aiAnimation** dest, const aiAnimation* src); @@ -370,6 +378,7 @@ public: static void Copy (aiBone** dest, const aiBone* src); static void Copy (aiLight** dest, const aiLight* src); static void Copy (aiNodeAnim** dest, const aiNodeAnim* src); + static void Copy (aiMeshMorphAnim** dest, const aiMeshMorphAnim* src); static void Copy (aiMetadata** dest, const aiMetadata* src); // recursive, of course diff --git a/include/assimp/SkeletonMeshBuilder.h b/include/assimp/SkeletonMeshBuilder.h index 993d9c84d..ad979a33f 100644 --- a/include/assimp/SkeletonMeshBuilder.h +++ b/include/assimp/SkeletonMeshBuilder.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -47,9 +47,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * for animation skeletons. */ +#pragma once #ifndef AI_SKELETONMESHBUILDER_H_INC #define AI_SKELETONMESHBUILDER_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include diff --git a/include/assimp/SmoothingGroups.h b/include/assimp/SmoothingGroups.h index 88345c66a..c1a93947f 100644 --- a/include/assimp/SmoothingGroups.h +++ b/include/assimp/SmoothingGroups.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -43,10 +43,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Defines the helper data structures for importing 3DS files. http://www.jalix.org/ressources/graphics/3DS/_unofficials/3ds-unofficial.txt */ +#pragma once #ifndef AI_SMOOTHINGGROUPS_H_INC #define AI_SMOOTHINGGROUPS_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include + #include #include diff --git a/include/assimp/SmoothingGroups.inl b/include/assimp/SmoothingGroups.inl index 84ea4a1b0..37ea083db 100644 --- a/include/assimp/SmoothingGroups.inl +++ b/include/assimp/SmoothingGroups.inl @@ -41,13 +41,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Generation of normal vectors basing on smoothing groups */ +#pragma once #ifndef AI_SMOOTHINGGROUPS_INL_INCLUDED #define AI_SMOOTHINGGROUPS_INL_INCLUDED -// internal headers +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include -// CRT header #include using namespace Assimp; diff --git a/include/assimp/SpatialSort.h b/include/assimp/SpatialSort.h index 8fb450841..9f9354315 100644 --- a/include/assimp/SpatialSort.h +++ b/include/assimp/SpatialSort.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -41,9 +41,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** Small helper classes to optimise finding vertizes close to a given location */ +#pragma once #ifndef AI_SPATIALSORT_H_INC #define AI_SPATIALSORT_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include diff --git a/include/assimp/StandardShapes.h b/include/assimp/StandardShapes.h index fdf1b034d..c594cb63f 100644 --- a/include/assimp/StandardShapes.h +++ b/include/assimp/StandardShapes.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -41,11 +41,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file Declares a helper class, "StandardShapes" which generates - * vertices for standard shapes, such as cylnders, cones, spheres .. + * vertices for standard shapes, such as cylinders, cones, spheres .. */ +#pragma once #ifndef AI_STANDARD_SHAPES_H_INC #define AI_STANDARD_SHAPES_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include diff --git a/include/assimp/StreamReader.h b/include/assimp/StreamReader.h index b01ee4b66..cb24f1595 100644 --- a/include/assimp/StreamReader.h +++ b/include/assimp/StreamReader.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -44,15 +44,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Defines the StreamReader class which reads data from * a binary stream with a well-defined endianness. */ - +#pragma once #ifndef AI_STREAMREADER_H_INCLUDED #define AI_STREAMREADER_H_INCLUDED -#include "ByteSwapper.h" -#include "Exceptional.h" -#include +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include +#include +#include + +#include namespace Assimp { @@ -314,7 +319,7 @@ private: const size_t read = stream->Read(current,1,s); // (read < s) can only happen if the stream was opened in text mode, in which case FileSize() is not reliable ai_assert(read <= s); - end = limit = &buffer[read]; + end = limit = &buffer[read-1] + 1; } private: diff --git a/include/assimp/StreamWriter.h b/include/assimp/StreamWriter.h index deb35fb4d..489e8adfe 100644 --- a/include/assimp/StreamWriter.h +++ b/include/assimp/StreamWriter.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -43,11 +43,15 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file Defines the StreamWriter class which writes data to * a binary stream with a well-defined endianness. */ - +#pragma once #ifndef AI_STREAMWRITER_H_INCLUDED #define AI_STREAMWRITER_H_INCLUDED -#include "ByteSwapper.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include #include #include diff --git a/include/assimp/StringComparison.h b/include/assimp/StringComparison.h index aea7f001a..d3ca3e971 100644 --- a/include/assimp/StringComparison.h +++ b/include/assimp/StringComparison.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -49,12 +49,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. These functions are not consistently available on all platforms, or the provided implementations behave too differently. */ +#pragma once #ifndef INCLUDED_AI_STRING_WORKERS_H #define INCLUDED_AI_STRING_WORKERS_H +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include -#include "StringComparison.h" +#include #include #include diff --git a/include/assimp/StringUtils.h b/include/assimp/StringUtils.h index 906898b53..af481f819 100644 --- a/include/assimp/StringUtils.h +++ b/include/assimp/StringUtils.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -39,9 +39,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ +#pragma once #ifndef INCLUDED_AI_STRINGUTILS_H #define INCLUDED_AI_STRINGUTILS_H +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include diff --git a/include/assimp/Subdivision.h b/include/assimp/Subdivision.h index 84aff68f1..e9450267e 100644 --- a/include/assimp/Subdivision.h +++ b/include/assimp/Subdivision.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,7 +45,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_SUBDISIVION_H_INC #define AI_SUBDISIVION_H_INC -#include +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include struct aiMesh; diff --git a/include/assimp/TinyFormatter.h b/include/assimp/TinyFormatter.h index 2ddc227e9..6227e42c5 100644 --- a/include/assimp/TinyFormatter.h +++ b/include/assimp/TinyFormatter.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -45,9 +45,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * to get rid of the boost::format dependency. Much slinker, * basically just extends stringstream. */ +#pragma once #ifndef INCLUDED_TINY_FORMATTER_H #define INCLUDED_TINY_FORMATTER_H +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include namespace Assimp { @@ -65,24 +70,15 @@ namespace Formatter { * @endcode */ template < typename T, typename CharTraits = std::char_traits, - typename Allocator = std::allocator -> -class basic_formatter -{ - + typename Allocator = std::allocator > +class basic_formatter { public: + typedef class std::basic_string string; + typedef class std::basic_ostringstream stringstream; - typedef class std::basic_string< - T,CharTraits,Allocator - > string; - - typedef class std::basic_ostringstream< - T,CharTraits,Allocator - > stringstream; - -public: - - basic_formatter() {} + basic_formatter() { + // empty + } /* Allow basic_formatter's to be used almost interchangeably * with std::(w)string or const (w)char* arguments because the @@ -104,14 +100,10 @@ public: } #endif - -public: - operator string () const { return underlying.str(); } - /* note - this is declared const because binding temporaries does only * work for const references, so many function prototypes will * include const basic_formatter& s but might still want to diff --git a/include/assimp/Vertex.h b/include/assimp/Vertex.h index f1c02ee07..5e63db5fe 100644 --- a/include/assimp/Vertex.h +++ b/include/assimp/Vertex.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -47,12 +47,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. that are not currently well-defined (and would cause compile errors due to missing operators in the math library), are commented. */ +#pragma once #ifndef AI_VERTEX_H_INC #define AI_VERTEX_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include #include + #include namespace Assimp { @@ -91,23 +97,14 @@ namespace Assimp { * to *all* vertex components equally. This is useful for stuff like interpolation * or subdivision, but won't work if special handling is required for some vertex components. */ // ------------------------------------------------------------------------------------------------ -class Vertex -{ +class Vertex { friend Vertex operator + (const Vertex&,const Vertex&); friend Vertex operator - (const Vertex&,const Vertex&); - -// friend Vertex operator + (const Vertex&,ai_real); -// friend Vertex operator - (const Vertex&,ai_real); friend Vertex operator * (const Vertex&,ai_real); friend Vertex operator / (const Vertex&,ai_real); - -// friend Vertex operator + (ai_real, const Vertex&); -// friend Vertex operator - (ai_real, const Vertex&); friend Vertex operator * (ai_real, const Vertex&); -// friend Vertex operator / (ai_real, const Vertex&); public: - Vertex() {} // ---------------------------------------------------------------------------- @@ -158,8 +155,6 @@ public: } } -public: - Vertex& operator += (const Vertex& v) { *this = *this+v; return *this; @@ -170,18 +165,6 @@ public: return *this; } - -/* - Vertex& operator += (ai_real v) { - *this = *this+v; - return *this; - } - - Vertex& operator -= (ai_real v) { - *this = *this-v; - return *this; - } -*/ Vertex& operator *= (ai_real v) { *this = *this*v; return *this; @@ -192,12 +175,9 @@ public: return *this; } -public: - // ---------------------------------------------------------------------------- /** Convert back to non-interleaved storage */ void SortBack(aiMesh* out, unsigned int idx) const { - ai_assert(idxmNumVertices); out->mVertices[idx] = position; @@ -291,8 +271,6 @@ public: aiColor4D colors[AI_MAX_NUMBER_OF_COLOR_SETS]; }; - - // ------------------------------------------------------------------------------------------------ AI_FORCE_INLINE Vertex operator + (const Vertex& v0,const Vertex& v1) { return Vertex::BinaryOp(v0,v1); @@ -302,19 +280,6 @@ AI_FORCE_INLINE Vertex operator - (const Vertex& v0,const Vertex& v1) { return Vertex::BinaryOp(v0,v1); } - -// ------------------------------------------------------------------------------------------------ -/* -AI_FORCE_INLINE Vertex operator + (const Vertex& v0,ai_real f) { - return Vertex::BinaryOp(v0,f); -} - -AI_FORCE_INLINE Vertex operator - (const Vertex& v0,ai_real f) { - return Vertex::BinaryOp(v0,f); -} - -*/ - AI_FORCE_INLINE Vertex operator * (const Vertex& v0,ai_real f) { return Vertex::BinaryOp(v0,f); } @@ -323,26 +288,10 @@ AI_FORCE_INLINE Vertex operator / (const Vertex& v0,ai_real f) { return Vertex::BinaryOp(v0,1.f/f); } -// ------------------------------------------------------------------------------------------------ -/* -AI_FORCE_INLINE Vertex operator + (ai_real f,const Vertex& v0) { - return Vertex::BinaryOp(f,v0); -} - -AI_FORCE_INLINE Vertex operator - (ai_real f,const Vertex& v0) { - return Vertex::BinaryOp(f,v0); -} -*/ - AI_FORCE_INLINE Vertex operator * (ai_real f,const Vertex& v0) { return Vertex::BinaryOp(f,v0); } -/* -AI_FORCE_INLINE Vertex operator / (ai_real f,const Vertex& v0) { - return Vertex::BinaryOp(f,v0); } -*/ -} -#endif +#endif // AI_VERTEX_H_INC diff --git a/include/assimp/XMLTools.h b/include/assimp/XMLTools.h index 4b76c4483..95f12cdeb 100644 --- a/include/assimp/XMLTools.h +++ b/include/assimp/XMLTools.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -40,9 +40,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ +#pragma once #ifndef INCLUDED_ASSIMP_XML_TOOLS_H #define INCLUDED_ASSIMP_XML_TOOLS_H +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include namespace Assimp { diff --git a/include/assimp/ZipArchiveIOSystem.h b/include/assimp/ZipArchiveIOSystem.h new file mode 100644 index 000000000..516ea84de --- /dev/null +++ b/include/assimp/ZipArchiveIOSystem.h @@ -0,0 +1,94 @@ +/* +--------------------------------------------------------------------------- +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.h + * @brief Implementation of IOSystem to read a ZIP file from another IOSystem +*/ + +#pragma once +#ifndef AI_ZIPARCHIVEIOSYSTEM_H_INC +#define AI_ZIPARCHIVEIOSYSTEM_H_INC + +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include +#include + +namespace Assimp { + +class ZipArchiveIOSystem : public IOSystem { +public: + //! Open a Zip using the proffered IOSystem + ZipArchiveIOSystem(IOSystem* pIOHandler, const char *pFilename, const char* pMode = "r"); + ZipArchiveIOSystem(IOSystem* pIOHandler, const std::string& rFilename, const char* pMode = "r"); + virtual ~ZipArchiveIOSystem(); + bool Exists(const char* pFilename) const override; + char getOsSeparator() const override; + IOStream* Open(const char* pFilename, const char* pMode = "rb") override; + void Close(IOStream* pFile) override; + + // Specific to ZIP + //! The file was opened and is a ZIP + bool isOpen() const; + + //! Get the list of all files with their simplified paths + //! Intended for use within Assimp library boundaries + void getFileList(std::vector& rFileList) const; + + //! Get the list of all files with extension (must be lowercase) + //! Intended for use within Assimp library boundaries + void getFileListExtension(std::vector& rFileList, const std::string& extension) const; + + static bool isZipArchive(IOSystem* pIOHandler, const char *pFilename); + static bool isZipArchive(IOSystem* pIOHandler, const std::string& rFilename); + +private: + class Implement; + Implement *pImpl = nullptr; +}; + +} // Namespace Assimp + +#endif // AI_ZIPARCHIVEIOSYSTEM_H_INC diff --git a/tools/assimp_qt_viewer/loggerview.cpp b/include/assimp/aabb.h similarity index 76% rename from tools/assimp_qt_viewer/loggerview.cpp rename to include/assimp/aabb.h index 2e0d15547..83bb62256 100644 --- a/tools/assimp_qt_viewer/loggerview.cpp +++ b/include/assimp/aabb.h @@ -1,11 +1,9 @@ -/* +/* --------------------------------------------------------------------------- Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -40,25 +38,42 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -#include "loggerview.hpp" -// Header files, Qt. -#include -#include +#pragma once +#ifndef AI_AABB_H_INC +#define AI_AABB_H_INC -CLoggerView::CLoggerView(QTextBrowser* pOutputWidget) -: mOutputWidget(pOutputWidget) { - // empty -} +#ifdef __GNUC__ +# pragma GCC system_header +#endif -CLoggerView::~CLoggerView() { - mOutputWidget = nullptr; -} +#include -void CLoggerView::write(const char *pMessage) { - if (nullptr == mOutputWidget) { - return; +struct aiAABB { + C_STRUCT aiVector3D mMin; + C_STRUCT aiVector3D mMax; + +#ifdef __cplusplus + + aiAABB() + : mMin() + , mMax() { + // empty } - mOutputWidget->insertPlainText(QString("[%1] %2").arg(QTime::currentTime().toString()).arg(pMessage)); -} + aiAABB(const aiVector3D &min, const aiVector3D &max ) + : mMin(min) + , mMax(max) { + // empty + } + + ~aiAABB() { + // empty + } + +#endif // __cplusplus + +}; + + +#endif // AI_AABB_H_INC diff --git a/include/assimp/ai_assert.h b/include/assimp/ai_assert.h index 7752763db..2b32b01d3 100644 --- a/include/assimp/ai_assert.h +++ b/include/assimp/ai_assert.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -44,11 +44,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_ASSERT_H_INC #define AI_ASSERT_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifdef ASSIMP_BUILD_DEBUG # include -# define ai_assert(expression) assert(expression) +# define ai_assert(expression) assert( expression ) +# define ai_assert_entry() assert( false ) #else # define ai_assert(expression) -#endif // +# define ai_assert_entry() +#endif // ASSIMP_BUILD_DEBUG #endif // AI_ASSERT_H_INC + diff --git a/include/assimp/anim.h b/include/assimp/anim.h index 8a0984192..e208b11ad 100644 --- a/include/assimp/anim.h +++ b/include/assimp/anim.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -50,6 +50,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_ANIM_H_INC #define AI_ANIM_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include diff --git a/include/assimp/camera.h b/include/assimp/camera.h index 6fea5a7d7..adb749ff5 100644 --- a/include/assimp/camera.h +++ b/include/assimp/camera.h @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -49,6 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_CAMERA_H_INC #define AI_CAMERA_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include "types.h" #ifdef __cplusplus @@ -60,7 +62,7 @@ extern "C" { * * Cameras have a representation in the node graph and can be animated. * An important aspect is that the camera itself is also part of the - * scenegraph. This means, any values such as the look-at vector are not + * scene-graph. This means, any values such as the look-at vector are not * *absolute*, they're relative to the coordinate system defined * by the node which corresponds to the camera. This allows for camera * animations. For static cameras parameters like the 'look-at' or 'up' vectors @@ -115,7 +117,6 @@ struct aiCamera */ C_STRUCT aiVector3D mPosition; - /** 'Up' - vector of the camera coordinate system relative to * the coordinate space defined by the corresponding node. * @@ -136,7 +137,6 @@ struct aiCamera */ C_STRUCT aiVector3D mLookAt; - /** Half horizontal field of view angle, in radians. * * The field of view angle is the angle between the center @@ -162,7 +162,6 @@ struct aiCamera */ float mClipPlaneFar; - /** Screen aspect ratio. * * This is the ration between the width and the height of the diff --git a/include/assimp/cexport.h b/include/assimp/cexport.h index 1d62dc26b..cbc0253d5 100644 --- a/include/assimp/cexport.h +++ b/include/assimp/cexport.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2011, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -46,6 +46,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_EXPORT_H_INC #define AI_EXPORT_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifndef ASSIMP_BUILD_NO_EXPORT // Public ASSIMP data structures diff --git a/include/assimp/cfileio.h b/include/assimp/cfileio.h index a7a56f81c..be90999d8 100644 --- a/include/assimp/cfileio.h +++ b/include/assimp/cfileio.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,10 +48,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_FILEIO_H_INC #define AI_FILEIO_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include + #ifdef __cplusplus extern "C" { #endif + struct aiFileIO; struct aiFile; diff --git a/include/assimp/cimport.h b/include/assimp/cimport.h index eb1e6e0d4..66b1c9a17 100644 --- a/include/assimp/cimport.h +++ b/include/assimp/cimport.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,8 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_ASSIMP_H_INC #define AI_ASSIMP_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include -#include "importerdesc.h" +#include #ifdef __cplusplus extern "C" { diff --git a/include/assimp/color4.h b/include/assimp/color4.h index fddd1b638..fa86128f4 100644 --- a/include/assimp/color4.h +++ b/include/assimp/color4.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -47,7 +47,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_COLOR4D_H_INC #define AI_COLOR4D_H_INC -#include "defs.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include #ifdef __cplusplus @@ -56,8 +60,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * alpha component. Color values range from 0 to 1. */ // ---------------------------------------------------------------------------------- template -class aiColor4t -{ +class aiColor4t { public: aiColor4t() AI_NO_EXCEPT : r(), g(), b(), a() {} aiColor4t (TReal _r, TReal _g, TReal _b, TReal _a) @@ -65,14 +68,12 @@ public: explicit aiColor4t (TReal _r) : r(_r), g(_r), b(_r), a(_r) {} aiColor4t (const aiColor4t& o) = default; -public: // combined operators const aiColor4t& operator += (const aiColor4t& o); const aiColor4t& operator -= (const aiColor4t& o); const aiColor4t& operator *= (TReal f); const aiColor4t& operator /= (TReal f); -public: // comparison bool operator == (const aiColor4t& other) const; bool operator != (const aiColor4t& other) const; @@ -85,8 +86,6 @@ public: /** check whether a color is (close to) black */ inline bool IsBlack() const; -public: - // Red, green, blue and alpha color values TReal r, g, b, a; }; // !struct aiColor4D diff --git a/include/assimp/color4.inl b/include/assimp/color4.inl index 6e27292b9..d4a2a9810 100644 --- a/include/assimp/color4.inl +++ b/include/assimp/color4.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,36 +48,61 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_COLOR4D_INL_INC #define AI_COLOR4D_INL_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifdef __cplusplus -#include "color4.h" +#include // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE const aiColor4t& aiColor4t::operator += (const aiColor4t& o) { - r += o.r; g += o.g; b += o.b; a += o.a; +AI_FORCE_INLINE +const aiColor4t& aiColor4t::operator += (const aiColor4t& o) { + r += o.r; + g += o.g; + b += o.b; + a += o.a; + return *this; } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE const aiColor4t& aiColor4t::operator -= (const aiColor4t& o) { - r -= o.r; g -= o.g; b -= o.b; a -= o.a; +AI_FORCE_INLINE +const aiColor4t& aiColor4t::operator -= (const aiColor4t& o) { + r -= o.r; + g -= o.g; + b -= o.b; + a -= o.a; + return *this; } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE const aiColor4t& aiColor4t::operator *= (TReal f) { - r *= f; g *= f; b *= f; a *= f; +AI_FORCE_INLINE +const aiColor4t& aiColor4t::operator *= (TReal f) { + r *= f; + g *= f; + b *= f; + a *= f; + return *this; } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE const aiColor4t& aiColor4t::operator /= (TReal f) { - r /= f; g /= f; b /= f; a /= f; +AI_FORCE_INLINE +const aiColor4t& aiColor4t::operator /= (TReal f) { + r /= f; + g /= f; + b /= f; + a /= f; + return *this; } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE TReal aiColor4t::operator[](unsigned int i) const { +AI_FORCE_INLINE +TReal aiColor4t::operator[](unsigned int i) const { switch ( i ) { case 0: return r; @@ -85,6 +110,8 @@ AI_FORCE_INLINE TReal aiColor4t::operator[](unsigned int i) const { return g; case 2: return b; + case 3: + return a; default: break; } @@ -92,7 +119,8 @@ AI_FORCE_INLINE TReal aiColor4t::operator[](unsigned int i) const { } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE TReal& aiColor4t::operator[](unsigned int i) { +AI_FORCE_INLINE +TReal& aiColor4t::operator[](unsigned int i) { switch ( i ) { case 0: return r; @@ -100,6 +128,8 @@ AI_FORCE_INLINE TReal& aiColor4t::operator[](unsigned int i) { return g; case 2: return b; + case 3: + return a; default: break; } @@ -107,17 +137,20 @@ AI_FORCE_INLINE TReal& aiColor4t::operator[](unsigned int i) { } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE bool aiColor4t::operator== (const aiColor4t& other) const { +AI_FORCE_INLINE +bool aiColor4t::operator== (const aiColor4t& other) const { return r == other.r && g == other.g && b == other.b && a == other.a; } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE bool aiColor4t::operator!= (const aiColor4t& other) const { +AI_FORCE_INLINE +bool aiColor4t::operator!= (const aiColor4t& other) const { return r != other.r || g != other.g || b != other.b || a != other.a; } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE bool aiColor4t::operator< (const aiColor4t& other) const { +AI_FORCE_INLINE +bool aiColor4t::operator< (const aiColor4t& other) const { return r < other.r || ( r == other.r && ( g < other.g || ( @@ -132,14 +165,17 @@ AI_FORCE_INLINE bool aiColor4t::operator< (const aiColor4t& other) ) ); } + // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator + (const aiColor4t& v1, const aiColor4t& v2) { +AI_FORCE_INLINE +aiColor4t operator + (const aiColor4t& v1, const aiColor4t& v2) { return aiColor4t( v1.r + v2.r, v1.g + v2.g, v1.b + v2.b, v1.a + v2.a); } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator - (const aiColor4t& v1, const aiColor4t& v2) { +AI_FORCE_INLINE +aiColor4t operator - (const aiColor4t& v1, const aiColor4t& v2) { return aiColor4t( v1.r - v2.r, v1.g - v2.g, v1.b - v2.b, v1.a - v2.a); } // ------------------------------------------------------------------------------------------------ @@ -149,53 +185,63 @@ AI_FORCE_INLINE aiColor4t operator * (const aiColor4t& v1, const a } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator / (const aiColor4t& v1, const aiColor4t& v2) { +AI_FORCE_INLINE +aiColor4t operator / (const aiColor4t& v1, const aiColor4t& v2) { return aiColor4t( v1.r / v2.r, v1.g / v2.g, v1.b / v2.b, v1.a / v2.a); } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator * ( TReal f, const aiColor4t& v) { +AI_FORCE_INLINE +aiColor4t operator * ( TReal f, const aiColor4t& v) { return aiColor4t( f*v.r, f*v.g, f*v.b, f*v.a); } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator * ( const aiColor4t& v, TReal f) { +AI_FORCE_INLINE +aiColor4t operator * ( const aiColor4t& v, TReal f) { return aiColor4t( f*v.r, f*v.g, f*v.b, f*v.a); } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator / ( const aiColor4t& v, TReal f) { +AI_FORCE_INLINE +aiColor4t operator / ( const aiColor4t& v, TReal f) { return v * (1/f); } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator / ( TReal f,const aiColor4t& v) { +AI_FORCE_INLINE +aiColor4t operator / ( TReal f,const aiColor4t& v) { return aiColor4t(f,f,f,f)/v; } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator + ( const aiColor4t& v, TReal f) { +AI_FORCE_INLINE +aiColor4t operator + ( const aiColor4t& v, TReal f) { return aiColor4t( f+v.r, f+v.g, f+v.b, f+v.a); } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator - ( const aiColor4t& v, TReal f) { +AI_FORCE_INLINE +aiColor4t operator - ( const aiColor4t& v, TReal f) { return aiColor4t( v.r-f, v.g-f, v.b-f, v.a-f); } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator + ( TReal f, const aiColor4t& v) { +AI_FORCE_INLINE +aiColor4t operator + ( TReal f, const aiColor4t& v) { return aiColor4t( f+v.r, f+v.g, f+v.b, f+v.a); } // ------------------------------------------------------------------------------------------------ template -AI_FORCE_INLINE aiColor4t operator - ( TReal f, const aiColor4t& v) { +AI_FORCE_INLINE +aiColor4t operator - ( TReal f, const aiColor4t& v) { return aiColor4t( f-v.r, f-v.g, f-v.b, f-v.a); } // ------------------------------------------------------------------------------------------------ template -inline bool aiColor4t :: IsBlack() const { +AI_FORCE_INLINE +bool aiColor4t::IsBlack() const { // The alpha component doesn't care here. black is black. static const TReal epsilon = 10e-3f; return std::fabs( r ) < epsilon && std::fabs( g ) < epsilon && std::fabs( b ) < epsilon; diff --git a/include/assimp/config.h.in b/include/assimp/config.h.in index fd828bc6e..3a6379bf4 100644 --- a/include/assimp/config.h.in +++ b/include/assimp/config.h.in @@ -498,6 +498,13 @@ enum aiComponent #define AI_CONFIG_PP_FID_ANIM_ACCURACY \ "PP_FID_ANIM_ACCURACY" +// --------------------------------------------------------------------------- +/** @brief Input parameter to the #aiProcess_FindInvalidData step: + * Set to true to ignore texture coordinates. This may be useful if you have + * to assign different kind of textures like one for the summer or one for the winter. + */ +#define AI_CONFIG_PP_FID_IGNORE_TEXTURECOORDS \ + "PP_FID_IGNORE_TEXTURECOORDS" // TransformUVCoords evaluates UV scalings #define AI_UVTRAFO_SCALING 0x1 @@ -644,13 +651,28 @@ enum aiComponent // --------------------------------------------------------------------------- /** @brief Set whether the fbx importer will use the legacy embedded texture naming. -* -* The default value is false (0) -* Property type: bool -*/ + * + * The default value is false (0) + * Property type: bool + */ #define AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING \ "AI_CONFIG_IMPORT_FBX_EMBEDDED_TEXTURES_LEGACY_NAMING" - + +// --------------------------------------------------------------------------- +/** @brief Set wether the importer shall not remove empty bones. + * + * Empty bone are often used to define connections for other models. + */ +#define AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES \ + "AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES" + + +// --------------------------------------------------------------------------- +/** @brief Set wether the FBX importer shall convert the unit from cm to m. + */ +#define AI_CONFIG_FBX_CONVERT_TO_M \ + "AI_CONFIG_FBX_CONVERT_TO_M" + // --------------------------------------------------------------------------- /** @brief Set the vertex animation keyframe to be imported * @@ -959,8 +981,12 @@ enum aiComponent #define AI_CONFIG_EXPORT_XFILE_64BIT "EXPORT_XFILE_64BIT" -/** - * +/** @brief Specifies whether the assimp export shall be able to export point clouds + * + * When this flag is not defined the render data has to contain valid faces. + * Point clouds are only a collection of vertices which have nor spatial organization + * by a face and the validation process will remove them. Enabling this feature will + * switch off the flag and enable the functionality to export pure point clouds. */ #define AI_CONFIG_EXPORT_POINT_CLOUDS "EXPORT_POINT_CLOUDS" @@ -973,6 +999,13 @@ enum aiComponent # define AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT 1.0f #endif // !! AI_DEBONE_THRESHOLD +#define AI_CONFIG_APP_SCALE_KEY "APP_SCALE_FACTOR" + +#if (!defined AI_CONFIG_APP_SCALE_KEY) +# define AI_CONFIG_APP_SCALE_KEY 1.0 +#endif // AI_CONFIG_APP_SCALE_KEY + + // ---------- All the Build/Compile-time defines ------------ /** @brief Specifies if double precision is supported inside assimp diff --git a/include/assimp/defs.h b/include/assimp/defs.h index e651a1f7b..71579a5c7 100644 --- a/include/assimp/defs.h +++ b/include/assimp/defs.h @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -50,6 +48,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_DEFINES_H_INC #define AI_DEFINES_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include ////////////////////////////////////////////////////////////////////////// @@ -122,7 +124,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OPTIMIZEANIMS * OPTIMIZEGRAPH * GENENTITYMESHES - * FIXTEXTUREPATHS */ + * FIXTEXTUREPATHS + * GENBOUNDINGBOXES */ ////////////////////////////////////////////////////////////////////////// #ifdef _MSC_VER @@ -214,10 +217,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif #if (defined(__BORLANDC__) || defined (__BCPLUSPLUS__)) -#error Currently, Borland is unsupported. Feel free to port Assimp. - -// "W8059 Packgröße der Struktur geändert" - +# error Currently, Borland is unsupported. Feel free to port Assimp. #endif @@ -243,10 +243,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. typedef double ai_real; typedef signed long long int ai_int; typedef unsigned long long int ai_uint; +#ifndef ASSIMP_AI_REAL_TEXT_PRECISION +#define ASSIMP_AI_REAL_TEXT_PRECISION 16 +#endif // ASSIMP_AI_REAL_TEXT_PRECISION #else // ASSIMP_DOUBLE_PRECISION typedef float ai_real; typedef signed int ai_int; typedef unsigned int ai_uint; +#ifndef ASSIMP_AI_REAL_TEXT_PRECISION +#define ASSIMP_AI_REAL_TEXT_PRECISION 8 +#endif // ASSIMP_AI_REAL_TEXT_PRECISION #endif // ASSIMP_DOUBLE_PRECISION ////////////////////////////////////////////////////////////////////////// @@ -267,6 +273,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_DEG_TO_RAD(x) ((x)*(ai_real)0.0174532925) #define AI_RAD_TO_DEG(x) ((x)*(ai_real)57.2957795) +/* Numerical limits */ +static const ai_real ai_epsilon = (ai_real) 0.00001; + /* Support for big-endian builds */ #if defined(__BYTE_ORDER__) # if (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) @@ -284,20 +293,30 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif -/* To avoid running out of memory - * This can be adjusted for specific use cases - * It's NOT a total limit, just a limit for individual allocations +/** + * To avoid running out of memory + * This can be adjusted for specific use cases + * It's NOT a total limit, just a limit for individual allocations */ #define AI_MAX_ALLOC(type) ((256U * 1024 * 1024) / sizeof(type)) #ifndef _MSC_VER # define AI_NO_EXCEPT noexcept #else -# if (_MSC_VER == 1915 ) +# if (_MSC_VER >= 1915 ) # define AI_NO_EXCEPT noexcept # else # define AI_NO_EXCEPT # endif +#endif // _MSC_VER + +/** + * 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 #endif // !! AI_DEFINES_H_INC diff --git a/include/assimp/fast_atof.h b/include/assimp/fast_atof.h index 62ea969e9..6e9a1bba7 100644 --- a/include/assimp/fast_atof.h +++ b/include/assimp/fast_atof.h @@ -13,10 +13,14 @@ // to ensure long numbers are handled correctly // ------------------------------------------------------------------------------------ - +#pragma once #ifndef FAST_A_TO_F_H_INCLUDED #define FAST_A_TO_F_H_INCLUDED +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include #include #include diff --git a/include/assimp/importerdesc.h b/include/assimp/importerdesc.h index 36b773e45..0a6919c1a 100644 --- a/include/assimp/importerdesc.h +++ b/include/assimp/importerdesc.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,11 +48,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_IMPORTER_DESC_H_INC #define AI_IMPORTER_DESC_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + /** Mixed set of flags for #aiImporterDesc, indicating some features * common to many importers*/ -enum aiImporterFlags -{ +enum aiImporterFlags { /** Indicates that there is a textual encoding of the * file format; and that it is supported.*/ aiImporterFlags_SupportTextFlavour = 0x1, @@ -87,8 +90,7 @@ enum aiImporterFlags * as importers/exporters are added to Assimp, so it might be useful * to have a common mechanism to query some rough importer * characteristics. */ -struct aiImporterDesc -{ +struct aiImporterDesc { /** Full name of the importer (i.e. Blender3D importer)*/ const char* mName; diff --git a/include/assimp/irrXMLWrapper.h b/include/assimp/irrXMLWrapper.h index 296f26a32..77cfd5e47 100644 --- a/include/assimp/irrXMLWrapper.h +++ b/include/assimp/irrXMLWrapper.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -44,7 +44,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define INCLUDED_AI_IRRXML_WRAPPER // some long includes .... -#include +#ifdef ASSIMP_USE_HUNTER +# include +#else +# include +#endif #include "IOStream.hpp" #include "BaseImporter.h" #include @@ -91,14 +95,15 @@ public: stream->Read(&data[0],data.size(),1); // Remove null characters from the input sequence otherwise the parsing will utterly fail - unsigned int size = 0; - unsigned int size_max = static_cast(data.size()); - for(unsigned int i = 0; i < size_max; i++) { - if(data[i] != '\0') { - data[size++] = data[i]; - } + // std::find is usually much faster than manually iterating + // It is very unlikely that there will be any null characters + auto null_char_iter = std::find(data.begin(), data.end(), '\0'); + + while (null_char_iter != data.end()) + { + null_char_iter = data.erase(null_char_iter); + null_char_iter = std::find(null_char_iter, data.end(), '\0'); } - data.resize(size); BaseImporter::ConvertToUTF8(data); } diff --git a/include/assimp/light.h b/include/assimp/light.h index dc0b8a4b6..bdb2368c4 100644 --- a/include/assimp/light.h +++ b/include/assimp/light.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -49,7 +49,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_LIGHT_H_INC #define AI_LIGHT_H_INC -#include "types.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include #ifdef __cplusplus extern "C" { diff --git a/include/assimp/material.h b/include/assimp/material.h index 45b4844a3..19a7c6970 100644 --- a/include/assimp/material.h +++ b/include/assimp/material.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,7 +48,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_MATERIAL_H_INC #define AI_MATERIAL_H_INC -#include "types.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include #ifdef __cplusplus extern "C" { @@ -196,36 +200,40 @@ enum aiTextureType * (#aiMaterialProperty::mSemantic) for all material properties * *not* related to textures. */ - aiTextureType_NONE = 0x0, - + aiTextureType_NONE = 0, + /** LEGACY API MATERIALS + * Legacy refers to materials which + * Were originally implemented in the specifications around 2000. + * These must never be removed, as most engines support them. + */ /** The texture is combined with the result of the diffuse * lighting equation. */ - aiTextureType_DIFFUSE = 0x1, + aiTextureType_DIFFUSE = 1, /** The texture is combined with the result of the specular * lighting equation. */ - aiTextureType_SPECULAR = 0x2, + aiTextureType_SPECULAR = 2, /** The texture is combined with the result of the ambient * lighting equation. */ - aiTextureType_AMBIENT = 0x3, + aiTextureType_AMBIENT = 3, /** The texture is added to the result of the lighting * calculation. It isn't influenced by incoming light. */ - aiTextureType_EMISSIVE = 0x4, + aiTextureType_EMISSIVE = 4, /** The texture is a height map. * * By convention, higher gray-scale values stand for * higher elevations from the base height. */ - aiTextureType_HEIGHT = 0x5, + aiTextureType_HEIGHT = 5, /** The texture is a (tangent space) normal-map. * @@ -233,7 +241,7 @@ enum aiTextureType * normal maps. Assimp does (intentionally) not * distinguish here. */ - aiTextureType_NORMALS = 0x6, + aiTextureType_NORMALS = 6, /** The texture defines the glossiness of the material. * @@ -242,21 +250,21 @@ enum aiTextureType * function defined to map the linear color values in the * texture to a suitable exponent. Have fun. */ - aiTextureType_SHININESS = 0x7, + aiTextureType_SHININESS = 7, /** The texture defines per-pixel opacity. * * Usually 'white' means opaque and 'black' means * 'transparency'. Or quite the opposite. Have fun. */ - aiTextureType_OPACITY = 0x8, + aiTextureType_OPACITY = 8, /** Displacement texture * * The exact purpose and format is application-dependent. * Higher color values stand for higher vertex displacements. */ - aiTextureType_DISPLACEMENT = 0x9, + aiTextureType_DISPLACEMENT = 9, /** Lightmap texture (aka Ambient Occlusion) * @@ -265,22 +273,36 @@ enum aiTextureType * scaling value for the final color value of a pixel. Its * intensity is not affected by incoming light. */ - aiTextureType_LIGHTMAP = 0xA, + aiTextureType_LIGHTMAP = 10, /** Reflection texture * * Contains the color of a perfect mirror reflection. * Rarely used, almost never for real-time applications. */ - aiTextureType_REFLECTION = 0xB, + aiTextureType_REFLECTION = 11, + + /** PBR Materials + * PBR definitions from maya and other modelling packages now use this standard. + * This was originally introduced around 2012. + * Support for this is in game engines like Godot, Unreal or Unity3D. + * Modelling packages which use this are very common now. + */ + + aiTextureType_BASE_COLOR = 12, + aiTextureType_NORMAL_CAMERA = 13, + aiTextureType_EMISSION_COLOR = 14, + aiTextureType_METALNESS = 15, + aiTextureType_DIFFUSE_ROUGHNESS = 16, + aiTextureType_AMBIENT_OCCLUSION = 17, /** Unknown texture * * A texture reference that does not match any of the definitions * above is considered to be 'unknown'. It is still imported, - * but is excluded from any further postprocessing. + * but is excluded from any further post-processing. */ - aiTextureType_UNKNOWN = 0xC, + aiTextureType_UNKNOWN = 18, #ifndef SWIG @@ -375,7 +397,7 @@ enum aiShadingMode */ enum aiTextureFlags { - /** The texture's color values have to be inverted (componentwise 1-n) + /** The texture's color values have to be inverted (component-wise 1-n) */ aiTextureFlags_Invert = 0x1, @@ -902,6 +924,7 @@ extern "C" { #define AI_MATKEY_ENABLE_WIREFRAME "$mat.wireframe",0,0 #define AI_MATKEY_BLEND_FUNC "$mat.blend",0,0 #define AI_MATKEY_OPACITY "$mat.opacity",0,0 +#define AI_MATKEY_TRANSPARENCYFACTOR "$mat.transparencyfactor",0,0 #define AI_MATKEY_BUMPSCALING "$mat.bumpscaling",0,0 #define AI_MATKEY_SHININESS "$mat.shininess",0,0 #define AI_MATKEY_REFLECTIVITY "$mat.reflectivity",0,0 @@ -914,6 +937,13 @@ extern "C" { #define AI_MATKEY_COLOR_TRANSPARENT "$clr.transparent",0,0 #define AI_MATKEY_COLOR_REFLECTIVE "$clr.reflective",0,0 #define AI_MATKEY_GLOBAL_BACKGROUND_IMAGE "?bg.global",0,0 +#define AI_MATKEY_GLOBAL_SHADERLANG "?sh.lang",0,0 +#define AI_MATKEY_SHADER_VERTEX "?sh.vs",0,0 +#define AI_MATKEY_SHADER_FRAGMENT "?sh.fs",0,0 +#define AI_MATKEY_SHADER_GEO "?sh.gs",0,0 +#define AI_MATKEY_SHADER_TESSELATION "?sh.ts",0,0 +#define AI_MATKEY_SHADER_PRIMITIVE "?sh.ps",0,0 +#define AI_MATKEY_SHADER_COMPUTE "?sh.cs",0,0 // --------------------------------------------------------------------------- // Pure key names for all texture-related properties @@ -1457,8 +1487,6 @@ inline aiReturn aiGetMaterialInteger(const C_STRUCT aiMaterial* pMat, #endif //!__cplusplus - - // --------------------------------------------------------------------------- /** @brief Retrieve a color value from the material property table * diff --git a/include/assimp/material.inl b/include/assimp/material.inl index 3d4b07c06..8ae6b88d3 100644 --- a/include/assimp/material.inl +++ b/include/assimp/material.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -49,14 +49,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_MATERIAL_INL_INC #define AI_MATERIAL_INL_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + // --------------------------------------------------------------------------- -inline aiPropertyTypeInfo ai_real_to_property_type_info(float) -{ +AI_FORCE_INLINE +aiPropertyTypeInfo ai_real_to_property_type_info(float) { return aiPTI_Float; } -inline aiPropertyTypeInfo ai_real_to_property_type_info(double) -{ +AI_FORCE_INLINE +aiPropertyTypeInfo ai_real_to_property_type_info(double) { return aiPTI_Double; } // --------------------------------------------------------------------------- @@ -64,30 +68,30 @@ inline aiPropertyTypeInfo ai_real_to_property_type_info(double) //! @cond never // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::GetTexture( aiTextureType type, - unsigned int index, - C_STRUCT aiString* path, - aiTextureMapping* mapping /*= NULL*/, - unsigned int* uvindex /*= NULL*/, - ai_real* blend /*= NULL*/, - aiTextureOp* op /*= NULL*/, - aiTextureMapMode* mapmode /*= NULL*/) const -{ +AI_FORCE_INLINE +aiReturn aiMaterial::GetTexture( aiTextureType type, + unsigned int index, + C_STRUCT aiString* path, + aiTextureMapping* mapping /*= NULL*/, + unsigned int* uvindex /*= NULL*/, + ai_real* blend /*= NULL*/, + aiTextureOp* op /*= NULL*/, + aiTextureMapMode* mapmode /*= NULL*/) const { return ::aiGetMaterialTexture(this,type,index,path,mapping,uvindex,blend,op,mapmode); } // --------------------------------------------------------------------------- -inline unsigned int aiMaterial::GetTextureCount(aiTextureType type) const -{ +AI_FORCE_INLINE +unsigned int aiMaterial::GetTextureCount(aiTextureType type) const { return ::aiGetMaterialTextureCount(this,type); } // --------------------------------------------------------------------------- template -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx, Type* pOut, - unsigned int* pMax) const -{ +AI_FORCE_INLINE +aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx, Type* pOut, + unsigned int* pMax) const { unsigned int iNum = pMax ? *pMax : 1; const aiMaterialProperty* prop; @@ -114,9 +118,9 @@ inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, // --------------------------------------------------------------------------- template -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,Type& pOut) const -{ +AI_FORCE_INLINE +aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,Type& pOut) const { const aiMaterialProperty* prop; const aiReturn ret = ::aiGetMaterialProperty(this,pKey,type,idx, (const aiMaterialProperty**)&prop); @@ -136,60 +140,56 @@ inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,ai_real* pOut, - unsigned int* pMax) const -{ +AI_FORCE_INLINE +aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,ai_real* pOut, + unsigned int* pMax) const { return ::aiGetMaterialFloatArray(this,pKey,type,idx,pOut,pMax); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,int* pOut, - unsigned int* pMax) const -{ +AI_FORCE_INLINE +aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,int* pOut, + unsigned int* pMax) const { return ::aiGetMaterialIntegerArray(this,pKey,type,idx,pOut,pMax); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,ai_real& pOut) const -{ +AI_FORCE_INLINE +aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,ai_real& pOut) const { return aiGetMaterialFloat(this,pKey,type,idx,&pOut); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,int& pOut) const -{ +AI_FORCE_INLINE +aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,int& pOut) const { return aiGetMaterialInteger(this,pKey,type,idx,&pOut); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,aiColor4D& pOut) const -{ +AI_FORCE_INLINE +aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,aiColor4D& pOut) const { return aiGetMaterialColor(this,pKey,type,idx,&pOut); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,aiColor3D& pOut) const -{ +AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,aiColor3D& pOut) const { aiColor4D c; const aiReturn ret = aiGetMaterialColor(this,pKey,type,idx,&c); pOut = aiColor3D(c.r,c.g,c.b); return ret; } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,aiString& pOut) const -{ +AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,aiString& pOut) const { return aiGetMaterialString(this,pKey,type,idx,&pOut); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::Get(const char* pKey,unsigned int type, - unsigned int idx,aiUVTransform& pOut) const -{ +AI_FORCE_INLINE aiReturn aiMaterial::Get(const char* pKey,unsigned int type, + unsigned int idx,aiUVTransform& pOut) const { return aiGetMaterialUVTransform(this,pKey,type,idx,&pOut); } - // --------------------------------------------------------------------------- template aiReturn aiMaterial::AddProperty (const TYPE* pInput, @@ -204,84 +204,83 @@ aiReturn aiMaterial::AddProperty (const TYPE* pInput, } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::AddProperty(const float* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE aiReturn aiMaterial::AddProperty(const float* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(float), pKey,type,index,aiPTI_Float); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::AddProperty(const double* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const double* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(double), pKey,type,index,aiPTI_Double); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::AddProperty(const aiUVTransform* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const aiUVTransform* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiUVTransform), pKey,type,index,ai_real_to_property_type_info(pInput->mRotation)); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::AddProperty(const aiColor4D* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const aiColor4D* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiColor4D), pKey,type,index,ai_real_to_property_type_info(pInput->a)); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::AddProperty(const aiColor3D* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const aiColor3D* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiColor3D), pKey,type,index,ai_real_to_property_type_info(pInput->b)); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::AddProperty(const aiVector3D* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const aiVector3D* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiVector3D), pKey,type,index,ai_real_to_property_type_info(pInput->x)); } // --------------------------------------------------------------------------- -inline aiReturn aiMaterial::AddProperty(const int* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const int* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(int), pKey,type,index,aiPTI_Integer); @@ -296,12 +295,12 @@ inline aiReturn aiMaterial::AddProperty(const int* pInput, // --------------------------------------------------------------------------- template<> -inline aiReturn aiMaterial::AddProperty(const float* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const float* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(float), pKey,type,index,aiPTI_Float); @@ -309,12 +308,12 @@ inline aiReturn aiMaterial::AddProperty(const float* pInput, // --------------------------------------------------------------------------- template<> -inline aiReturn aiMaterial::AddProperty(const double* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const double* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(double), pKey,type,index,aiPTI_Double); @@ -322,12 +321,12 @@ inline aiReturn aiMaterial::AddProperty(const double* pInput, // --------------------------------------------------------------------------- template<> -inline aiReturn aiMaterial::AddProperty(const aiUVTransform* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const aiUVTransform* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiUVTransform), pKey,type,index,aiPTI_Float); @@ -335,12 +334,12 @@ inline aiReturn aiMaterial::AddProperty(const aiUVTransform* pInp // --------------------------------------------------------------------------- template<> -inline aiReturn aiMaterial::AddProperty(const aiColor4D* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const aiColor4D* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiColor4D), pKey,type,index,aiPTI_Float); @@ -348,12 +347,12 @@ inline aiReturn aiMaterial::AddProperty(const aiColor4D* pInput, // --------------------------------------------------------------------------- template<> -inline aiReturn aiMaterial::AddProperty(const aiColor3D* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const aiColor3D* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiColor3D), pKey,type,index,aiPTI_Float); @@ -361,12 +360,12 @@ inline aiReturn aiMaterial::AddProperty(const aiColor3D* pInput, // --------------------------------------------------------------------------- template<> -inline aiReturn aiMaterial::AddProperty(const aiVector3D* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const aiVector3D* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiVector3D), pKey,type,index,aiPTI_Float); @@ -374,12 +373,12 @@ inline aiReturn aiMaterial::AddProperty(const aiVector3D* pInput, // --------------------------------------------------------------------------- template<> -inline aiReturn aiMaterial::AddProperty(const int* pInput, - const unsigned int pNumValues, - const char* pKey, - unsigned int type, - unsigned int index) -{ +AI_FORCE_INLINE +aiReturn aiMaterial::AddProperty(const int* pInput, + const unsigned int pNumValues, + const char* pKey, + unsigned int type, + unsigned int index) { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(int), pKey,type,index,aiPTI_Integer); diff --git a/include/assimp/matrix3x3.h b/include/assimp/matrix3x3.h index 4bb55ad21..2c26cf92b 100644 --- a/include/assimp/matrix3x3.h +++ b/include/assimp/matrix3x3.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,7 +48,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_MATRIX3X3_H_INC #define AI_MATRIX3X3_H_INC -#include "defs.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include #ifdef __cplusplus @@ -65,10 +69,8 @@ template class aiVector2t; * defined thereby. */ template -class aiMatrix3x3t -{ +class aiMatrix3x3t { public: - aiMatrix3x3t() AI_NO_EXCEPT : a1(static_cast(1.0f)), a2(), a3(), b1(), b2(static_cast(1.0f)), b3(), @@ -82,8 +84,6 @@ public: c1(_c1), c2(_c2), c3(_c3) {} -public: - // matrix multiplication. aiMatrix3x3t& operator *= (const aiMatrix3x3t& m); aiMatrix3x3t operator * (const aiMatrix3x3t& m) const; @@ -101,8 +101,6 @@ public: template operator aiMatrix3x3t () const; -public: - // ------------------------------------------------------------------- /** @brief Construction from a 4x4 matrix. The remaining parts * of the matrix are ignored. @@ -122,7 +120,6 @@ public: aiMatrix3x3t& Inverse(); TReal Determinant() const; -public: // ------------------------------------------------------------------- /** @brief Returns a rotation matrix for a rotation around z * @param a Rotation angle, in radians diff --git a/include/assimp/matrix3x3.inl b/include/assimp/matrix3x3.inl index ab2cc410b..1ce8c9691 100644 --- a/include/assimp/matrix3x3.inl +++ b/include/assimp/matrix3x3.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,10 +48,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_MATRIX3X3_INL_INC #define AI_MATRIX3X3_INL_INC -#ifdef __cplusplus -#include "matrix3x3.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#ifdef __cplusplus +#include +#include -#include "matrix4x4.h" #include #include #include @@ -59,8 +63,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ------------------------------------------------------------------------------------------------ // Construction from a 4x4 matrix. The remaining parts of the matrix are ignored. template -inline aiMatrix3x3t::aiMatrix3x3t( const aiMatrix4x4t& pMatrix) -{ +AI_FORCE_INLINE +aiMatrix3x3t::aiMatrix3x3t( const aiMatrix4x4t& pMatrix) { a1 = pMatrix.a1; a2 = pMatrix.a2; a3 = pMatrix.a3; b1 = pMatrix.b1; b2 = pMatrix.b2; b3 = pMatrix.b3; c1 = pMatrix.c1; c2 = pMatrix.c2; c3 = pMatrix.c3; @@ -68,8 +72,8 @@ inline aiMatrix3x3t::aiMatrix3x3t( const aiMatrix4x4t& pMatrix) // ------------------------------------------------------------------------------------------------ template -inline aiMatrix3x3t& aiMatrix3x3t::operator *= (const aiMatrix3x3t& m) -{ +AI_FORCE_INLINE +aiMatrix3x3t& aiMatrix3x3t::operator *= (const aiMatrix3x3t& m) { *this = aiMatrix3x3t(m.a1 * a1 + m.b1 * a2 + m.c1 * a3, m.a2 * a1 + m.b2 * a2 + m.c2 * a3, m.a3 * a1 + m.b3 * a2 + m.c3 * a3, @@ -85,8 +89,7 @@ inline aiMatrix3x3t& aiMatrix3x3t::operator *= (const aiMatrix3x3t // ------------------------------------------------------------------------------------------------ template template -aiMatrix3x3t::operator aiMatrix3x3t () const -{ +aiMatrix3x3t::operator aiMatrix3x3t () const { return aiMatrix3x3t(static_cast(a1),static_cast(a2),static_cast(a3), static_cast(b1),static_cast(b2),static_cast(b3), static_cast(c1),static_cast(c2),static_cast(c3)); @@ -94,8 +97,8 @@ aiMatrix3x3t::operator aiMatrix3x3t () const // ------------------------------------------------------------------------------------------------ template -inline aiMatrix3x3t aiMatrix3x3t::operator* (const aiMatrix3x3t& m) const -{ +AI_FORCE_INLINE +aiMatrix3x3t aiMatrix3x3t::operator* (const aiMatrix3x3t& m) const { aiMatrix3x3t temp( *this); temp *= m; return temp; @@ -103,7 +106,8 @@ inline aiMatrix3x3t aiMatrix3x3t::operator* (const aiMatrix3x3t -inline TReal* aiMatrix3x3t::operator[] (unsigned int p_iIndex) { +AI_FORCE_INLINE +TReal* aiMatrix3x3t::operator[] (unsigned int p_iIndex) { switch ( p_iIndex ) { case 0: return &a1; @@ -119,7 +123,8 @@ inline TReal* aiMatrix3x3t::operator[] (unsigned int p_iIndex) { // ------------------------------------------------------------------------------------------------ template -inline const TReal* aiMatrix3x3t::operator[] (unsigned int p_iIndex) const { +AI_FORCE_INLINE +const TReal* aiMatrix3x3t::operator[] (unsigned int p_iIndex) const { switch ( p_iIndex ) { case 0: return &a1; @@ -135,8 +140,8 @@ inline const TReal* aiMatrix3x3t::operator[] (unsigned int p_iIndex) cons // ------------------------------------------------------------------------------------------------ template -inline bool aiMatrix3x3t::operator== (const aiMatrix4x4t& m) const -{ +AI_FORCE_INLINE +bool aiMatrix3x3t::operator== (const aiMatrix4x4t& m) const { return a1 == m.a1 && a2 == m.a2 && a3 == m.a3 && b1 == m.b1 && b2 == m.b2 && b3 == m.b3 && c1 == m.c1 && c2 == m.c2 && c3 == m.c3; @@ -144,14 +149,15 @@ inline bool aiMatrix3x3t::operator== (const aiMatrix4x4t& m) const // ------------------------------------------------------------------------------------------------ template -inline bool aiMatrix3x3t::operator!= (const aiMatrix4x4t& m) const -{ +AI_FORCE_INLINE +bool aiMatrix3x3t::operator!= (const aiMatrix4x4t& m) const { return !(*this == m); } // --------------------------------------------------------------------------- template -inline bool aiMatrix3x3t::Equal(const aiMatrix4x4t& m, TReal epsilon) const { +AI_FORCE_INLINE +bool aiMatrix3x3t::Equal(const aiMatrix4x4t& m, TReal epsilon) const { return std::abs(a1 - m.a1) <= epsilon && std::abs(a2 - m.a2) <= epsilon && @@ -166,8 +172,8 @@ inline bool aiMatrix3x3t::Equal(const aiMatrix4x4t& m, TReal epsil // ------------------------------------------------------------------------------------------------ template -inline aiMatrix3x3t& aiMatrix3x3t::Transpose() -{ +AI_FORCE_INLINE +aiMatrix3x3t& aiMatrix3x3t::Transpose() { // (TReal&) don't remove, GCC complains cause of packed fields std::swap( (TReal&)a2, (TReal&)b1); std::swap( (TReal&)a3, (TReal&)c1); @@ -177,15 +183,15 @@ inline aiMatrix3x3t& aiMatrix3x3t::Transpose() // ---------------------------------------------------------------------------------------- template -inline TReal aiMatrix3x3t::Determinant() const -{ +AI_FORCE_INLINE +TReal aiMatrix3x3t::Determinant() const { return a1*b2*c3 - a1*b3*c2 + a2*b3*c1 - a2*b1*c3 + a3*b1*c2 - a3*b2*c1; } // ---------------------------------------------------------------------------------------- template -inline aiMatrix3x3t& aiMatrix3x3t::Inverse() -{ +AI_FORCE_INLINE +aiMatrix3x3t& aiMatrix3x3t::Inverse() { // Compute the reciprocal determinant TReal det = Determinant(); if(det == static_cast(0.0)) @@ -219,8 +225,8 @@ inline aiMatrix3x3t& aiMatrix3x3t::Inverse() // ------------------------------------------------------------------------------------------------ template -inline aiMatrix3x3t& aiMatrix3x3t::RotationZ(TReal a, aiMatrix3x3t& out) -{ +AI_FORCE_INLINE +aiMatrix3x3t& aiMatrix3x3t::RotationZ(TReal a, aiMatrix3x3t& out) { out.a1 = out.b2 = std::cos(a); out.b1 = std::sin(a); out.a2 = - out.b1; @@ -234,8 +240,8 @@ inline aiMatrix3x3t& aiMatrix3x3t::RotationZ(TReal a, aiMatrix3x3t // ------------------------------------------------------------------------------------------------ // Returns a rotation matrix for a rotation around an arbitrary axis. template -inline aiMatrix3x3t& aiMatrix3x3t::Rotation( TReal a, const aiVector3t& axis, aiMatrix3x3t& out) -{ +AI_FORCE_INLINE +aiMatrix3x3t& aiMatrix3x3t::Rotation( TReal a, const aiVector3t& axis, aiMatrix3x3t& out) { TReal c = std::cos( a), s = std::sin( a), t = 1 - c; TReal x = axis.x, y = axis.y, z = axis.z; @@ -249,8 +255,8 @@ inline aiMatrix3x3t& aiMatrix3x3t::Rotation( TReal a, const aiVect // ------------------------------------------------------------------------------------------------ template -inline aiMatrix3x3t& aiMatrix3x3t::Translation( const aiVector2t& v, aiMatrix3x3t& out) -{ +AI_FORCE_INLINE +aiMatrix3x3t& aiMatrix3x3t::Translation( const aiVector2t& v, aiMatrix3x3t& out) { out = aiMatrix3x3t(); out.a3 = v.x; out.b3 = v.y; @@ -268,9 +274,8 @@ inline aiMatrix3x3t& aiMatrix3x3t::Translation( const aiVector2t -inline aiMatrix3x3t& aiMatrix3x3t::FromToMatrix(const aiVector3t& from, - const aiVector3t& to, aiMatrix3x3t& mtx) -{ +AI_FORCE_INLINE aiMatrix3x3t& aiMatrix3x3t::FromToMatrix(const aiVector3t& from, + const aiVector3t& to, aiMatrix3x3t& mtx) { const TReal e = from * to; const TReal f = (e < 0)? -e:e; @@ -352,6 +357,5 @@ inline aiMatrix3x3t& aiMatrix3x3t::FromToMatrix(const aiVector3t +#include #ifdef __cplusplus @@ -66,8 +70,7 @@ template class aiQuaterniont; * defined thereby. */ template -class aiMatrix4x4t -{ +class aiMatrix4x4t { public: /** set to identity */ @@ -91,8 +94,6 @@ public: aiMatrix4x4t(const aiVector3t& scaling, const aiQuaterniont& rotation, const aiVector3t& position); -public: - // array access operators /** @fn TReal* operator[] (unsigned int p_iIndex) * @param [in] p_iIndex - index of the row. @@ -120,8 +121,6 @@ public: template operator aiMatrix4x4t () const; -public: - // ------------------------------------------------------------------- /** @brief Transpose the matrix */ aiMatrix4x4t& Transpose(); @@ -182,7 +181,6 @@ public: void DecomposeNoScaling (aiQuaterniont& rotation, aiVector3t& position) const; - // ------------------------------------------------------------------- /** @brief Creates a trafo matrix from a set of euler angles * @param x Rotation angle for the x-axis, in radians @@ -192,7 +190,6 @@ public: aiMatrix4x4t& FromEulerAnglesXYZ(TReal x, TReal y, TReal z); aiMatrix4x4t& FromEulerAnglesXYZ(const aiVector3t& blubb); -public: // ------------------------------------------------------------------- /** @brief Returns a rotation matrix for a rotation around the x axis * @param a Rotation angle, in radians @@ -256,7 +253,6 @@ public: static aiMatrix4x4t& FromToMatrix(const aiVector3t& from, const aiVector3t& to, aiMatrix4x4t& out); -public: TReal a1, a2, a3, a4; TReal b1, b2, b3, b4; TReal c1, c2, c3, c4; diff --git a/include/assimp/matrix4x4.inl b/include/assimp/matrix4x4.inl index 680d7666d..84079974f 100644 --- a/include/assimp/matrix4x4.inl +++ b/include/assimp/matrix4x4.inl @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -53,6 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "matrix4x4.h" #include "matrix3x3.h" #include "quaternion.h" +#include "MathFunctions.h" #include #include @@ -61,12 +60,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ---------------------------------------------------------------------------------------- template aiMatrix4x4t::aiMatrix4x4t() AI_NO_EXCEPT : - a1(1.0f), a2(), a3(), a4(), - b1(), b2(1.0f), b3(), b4(), - c1(), c2(), c3(1.0f), c4(), - d1(), d2(), d3(), d4(1.0f) -{ - + a1(1.0f), a2(), a3(), a4(), + b1(), b2(1.0f), b3(), b4(), + c1(), c2(), c3(1.0f), c4(), + d1(), d2(), d3(), d4(1.0f) { + // empty } // ---------------------------------------------------------------------------------------- @@ -75,19 +73,17 @@ aiMatrix4x4t::aiMatrix4x4t (TReal _a1, TReal _a2, TReal _a3, TReal _a4, TReal _b1, TReal _b2, TReal _b3, TReal _b4, TReal _c1, TReal _c2, TReal _c3, TReal _c4, TReal _d1, TReal _d2, TReal _d3, TReal _d4) : - a1(_a1), a2(_a2), a3(_a3), a4(_a4), - b1(_b1), b2(_b2), b3(_b3), b4(_b4), - c1(_c1), c2(_c2), c3(_c3), c4(_c4), - d1(_d1), d2(_d2), d3(_d3), d4(_d4) -{ - + a1(_a1), a2(_a2), a3(_a3), a4(_a4), + b1(_b1), b2(_b2), b3(_b3), b4(_b4), + c1(_c1), c2(_c2), c3(_c3), c4(_c4), + d1(_d1), d2(_d2), d3(_d3), d4(_d4) { + // empty } // ------------------------------------------------------------------------------------------------ template template -aiMatrix4x4t::operator aiMatrix4x4t () const -{ +aiMatrix4x4t::operator aiMatrix4x4t () const { return aiMatrix4x4t(static_cast(a1),static_cast(a2),static_cast(a3),static_cast(a4), static_cast(b1),static_cast(b2),static_cast(b3),static_cast(b4), static_cast(c1),static_cast(c2),static_cast(c3),static_cast(c4), @@ -97,8 +93,8 @@ aiMatrix4x4t::operator aiMatrix4x4t () const // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t::aiMatrix4x4t (const aiMatrix3x3t& m) -{ +AI_FORCE_INLINE +aiMatrix4x4t::aiMatrix4x4t (const aiMatrix3x3t& m) { a1 = m.a1; a2 = m.a2; a3 = m.a3; a4 = static_cast(0.0); b1 = m.b1; b2 = m.b2; b3 = m.b3; b4 = static_cast(0.0); c1 = m.c1; c2 = m.c2; c3 = m.c3; c4 = static_cast(0.0); @@ -107,8 +103,8 @@ inline aiMatrix4x4t::aiMatrix4x4t (const aiMatrix3x3t& m) // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t::aiMatrix4x4t (const aiVector3t& scaling, const aiQuaterniont& rotation, const aiVector3t& position) -{ +AI_FORCE_INLINE +aiMatrix4x4t::aiMatrix4x4t (const aiVector3t& scaling, const aiQuaterniont& rotation, const aiVector3t& position) { // build a 3x3 rotation matrix aiMatrix3x3t m = rotation.GetMatrix(); @@ -135,8 +131,8 @@ inline aiMatrix4x4t::aiMatrix4x4t (const aiVector3t& scaling, cons // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::operator *= (const aiMatrix4x4t& m) -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::operator *= (const aiMatrix4x4t& m) { *this = aiMatrix4x4t( m.a1 * a1 + m.b1 * a2 + m.c1 * a3 + m.d1 * a4, m.a2 * a1 + m.b2 * a2 + m.c2 * a3 + m.d2 * a4, @@ -159,8 +155,7 @@ inline aiMatrix4x4t& aiMatrix4x4t::operator *= (const aiMatrix4x4t // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t aiMatrix4x4t::operator* (const TReal& aFloat) const -{ +AI_FORCE_INLINE aiMatrix4x4t aiMatrix4x4t::operator* (const TReal& aFloat) const { aiMatrix4x4t temp( a1 * aFloat, a2 * aFloat, @@ -183,8 +178,8 @@ inline aiMatrix4x4t aiMatrix4x4t::operator* (const TReal& aFloat) // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t aiMatrix4x4t::operator+ (const aiMatrix4x4t& m) const -{ +AI_FORCE_INLINE +aiMatrix4x4t aiMatrix4x4t::operator+ (const aiMatrix4x4t& m) const { aiMatrix4x4t temp( m.a1 + a1, m.a2 + a2, @@ -207,18 +202,16 @@ inline aiMatrix4x4t aiMatrix4x4t::operator+ (const aiMatrix4x4t -inline aiMatrix4x4t aiMatrix4x4t::operator* (const aiMatrix4x4t& m) const -{ +AI_FORCE_INLINE +aiMatrix4x4t aiMatrix4x4t::operator* (const aiMatrix4x4t& m) const { aiMatrix4x4t temp( *this); temp *= m; return temp; } - // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::Transpose() -{ +AI_FORCE_INLINE aiMatrix4x4t& aiMatrix4x4t::Transpose() { // (TReal&) don't remove, GCC complains cause of packed fields std::swap( (TReal&)b1, (TReal&)a2); std::swap( (TReal&)c1, (TReal&)a3); @@ -229,11 +222,10 @@ inline aiMatrix4x4t& aiMatrix4x4t::Transpose() return *this; } - // ---------------------------------------------------------------------------------------- template -inline TReal aiMatrix4x4t::Determinant() const -{ +AI_FORCE_INLINE +TReal aiMatrix4x4t::Determinant() const { return a1*b2*c3*d4 - a1*b2*c4*d3 + a1*b3*c4*d2 - a1*b3*c2*d4 + a1*b4*c2*d3 - a1*b4*c3*d2 - a2*b3*c4*d1 + a2*b3*c1*d4 - a2*b4*c1*d3 + a2*b4*c3*d1 - a2*b1*c3*d4 + a2*b1*c4*d3 @@ -244,8 +236,8 @@ inline TReal aiMatrix4x4t::Determinant() const // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::Inverse() -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::Inverse() { // Compute the reciprocal determinant const TReal det = Determinant(); if(det == static_cast(0.0)) @@ -289,9 +281,10 @@ inline aiMatrix4x4t& aiMatrix4x4t::Inverse() // ---------------------------------------------------------------------------------------- template -inline TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) { +AI_FORCE_INLINE +TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) { if (p_iIndex > 3) { - return NULL; + return nullptr; } switch ( p_iIndex ) { case 0: @@ -310,9 +303,10 @@ inline TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) { // ---------------------------------------------------------------------------------------- template -inline const TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) const { +AI_FORCE_INLINE +const TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) const { if (p_iIndex > 3) { - return NULL; + return nullptr; } switch ( p_iIndex ) { @@ -332,8 +326,8 @@ inline const TReal* aiMatrix4x4t::operator[](unsigned int p_iIndex) const // ---------------------------------------------------------------------------------------- template -inline bool aiMatrix4x4t::operator== (const aiMatrix4x4t& m) const -{ +AI_FORCE_INLINE +bool aiMatrix4x4t::operator== (const aiMatrix4x4t& m) const { return (a1 == m.a1 && a2 == m.a2 && a3 == m.a3 && a4 == m.a4 && b1 == m.b1 && b2 == m.b2 && b3 == m.b3 && b4 == m.b4 && c1 == m.c1 && c2 == m.c2 && c3 == m.c3 && c4 == m.c4 && @@ -342,14 +336,15 @@ inline bool aiMatrix4x4t::operator== (const aiMatrix4x4t& m) const // ---------------------------------------------------------------------------------------- template -inline bool aiMatrix4x4t::operator!= (const aiMatrix4x4t& m) const -{ +AI_FORCE_INLINE +bool aiMatrix4x4t::operator!= (const aiMatrix4x4t& m) const { return !(*this == m); } // --------------------------------------------------------------------------- template -inline bool aiMatrix4x4t::Equal(const aiMatrix4x4t& m, TReal epsilon) const { +AI_FORCE_INLINE +bool aiMatrix4x4t::Equal(const aiMatrix4x4t& m, TReal epsilon) const { return std::abs(a1 - m.a1) <= epsilon && std::abs(a2 - m.a2) <= epsilon && @@ -401,13 +396,10 @@ inline bool aiMatrix4x4t::Equal(const aiMatrix4x4t& m, TReal epsil \ do {} while(false) - - - template -inline void aiMatrix4x4t::Decompose (aiVector3t& pScaling, aiQuaterniont& pRotation, - aiVector3t& pPosition) const -{ +AI_FORCE_INLINE +void aiMatrix4x4t::Decompose (aiVector3t& pScaling, aiQuaterniont& pRotation, + aiVector3t& pPosition) const { ASSIMP_MATRIX4_4_DECOMPOSE_PART; // build a 3x3 rotation matrix @@ -420,8 +412,8 @@ inline void aiMatrix4x4t::Decompose (aiVector3t& pScaling, aiQuate } template -inline void aiMatrix4x4t::Decompose(aiVector3t& pScaling, aiVector3t& pRotation, aiVector3t& pPosition) const -{ +AI_FORCE_INLINE +void aiMatrix4x4t::Decompose(aiVector3t& pScaling, aiVector3t& pRotation, aiVector3t& pPosition) const { ASSIMP_MATRIX4_4_DECOMPOSE_PART; /* @@ -442,7 +434,7 @@ inline void aiMatrix4x4t::Decompose(aiVector3t& pScaling, aiVector */ // Use a small epsilon to solve floating-point inaccuracies - const TReal epsilon = 10e-3f; + const TReal epsilon = Assimp::Math::getEpsilon(); pRotation.y = std::asin(-vCols[0].z);// D. Angle around oY. @@ -475,10 +467,10 @@ inline void aiMatrix4x4t::Decompose(aiVector3t& pScaling, aiVector #undef ASSIMP_MATRIX4_4_DECOMPOSE_PART template -inline void aiMatrix4x4t::Decompose(aiVector3t& pScaling, aiVector3t& pRotationAxis, TReal& pRotationAngle, - aiVector3t& pPosition) const -{ -aiQuaterniont pRotation; +AI_FORCE_INLINE +void aiMatrix4x4t::Decompose(aiVector3t& pScaling, aiVector3t& pRotationAxis, TReal& pRotationAngle, + aiVector3t& pPosition) const { + aiQuaterniont pRotation; Decompose(pScaling, pRotation, pPosition); pRotation.Normalize(); @@ -500,9 +492,9 @@ aiQuaterniont pRotation; // ---------------------------------------------------------------------------------------- template -inline void aiMatrix4x4t::DecomposeNoScaling (aiQuaterniont& rotation, - aiVector3t& position) const -{ +AI_FORCE_INLINE +void aiMatrix4x4t::DecomposeNoScaling (aiQuaterniont& rotation, + aiVector3t& position) const { const aiMatrix4x4t& _this = *this; // extract translation @@ -516,15 +508,15 @@ inline void aiMatrix4x4t::DecomposeNoScaling (aiQuaterniont& rotat // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::FromEulerAnglesXYZ(const aiVector3t& blubb) -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::FromEulerAnglesXYZ(const aiVector3t& blubb) { return FromEulerAnglesXYZ(blubb.x,blubb.y,blubb.z); } // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::FromEulerAnglesXYZ(TReal x, TReal y, TReal z) -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::FromEulerAnglesXYZ(TReal x, TReal y, TReal z) { aiMatrix4x4t& _this = *this; TReal cx = std::cos(x); @@ -552,8 +544,8 @@ inline aiMatrix4x4t& aiMatrix4x4t::FromEulerAnglesXYZ(TReal x, TRe // ---------------------------------------------------------------------------------------- template -inline bool aiMatrix4x4t::IsIdentity() const -{ +AI_FORCE_INLINE +bool aiMatrix4x4t::IsIdentity() const { // Use a small epsilon to solve floating-point inaccuracies const static TReal epsilon = 10e-3f; @@ -577,8 +569,8 @@ inline bool aiMatrix4x4t::IsIdentity() const // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::RotationX(TReal a, aiMatrix4x4t& out) -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::RotationX(TReal a, aiMatrix4x4t& out) { /* | 1 0 0 0 | M = | 0 cos(A) -sin(A) 0 | @@ -592,8 +584,8 @@ inline aiMatrix4x4t& aiMatrix4x4t::RotationX(TReal a, aiMatrix4x4t // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::RotationY(TReal a, aiMatrix4x4t& out) -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::RotationY(TReal a, aiMatrix4x4t& out) { /* | cos(A) 0 sin(A) 0 | M = | 0 1 0 0 | @@ -608,8 +600,8 @@ inline aiMatrix4x4t& aiMatrix4x4t::RotationY(TReal a, aiMatrix4x4t // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::RotationZ(TReal a, aiMatrix4x4t& out) -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::RotationZ(TReal a, aiMatrix4x4t& out) { /* | cos(A) -sin(A) 0 0 | M = | sin(A) cos(A) 0 0 | @@ -624,26 +616,25 @@ inline aiMatrix4x4t& aiMatrix4x4t::RotationZ(TReal a, aiMatrix4x4t // ---------------------------------------------------------------------------------------- // Returns a rotation matrix for a rotation around an arbitrary axis. template -inline aiMatrix4x4t& aiMatrix4x4t::Rotation( TReal a, const aiVector3t& axis, aiMatrix4x4t& out) -{ - TReal c = std::cos( a), s = std::sin( a), t = 1 - c; - TReal x = axis.x, y = axis.y, z = axis.z; +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::Rotation( TReal a, const aiVector3t& axis, aiMatrix4x4t& out) { + TReal c = std::cos( a), s = std::sin( a), t = 1 - c; + TReal x = axis.x, y = axis.y, z = axis.z; - // Many thanks to MathWorld and Wikipedia - out.a1 = t*x*x + c; out.a2 = t*x*y - s*z; out.a3 = t*x*z + s*y; - out.b1 = t*x*y + s*z; out.b2 = t*y*y + c; out.b3 = t*y*z - s*x; - out.c1 = t*x*z - s*y; out.c2 = t*y*z + s*x; out.c3 = t*z*z + c; - out.a4 = out.b4 = out.c4 = static_cast(0.0); - out.d1 = out.d2 = out.d3 = static_cast(0.0); - out.d4 = static_cast(1.0); + // Many thanks to MathWorld and Wikipedia + out.a1 = t*x*x + c; out.a2 = t*x*y - s*z; out.a3 = t*x*z + s*y; + out.b1 = t*x*y + s*z; out.b2 = t*y*y + c; out.b3 = t*y*z - s*x; + out.c1 = t*x*z - s*y; out.c2 = t*y*z + s*x; out.c3 = t*z*z + c; + out.a4 = out.b4 = out.c4 = static_cast(0.0); + out.d1 = out.d2 = out.d3 = static_cast(0.0); + out.d4 = static_cast(1.0); - return out; + return out; } // ---------------------------------------------------------------------------------------- template -inline aiMatrix4x4t& aiMatrix4x4t::Translation( const aiVector3t& v, aiMatrix4x4t& out) -{ +AI_FORCE_INLINE aiMatrix4x4t& aiMatrix4x4t::Translation( const aiVector3t& v, aiMatrix4x4t& out) { out = aiMatrix4x4t(); out.a4 = v.x; out.b4 = v.y; @@ -653,8 +644,8 @@ inline aiMatrix4x4t& aiMatrix4x4t::Translation( const aiVector3t -inline aiMatrix4x4t& aiMatrix4x4t::Scaling( const aiVector3t& v, aiMatrix4x4t& out) -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::Scaling( const aiVector3t& v, aiMatrix4x4t& out) { out = aiMatrix4x4t(); out.a1 = v.x; out.b2 = v.y; @@ -673,9 +664,9 @@ inline aiMatrix4x4t& aiMatrix4x4t::Scaling( const aiVector3t -inline aiMatrix4x4t& aiMatrix4x4t::FromToMatrix(const aiVector3t& from, - const aiVector3t& to, aiMatrix4x4t& mtx) -{ +AI_FORCE_INLINE +aiMatrix4x4t& aiMatrix4x4t::FromToMatrix(const aiVector3t& from, + const aiVector3t& to, aiMatrix4x4t& mtx) { aiMatrix3x3t m3; aiMatrix3x3t::FromToMatrix(from,to,m3); mtx = aiMatrix4x4t(m3); diff --git a/include/assimp/mesh.h b/include/assimp/mesh.h index f47d5fd00..eb30ad5df 100644 --- a/include/assimp/mesh.h +++ b/include/assimp/mesh.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -48,7 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_MESH_H_INC #define AI_MESH_H_INC -#include "types.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include +#include #ifdef __cplusplus extern "C" { @@ -402,7 +407,7 @@ enum aiPrimitiveType // --------------------------------------------------------------------------- -/** @brief NOT CURRENTLY IN USE. An AnimMesh is an attachment to an #aiMesh stores per-vertex +/** @brief An AnimMesh is an attachment to an #aiMesh stores per-vertex * animations for a particular frame. * * You may think of an #aiAnimMesh as a `patch` for the host mesh, which @@ -414,6 +419,9 @@ enum aiPrimitiveType */ struct aiAnimMesh { + /**Anim Mesh name */ + C_STRUCT aiString mName; + /** Replacement for aiMesh::mVertices. If this array is non-NULL, * it *must* contain mNumVertices entries. The corresponding * array in the host mesh must be non-NULL as well - animation @@ -466,10 +474,10 @@ struct aiAnimMesh { // fixme consider moving this to the ctor initializer list as well for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++){ - mTextureCoords[a] = NULL; + mTextureCoords[a] = nullptr; } for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; a++) { - mColors[a] = NULL; + mColors[a] = nullptr; } } @@ -490,34 +498,34 @@ struct aiAnimMesh /** Check whether the anim mesh overrides the vertex positions * of its host mesh*/ bool HasPositions() const { - return mVertices != NULL; + return mVertices != nullptr; } /** Check whether the anim mesh overrides the vertex normals * of its host mesh*/ bool HasNormals() const { - return mNormals != NULL; + return mNormals != nullptr; } /** Check whether the anim mesh overrides the vertex tangents * and bitangents of its host mesh. As for aiMesh, * tangents and bitangents always go together. */ bool HasTangentsAndBitangents() const { - return mTangents != NULL; + return mTangents != nullptr; } /** Check whether the anim mesh overrides a particular * set of vertex colors on his host mesh. * @param pIndex 0= AI_MAX_NUMBER_OF_COLOR_SETS ? false : mColors[pIndex] != NULL; + return pIndex >= AI_MAX_NUMBER_OF_COLOR_SETS ? false : mColors[pIndex] != nullptr; } /** Check whether the anim mesh overrides a particular * set of texture coordinates on his host mesh. * @param pIndex 0= AI_MAX_NUMBER_OF_TEXTURECOORDS ? false : mTextureCoords[pIndex] != NULL; + return pIndex >= AI_MAX_NUMBER_OF_TEXTURECOORDS ? false : mTextureCoords[pIndex] != nullptr; } #endif @@ -711,6 +719,11 @@ struct aiMesh * Method of morphing when animeshes are specified. */ unsigned int mMethod; + + /** + * + */ + C_STRUCT aiAABB mAABB; #ifdef __cplusplus @@ -732,7 +745,8 @@ struct aiMesh , mMaterialIndex( 0 ) , mNumAnimMeshes( 0 ) , mAnimMeshes(nullptr) - , mMethod( 0 ) { + , mMethod( 0 ) + , mAABB() { for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) { mNumUVComponents[a] = 0; mTextureCoords[a] = nullptr; diff --git a/include/assimp/metadata.h b/include/assimp/metadata.h index 498e2f6d1..849d90f48 100644 --- a/include/assimp/metadata.h +++ b/include/assimp/metadata.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,6 +48,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_METADATA_H_INC #define AI_METADATA_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #if defined(_MSC_VER) && (_MSC_VER <= 1500) # include "Compiler/pstdint.h" #else diff --git a/include/assimp/pbrmaterial.h b/include/assimp/pbrmaterial.h index 723957300..892a6347f 100644 --- a/include/assimp/pbrmaterial.h +++ b/include/assimp/pbrmaterial.h @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -44,9 +42,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** @file pbrmaterial.h * @brief Defines the material system of the library */ +#pragma once #ifndef AI_PBRMATERIAL_H_INC #define AI_PBRMATERIAL_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_BASE_COLOR_FACTOR "$mat.gltf.pbrMetallicRoughness.baseColorFactor", 0, 0 #define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR "$mat.gltf.pbrMetallicRoughness.metallicFactor", 0, 0 #define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR "$mat.gltf.pbrMetallicRoughness.roughnessFactor", 0, 0 diff --git a/include/assimp/postprocess.h b/include/assimp/postprocess.h index a0ae0a1bc..77d387c7e 100644 --- a/include/assimp/postprocess.h +++ b/include/assimp/postprocess.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -47,7 +47,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_POSTPROCESS_H_INC #define AI_POSTPROCESS_H_INC -#include "types.h" +#include + +#ifdef __GNUC__ +# pragma GCC system_header +#endif #ifdef __cplusplus extern "C" { @@ -438,7 +442,7 @@ enum aiPostProcessSteps aiProcess_FindInstances = 0x100000, // ------------------------------------------------------------------------- - /**
    A postprocessing step to reduce the number of meshes. + /**
    A post-processing step to reduce the number of meshes. * * This will, in fact, reduce the number of draw calls. * @@ -450,7 +454,7 @@ enum aiPostProcessSteps // ------------------------------------------------------------------------- - /**
    A postprocessing step to optimize the scene hierarchy. + /**
    A post-processing step to optimize the scene hierarchy. * * Nodes without animations, bones, lights or cameras assigned are * collapsed and joined. @@ -514,7 +518,7 @@ enum aiPostProcessSteps // ------------------------------------------------------------------------- /**
    This step splits meshes with many bones into sub-meshes so that each - * su-bmesh has fewer or as many bones as a given limit. + * sub-mesh has fewer or as many bones as a given limit. */ aiProcess_SplitByBoneCount = 0x2000000, @@ -541,7 +545,7 @@ enum aiPostProcessSteps * global scaling from your importer settings like in FBX. Use the flag * AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY from the global property table to configure this. * - * Use #AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY to setup the global scaing factor. + * Use #AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY to setup the global scaling factor. */ aiProcess_GlobalScale = 0x8000000, @@ -574,6 +578,11 @@ enum aiPostProcessSteps * This process gives sense back to aiProcess_JoinIdenticalVertices */ aiProcess_DropNormals = 0x40000000, + + // ------------------------------------------------------------------------- + /** + */ + aiProcess_GenBoundingBoxes = 0x80000000 }; diff --git a/include/assimp/qnan.h b/include/assimp/qnan.h index 251688989..06780da5b 100644 --- a/include/assimp/qnan.h +++ b/include/assimp/qnan.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -50,19 +50,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * but last time I checked compiler coverage was so bad that I decided * to reinvent the wheel. */ - +#pragma once #ifndef AI_QNAN_H_INCLUDED #define AI_QNAN_H_INCLUDED +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #include + #include #include // --------------------------------------------------------------------------- /** Data structure to represent the bit pattern of a 32 Bit * IEEE 754 floating-point number. */ -union _IEEESingle -{ +union _IEEESingle { float Float; struct { @@ -75,8 +79,7 @@ union _IEEESingle // --------------------------------------------------------------------------- /** Data structure to represent the bit pattern of a 64 Bit * IEEE 754 floating-point number. */ -union _IEEEDouble -{ +union _IEEEDouble { double Double; struct { @@ -89,8 +92,7 @@ union _IEEEDouble // --------------------------------------------------------------------------- /** Check whether a given float is qNaN. * @param in Input value */ -AI_FORCE_INLINE bool is_qnan(float in) -{ +AI_FORCE_INLINE bool is_qnan(float in) { // the straightforward solution does not work: // return (in != in); // compiler generates code like this @@ -107,8 +109,7 @@ AI_FORCE_INLINE bool is_qnan(float in) // --------------------------------------------------------------------------- /** Check whether a given double is qNaN. * @param in Input value */ -AI_FORCE_INLINE bool is_qnan(double in) -{ +AI_FORCE_INLINE bool is_qnan(double in) { // the straightforward solution does not work: // return (in != in); // compiler generates code like this @@ -127,8 +128,7 @@ AI_FORCE_INLINE bool is_qnan(double in) * * Denorms return false, they're treated like normal values. * @param in Input value */ -AI_FORCE_INLINE bool is_special_float(float in) -{ +AI_FORCE_INLINE bool is_special_float(float in) { _IEEESingle temp; memcpy(&temp, &in, sizeof(float)); return (temp.IEEE.Exp == (1u << 8)-1); @@ -139,8 +139,7 @@ AI_FORCE_INLINE bool is_special_float(float in) * * Denorms return false, they're treated like normal values. * @param in Input value */ -AI_FORCE_INLINE bool is_special_float(double in) -{ +AI_FORCE_INLINE bool is_special_float(double in) { _IEEESingle temp; memcpy(&temp, &in, sizeof(float)); return (temp.IEEE.Exp == (1u << 11)-1); @@ -150,15 +149,13 @@ AI_FORCE_INLINE bool is_special_float(double in) /** Check whether a float is NOT qNaN. * @param in Input value */ template -AI_FORCE_INLINE bool is_not_qnan(TReal in) -{ +AI_FORCE_INLINE bool is_not_qnan(TReal in) { return !is_qnan(in); } // --------------------------------------------------------------------------- /** @brief Get a fresh qnan. */ -AI_FORCE_INLINE ai_real get_qnan() -{ +AI_FORCE_INLINE ai_real get_qnan() { return std::numeric_limits::quiet_NaN(); } diff --git a/include/assimp/quaternion.h b/include/assimp/quaternion.h index e2479f2ed..ae45959b4 100644 --- a/include/assimp/quaternion.h +++ b/include/assimp/quaternion.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -49,7 +49,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifdef __cplusplus -#include "defs.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include template class aiVector3t; template class aiMatrix3x3t; diff --git a/include/assimp/quaternion.inl b/include/assimp/quaternion.inl index 0a2c92937..3ce514d1b 100644 --- a/include/assimp/quaternion.inl +++ b/include/assimp/quaternion.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,8 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_QUATERNION_INL_INC #define AI_QUATERNION_INL_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifdef __cplusplus -#include "quaternion.h" +#include #include diff --git a/include/assimp/scene.h b/include/assimp/scene.h index 867e87de0..e69c81803 100644 --- a/include/assimp/scene.h +++ b/include/assimp/scene.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,16 +48,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_SCENE_H_INC #define AI_SCENE_H_INC -#include "types.h" -#include "texture.h" -#include "mesh.h" -#include "light.h" -#include "camera.h" -#include "material.h" -#include "anim.h" -#include "metadata.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include +#include +#include +#include +#include +#include +#include +#include #ifdef __cplusplus +# include extern "C" { #endif @@ -389,6 +394,14 @@ struct aiScene //! Returns an embedded texture const aiTexture* GetEmbeddedTexture(const char* filename) const { + // lookup using texture ID (if referenced like: "*1", "*2", etc.) + if ('*' == *filename) { + int index = std::atoi(filename + 1); + if (0 > index || mNumTextures <= static_cast(index)) + return nullptr; + return mTextures[index]; + } + // lookup using filename const char* shortFilename = GetShortFilename(filename); for (unsigned int i = 0; i < mNumTextures; i++) { const char* shortTextureFilename = GetShortFilename(mTextures[i]->mFilename.C_Str()); diff --git a/include/assimp/texture.h b/include/assimp/texture.h index 5be7229ec..0867659f4 100644 --- a/include/assimp/texture.h +++ b/include/assimp/texture.h @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -53,13 +51,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_TEXTURE_H_INC #define AI_TEXTURE_H_INC -#include "types.h" +#ifdef __GNUC__ +# pragma GCC system_header +#endif + +#include #ifdef __cplusplus extern "C" { #endif - // -------------------------------------------------------------------------------- /** \def AI_EMBEDDED_TEXNAME_PREFIX @@ -79,7 +80,6 @@ extern "C" { # define AI_MAKE_EMBEDDED_TEXNAME(_n_) AI_EMBEDDED_TEXNAME_PREFIX # _n_ #endif - #include "./Compiler/pushpack1.h" // -------------------------------------------------------------------------------- @@ -87,8 +87,7 @@ extern "C" { * * Used by aiTexture. */ -struct aiTexel -{ +struct aiTexel { unsigned char b,g,r,a; #ifdef __cplusplus @@ -117,6 +116,8 @@ struct aiTexel #include "./Compiler/poppack1.h" +#define HINTMAXTEXTURELEN 9 + // -------------------------------------------------------------------------------- /** Helper structure to describe an embedded texture * @@ -166,7 +167,7 @@ struct aiTexture { * E.g. 'dds\\0', 'pcx\\0', 'jpg\\0'. All characters are lower-case. * The fourth character will always be '\\0'. */ - char achFormatHint[9];// 8 for string + 1 for terminator. + char achFormatHint[ HINTMAXTEXTURELEN ];// 8 for string + 1 for terminator. /** Data of the texture. * diff --git a/include/assimp/types.h b/include/assimp/types.h index 660479f8a..e32cae331 100644 --- a/include/assimp/types.h +++ b/include/assimp/types.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,22 +48,30 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_TYPES_H_INC #define AI_TYPES_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + // Some runtime headers #include #include #include #include +#include // Our compile configuration -#include "defs.h" +#include // Some types moved to separate header due to size of operators -#include "vector3.h" -#include "vector2.h" -#include "color4.h" -#include "matrix3x3.h" -#include "matrix4x4.h" -#include "quaternion.h" +#include +#include +#include +#include +#include +#include + +typedef int32_t ai_int32; +typedef uint32_t ai_uint32 ; #ifdef __cplusplus #include @@ -71,7 +79,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include // for aiString::Set(const std::string&) namespace Assimp { - //! @cond never +//! @cond never namespace Intern { // -------------------------------------------------------------------- /** @brief Internal helper class to utilize our internal new/delete @@ -161,7 +169,14 @@ struct aiColor3D explicit aiColor3D (ai_real _r) : r(_r), g(_r), b(_r) {} aiColor3D (const aiColor3D& o) : r(o.r), g(o.g), b(o.b) {} - /** Component-wise comparison */ + aiColor3D &operator=(const aiColor3D &o) { + r = o.r; + g = o.g; + b = o.b; + return *this; + } + + /** Component-wise comparison */ // TODO: add epsilon? bool operator == (const aiColor3D& other) const {return r == other.r && g == other.g && b == other.b;} @@ -262,8 +277,8 @@ struct aiString } /** Copy constructor */ - aiString(const aiString& rOther) : - length(rOther.length) + aiString(const aiString& rOther) + : length(rOther.length) { // Crop the string to the maximum length length = length>=MAXLEN?MAXLEN-1:length; @@ -273,7 +288,7 @@ struct aiString /** Constructor from std::string */ explicit aiString(const std::string& pString) : - length(pString.length()) + length( (ai_uint32) pString.length()) { length = length>=MAXLEN?MAXLEN-1:length; memcpy( data, pString.c_str(), length); @@ -285,15 +300,15 @@ struct aiString if( pString.length() > MAXLEN - 1) { return; } - length = pString.length(); + length = (ai_uint32)pString.length(); memcpy( data, pString.c_str(), length); data[length] = 0; } /** Copy a const char* to the aiString */ void Set( const char* sz) { - const size_t len = ::strlen(sz); - if( len > MAXLEN - 1) { + const ai_int32 len = (ai_uint32) ::strlen(sz); + if( len > (ai_int32)MAXLEN - 1) { return; } length = len; @@ -339,7 +354,7 @@ struct aiString /** Append a string to the string */ void Append (const char* app) { - const size_t len = ::strlen(app); + const ai_uint32 len = (ai_uint32) ::strlen(app); if (!len) { return; } @@ -372,7 +387,7 @@ struct aiString /** Binary length of the string excluding the terminal 0. This is NOT the * logical length of strings containing UTF-8 multi-byte sequences! It's * the number of bytes from the beginning of the string to its end.*/ - size_t length; + ai_uint32 length; /** String buffer. Size limit is MAXLEN */ char data[MAXLEN]; diff --git a/include/assimp/vector2.h b/include/assimp/vector2.h index 85ca6d0a4..c8b1ebbbc 100644 --- a/include/assimp/vector2.h +++ b/include/assimp/vector2.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -47,6 +47,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_VECTOR2D_H_INC #define AI_VECTOR2D_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifdef __cplusplus # include #else diff --git a/include/assimp/vector2.inl b/include/assimp/vector2.inl index 46c6c9d27..4bbf432ff 100644 --- a/include/assimp/vector2.inl +++ b/include/assimp/vector2.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,8 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_VECTOR2D_INL_INC #define AI_VECTOR2D_INL_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifdef __cplusplus -#include "vector2.h" +#include #include diff --git a/include/assimp/vector3.h b/include/assimp/vector3.h index 33ae7d22f..fffeb12ad 100644 --- a/include/assimp/vector3.h +++ b/include/assimp/vector3.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -47,13 +47,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_VECTOR3D_H_INC #define AI_VECTOR3D_H_INC +#ifdef __GNUC__ +# pragma GCC system_header +#endif + #ifdef __cplusplus # include #else # include #endif -#include "defs.h" +#include #ifdef __cplusplus @@ -63,16 +67,13 @@ template class aiMatrix4x4t; // --------------------------------------------------------------------------- /** Represents a three-dimensional vector. */ template -class aiVector3t -{ +class aiVector3t { public: aiVector3t() AI_NO_EXCEPT : x(), y(), z() {} aiVector3t(TReal _x, TReal _y, TReal _z) : x(_x), y(_y), z(_z) {} explicit aiVector3t (TReal _xyz ) : x(_xyz), y(_xyz), z(_xyz) {} aiVector3t( const aiVector3t& o ) = default; -public: - // combined operators const aiVector3t& operator += (const aiVector3t& o); const aiVector3t& operator -= (const aiVector3t& o); @@ -97,7 +98,6 @@ public: template operator aiVector3t () const; -public: /** @brief Set the components of a vector * @param pX X component * @param pY Y component diff --git a/include/assimp/vector3.inl b/include/assimp/vector3.inl index ebe2f82e9..6682d3b32 100644 --- a/include/assimp/vector3.inl +++ b/include/assimp/vector3.inl @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_VECTOR3D_INL_INC #ifdef __cplusplus -#include "vector3.h" +#include #include diff --git a/include/assimp/version.h b/include/assimp/version.h index 470166edf..2fdd37a43 100644 --- a/include/assimp/version.h +++ b/include/assimp/version.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -49,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_VERSION_H_INC #define AI_VERSION_H_INC -#include "defs.h" +#include #ifdef __cplusplus extern "C" { diff --git a/packaging/windows-innosetup/script.iss b/packaging/windows-innosetup/script.iss deleted file mode 100644 index 695740679..000000000 --- a/packaging/windows-innosetup/script.iss +++ /dev/null @@ -1,103 +0,0 @@ -; Setup script for use with Inno Setup. - -[Setup] -AppName=Open Asset Import Library - SDK -AppVerName=Open Asset Import Library - SDK (v4.1.0) -DefaultDirName={pf}\Assimp -DefaultGroupName=Assimp -UninstallDisplayIcon={app}\bin\x86\assimp.exe -OutputDir=out -AppCopyright=Assimp Development Team -SetupIconFile=..\..\tools\shared\assimp_tools_icon.ico -WizardImageFile=compiler:WizModernImage-IS.BMP -WizardSmallImageFile=compiler:WizModernSmallImage-IS.BMP -LicenseFile=License.rtf -OutputBaseFileName=assimp-sdk-4.1.0-setup -VersionInfoVersion=4.1.0.0 -VersionInfoTextVersion=4.1.0 -VersionInfoCompany=Assimp Development Team -ArchitecturesInstallIn64BitMode=x64 - -[Types] -Name: "full"; Description: "Full installation" -Name: "compact"; Description: "Compact installation, no test models or language bindings" -Name: "custom"; Description: "Custom installation"; Flags: iscustom - -[Components] -Name: "main"; Description: "Main Files (32 and 64 Bit)"; Types: full compact custom; Flags: fixed -Name: "tools"; Description: "Asset Viewer & Command Line Tools (32 and 64 Bit)"; Types: full compact -Name: "help"; Description: "Help Files"; Types: full compact -Name: "samples"; Description: "Samples"; Types: full -Name: "test"; Description: "Test Models (BSD-licensed)"; Types: full -Name: "test_nonbsd"; Description: "Test Models (other (free) licenses)"; Types: full -;Name: "pyassimp"; Description: "Python Bindings"; Types: full -;Name: "dassimp"; Description: "D Bindings"; Types: full -;Name: "assimp_net"; Description: "C#/.NET Bindings"; Types: full - -[Run] -;Filename: "{app}\stub\vc_redist.x86.exe"; Parameters: "/qb"; StatusMsg: "Installing VS2017 redistributable package (32 Bit)"; Check: not IsWin64 -Filename: "{app}\stub\vc_redist.x64.exe"; Parameters: "/qb"; StatusMsg: "Installing VS2017 redistributable package (64 Bit)"; Check: IsWin64 - -[Files] -Source: "readme_installer.txt"; DestDir: "{app}"; Flags: isreadme - -; Installer stub -;Source: "vc_redist.x86.exe"; DestDir: "{app}\stub\"; Check: not IsWin64 -Source: "vc_redist.x64.exe"; DestDir: "{app}\stub\"; Check: IsWin64 - -; Common stuff -Source: "..\..\CREDITS"; DestDir: "{app}" -Source: "..\..\LICENSE"; DestDir: "{app}" -Source: "..\..\README"; DestDir: "{app}" -Source: "WEB"; DestDir: "{app}" - -Source: "..\..\scripts\*"; DestDir: "{app}\scripts"; Flags: recursesubdirs - -; x86 binaries -;Source: "..\..\bin\release\x86\assimp-vc140-mt.dll"; DestDir: "{app}\bin\x86" -;Source: "..\..\bin\release\x86\assimp_viewer.exe"; DestDir: "{app}\bin\x86"; Components: tools -;Source: "C:\Windows\SysWOW64\D3DCompiler_42.dll"; DestDir: "{app}\bin\x86"; Components: tools -;Source: "C:\Windows\SysWOW64\D3DX9_42.dll"; DestDir: "{app}\bin\x86"; Components: tools -;Source: "..\..\bin\release\x86\assimp.exe"; DestDir: "{app}\bin\x86"; Components: tools - -; x64 binaries -Source: "..\..\bin\release\assimp-vc140-mt.dll"; DestDir: "{app}\bin\x64" -Source: "..\..\bin\release\assimp_viewer.exe"; DestDir: "{app}\bin\x64"; Components: tools -Source: "C:\Windows\SysWOW64\D3DCompiler_42.dll"; DestDir: "{app}\bin\x64"; DestName: "D3DCompiler_42.dll"; Components: tools -Source: "C:\Windows\SysWOW64\D3DX9_42.dll"; DestDir: "{app}\bin\x64"; DestName: "D3DX9_42.dll"; Components: tools -Source: "..\..\bin\release\assimp.exe"; DestDir: "{app}\bin\x64"; Components: tools - -; Documentation -;Source: "..\..\doc\AssimpDoc_Html\AssimpDoc.chm"; DestDir: "{app}\doc"; Components: help -;Source: "..\..\doc\AssimpCmdDoc_Html\AssimpCmdDoc.chm"; DestDir: "{app}\doc"; Components: help -;Source: "..\..\doc\datastructure.xml"; DestDir: "{app}\doc"; Components: help - -; Import libraries -;Source: "..\..\lib\release\x86\assimp.lib"; DestDir: "{app}\lib\x86" -Source: "..\..\lib\release\assimp-vc140-mt.lib"; DestDir: "{app}\lib\x64" - -; Samples -Source: "..\..\samples\*"; DestDir: "{app}\samples"; Flags: recursesubdirs; Components: samples - -; Include files -Source: "..\..\include\*"; DestDir: "{app}\include"; Flags: recursesubdirs - -; dAssimp -;Source: "..\..\port\dAssimp\*"; DestDir: "{app}\port\D"; Flags: recursesubdirs; Components: dassimp - -; Assimp.NET -;Source: "..\..\port\Assimp.NET\*"; DestDir: "{app}\port\C#"; Flags: recursesubdirs; Components: assimp_net - -; PyAssimp -;Source: "..\..\port\PyAssimp\*"; DestDir: "{app}\port\Python"; Excludes: "*.pyc,*.dll"; Flags: recursesubdirs; Components: pyassimp - -; Test repository -;Source: "..\..\test\models\*"; DestDir: "{app}\test\models"; Flags: recursesubdirs; Components: test -;Source: "..\..\test\regression\*"; DestDir: "{app}\test\regression"; Flags: recursesubdirs; Components: test -;Source: "..\..\test\models-nonbsd\*"; DestDir: "{app}\test\models-nonbsd"; Flags: recursesubdirs; Components: test_nonbsd - -[Icons] -Name: "{group}\Assimp Manual"; Filename: "{app}\doc\AssimpDoc.chm" ; Components: help -Name: "{group}\Assimp Command Line Manual"; Filename: "{app}\doc\AssimpCmdDoc.chm"; Components: help -Name: "{group}\AssimpView"; Filename: "{app}\bin\x64\assimp_view.exe"; Components: tools; Check: IsWin64 -Name: "{group}\AssimpView"; Filename: "{app}\bin\x86\assimp_view.exe"; Components: tools; Check: not IsWin64 diff --git a/packaging/windows-innosetup/script_x64.iss b/packaging/windows-innosetup/script_x64.iss new file mode 100644 index 000000000..4d1b67cd0 --- /dev/null +++ b/packaging/windows-innosetup/script_x64.iss @@ -0,0 +1,74 @@ +; Setup script for use with Inno Setup. + +[Setup] +AppName=Open Asset Import Library - SDK +AppVerName=Open Asset Import Library - SDK (v5.0.0) +DefaultDirName={pf}\Assimp +DefaultGroupName=Assimp +UninstallDisplayIcon={app}\bin\x64\assimp.exe +OutputDir=out +AppCopyright=Assimp Development Team +SetupIconFile=..\..\tools\shared\assimp_tools_icon.ico +WizardImageFile=compiler:WizModernImage-IS.BMP +WizardSmallImageFile=compiler:WizModernSmallImage-IS.BMP +LicenseFile=License.rtf +OutputBaseFileName=assimp-sdk-5.0.0-setup +VersionInfoVersion=5.0.0.0 +VersionInfoTextVersion=5.0.0 +VersionInfoCompany=Assimp Development Team +ArchitecturesInstallIn64BitMode=x64 + +[Types] +Name: "full"; Description: "Full installation" +Name: "compact"; Description: "Compact installation, no test models or language bindings" +Name: "custom"; Description: "Custom installation"; Flags: iscustom + +[Components] +Name: "main"; Description: "Main Files ( 64 Bit )"; Types: full compact custom; Flags: fixed +Name: "tools"; Description: "Asset Viewer & Command Line Tools (32 and 64 Bit)"; Types: full compact +Name: "help"; Description: "Help Files"; Types: full compact +Name: "samples"; Description: "Samples"; Types: full +Name: "test"; Description: "Test Models (BSD-licensed)"; Types: full +Name: "test_nonbsd"; Description: "Test Models (other (free) licenses)"; Types: full + +[Run] +Filename: "{app}\stub\vc_redist.x64.exe"; Parameters: "/qb /passive /quiet"; StatusMsg: "Installing VS2017 redistributable package (64 Bit)"; Check: IsWin64 + +[Files] +Source: "readme_installer.txt"; DestDir: "{app}"; Flags: isreadme + +; Installer stub +Source: "vc_redist.x64.exe"; DestDir: "{app}\stub\"; Check: IsWin64 + +; Common stuff +Source: "..\..\CREDITS"; DestDir: "{app}" +Source: "..\..\LICENSE"; DestDir: "{app}" +Source: "..\..\README"; DestDir: "{app}" +Source: "WEB"; DestDir: "{app}" + +Source: "..\..\scripts\*"; DestDir: "{app}\scripts"; Flags: recursesubdirs + +; x64 binaries +Source: "..\..\bin\release\assimp-vc141-mt.dll"; DestDir: "{app}\bin\x64" +Source: "..\..\bin\release\assimp_viewer.exe"; DestDir: "{app}\bin\x64"; Components: tools +Source: "C:\Windows\SysWOW64\D3DCompiler_42.dll"; DestDir: "{app}\bin\x64"; DestName: "D3DCompiler_42.dll"; Components: tools +Source: "C:\Windows\SysWOW64\D3DX9_42.dll"; DestDir: "{app}\bin\x64"; DestName: "D3DX9_42.dll"; Components: tools +Source: "..\..\bin\release\assimp.exe"; DestDir: "{app}\bin\x64"; Components: tools + +; Import libraries +Source: "..\..\lib\release\assimp-vc141-mt.lib"; DestDir: "{app}\lib\x64" + +; Samples +Source: "..\..\samples\*"; DestDir: "{app}\samples"; Flags: recursesubdirs; Components: samples + +; Include files +Source: "..\..\include\*"; DestDir: "{app}\include"; Flags: recursesubdirs + +; CMake files +Source: "..\..\cmake-modules\*"; DestDir: "{app}\cmake-modules"; Flags: recursesubdirs + +[Icons] +; Name: "{group}\Assimp Manual"; Filename: "{app}\doc\AssimpDoc.chm" ; Components: help +; Name: "{group}\Assimp Command Line Manual"; Filename: "{app}\doc\AssimpCmdDoc.chm"; Components: help +; Name: "{group}\AssimpView"; Filename: "{app}\bin\x64\assimp_view.exe"; Components: tools; Check: IsWin64 +; Name: "{group}\AssimpView"; Filename: "{app}\bin\x86\assimp_view.exe"; Components: tools; Check: not IsWin64 diff --git a/packaging/windows-innosetup/script_x86.iss b/packaging/windows-innosetup/script_x86.iss new file mode 100644 index 000000000..d22d23b64 --- /dev/null +++ b/packaging/windows-innosetup/script_x86.iss @@ -0,0 +1,75 @@ +; Setup script for use with Inno Setup. + +[Setup] +AppName=Open Asset Import Library - SDK +AppVerName=Open Asset Import Library - SDK (v5.0.0) +DefaultDirName={pf}\Assimp +DefaultGroupName=Assimp +UninstallDisplayIcon={app}\bin\x86\assimp.exe +OutputDir=out +AppCopyright=Assimp Development Team +SetupIconFile=..\..\tools\shared\assimp_tools_icon.ico +WizardImageFile=compiler:WizModernImage-IS.BMP +WizardSmallImageFile=compiler:WizModernSmallImage-IS.BMP +LicenseFile=License.rtf +OutputBaseFileName=assimp-sdk-5.0.0-setup +VersionInfoVersion=4.1.0.0 +VersionInfoTextVersion=4.1.0 +VersionInfoCompany=Assimp Development Team +;ArchitecturesInstallIn64BitMode=x64 + +[Types] +Name: "full"; Description: "Full installation" +Name: "compact"; Description: "Compact installation, no test models or language bindings" +Name: "custom"; Description: "Custom installation"; Flags: iscustom + +[Components] +Name: "main"; Description: "Main Files (32 and 64 Bit)"; Types: full compact custom; Flags: fixed +Name: "tools"; Description: "Asset Viewer & Command Line Tools (32 and 64 Bit)"; Types: full compact +Name: "help"; Description: "Help Files"; Types: full compact +Name: "samples"; Description: "Samples"; Types: full +Name: "test"; Description: "Test Models (BSD-licensed)"; Types: full +Name: "test_nonbsd"; Description: "Test Models (other (free) licenses)"; Types: full + +[Run] +Filename: "{app}\stub\vc_redist.x86.exe"; Parameters: "/qb /passive /quiet"; StatusMsg: "Installing VS2017 redistributable package (32 Bit)"; Check: not IsWin64 + +[Files] +Source: "readme_installer.txt"; DestDir: "{app}"; Flags: isreadme + +; Installer stub +Source: "vc_redist.x86.exe"; DestDir: "{app}\stub\"; Check: not IsWin64 + +; Common stuff +Source: "..\..\CREDITS"; DestDir: "{app}" +Source: "..\..\LICENSE"; DestDir: "{app}" +Source: "..\..\README"; DestDir: "{app}" +Source: "WEB"; DestDir: "{app}" + +Source: "..\..\scripts\*"; DestDir: "{app}\scripts"; Flags: recursesubdirs + +; x86 binaries +Source: "..\..\bin\release\assimp-vc141-mt.dll"; DestDir: "{app}\bin\x86" +Source: "..\..\bin\release\assimp_viewer.exe"; DestDir: "{app}\bin\x86"; Components: tools +Source: "C:\Windows\SysWOW64\D3DCompiler_42.dll"; DestDir: "{app}\bin\x86"; Components: tools +Source: "C:\Windows\SysWOW64\D3DX9_42.dll"; DestDir: "{app}\bin\x86"; Components: tools +Source: "..\..\bin\release\assimp.exe"; DestDir: "{app}\bin\x86"; Components: tools + + +; Import libraries +Source: "..\..\lib\release\assimp-vc141-mt.lib"; DestDir: "{app}\lib\x86" + +; Samples +Source: "..\..\samples\*"; DestDir: "{app}\samples"; Flags: recursesubdirs; Components: samples + +; Include files +Source: "..\..\include\*"; DestDir: "{app}\include"; Flags: recursesubdirs + +; CMake files +Source: "..\..\cmake-modules\*"; DestDir: "{app}\cmake-modules"; Flags: recursesubdirs + +[Icons] +; Name: "{group}\Assimp Manual"; Filename: "{app}\doc\AssimpDoc.chm" ; Components: help +; Name: "{group}\Assimp Command Line Manual"; Filename: "{app}\doc\AssimpCmdDoc.chm"; Components: help +; Name: "{group}\AssimpView"; Filename: "{app}\bin\x64\assimp_view.exe"; Components: tools; Check: IsWin64 +; Name: "{group}\AssimpView"; Filename: "{app}\bin\x86\assimp_view.exe"; Components: tools; Check: not IsWin64 diff --git a/port/AndroidJNI/README.md b/port/AndroidJNI/README.md index 570ca4fb3..0b95efd04 100644 --- a/port/AndroidJNI/README.md +++ b/port/AndroidJNI/README.md @@ -1,7 +1,7 @@ Build Asset Importer Lib for Android ==================================== -This module provides a fascade for the io-stream-access to files behind the -android-asset-management within an Android native application. +This module provides a facade for the io-stream-access to files behind the android-asset-management within +an Android-native application. - It is built as a static library - It requires Android NDK with android API > 9 support. @@ -20,6 +20,8 @@ A small example how to wrap assimp for Android: #include Assimp::Importer* importer = new Assimp::Importer(); -Assimp::AndroidJNIIOSystem* ioSystem = new Assimp::AndroidJNIIOSystem(app->activity); -importer->SetIOHandler(ioSystem); +Assimp::AndroidJNIIOSystem *ioSystem = new Assimp::AndroidJNIIOSystem(app->activity); +if ( nullptr != iosSystem ) { + importer->SetIOHandler(ioSystem); +} ``` diff --git a/port/AssimpNET/Readme.md b/port/AssimpNET/Readme.md index bcbfebab1..814cab3e0 100644 --- a/port/AssimpNET/Readme.md +++ b/port/AssimpNET/Readme.md @@ -1 +1 @@ -Please check the following git-repo for the source: https://bitbucket.org/Starnick/assimpnet +Please check the following git-repo for the source: https://github.com/kebby/assimp-net diff --git a/port/PyAssimp/README.md b/port/PyAssimp/README.md new file mode 100644 index 000000000..d64d72763 --- /dev/null +++ b/port/PyAssimp/README.md @@ -0,0 +1,91 @@ +PyAssimp Readme +=============== + +A simple Python wrapper for Assimp using `ctypes` to access the library. +Requires Python >= 2.6. + +Python 3 support is mostly here, but not well tested. + +Note that pyassimp is not complete. Many ASSIMP features are missing. + +USAGE +----- + +### Complete example: 3D viewer + +`pyassimp` comes with a simple 3D viewer that shows how to load and display a 3D +model using a shader-based OpenGL pipeline. + +![Screenshot](3d_viewer_screenshot.png) + +To use it, from within `/port/PyAssimp`: + +```console +$ cd scripts +$ python ./3D-viewer +``` + +You can use this code as starting point in your applications. + +### Writing your own code + +To get started with `pyassimp`, examine the simpler `sample.py` script in `scripts/`, +which illustrates the basic usage. All Assimp data structures are wrapped using +`ctypes`. All the data+length fields in Assimp's data structures (such as +`aiMesh::mNumVertices`, `aiMesh::mVertices`) are replaced by simple python +lists, so you can call `len()` on them to get their respective size and access +members using `[]`. + +For example, to load a file named `hello.3ds` and print the first +vertex of the first mesh, you would do (proper error handling +substituted by assertions ...): + +```python + +from pyassimp import * +scene = load('hello.3ds') + +assert len(scene.meshes) +mesh = scene.meshes[0] + +assert len(mesh.vertices) +print(mesh.vertices[0]) + +# don't forget this one, or you will leak! +release(scene) + +``` + +Another example to list the 'top nodes' in a +scene: + +```python + +from pyassimp import * +scene = load('hello.3ds') + +for c in scene.rootnode.children: + print(str(c)) + +release(scene) + +``` + +INSTALL +------- + +Install `pyassimp` by running: + +```console +$ python setup.py install +``` + +PyAssimp requires a assimp dynamic library (`DLL` on windows, +`.so` on linux, `.dynlib` on macOS) in order to work. The default search directories are: + - the current directory + - on linux additionally: `/usr/lib`, `/usr/local/lib`, + `/usr/lib/x86_64-linux-gnu` + +To build that library, refer to the Assimp master `INSTALL` +instructions. To look in more places, edit `./pyassimp/helper.py`. +There's an `additional_dirs` list waiting for your entries. diff --git a/port/PyAssimp/pyassimp/core.py b/port/PyAssimp/pyassimp/core.py index 64dd351a7..c346e2652 100644 --- a/port/PyAssimp/pyassimp/core.py +++ b/port/PyAssimp/pyassimp/core.py @@ -1,550 +1,546 @@ -""" -PyAssimp - -This is the main-module of PyAssimp. -""" - -import sys -if sys.version_info < (2,6): - raise 'pyassimp: need python 2.6 or newer' - -# xrange was renamed range in Python 3 and the original range from Python 2 was removed. -# To keep compatibility with both Python 2 and 3, xrange is set to range for version 3.0 and up. -if sys.version_info >= (3,0): - xrange = range - -import ctypes -import os - -try: import numpy -except: numpy = None - -import logging -logger = logging.getLogger("pyassimp") -# attach default null handler to logger so it doesn't complain -# even if you don't attach another handler to logger -logger.addHandler(logging.NullHandler()) - -from . import structs -from . import helper -from . import postprocess -from .errors import AssimpError -from .formats import available_formats - -class AssimpLib(object): - """ - Assimp-Singleton - """ - load, load_mem, export, export_blob, release, dll = helper.search_library() -_assimp_lib = AssimpLib() - -def make_tuple(ai_obj, type = None): - res = None - - #notes: - # ai_obj._fields_ = [ ("attr", c_type), ... ] - # getattr(ai_obj, e[0]).__class__ == float - - if isinstance(ai_obj, structs.Matrix4x4): - if numpy: - res = numpy.array([getattr(ai_obj, e[0]) for e in ai_obj._fields_]).reshape((4,4)) - #import pdb;pdb.set_trace() - else: - res = [getattr(ai_obj, e[0]) for e in ai_obj._fields_] - res = [res[i:i+4] for i in xrange(0,16,4)] - elif isinstance(ai_obj, structs.Matrix3x3): - if numpy: - res = numpy.array([getattr(ai_obj, e[0]) for e in ai_obj._fields_]).reshape((3,3)) - else: - res = [getattr(ai_obj, e[0]) for e in ai_obj._fields_] - res = [res[i:i+3] for i in xrange(0,9,3)] - else: - if numpy: - res = numpy.array([getattr(ai_obj, e[0]) for e in ai_obj._fields_]) - else: - res = [getattr(ai_obj, e[0]) for e in ai_obj._fields_] - - return res - -# Returns unicode object for Python 2, and str object for Python 3. -def _convert_assimp_string(assimp_string): - try: - return unicode(assimp_string.data, errors='ignore') - except: - return str(assimp_string.data, errors='ignore') - -# It is faster and more correct to have an init function for each assimp class -def _init_face(aiFace): - aiFace.indices = [aiFace.mIndices[i] for i in range(aiFace.mNumIndices)] -assimp_struct_inits = { structs.Face : _init_face } - -def call_init(obj, caller = None): - if helper.hasattr_silent(obj,'contents'): #pointer - _init(obj.contents, obj, caller) - else: - _init(obj,parent=caller) - -def _is_init_type(obj): - if helper.hasattr_silent(obj,'contents'): #pointer - return _is_init_type(obj[0]) - # null-pointer case that arises when we reach a mesh attribute - # like mBitangents which use mNumVertices rather than mNumBitangents - # so it breaks the 'is iterable' check. - # Basically: - # FIXME! - elif not bool(obj): - return False - tname = obj.__class__.__name__ - return not (tname[:2] == 'c_' or tname == 'Structure' \ - or tname == 'POINTER') and not isinstance(obj,int) - -def _init(self, target = None, parent = None): - """ - Custom initialize() for C structs, adds safely accessible member functionality. - - :param target: set the object which receive the added methods. Useful when manipulating - pointers, to skip the intermediate 'contents' deferencing. - """ - if not target: - target = self - - dirself = dir(self) - for m in dirself: - - if m.startswith("_"): - continue - - if m.startswith('mNum'): - if 'm' + m[4:] in dirself: - continue # will be processed later on - else: - name = m[1:].lower() - - obj = getattr(self, m) - setattr(target, name, obj) - continue - - if m == 'mName': - target.name = str(_convert_assimp_string(self.mName)) - target.__class__.__repr__ = lambda x: str(x.__class__) + "(" + getattr(x, 'name','') + ")" - target.__class__.__str__ = lambda x: getattr(x, 'name', '') - continue - - name = m[1:].lower() - - obj = getattr(self, m) - - # Create tuples - if isinstance(obj, structs.assimp_structs_as_tuple): - setattr(target, name, make_tuple(obj)) - logger.debug(str(self) + ": Added array " + str(getattr(target, name)) + " as self." + name.lower()) - continue - - if m.startswith('m'): - - if name == "parent": - setattr(target, name, parent) - logger.debug("Added a parent as self." + name) - continue - - if helper.hasattr_silent(self, 'mNum' + m[1:]): - - length = getattr(self, 'mNum' + m[1:]) - - # -> special case: properties are - # stored as a dict. - if m == 'mProperties': - setattr(target, name, _get_properties(obj, length)) - continue - - - if not length: # empty! - setattr(target, name, []) - logger.debug(str(self) + ": " + name + " is an empty list.") - continue - - - try: - if obj._type_ in structs.assimp_structs_as_tuple: - if numpy: - setattr(target, name, numpy.array([make_tuple(obj[i]) for i in range(length)], dtype=numpy.float32)) - - logger.debug(str(self) + ": Added an array of numpy arrays (type "+ str(type(obj)) + ") as self." + name) - else: - setattr(target, name, [make_tuple(obj[i]) for i in range(length)]) - - logger.debug(str(self) + ": Added a list of lists (type "+ str(type(obj)) + ") as self." + name) - - else: - setattr(target, name, [obj[i] for i in range(length)]) #TODO: maybe not necessary to recreate an array? - - logger.debug(str(self) + ": Added list of " + str(obj) + " " + name + " as self." + name + " (type: " + str(type(obj)) + ")") - - # initialize array elements - try: - init = assimp_struct_inits[type(obj[0])] - except KeyError: - if _is_init_type(obj[0]): - for e in getattr(target, name): - call_init(e, target) - else: - for e in getattr(target, name): - init(e) - - - except IndexError: - logger.error("in " + str(self) +" : mismatch between mNum" + name + " and the actual amount of data in m" + name + ". This may be due to version mismatch between libassimp and pyassimp. Quitting now.") - sys.exit(1) - - except ValueError as e: - - logger.error("In " + str(self) + "->" + name + ": " + str(e) + ". Quitting now.") - if "setting an array element with a sequence" in str(e): - logger.error("Note that pyassimp does not currently " - "support meshes with mixed triangles " - "and quads. Try to load your mesh with" - " a post-processing to triangulate your" - " faces.") - raise e - - - - else: # starts with 'm' but not iterable - setattr(target, name, obj) - logger.debug("Added " + name + " as self." + name + " (type: " + str(type(obj)) + ")") - - if _is_init_type(obj): - call_init(obj, target) - - if isinstance(self, structs.Mesh): - _finalize_mesh(self, target) - - if isinstance(self, structs.Texture): - _finalize_texture(self, target) - - if isinstance(self, structs.Metadata): - _finalize_metadata(self, target) - - - return self - - -def pythonize_assimp(type, obj, scene): - """ This method modify the Assimp data structures - to make them easier to work with in Python. - - Supported operations: - - MESH: replace a list of mesh IDs by reference to these meshes - - ADDTRANSFORMATION: add a reference to an object's transformation taken from their associated node. - - :param type: the type of modification to operate (cf above) - :param obj: the input object to modify - :param scene: a reference to the whole scene - """ - - if type == "MESH": - meshes = [] - for i in obj: - meshes.append(scene.meshes[i]) - return meshes - - if type == "ADDTRANSFORMATION": - def getnode(node, name): - if node.name == name: return node - for child in node.children: - n = getnode(child, name) - if n: return n - - node = getnode(scene.rootnode, obj.name) - if not node: - raise AssimpError("Object " + str(obj) + " has no associated node!") - setattr(obj, "transformation", node.transformation) - -def recur_pythonize(node, scene): - ''' - Recursively call pythonize_assimp on - nodes tree to apply several post-processing to - pythonize the assimp datastructures. - ''' - node.meshes = pythonize_assimp("MESH", node.meshes, scene) - for mesh in node.meshes: - mesh.material = scene.materials[mesh.materialindex] - for cam in scene.cameras: - pythonize_assimp("ADDTRANSFORMATION", cam, scene) - for c in node.children: - recur_pythonize(c, scene) - -def load(filename, - file_type = None, - processing = postprocess.aiProcess_Triangulate): - ''' - Load a model into a scene. On failure throws AssimpError. - - Arguments - --------- - filename: Either a filename or a file object to load model from. - If a file object is passed, file_type MUST be specified - Otherwise Assimp has no idea which importer to use. - This is named 'filename' so as to not break legacy code. - processing: assimp postprocessing parameters. Verbose keywords are imported - from postprocessing, and the parameters can be combined bitwise to - generate the final processing value. Note that the default value will - triangulate quad faces. Example of generating other possible values: - processing = (pyassimp.postprocess.aiProcess_Triangulate | - pyassimp.postprocess.aiProcess_OptimizeMeshes) - file_type: string of file extension, such as 'stl' - - Returns - --------- - Scene object with model data - ''' - - if hasattr(filename, 'read'): - ''' - This is the case where a file object has been passed to load. - It is calling the following function: - const aiScene* aiImportFileFromMemory(const char* pBuffer, - unsigned int pLength, - unsigned int pFlags, - const char* pHint) - ''' - if file_type == None: - raise AssimpError('File type must be specified when passing file objects!') - data = filename.read() - model = _assimp_lib.load_mem(data, - len(data), - processing, - file_type) - else: - # a filename string has been passed - model = _assimp_lib.load(filename.encode(sys.getfilesystemencoding()), processing) - - if not model: - raise AssimpError('Could not import file!') - scene = _init(model.contents) - recur_pythonize(scene.rootnode, scene) - return scene - -def export(scene, - filename, - file_type = None, - processing = postprocess.aiProcess_Triangulate): - ''' - Export a scene. On failure throws AssimpError. - - Arguments - --------- - scene: scene to export. - filename: Filename that the scene should be exported to. - file_type: string of file exporter to use. For example "collada". - processing: assimp postprocessing parameters. Verbose keywords are imported - from postprocessing, and the parameters can be combined bitwise to - generate the final processing value. Note that the default value will - triangulate quad faces. Example of generating other possible values: - processing = (pyassimp.postprocess.aiProcess_Triangulate | - pyassimp.postprocess.aiProcess_OptimizeMeshes) - - ''' - - from ctypes import pointer - exportStatus = _assimp_lib.export(pointer(scene), file_type.encode("ascii"), filename.encode(sys.getfilesystemencoding()), processing) - - if exportStatus != 0: - raise AssimpError('Could not export scene!') - -def export_blob(scene, - file_type = None, - processing = postprocess.aiProcess_Triangulate): - ''' - Export a scene and return a blob in the correct format. On failure throws AssimpError. - - Arguments - --------- - scene: scene to export. - file_type: string of file exporter to use. For example "collada". - processing: assimp postprocessing parameters. Verbose keywords are imported - from postprocessing, and the parameters can be combined bitwise to - generate the final processing value. Note that the default value will - triangulate quad faces. Example of generating other possible values: - processing = (pyassimp.postprocess.aiProcess_Triangulate | - pyassimp.postprocess.aiProcess_OptimizeMeshes) - Returns - --------- - Pointer to structs.ExportDataBlob - ''' - from ctypes import pointer - exportBlobPtr = _assimp_lib.export_blob(pointer(scene), file_type.encode("ascii"), processing) - - if exportBlobPtr == 0: - raise AssimpError('Could not export scene to blob!') - return exportBlobPtr - -def release(scene): - from ctypes import pointer - _assimp_lib.release(pointer(scene)) - -def _finalize_texture(tex, target): - setattr(target, "achformathint", tex.achFormatHint) - if numpy: - data = numpy.array([make_tuple(getattr(tex, "pcData")[i]) for i in range(tex.mWidth * tex.mHeight)]) - else: - data = [make_tuple(getattr(tex, "pcData")[i]) for i in range(tex.mWidth * tex.mHeight)] - setattr(target, "data", data) - -def _finalize_mesh(mesh, target): - """ Building of meshes is a bit specific. - - We override here the various datasets that can - not be process as regular fields. - - For instance, the length of the normals array is - mNumVertices (no mNumNormals is available) - """ - nb_vertices = getattr(mesh, "mNumVertices") - - def fill(name): - mAttr = getattr(mesh, name) - if numpy: - if mAttr: - data = numpy.array([make_tuple(getattr(mesh, name)[i]) for i in range(nb_vertices)], dtype=numpy.float32) - setattr(target, name[1:].lower(), data) - else: - setattr(target, name[1:].lower(), numpy.array([], dtype="float32")) - else: - if mAttr: - data = [make_tuple(getattr(mesh, name)[i]) for i in range(nb_vertices)] - setattr(target, name[1:].lower(), data) - else: - setattr(target, name[1:].lower(), []) - - def fillarray(name): - mAttr = getattr(mesh, name) - - data = [] - for index, mSubAttr in enumerate(mAttr): - if mSubAttr: - data.append([make_tuple(getattr(mesh, name)[index][i]) for i in range(nb_vertices)]) - - if numpy: - setattr(target, name[1:].lower(), numpy.array(data, dtype=numpy.float32)) - else: - setattr(target, name[1:].lower(), data) - - fill("mNormals") - fill("mTangents") - fill("mBitangents") - - fillarray("mColors") - fillarray("mTextureCoords") - - # prepare faces - if numpy: - faces = numpy.array([f.indices for f in target.faces], dtype=numpy.int32) - else: - faces = [f.indices for f in target.faces] - setattr(target, 'faces', faces) - -def _init_metadata_entry(entry): - from ctypes import POINTER, c_bool, c_int32, c_uint64, c_float, c_double, cast - - entry.type = entry.mType - if entry.type == structs.MetadataEntry.AI_BOOL: - entry.data = cast(entry.mData, POINTER(c_bool)).contents.value - elif entry.type == structs.MetadataEntry.AI_INT32: - entry.data = cast(entry.mData, POINTER(c_int32)).contents.value - elif entry.type == structs.MetadataEntry.AI_UINT64: - entry.data = cast(entry.mData, POINTER(c_uint64)).contents.value - elif entry.type == structs.MetadataEntry.AI_FLOAT: - entry.data = cast(entry.mData, POINTER(c_float)).contents.value - elif entry.type == structs.MetadataEntry.AI_DOUBLE: - entry.data = cast(entry.mData, POINTER(c_double)).contents.value - elif entry.type == structs.MetadataEntry.AI_AISTRING: - assimp_string = cast(entry.mData, POINTER(structs.String)).contents - entry.data = _convert_assimp_string(assimp_string) - elif entry.type == structs.MetadataEntry.AI_AIVECTOR3D: - assimp_vector = cast(entry.mData, POINTER(structs.Vector3D)).contents - entry.data = make_tuple(assimp_vector) - - return entry - -def _finalize_metadata(metadata, target): - """ Building the metadata object is a bit specific. - - Firstly, there are two separate arrays: one with metadata keys and one - with metadata values, and there are no corresponding mNum* attributes, - so the C arrays are not converted to Python arrays using the generic - code in the _init function. - - Secondly, a metadata entry value has to be cast according to declared - metadata entry type. - """ - length = metadata.mNumProperties - setattr(target, 'keys', [str(_convert_assimp_string(metadata.mKeys[i])) for i in range(length)]) - setattr(target, 'values', [_init_metadata_entry(metadata.mValues[i]) for i in range(length)]) - -class PropertyGetter(dict): - def __getitem__(self, key): - semantic = 0 - if isinstance(key, tuple): - key, semantic = key - - return dict.__getitem__(self, (key, semantic)) - - def keys(self): - for k in dict.keys(self): - yield k[0] - - def __iter__(self): - return self.keys() - - def items(self): - for k, v in dict.items(self): - yield k[0], v - - -def _get_properties(properties, length): - """ - Convenience Function to get the material properties as a dict - and values in a python format. - """ - result = {} - #read all properties - for p in [properties[i] for i in range(length)]: - #the name - p = p.contents - key = str(_convert_assimp_string(p.mKey)) - key = (key.split('.')[1], p.mSemantic) - - #the data - from ctypes import POINTER, cast, c_int, c_float, sizeof - if p.mType == 1: - arr = cast(p.mData, POINTER(c_float * int(p.mDataLength/sizeof(c_float)) )).contents - value = [x for x in arr] - elif p.mType == 3: #string can't be an array - value = _convert_assimp_string(cast(p.mData, POINTER(structs.MaterialPropertyString)).contents) - - elif p.mType == 4: - arr = cast(p.mData, POINTER(c_int * int(p.mDataLength/sizeof(c_int)) )).contents - value = [x for x in arr] - else: - value = p.mData[:p.mDataLength] - - if len(value) == 1: - [value] = value - - result[key] = value - - return PropertyGetter(result) - -def decompose_matrix(matrix): - if not isinstance(matrix, structs.Matrix4x4): - raise AssimpError("pyassimp.decompose_matrix failed: Not a Matrix4x4!") - - scaling = structs.Vector3D() - rotation = structs.Quaternion() - position = structs.Vector3D() - - from ctypes import byref, pointer - _assimp_lib.dll.aiDecomposeMatrix(pointer(matrix), byref(scaling), byref(rotation), byref(position)) - return scaling._init(), rotation._init(), position._init() - +""" +PyAssimp + +This is the main-module of PyAssimp. +""" + +import sys +if sys.version_info < (2,6): + raise RuntimeError('pyassimp: need python 2.6 or newer') + +# xrange was renamed range in Python 3 and the original range from Python 2 was removed. +# To keep compatibility with both Python 2 and 3, xrange is set to range for version 3.0 and up. +if sys.version_info >= (3,0): + xrange = range + + +try: import numpy +except ImportError: numpy = None +import logging +import ctypes +logger = logging.getLogger("pyassimp") +# attach default null handler to logger so it doesn't complain +# even if you don't attach another handler to logger +logger.addHandler(logging.NullHandler()) + +from . import structs +from . import helper +from . import postprocess +from .errors import AssimpError + +class AssimpLib(object): + """ + Assimp-Singleton + """ + load, load_mem, export, export_blob, release, dll = helper.search_library() +_assimp_lib = AssimpLib() + +def make_tuple(ai_obj, type = None): + res = None + + #notes: + # ai_obj._fields_ = [ ("attr", c_type), ... ] + # getattr(ai_obj, e[0]).__class__ == float + + if isinstance(ai_obj, structs.Matrix4x4): + if numpy: + res = numpy.array([getattr(ai_obj, e[0]) for e in ai_obj._fields_]).reshape((4,4)) + #import pdb;pdb.set_trace() + else: + res = [getattr(ai_obj, e[0]) for e in ai_obj._fields_] + res = [res[i:i+4] for i in xrange(0,16,4)] + elif isinstance(ai_obj, structs.Matrix3x3): + if numpy: + res = numpy.array([getattr(ai_obj, e[0]) for e in ai_obj._fields_]).reshape((3,3)) + else: + res = [getattr(ai_obj, e[0]) for e in ai_obj._fields_] + res = [res[i:i+3] for i in xrange(0,9,3)] + else: + if numpy: + res = numpy.array([getattr(ai_obj, e[0]) for e in ai_obj._fields_]) + else: + res = [getattr(ai_obj, e[0]) for e in ai_obj._fields_] + + return res + +# Returns unicode object for Python 2, and str object for Python 3. +def _convert_assimp_string(assimp_string): + if sys.version_info >= (3, 0): + return str(assimp_string.data, errors='ignore') + else: + return unicode(assimp_string.data, errors='ignore') + +# It is faster and more correct to have an init function for each assimp class +def _init_face(aiFace): + aiFace.indices = [aiFace.mIndices[i] for i in range(aiFace.mNumIndices)] +assimp_struct_inits = { structs.Face : _init_face } + +def call_init(obj, caller = None): + if helper.hasattr_silent(obj,'contents'): #pointer + _init(obj.contents, obj, caller) + else: + _init(obj,parent=caller) + +def _is_init_type(obj): + + if obj and helper.hasattr_silent(obj,'contents'): #pointer + return _is_init_type(obj[0]) + # null-pointer case that arises when we reach a mesh attribute + # like mBitangents which use mNumVertices rather than mNumBitangents + # so it breaks the 'is iterable' check. + # Basically: + # FIXME! + elif not bool(obj): + return False + tname = obj.__class__.__name__ + return not (tname[:2] == 'c_' or tname == 'Structure' \ + or tname == 'POINTER') and not isinstance(obj, (int, str, bytes)) + +def _init(self, target = None, parent = None): + """ + Custom initialize() for C structs, adds safely accessible member functionality. + + :param target: set the object which receive the added methods. Useful when manipulating + pointers, to skip the intermediate 'contents' deferencing. + """ + if not target: + target = self + + dirself = dir(self) + for m in dirself: + + if m.startswith("_"): + continue + + if m.startswith('mNum'): + if 'm' + m[4:] in dirself: + continue # will be processed later on + else: + name = m[1:].lower() + + obj = getattr(self, m) + setattr(target, name, obj) + continue + + if m == 'mName': + target.name = str(_convert_assimp_string(self.mName)) + target.__class__.__repr__ = lambda x: str(x.__class__) + "(" + getattr(x, 'name','') + ")" + target.__class__.__str__ = lambda x: getattr(x, 'name', '') + continue + + name = m[1:].lower() + + obj = getattr(self, m) + + # Create tuples + if isinstance(obj, structs.assimp_structs_as_tuple): + setattr(target, name, make_tuple(obj)) + logger.debug(str(self) + ": Added array " + str(getattr(target, name)) + " as self." + name.lower()) + continue + + if m.startswith('m'): + + if name == "parent": + setattr(target, name, parent) + logger.debug("Added a parent as self." + name) + continue + + if helper.hasattr_silent(self, 'mNum' + m[1:]): + + length = getattr(self, 'mNum' + m[1:]) + + # -> special case: properties are + # stored as a dict. + if m == 'mProperties': + setattr(target, name, _get_properties(obj, length)) + continue + + + if not length: # empty! + setattr(target, name, []) + logger.debug(str(self) + ": " + name + " is an empty list.") + continue + + + try: + if obj._type_ in structs.assimp_structs_as_tuple: + if numpy: + setattr(target, name, numpy.array([make_tuple(obj[i]) for i in range(length)], dtype=numpy.float32)) + + logger.debug(str(self) + ": Added an array of numpy arrays (type "+ str(type(obj)) + ") as self." + name) + else: + setattr(target, name, [make_tuple(obj[i]) for i in range(length)]) + + logger.debug(str(self) + ": Added a list of lists (type "+ str(type(obj)) + ") as self." + name) + + else: + setattr(target, name, [obj[i] for i in range(length)]) #TODO: maybe not necessary to recreate an array? + + logger.debug(str(self) + ": Added list of " + str(obj) + " " + name + " as self." + name + " (type: " + str(type(obj)) + ")") + + # initialize array elements + try: + init = assimp_struct_inits[type(obj[0])] + except KeyError: + if _is_init_type(obj[0]): + for e in getattr(target, name): + call_init(e, target) + else: + for e in getattr(target, name): + init(e) + + + except IndexError: + logger.error("in " + str(self) +" : mismatch between mNum" + name + " and the actual amount of data in m" + name + ". This may be due to version mismatch between libassimp and pyassimp. Quitting now.") + sys.exit(1) + + except ValueError as e: + + logger.error("In " + str(self) + "->" + name + ": " + str(e) + ". Quitting now.") + if "setting an array element with a sequence" in str(e): + logger.error("Note that pyassimp does not currently " + "support meshes with mixed triangles " + "and quads. Try to load your mesh with" + " a post-processing to triangulate your" + " faces.") + raise e + + + + else: # starts with 'm' but not iterable + setattr(target, name, obj) + logger.debug("Added " + name + " as self." + name + " (type: " + str(type(obj)) + ")") + + if _is_init_type(obj): + call_init(obj, target) + + if isinstance(self, structs.Mesh): + _finalize_mesh(self, target) + + if isinstance(self, structs.Texture): + _finalize_texture(self, target) + + if isinstance(self, structs.Metadata): + _finalize_metadata(self, target) + + + return self + + +def pythonize_assimp(type, obj, scene): + """ This method modify the Assimp data structures + to make them easier to work with in Python. + + Supported operations: + - MESH: replace a list of mesh IDs by reference to these meshes + - ADDTRANSFORMATION: add a reference to an object's transformation taken from their associated node. + + :param type: the type of modification to operate (cf above) + :param obj: the input object to modify + :param scene: a reference to the whole scene + """ + + if type == "MESH": + meshes = [] + for i in obj: + meshes.append(scene.meshes[i]) + return meshes + + if type == "ADDTRANSFORMATION": + def getnode(node, name): + if node.name == name: return node + for child in node.children: + n = getnode(child, name) + if n: return n + + node = getnode(scene.rootnode, obj.name) + if not node: + raise AssimpError("Object " + str(obj) + " has no associated node!") + setattr(obj, "transformation", node.transformation) + +def recur_pythonize(node, scene): + ''' + Recursively call pythonize_assimp on + nodes tree to apply several post-processing to + pythonize the assimp datastructures. + ''' + node.meshes = pythonize_assimp("MESH", node.meshes, scene) + for mesh in node.meshes: + mesh.material = scene.materials[mesh.materialindex] + for cam in scene.cameras: + pythonize_assimp("ADDTRANSFORMATION", cam, scene) + for c in node.children: + recur_pythonize(c, scene) + +def load(filename, + file_type = None, + processing = postprocess.aiProcess_Triangulate): + ''' + Load a model into a scene. On failure throws AssimpError. + + Arguments + --------- + filename: Either a filename or a file object to load model from. + If a file object is passed, file_type MUST be specified + Otherwise Assimp has no idea which importer to use. + This is named 'filename' so as to not break legacy code. + processing: assimp postprocessing parameters. Verbose keywords are imported + from postprocessing, and the parameters can be combined bitwise to + generate the final processing value. Note that the default value will + triangulate quad faces. Example of generating other possible values: + processing = (pyassimp.postprocess.aiProcess_Triangulate | + pyassimp.postprocess.aiProcess_OptimizeMeshes) + file_type: string of file extension, such as 'stl' + + Returns + --------- + Scene object with model data + ''' + + if hasattr(filename, 'read'): + # This is the case where a file object has been passed to load. + # It is calling the following function: + # const aiScene* aiImportFileFromMemory(const char* pBuffer, + # unsigned int pLength, + # unsigned int pFlags, + # const char* pHint) + if file_type is None: + raise AssimpError('File type must be specified when passing file objects!') + data = filename.read() + model = _assimp_lib.load_mem(data, + len(data), + processing, + file_type) + else: + # a filename string has been passed + model = _assimp_lib.load(filename.encode(sys.getfilesystemencoding()), processing) + + if not model: + raise AssimpError('Could not import file!') + scene = _init(model.contents) + recur_pythonize(scene.rootnode, scene) + return scene + +def export(scene, + filename, + file_type = None, + processing = postprocess.aiProcess_Triangulate): + ''' + Export a scene. On failure throws AssimpError. + + Arguments + --------- + scene: scene to export. + filename: Filename that the scene should be exported to. + file_type: string of file exporter to use. For example "collada". + processing: assimp postprocessing parameters. Verbose keywords are imported + from postprocessing, and the parameters can be combined bitwise to + generate the final processing value. Note that the default value will + triangulate quad faces. Example of generating other possible values: + processing = (pyassimp.postprocess.aiProcess_Triangulate | + pyassimp.postprocess.aiProcess_OptimizeMeshes) + + ''' + + exportStatus = _assimp_lib.export(ctypes.pointer(scene), file_type.encode("ascii"), filename.encode(sys.getfilesystemencoding()), processing) + + if exportStatus != 0: + raise AssimpError('Could not export scene!') + +def export_blob(scene, + file_type = None, + processing = postprocess.aiProcess_Triangulate): + ''' + Export a scene and return a blob in the correct format. On failure throws AssimpError. + + Arguments + --------- + scene: scene to export. + file_type: string of file exporter to use. For example "collada". + processing: assimp postprocessing parameters. Verbose keywords are imported + from postprocessing, and the parameters can be combined bitwise to + generate the final processing value. Note that the default value will + triangulate quad faces. Example of generating other possible values: + processing = (pyassimp.postprocess.aiProcess_Triangulate | + pyassimp.postprocess.aiProcess_OptimizeMeshes) + Returns + --------- + Pointer to structs.ExportDataBlob + ''' + exportBlobPtr = _assimp_lib.export_blob(ctypes.pointer(scene), file_type.encode("ascii"), processing) + + if exportBlobPtr == 0: + raise AssimpError('Could not export scene to blob!') + return exportBlobPtr + +def release(scene): + _assimp_lib.release(ctypes.pointer(scene)) + +def _finalize_texture(tex, target): + setattr(target, "achformathint", tex.achFormatHint) + if numpy: + data = numpy.array([make_tuple(getattr(tex, "pcData")[i]) for i in range(tex.mWidth * tex.mHeight)]) + else: + data = [make_tuple(getattr(tex, "pcData")[i]) for i in range(tex.mWidth * tex.mHeight)] + setattr(target, "data", data) + +def _finalize_mesh(mesh, target): + """ Building of meshes is a bit specific. + + We override here the various datasets that can + not be process as regular fields. + + For instance, the length of the normals array is + mNumVertices (no mNumNormals is available) + """ + nb_vertices = getattr(mesh, "mNumVertices") + + def fill(name): + mAttr = getattr(mesh, name) + if numpy: + if mAttr: + data = numpy.array([make_tuple(getattr(mesh, name)[i]) for i in range(nb_vertices)], dtype=numpy.float32) + setattr(target, name[1:].lower(), data) + else: + setattr(target, name[1:].lower(), numpy.array([], dtype="float32")) + else: + if mAttr: + data = [make_tuple(getattr(mesh, name)[i]) for i in range(nb_vertices)] + setattr(target, name[1:].lower(), data) + else: + setattr(target, name[1:].lower(), []) + + def fillarray(name): + mAttr = getattr(mesh, name) + + data = [] + for index, mSubAttr in enumerate(mAttr): + if mSubAttr: + data.append([make_tuple(getattr(mesh, name)[index][i]) for i in range(nb_vertices)]) + + if numpy: + setattr(target, name[1:].lower(), numpy.array(data, dtype=numpy.float32)) + else: + setattr(target, name[1:].lower(), data) + + fill("mNormals") + fill("mTangents") + fill("mBitangents") + + fillarray("mColors") + fillarray("mTextureCoords") + + # prepare faces + if numpy: + faces = numpy.array([f.indices for f in target.faces], dtype=numpy.int32) + else: + faces = [f.indices for f in target.faces] + setattr(target, 'faces', faces) + +def _init_metadata_entry(entry): + entry.type = entry.mType + if entry.type == structs.MetadataEntry.AI_BOOL: + entry.data = ctypes.cast(entry.mData, ctypes.POINTER(ctypes.c_bool)).contents.value + elif entry.type == structs.MetadataEntry.AI_INT32: + entry.data = ctypes.cast(entry.mData, ctypes.POINTER(ctypes.c_int32)).contents.value + elif entry.type == structs.MetadataEntry.AI_UINT64: + entry.data = ctypes.cast(entry.mData, ctypes.POINTER(ctypes.c_uint64)).contents.value + elif entry.type == structs.MetadataEntry.AI_FLOAT: + entry.data = ctypes.cast(entry.mData, ctypes.POINTER(ctypes.c_float)).contents.value + elif entry.type == structs.MetadataEntry.AI_DOUBLE: + entry.data = ctypes.cast(entry.mData, ctypes.POINTER(ctypes.c_double)).contents.value + elif entry.type == structs.MetadataEntry.AI_AISTRING: + assimp_string = ctypes.cast(entry.mData, ctypes.POINTER(structs.String)).contents + entry.data = _convert_assimp_string(assimp_string) + elif entry.type == structs.MetadataEntry.AI_AIVECTOR3D: + assimp_vector = ctypes.cast(entry.mData, ctypes.POINTER(structs.Vector3D)).contents + entry.data = make_tuple(assimp_vector) + + return entry + +def _finalize_metadata(metadata, target): + """ Building the metadata object is a bit specific. + + Firstly, there are two separate arrays: one with metadata keys and one + with metadata values, and there are no corresponding mNum* attributes, + so the C arrays are not converted to Python arrays using the generic + code in the _init function. + + Secondly, a metadata entry value has to be cast according to declared + metadata entry type. + """ + length = metadata.mNumProperties + setattr(target, 'keys', [str(_convert_assimp_string(metadata.mKeys[i])) for i in range(length)]) + setattr(target, 'values', [_init_metadata_entry(metadata.mValues[i]) for i in range(length)]) + +class PropertyGetter(dict): + def __getitem__(self, key): + semantic = 0 + if isinstance(key, tuple): + key, semantic = key + + return dict.__getitem__(self, (key, semantic)) + + def keys(self): + for k in dict.keys(self): + yield k[0] + + def __iter__(self): + return self.keys() + + def items(self): + for k, v in dict.items(self): + yield k[0], v + + +def _get_properties(properties, length): + """ + Convenience Function to get the material properties as a dict + and values in a python format. + """ + result = {} + #read all properties + for p in [properties[i] for i in range(length)]: + #the name + p = p.contents + key = str(_convert_assimp_string(p.mKey)) + key = (key.split('.')[1], p.mSemantic) + + #the data + if p.mType == 1: + arr = ctypes.cast(p.mData, + ctypes.POINTER(ctypes.c_float * int(p.mDataLength/ctypes.sizeof(ctypes.c_float))) + ).contents + value = [x for x in arr] + elif p.mType == 3: #string can't be an array + value = _convert_assimp_string(ctypes.cast(p.mData, ctypes.POINTER(structs.MaterialPropertyString)).contents) + + elif p.mType == 4: + arr = ctypes.cast(p.mData, + ctypes.POINTER(ctypes.c_int * int(p.mDataLength/ctypes.sizeof(ctypes.c_int))) + ).contents + value = [x for x in arr] + else: + value = p.mData[:p.mDataLength] + + if len(value) == 1: + [value] = value + + result[key] = value + + return PropertyGetter(result) + +def decompose_matrix(matrix): + if not isinstance(matrix, structs.Matrix4x4): + raise AssimpError("pyassimp.decompose_matrix failed: Not a Matrix4x4!") + + scaling = structs.Vector3D() + rotation = structs.Quaternion() + position = structs.Vector3D() + + _assimp_lib.dll.aiDecomposeMatrix(ctypes.pointer(matrix), + ctypes.byref(scaling), + ctypes.byref(rotation), + ctypes.byref(position)) + return scaling._init(), rotation._init(), position._init() + diff --git a/port/PyAssimp/pyassimp/formats.py b/port/PyAssimp/pyassimp/formats.py index baba1645c..5d454e5b7 100644 --- a/port/PyAssimp/pyassimp/formats.py +++ b/port/PyAssimp/pyassimp/formats.py @@ -21,7 +21,7 @@ FORMATS = ["CSM", "STL", "IRR", "Q3O", - "Q3D" + "Q3D", "MS3D", "Q3S", "ZGL", diff --git a/port/PyAssimp/pyassimp/helper.py b/port/PyAssimp/pyassimp/helper.py index 4e9f10e94..5c1aca827 100644 --- a/port/PyAssimp/pyassimp/helper.py +++ b/port/PyAssimp/pyassimp/helper.py @@ -1,280 +1,281 @@ -#-*- coding: UTF-8 -*- - -""" -Some fancy helper functions. -""" - -import os -import ctypes -from ctypes import POINTER -import operator - -from distutils.sysconfig import get_python_lib -import re -import sys - -try: import numpy -except: numpy = None - -import logging;logger = logging.getLogger("pyassimp") - -from .errors import AssimpError - -additional_dirs, ext_whitelist = [],[] - -# populate search directories and lists of allowed file extensions -# depending on the platform we're running on. -if os.name=='posix': - additional_dirs.append('./') - additional_dirs.append('/usr/lib/') - additional_dirs.append('/usr/lib/x86_64-linux-gnu/') - additional_dirs.append('/usr/local/lib/') - - if 'LD_LIBRARY_PATH' in os.environ: - additional_dirs.extend([item for item in os.environ['LD_LIBRARY_PATH'].split(':') if item]) - - # check if running from anaconda. - if "conda" or "continuum" in sys.version.lower(): - cur_path = get_python_lib() - pattern = re.compile('.*\/lib\/') - conda_lib = pattern.match(cur_path).group() - logger.info("Adding Anaconda lib path:"+ conda_lib) - additional_dirs.append(conda_lib) - - # note - this won't catch libassimp.so.N.n, but - # currently there's always a symlink called - # libassimp.so in /usr/local/lib. - ext_whitelist.append('.so') - # libassimp.dylib in /usr/local/lib - ext_whitelist.append('.dylib') - -elif os.name=='nt': - ext_whitelist.append('.dll') - path_dirs = os.environ['PATH'].split(';') - additional_dirs.extend(path_dirs) - -def vec2tuple(x): - """ Converts a VECTOR3D to a Tuple """ - return (x.x, x.y, x.z) - -def transform(vector3, matrix4x4): - """ Apply a transformation matrix on a 3D vector. - - :param vector3: array with 3 elements - :param matrix4x4: 4x4 matrix - """ - if numpy: - return numpy.dot(matrix4x4, numpy.append(vector3, 1.)) - else: - m0,m1,m2,m3 = matrix4x4; x,y,z = vector3 - return [ - m0[0]*x + m0[1]*y + m0[2]*z + m0[3], - m1[0]*x + m1[1]*y + m1[2]*z + m1[3], - m2[0]*x + m2[1]*y + m2[2]*z + m2[3], - m3[0]*x + m3[1]*y + m3[2]*z + m3[3] - ] - -def _inv(matrix4x4): - m0,m1,m2,m3 = matrix4x4 - - det = m0[3]*m1[2]*m2[1]*m3[0] - m0[2]*m1[3]*m2[1]*m3[0] - \ - m0[3]*m1[1]*m2[2]*m3[0] + m0[1]*m1[3]*m2[2]*m3[0] + \ - m0[2]*m1[1]*m2[3]*m3[0] - m0[1]*m1[2]*m2[3]*m3[0] - \ - m0[3]*m1[2]*m2[0]*m3[1] + m0[2]*m1[3]*m2[0]*m3[1] + \ - m0[3]*m1[0]*m2[2]*m3[1] - m0[0]*m1[3]*m2[2]*m3[1] - \ - m0[2]*m1[0]*m2[3]*m3[1] + m0[0]*m1[2]*m2[3]*m3[1] + \ - m0[3]*m1[1]*m2[0]*m3[2] - m0[1]*m1[3]*m2[0]*m3[2] - \ - m0[3]*m1[0]*m2[1]*m3[2] + m0[0]*m1[3]*m2[1]*m3[2] + \ - m0[1]*m1[0]*m2[3]*m3[2] - m0[0]*m1[1]*m2[3]*m3[2] - \ - m0[2]*m1[1]*m2[0]*m3[3] + m0[1]*m1[2]*m2[0]*m3[3] + \ - m0[2]*m1[0]*m2[1]*m3[3] - m0[0]*m1[2]*m2[1]*m3[3] - \ - m0[1]*m1[0]*m2[2]*m3[3] + m0[0]*m1[1]*m2[2]*m3[3] - - return[[( m1[2]*m2[3]*m3[1] - m1[3]*m2[2]*m3[1] + m1[3]*m2[1]*m3[2] - m1[1]*m2[3]*m3[2] - m1[2]*m2[1]*m3[3] + m1[1]*m2[2]*m3[3]) /det, - ( m0[3]*m2[2]*m3[1] - m0[2]*m2[3]*m3[1] - m0[3]*m2[1]*m3[2] + m0[1]*m2[3]*m3[2] + m0[2]*m2[1]*m3[3] - m0[1]*m2[2]*m3[3]) /det, - ( m0[2]*m1[3]*m3[1] - m0[3]*m1[2]*m3[1] + m0[3]*m1[1]*m3[2] - m0[1]*m1[3]*m3[2] - m0[2]*m1[1]*m3[3] + m0[1]*m1[2]*m3[3]) /det, - ( m0[3]*m1[2]*m2[1] - m0[2]*m1[3]*m2[1] - m0[3]*m1[1]*m2[2] + m0[1]*m1[3]*m2[2] + m0[2]*m1[1]*m2[3] - m0[1]*m1[2]*m2[3]) /det], - [( m1[3]*m2[2]*m3[0] - m1[2]*m2[3]*m3[0] - m1[3]*m2[0]*m3[2] + m1[0]*m2[3]*m3[2] + m1[2]*m2[0]*m3[3] - m1[0]*m2[2]*m3[3]) /det, - ( m0[2]*m2[3]*m3[0] - m0[3]*m2[2]*m3[0] + m0[3]*m2[0]*m3[2] - m0[0]*m2[3]*m3[2] - m0[2]*m2[0]*m3[3] + m0[0]*m2[2]*m3[3]) /det, - ( m0[3]*m1[2]*m3[0] - m0[2]*m1[3]*m3[0] - m0[3]*m1[0]*m3[2] + m0[0]*m1[3]*m3[2] + m0[2]*m1[0]*m3[3] - m0[0]*m1[2]*m3[3]) /det, - ( m0[2]*m1[3]*m2[0] - m0[3]*m1[2]*m2[0] + m0[3]*m1[0]*m2[2] - m0[0]*m1[3]*m2[2] - m0[2]*m1[0]*m2[3] + m0[0]*m1[2]*m2[3]) /det], - [( m1[1]*m2[3]*m3[0] - m1[3]*m2[1]*m3[0] + m1[3]*m2[0]*m3[1] - m1[0]*m2[3]*m3[1] - m1[1]*m2[0]*m3[3] + m1[0]*m2[1]*m3[3]) /det, - ( m0[3]*m2[1]*m3[0] - m0[1]*m2[3]*m3[0] - m0[3]*m2[0]*m3[1] + m0[0]*m2[3]*m3[1] + m0[1]*m2[0]*m3[3] - m0[0]*m2[1]*m3[3]) /det, - ( m0[1]*m1[3]*m3[0] - m0[3]*m1[1]*m3[0] + m0[3]*m1[0]*m3[1] - m0[0]*m1[3]*m3[1] - m0[1]*m1[0]*m3[3] + m0[0]*m1[1]*m3[3]) /det, - ( m0[3]*m1[1]*m2[0] - m0[1]*m1[3]*m2[0] - m0[3]*m1[0]*m2[1] + m0[0]*m1[3]*m2[1] + m0[1]*m1[0]*m2[3] - m0[0]*m1[1]*m2[3]) /det], - [( m1[2]*m2[1]*m3[0] - m1[1]*m2[2]*m3[0] - m1[2]*m2[0]*m3[1] + m1[0]*m2[2]*m3[1] + m1[1]*m2[0]*m3[2] - m1[0]*m2[1]*m3[2]) /det, - ( m0[1]*m2[2]*m3[0] - m0[2]*m2[1]*m3[0] + m0[2]*m2[0]*m3[1] - m0[0]*m2[2]*m3[1] - m0[1]*m2[0]*m3[2] + m0[0]*m2[1]*m3[2]) /det, - ( m0[2]*m1[1]*m3[0] - m0[1]*m1[2]*m3[0] - m0[2]*m1[0]*m3[1] + m0[0]*m1[2]*m3[1] + m0[1]*m1[0]*m3[2] - m0[0]*m1[1]*m3[2]) /det, - ( m0[1]*m1[2]*m2[0] - m0[2]*m1[1]*m2[0] + m0[2]*m1[0]*m2[1] - m0[0]*m1[2]*m2[1] - m0[1]*m1[0]*m2[2] + m0[0]*m1[1]*m2[2]) /det]] - -def get_bounding_box(scene): - bb_min = [1e10, 1e10, 1e10] # x,y,z - bb_max = [-1e10, -1e10, -1e10] # x,y,z - inv = numpy.linalg.inv if numpy else _inv - return get_bounding_box_for_node(scene.rootnode, bb_min, bb_max, inv(scene.rootnode.transformation)) - -def get_bounding_box_for_node(node, bb_min, bb_max, transformation): - - if numpy: - transformation = numpy.dot(transformation, node.transformation) - else: - t0,t1,t2,t3 = transformation - T0,T1,T2,T3 = node.transformation - transformation = [ [ - t0[0]*T0[0] + t0[1]*T1[0] + t0[2]*T2[0] + t0[3]*T3[0], - t0[0]*T0[1] + t0[1]*T1[1] + t0[2]*T2[1] + t0[3]*T3[1], - t0[0]*T0[2] + t0[1]*T1[2] + t0[2]*T2[2] + t0[3]*T3[2], - t0[0]*T0[3] + t0[1]*T1[3] + t0[2]*T2[3] + t0[3]*T3[3] - ],[ - t1[0]*T0[0] + t1[1]*T1[0] + t1[2]*T2[0] + t1[3]*T3[0], - t1[0]*T0[1] + t1[1]*T1[1] + t1[2]*T2[1] + t1[3]*T3[1], - t1[0]*T0[2] + t1[1]*T1[2] + t1[2]*T2[2] + t1[3]*T3[2], - t1[0]*T0[3] + t1[1]*T1[3] + t1[2]*T2[3] + t1[3]*T3[3] - ],[ - t2[0]*T0[0] + t2[1]*T1[0] + t2[2]*T2[0] + t2[3]*T3[0], - t2[0]*T0[1] + t2[1]*T1[1] + t2[2]*T2[1] + t2[3]*T3[1], - t2[0]*T0[2] + t2[1]*T1[2] + t2[2]*T2[2] + t2[3]*T3[2], - t2[0]*T0[3] + t2[1]*T1[3] + t2[2]*T2[3] + t2[3]*T3[3] - ],[ - t3[0]*T0[0] + t3[1]*T1[0] + t3[2]*T2[0] + t3[3]*T3[0], - t3[0]*T0[1] + t3[1]*T1[1] + t3[2]*T2[1] + t3[3]*T3[1], - t3[0]*T0[2] + t3[1]*T1[2] + t3[2]*T2[2] + t3[3]*T3[2], - t3[0]*T0[3] + t3[1]*T1[3] + t3[2]*T2[3] + t3[3]*T3[3] - ] ] - - for mesh in node.meshes: - for v in mesh.vertices: - v = transform(v, transformation) - bb_min[0] = min(bb_min[0], v[0]) - bb_min[1] = min(bb_min[1], v[1]) - bb_min[2] = min(bb_min[2], v[2]) - bb_max[0] = max(bb_max[0], v[0]) - bb_max[1] = max(bb_max[1], v[1]) - bb_max[2] = max(bb_max[2], v[2]) - - - for child in node.children: - bb_min, bb_max = get_bounding_box_for_node(child, bb_min, bb_max, transformation) - - return bb_min, bb_max - -def try_load_functions(library_path, dll): - ''' - Try to bind to aiImportFile and aiReleaseImport - - Arguments - --------- - library_path: path to current lib - dll: ctypes handle to library - - Returns - --------- - If unsuccessful: - None - If successful: - Tuple containing (library_path, - load from filename function, - load from memory function, - export to filename function, - export to blob function, - release function, - ctypes handle to assimp library) - ''' - - try: - load = dll.aiImportFile - release = dll.aiReleaseImport - load_mem = dll.aiImportFileFromMemory - export = dll.aiExportScene - export2blob = dll.aiExportSceneToBlob - except AttributeError: - #OK, this is a library, but it doesn't have the functions we need - return None - - # library found! - from .structs import Scene, ExportDataBlob - load.restype = POINTER(Scene) - load_mem.restype = POINTER(Scene) - export2blob.restype = POINTER(ExportDataBlob) - return (library_path, load, load_mem, export, export2blob, release, dll) - -def search_library(): - ''' - Loads the assimp library. - Throws exception AssimpError if no library_path is found - - Returns: tuple, (load from filename function, - load from memory function, - export to filename function, - export to blob function, - release function, - dll) - ''' - #this path - folder = os.path.dirname(__file__) - - # silence 'DLL not found' message boxes on win - try: - ctypes.windll.kernel32.SetErrorMode(0x8007) - except AttributeError: - pass - - candidates = [] - # test every file - for curfolder in [folder]+additional_dirs: - if os.path.isdir(curfolder): - for filename in os.listdir(curfolder): - # our minimum requirement for candidates is that - # they should contain 'assimp' somewhere in - # their name - if filename.lower().find('assimp')==-1 : - continue - is_out=1 - for et in ext_whitelist: - if et in filename.lower(): - is_out=0 - break - if is_out: - continue - - library_path = os.path.join(curfolder, filename) - logger.debug('Try ' + library_path) - try: - dll = ctypes.cdll.LoadLibrary(library_path) - except Exception as e: - logger.warning(str(e)) - # OK, this except is evil. But different OSs will throw different - # errors. So just ignore any errors. - continue - # see if the functions we need are in the dll - loaded = try_load_functions(library_path, dll) - if loaded: candidates.append(loaded) - - if not candidates: - # no library found - raise AssimpError("assimp library not found") - else: - # get the newest library_path - candidates = map(lambda x: (os.lstat(x[0])[-2], x), candidates) - res = max(candidates, key=operator.itemgetter(0))[1] - logger.debug('Using assimp library located at ' + res[0]) - - # XXX: if there are 1000 dll/so files containing 'assimp' - # in their name, do we have all of them in our address - # space now until gc kicks in? - - # XXX: take version postfix of the .so on linux? - return res[1:] - -def hasattr_silent(object, name): - """ - Calls hasttr() with the given parameters and preserves the legacy (pre-Python 3.2) - functionality of silently catching exceptions. - - Returns the result of hasatter() or False if an exception was raised. - """ - - try: - return hasattr(object, name) - except: - return False +#-*- coding: UTF-8 -*- + +""" +Some fancy helper functions. +""" + +import os +import ctypes +import operator + +from distutils.sysconfig import get_python_lib +import re +import sys + +try: import numpy +except ImportError: numpy = None + +import logging;logger = logging.getLogger("pyassimp") + +from .errors import AssimpError + +additional_dirs, ext_whitelist = [],[] + +# populate search directories and lists of allowed file extensions +# depending on the platform we're running on. +if os.name=='posix': + additional_dirs.append('./') + additional_dirs.append('/usr/lib/') + additional_dirs.append('/usr/lib/x86_64-linux-gnu/') + additional_dirs.append('/usr/local/lib/') + + if 'LD_LIBRARY_PATH' in os.environ: + additional_dirs.extend([item for item in os.environ['LD_LIBRARY_PATH'].split(':') if item]) + + # check if running from anaconda. + if "conda" or "continuum" in sys.version.lower(): + cur_path = get_python_lib() + pattern = re.compile('.*\/lib\/') + conda_lib = pattern.match(cur_path).group() + logger.info("Adding Anaconda lib path:"+ conda_lib) + additional_dirs.append(conda_lib) + + # note - this won't catch libassimp.so.N.n, but + # currently there's always a symlink called + # libassimp.so in /usr/local/lib. + ext_whitelist.append('.so') + # libassimp.dylib in /usr/local/lib + ext_whitelist.append('.dylib') + +elif os.name=='nt': + ext_whitelist.append('.dll') + path_dirs = os.environ['PATH'].split(';') + additional_dirs.extend(path_dirs) + +def vec2tuple(x): + """ Converts a VECTOR3D to a Tuple """ + return (x.x, x.y, x.z) + +def transform(vector3, matrix4x4): + """ Apply a transformation matrix on a 3D vector. + + :param vector3: array with 3 elements + :param matrix4x4: 4x4 matrix + """ + if numpy: + return numpy.dot(matrix4x4, numpy.append(vector3, 1.)) + else: + m0,m1,m2,m3 = matrix4x4; x,y,z = vector3 + return [ + m0[0]*x + m0[1]*y + m0[2]*z + m0[3], + m1[0]*x + m1[1]*y + m1[2]*z + m1[3], + m2[0]*x + m2[1]*y + m2[2]*z + m2[3], + m3[0]*x + m3[1]*y + m3[2]*z + m3[3] + ] + +def _inv(matrix4x4): + m0,m1,m2,m3 = matrix4x4 + + det = m0[3]*m1[2]*m2[1]*m3[0] - m0[2]*m1[3]*m2[1]*m3[0] - \ + m0[3]*m1[1]*m2[2]*m3[0] + m0[1]*m1[3]*m2[2]*m3[0] + \ + m0[2]*m1[1]*m2[3]*m3[0] - m0[1]*m1[2]*m2[3]*m3[0] - \ + m0[3]*m1[2]*m2[0]*m3[1] + m0[2]*m1[3]*m2[0]*m3[1] + \ + m0[3]*m1[0]*m2[2]*m3[1] - m0[0]*m1[3]*m2[2]*m3[1] - \ + m0[2]*m1[0]*m2[3]*m3[1] + m0[0]*m1[2]*m2[3]*m3[1] + \ + m0[3]*m1[1]*m2[0]*m3[2] - m0[1]*m1[3]*m2[0]*m3[2] - \ + m0[3]*m1[0]*m2[1]*m3[2] + m0[0]*m1[3]*m2[1]*m3[2] + \ + m0[1]*m1[0]*m2[3]*m3[2] - m0[0]*m1[1]*m2[3]*m3[2] - \ + m0[2]*m1[1]*m2[0]*m3[3] + m0[1]*m1[2]*m2[0]*m3[3] + \ + m0[2]*m1[0]*m2[1]*m3[3] - m0[0]*m1[2]*m2[1]*m3[3] - \ + m0[1]*m1[0]*m2[2]*m3[3] + m0[0]*m1[1]*m2[2]*m3[3] + + return[[( m1[2]*m2[3]*m3[1] - m1[3]*m2[2]*m3[1] + m1[3]*m2[1]*m3[2] - m1[1]*m2[3]*m3[2] - m1[2]*m2[1]*m3[3] + m1[1]*m2[2]*m3[3]) /det, + ( m0[3]*m2[2]*m3[1] - m0[2]*m2[3]*m3[1] - m0[3]*m2[1]*m3[2] + m0[1]*m2[3]*m3[2] + m0[2]*m2[1]*m3[3] - m0[1]*m2[2]*m3[3]) /det, + ( m0[2]*m1[3]*m3[1] - m0[3]*m1[2]*m3[1] + m0[3]*m1[1]*m3[2] - m0[1]*m1[3]*m3[2] - m0[2]*m1[1]*m3[3] + m0[1]*m1[2]*m3[3]) /det, + ( m0[3]*m1[2]*m2[1] - m0[2]*m1[3]*m2[1] - m0[3]*m1[1]*m2[2] + m0[1]*m1[3]*m2[2] + m0[2]*m1[1]*m2[3] - m0[1]*m1[2]*m2[3]) /det], + [( m1[3]*m2[2]*m3[0] - m1[2]*m2[3]*m3[0] - m1[3]*m2[0]*m3[2] + m1[0]*m2[3]*m3[2] + m1[2]*m2[0]*m3[3] - m1[0]*m2[2]*m3[3]) /det, + ( m0[2]*m2[3]*m3[0] - m0[3]*m2[2]*m3[0] + m0[3]*m2[0]*m3[2] - m0[0]*m2[3]*m3[2] - m0[2]*m2[0]*m3[3] + m0[0]*m2[2]*m3[3]) /det, + ( m0[3]*m1[2]*m3[0] - m0[2]*m1[3]*m3[0] - m0[3]*m1[0]*m3[2] + m0[0]*m1[3]*m3[2] + m0[2]*m1[0]*m3[3] - m0[0]*m1[2]*m3[3]) /det, + ( m0[2]*m1[3]*m2[0] - m0[3]*m1[2]*m2[0] + m0[3]*m1[0]*m2[2] - m0[0]*m1[3]*m2[2] - m0[2]*m1[0]*m2[3] + m0[0]*m1[2]*m2[3]) /det], + [( m1[1]*m2[3]*m3[0] - m1[3]*m2[1]*m3[0] + m1[3]*m2[0]*m3[1] - m1[0]*m2[3]*m3[1] - m1[1]*m2[0]*m3[3] + m1[0]*m2[1]*m3[3]) /det, + ( m0[3]*m2[1]*m3[0] - m0[1]*m2[3]*m3[0] - m0[3]*m2[0]*m3[1] + m0[0]*m2[3]*m3[1] + m0[1]*m2[0]*m3[3] - m0[0]*m2[1]*m3[3]) /det, + ( m0[1]*m1[3]*m3[0] - m0[3]*m1[1]*m3[0] + m0[3]*m1[0]*m3[1] - m0[0]*m1[3]*m3[1] - m0[1]*m1[0]*m3[3] + m0[0]*m1[1]*m3[3]) /det, + ( m0[3]*m1[1]*m2[0] - m0[1]*m1[3]*m2[0] - m0[3]*m1[0]*m2[1] + m0[0]*m1[3]*m2[1] + m0[1]*m1[0]*m2[3] - m0[0]*m1[1]*m2[3]) /det], + [( m1[2]*m2[1]*m3[0] - m1[1]*m2[2]*m3[0] - m1[2]*m2[0]*m3[1] + m1[0]*m2[2]*m3[1] + m1[1]*m2[0]*m3[2] - m1[0]*m2[1]*m3[2]) /det, + ( m0[1]*m2[2]*m3[0] - m0[2]*m2[1]*m3[0] + m0[2]*m2[0]*m3[1] - m0[0]*m2[2]*m3[1] - m0[1]*m2[0]*m3[2] + m0[0]*m2[1]*m3[2]) /det, + ( m0[2]*m1[1]*m3[0] - m0[1]*m1[2]*m3[0] - m0[2]*m1[0]*m3[1] + m0[0]*m1[2]*m3[1] + m0[1]*m1[0]*m3[2] - m0[0]*m1[1]*m3[2]) /det, + ( m0[1]*m1[2]*m2[0] - m0[2]*m1[1]*m2[0] + m0[2]*m1[0]*m2[1] - m0[0]*m1[2]*m2[1] - m0[1]*m1[0]*m2[2] + m0[0]*m1[1]*m2[2]) /det]] + +def get_bounding_box(scene): + bb_min = [1e10, 1e10, 1e10] # x,y,z + bb_max = [-1e10, -1e10, -1e10] # x,y,z + inv = numpy.linalg.inv if numpy else _inv + return get_bounding_box_for_node(scene.rootnode, bb_min, bb_max, inv(scene.rootnode.transformation)) + +def get_bounding_box_for_node(node, bb_min, bb_max, transformation): + + if numpy: + transformation = numpy.dot(transformation, node.transformation) + else: + t0,t1,t2,t3 = transformation + T0,T1,T2,T3 = node.transformation + transformation = [ [ + t0[0]*T0[0] + t0[1]*T1[0] + t0[2]*T2[0] + t0[3]*T3[0], + t0[0]*T0[1] + t0[1]*T1[1] + t0[2]*T2[1] + t0[3]*T3[1], + t0[0]*T0[2] + t0[1]*T1[2] + t0[2]*T2[2] + t0[3]*T3[2], + t0[0]*T0[3] + t0[1]*T1[3] + t0[2]*T2[3] + t0[3]*T3[3] + ],[ + t1[0]*T0[0] + t1[1]*T1[0] + t1[2]*T2[0] + t1[3]*T3[0], + t1[0]*T0[1] + t1[1]*T1[1] + t1[2]*T2[1] + t1[3]*T3[1], + t1[0]*T0[2] + t1[1]*T1[2] + t1[2]*T2[2] + t1[3]*T3[2], + t1[0]*T0[3] + t1[1]*T1[3] + t1[2]*T2[3] + t1[3]*T3[3] + ],[ + t2[0]*T0[0] + t2[1]*T1[0] + t2[2]*T2[0] + t2[3]*T3[0], + t2[0]*T0[1] + t2[1]*T1[1] + t2[2]*T2[1] + t2[3]*T3[1], + t2[0]*T0[2] + t2[1]*T1[2] + t2[2]*T2[2] + t2[3]*T3[2], + t2[0]*T0[3] + t2[1]*T1[3] + t2[2]*T2[3] + t2[3]*T3[3] + ],[ + t3[0]*T0[0] + t3[1]*T1[0] + t3[2]*T2[0] + t3[3]*T3[0], + t3[0]*T0[1] + t3[1]*T1[1] + t3[2]*T2[1] + t3[3]*T3[1], + t3[0]*T0[2] + t3[1]*T1[2] + t3[2]*T2[2] + t3[3]*T3[2], + t3[0]*T0[3] + t3[1]*T1[3] + t3[2]*T2[3] + t3[3]*T3[3] + ] ] + + for mesh in node.meshes: + for v in mesh.vertices: + v = transform(v, transformation) + bb_min[0] = min(bb_min[0], v[0]) + bb_min[1] = min(bb_min[1], v[1]) + bb_min[2] = min(bb_min[2], v[2]) + bb_max[0] = max(bb_max[0], v[0]) + bb_max[1] = max(bb_max[1], v[1]) + bb_max[2] = max(bb_max[2], v[2]) + + + for child in node.children: + bb_min, bb_max = get_bounding_box_for_node(child, bb_min, bb_max, transformation) + + return bb_min, bb_max + +def try_load_functions(library_path, dll): + ''' + Try to bind to aiImportFile and aiReleaseImport + + Arguments + --------- + library_path: path to current lib + dll: ctypes handle to library + + Returns + --------- + If unsuccessful: + None + If successful: + Tuple containing (library_path, + load from filename function, + load from memory function, + export to filename function, + export to blob function, + release function, + ctypes handle to assimp library) + ''' + + try: + load = dll.aiImportFile + release = dll.aiReleaseImport + load_mem = dll.aiImportFileFromMemory + export = dll.aiExportScene + export2blob = dll.aiExportSceneToBlob + except AttributeError: + #OK, this is a library, but it doesn't have the functions we need + return None + + # library found! + from .structs import Scene, ExportDataBlob + load.restype = ctypes.POINTER(Scene) + load_mem.restype = ctypes.POINTER(Scene) + export2blob.restype = ctypes.POINTER(ExportDataBlob) + return (library_path, load, load_mem, export, export2blob, release, dll) + +def search_library(): + ''' + Loads the assimp library. + Throws exception AssimpError if no library_path is found + + Returns: tuple, (load from filename function, + load from memory function, + export to filename function, + export to blob function, + release function, + dll) + ''' + #this path + folder = os.path.dirname(__file__) + + # silence 'DLL not found' message boxes on win + try: + ctypes.windll.kernel32.SetErrorMode(0x8007) + except AttributeError: + pass + + candidates = [] + # test every file + for curfolder in [folder]+additional_dirs: + if os.path.isdir(curfolder): + for filename in os.listdir(curfolder): + # our minimum requirement for candidates is that + # they should contain 'assimp' somewhere in + # their name + if filename.lower().find('assimp')==-1 : + continue + is_out=1 + for et in ext_whitelist: + if et in filename.lower(): + is_out=0 + break + if is_out: + continue + + library_path = os.path.join(curfolder, filename) + logger.debug('Try ' + library_path) + try: + dll = ctypes.cdll.LoadLibrary(library_path) + except Exception as e: + logger.warning(str(e)) + # OK, this except is evil. But different OSs will throw different + # errors. So just ignore any errors. + continue + # see if the functions we need are in the dll + loaded = try_load_functions(library_path, dll) + if loaded: candidates.append(loaded) + + if not candidates: + # no library found + raise AssimpError("assimp library not found") + else: + # get the newest library_path + candidates = map(lambda x: (os.lstat(x[0])[-2], x), candidates) + res = max(candidates, key=operator.itemgetter(0))[1] + logger.debug('Using assimp library located at ' + res[0]) + + # XXX: if there are 1000 dll/so files containing 'assimp' + # in their name, do we have all of them in our address + # space now until gc kicks in? + + # XXX: take version postfix of the .so on linux? + return res[1:] + +def hasattr_silent(object, name): + """ + Calls hasttr() with the given parameters and preserves the legacy (pre-Python 3.2) + functionality of silently catching exceptions. + + Returns the result of hasatter() or False if an exception was raised. + """ + + try: + if not object: + return False + return hasattr(object, name) + except AttributeError: + return False diff --git a/port/PyAssimp/pyassimp/postprocess.py b/port/PyAssimp/pyassimp/postprocess.py index 932c7c660..0c55d6798 100644 --- a/port/PyAssimp/pyassimp/postprocess.py +++ b/port/PyAssimp/pyassimp/postprocess.py @@ -435,6 +435,7 @@ aiProcess_Debone = 0x4000000 aiProcess_GenEntityMeshes = 0x100000 aiProcess_OptimizeAnimations = 0x200000 aiProcess_FixTexturePaths = 0x200000 +aiProcess_EmbedTextures = 0x10000000, ## @def aiProcess_ConvertToLeftHanded # @brief Shortcut flag for Direct3D-based applications. diff --git a/port/PyAssimp/pyassimp/structs.py b/port/PyAssimp/pyassimp/structs.py index ddfd87f8a..d478b861b 100644 --- a/port/PyAssimp/pyassimp/structs.py +++ b/port/PyAssimp/pyassimp/structs.py @@ -1,6 +1,6 @@ #-*- coding: UTF-8 -*- -from ctypes import POINTER, c_void_p, c_int, c_uint, c_char, c_float, Structure, c_char_p, c_double, c_ubyte, c_size_t, c_uint32 +from ctypes import POINTER, c_void_p, c_uint, c_char, c_float, Structure, c_char_p, c_double, c_ubyte, c_size_t, c_uint32 class Vector2D(Structure): @@ -70,7 +70,7 @@ class String(Structure): See 'types.h' for details. """ - MAXLEN = 1024 + MAXLEN = 1024 _fields_ = [ # Binary length of the string excluding the terminal 0. This is NOT the diff --git a/port/PyAssimp/scripts/3d_viewer_py3.py b/port/PyAssimp/scripts/3d_viewer_py3.py index 4c88edc7b..fcee63717 100755 --- a/port/PyAssimp/scripts/3d_viewer_py3.py +++ b/port/PyAssimp/scripts/3d_viewer_py3.py @@ -468,7 +468,7 @@ class PyAssimp3DViewer: try: self.set_shaders_v130() self.prepare_shaders() - except RuntimeError, message: + except RuntimeError as message: sys.stderr.write("%s\n" % message) sys.stdout.write("Could not compile shaders in version 1.30, trying version 1.20\n") @@ -1177,6 +1177,22 @@ class PyAssimp3DViewer: return True def controls_3d(self, dx, dy, zooming_one_shot=False): + """ Orbiting the camera is implemented the following way: + + - the rotation is split into a rotation around the *world* Z axis + (controlled by the horizontal mouse motion along X) and a + rotation around the *X* axis of the camera (pitch) *shifted to + the focal origin* (the world origin for now). This is controlled + by the vertical motion of the mouse (Y axis). + - as a result, the resulting transformation of the camera in the + world frame C' is: + C' = (T · Rx · Tâ»Â¹ · (Rz · C)â»Â¹)â»Â¹ + where: + - C is the original camera transformation in the world frame, + - Rz is the rotation along the Z axis (in the world frame) + - T is the translation camera -> world (ie, the inverse of the + translation part of C + - Rx is the rotation around X in the (translated) camera frame """ CAMERA_TRANSLATION_FACTOR = 0.01 CAMERA_ROTATION_FACTOR = 0.01 @@ -1188,26 +1204,6 @@ class PyAssimp3DViewer: distance = numpy.linalg.norm(self.focal_point - current_pos) if self.is_rotating: - """ Orbiting the camera is implemented the following way: - - - the rotation is split into a rotation around the *world* Z axis - (controlled by the horizontal mouse motion along X) and a - rotation around the *X* axis of the camera (pitch) *shifted to - the focal origin* (the world origin for now). This is controlled - by the vertical motion of the mouse (Y axis). - - - as a result, the resulting transformation of the camera in the - world frame C' is: - C' = (T · Rx · Tâ»Â¹ · (Rz · C)â»Â¹)â»Â¹ - - where: - - C is the original camera transformation in the world frame, - - Rz is the rotation along the Z axis (in the world frame) - - T is the translation camera -> world (ie, the inverse of the - translation part of C - - Rx is the rotation around X in the (translated) camera frame - """ - rotation_camera_x = dy * CAMERA_ROTATION_FACTOR rotation_world_z = dx * CAMERA_ROTATION_FACTOR world_z_rotation = transformations.euler_matrix(0, 0, rotation_world_z) diff --git a/port/PyAssimp/scripts/fixed_pipeline_3d_viewer.py b/port/PyAssimp/scripts/fixed_pipeline_3d_viewer.py index 7f98b9004..c2f6cebb7 100755 --- a/port/PyAssimp/scripts/fixed_pipeline_3d_viewer.py +++ b/port/PyAssimp/scripts/fixed_pipeline_3d_viewer.py @@ -24,12 +24,13 @@ This sample is based on several sources, including: - ASSIMP's C++ SimpleOpenGL viewer """ -import os, sys +import sys from OpenGL.GLUT import * from OpenGL.GLU import * from OpenGL.GL import * -import logging;logger = logging.getLogger("pyassimp_opengl") +import logging +logger = logging.getLogger("pyassimp_opengl") logging.basicConfig(level=logging.INFO) import math diff --git a/port/PyAssimp/scripts/sample.py b/port/PyAssimp/scripts/sample.py index 9012eb374..3cd4b3ec4 100755 --- a/port/PyAssimp/scripts/sample.py +++ b/port/PyAssimp/scripts/sample.py @@ -5,7 +5,7 @@ This module demonstrates the functionality of PyAssimp. """ -import os, sys +import sys import logging logging.basicConfig(level=logging.INFO) @@ -50,8 +50,8 @@ def main(filename=None): print(" colors:" + str(len(mesh.colors))) tcs = mesh.texturecoords if tcs.any(): - for index, tc in enumerate(tcs): - print(" texture-coords "+ str(index) + ":" + str(len(tcs[index])) + "first3:" + str(tcs[index][:3])) + for tc_index, tc in enumerate(tcs): + print(" texture-coords "+ str(tc_index) + ":" + str(len(tcs[tc_index])) + "first3:" + str(tcs[tc_index][:3])) else: print(" no texture coordinates") diff --git a/port/PyAssimp/setup.py b/port/PyAssimp/setup.py index e19e497f0..a3497d657 100644 --- a/port/PyAssimp/setup.py +++ b/port/PyAssimp/setup.py @@ -8,7 +8,7 @@ def readme(): return f.read() setup(name='pyassimp', - version='4.1.3', + version='4.1.4', license='ISC', description='Python bindings for the Open Asset Import Library (ASSIMP)', long_description=readme(), diff --git a/port/iOS/IPHONEOS_ARM64E_TOOLCHAIN.cmake b/port/iOS/IPHONEOS_ARM64E_TOOLCHAIN.cmake new file mode 100644 index 000000000..0cf2b6b66 --- /dev/null +++ b/port/iOS/IPHONEOS_ARM64E_TOOLCHAIN.cmake @@ -0,0 +1,17 @@ +INCLUDE(CMakeForceCompiler) + +SET (CMAKE_CROSSCOMPILING TRUE) +SET (CMAKE_SYSTEM_NAME "Darwin") +SET (CMAKE_SYSTEM_PROCESSOR "arm64e") +SET (IOS TRUE) + +SET (IOS_SDK_DEVICE iPhoneOS) + +SET (SDKVER "${IOS_SDK_VERSION}") +SET (DEVROOT "${XCODE_ROOT_DIR}/Platforms/${IOS_SDK_DEVICE}.platform/Developer") + + +SET (CMAKE_FIND_ROOT_PATH "${SDKROOT}" "${DEVROOT}") +SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) \ No newline at end of file diff --git a/port/iOS/build.sh b/port/iOS/build.sh index 288c9c4a4..f118c45c1 100755 --- a/port/iOS/build.sh +++ b/port/iOS/build.sh @@ -31,7 +31,7 @@ TOOLCHAIN=$XCODE_ROOT_DIR/Toolchains/XcodeDefault.xctoolchain CMAKE_C_COMPILER=$(xcrun -find cc) CMAKE_CXX_COMPILER=$(xcrun -find c++) -BUILD_ARCHS_DEVICE="arm64 armv7s armv7" +BUILD_ARCHS_DEVICE="arm64e arm64 armv7s armv7" BUILD_ARCHS_SIMULATOR="x86_64 i386" BUILD_ARCHS_ALL=($BUILD_ARCHS_DEVICE $BUILD_ARCHS_SIMULATOR) diff --git a/port/jassimp/jassimp-native/src/jassimp.cpp b/port/jassimp/jassimp-native/src/jassimp.cpp index 070dbc95d..0cf01b1e3 100644 --- a/port/jassimp/jassimp-native/src/jassimp.cpp +++ b/port/jassimp/jassimp-native/src/jassimp.cpp @@ -1,6 +1,7 @@ #include "jassimp.h" #include +#include #include #include #include @@ -248,7 +249,7 @@ static bool call(JNIEnv *env, jobject object, const char* typeName, const char* return false; } - jboolean jReturnValue = env->CallBooleanMethod(object, mid, params[0].l); + jboolean jReturnValue = env->CallBooleanMethodA(object, mid, params); return (bool)jReturnValue; } @@ -591,6 +592,24 @@ class JavaIOSystem : public Assimp::IOSystem { }; +class JavaProgressHandler : public Assimp::ProgressHandler { + private: + JNIEnv* mJniEnv; + jobject& mJavaProgressHandler; + + public: + JavaProgressHandler(JNIEnv* env, jobject& javaProgressHandler) : + mJniEnv(env), + mJavaProgressHandler(javaProgressHandler) + {}; + + bool Update(float percentage) + { + jvalue params[1]; + params[0].f = percentage; + return call(mJniEnv, mJavaProgressHandler, "jassimp/AiProgressHandler", "update", "(F)Z", params); + } +}; static bool loadMeshes(JNIEnv *env, const aiScene* cScene, jobject& jScene) { @@ -1880,7 +1899,7 @@ JNIEXPORT jstring JNICALL Java_jassimp_Jassimp_getErrorString JNIEXPORT jobject JNICALL Java_jassimp_Jassimp_aiImportFile - (JNIEnv *env, jclass jClazz, jstring jFilename, jlong postProcess, jobject ioSystem) + (JNIEnv *env, jclass jClazz, jstring jFilename, jlong postProcess, jobject ioSystem, jobject progressHandler) { jobject jScene = NULL; @@ -1896,6 +1915,11 @@ JNIEXPORT jobject JNICALL Java_jassimp_Jassimp_aiImportFile lprintf("Created aiFileIO\n"); } + if(progressHandler != NULL) + { + imp.SetProgressHandler(new JavaProgressHandler(env, progressHandler)); + } + lprintf("opening file: %s\n", cFilename); /* do import */ diff --git a/port/jassimp/jassimp-native/src/jassimp.h b/port/jassimp/jassimp-native/src/jassimp.h index 7d4b66e29..2a4a84538 100644 --- a/port/jassimp/jassimp-native/src/jassimp.h +++ b/port/jassimp/jassimp-native/src/jassimp.h @@ -39,7 +39,7 @@ JNIEXPORT jstring JNICALL Java_jassimp_Jassimp_getErrorString * Signature: (Ljava/lang/String;J)Ljassimp/AiScene; */ JNIEXPORT jobject JNICALL Java_jassimp_Jassimp_aiImportFile - (JNIEnv *, jclass, jstring, jlong, jobject); + (JNIEnv *, jclass, jstring, jlong, jobject, jobject); #ifdef __cplusplus } diff --git a/port/jassimp/jassimp/src/jassimp/AiAnimation.java b/port/jassimp/jassimp/src/jassimp/AiAnimation.java index fca3bc53d..777d2a9fe 100644 --- a/port/jassimp/jassimp/src/jassimp/AiAnimation.java +++ b/port/jassimp/jassimp/src/jassimp/AiAnimation.java @@ -54,6 +54,26 @@ import java.util.List; * {@link AiMesh} for a description and comparison of these APIs. */ public final class AiAnimation { + /** + * Name. + */ + private final String m_name; + + /** + * Duration. + */ + private final double m_duration; + + /** + * Ticks per second. + */ + private final double m_ticksPerSecond; + + /** + * Bone animation channels. + */ + private final List m_nodeAnims = new ArrayList(); + /** * Constructor. * @@ -151,29 +171,5 @@ public final class AiAnimation { */ public List getMeshChannels() { throw new UnsupportedOperationException("not implemented yet"); - } - - - /** - * Name. - */ - private final String m_name; - - - /** - * Duration. - */ - private final double m_duration; - - - /** - * Ticks per second. - */ - private final double m_ticksPerSecond; - - - /** - * Bone animation channels. - */ - private final List m_nodeAnims = new ArrayList(); + } } \ No newline at end of file diff --git a/port/jassimp/jassimp/src/jassimp/AiBone.java b/port/jassimp/jassimp/src/jassimp/AiBone.java index 87c4b8199..1e6d49beb 100644 --- a/port/jassimp/jassimp/src/jassimp/AiBone.java +++ b/port/jassimp/jassimp/src/jassimp/AiBone.java @@ -55,6 +55,24 @@ import java.util.List; * writable and may be modified. */ public final class AiBone { + /** + * Name of the bone. + */ + private String m_name; + + + /** + * Bone weights. + */ + private final List m_boneWeights = + new ArrayList(); + + + /** + * Offset matrix. + */ + private Object m_offsetMatrix; + /** * Constructor. */ @@ -114,24 +132,5 @@ public final class AiBone { AiWrapperProvider wrapperProvider) { return (M4) m_offsetMatrix; - } - - - /** - * Name of the bone. - */ - private String m_name; - - - /** - * Bone weights. - */ - private final List m_boneWeights = - new ArrayList(); - - - /** - * Offset matrix. - */ - private Object m_offsetMatrix; + } } diff --git a/port/jassimp/jassimp/src/jassimp/AiClassLoaderIOSystem.java b/port/jassimp/jassimp/src/jassimp/AiClassLoaderIOSystem.java index e14a87f77..95afc2e02 100644 --- a/port/jassimp/jassimp/src/jassimp/AiClassLoaderIOSystem.java +++ b/port/jassimp/jassimp/src/jassimp/AiClassLoaderIOSystem.java @@ -139,10 +139,8 @@ public class AiClassLoaderIOSystem implements AiIOSystem { return false; } - else - { - return true; - } + + return true; } diff --git a/port/jassimp/jassimp/src/jassimp/AiColor.java b/port/jassimp/jassimp/src/jassimp/AiColor.java index 25eb251d6..6befeecbd 100644 --- a/port/jassimp/jassimp/src/jassimp/AiColor.java +++ b/port/jassimp/jassimp/src/jassimp/AiColor.java @@ -50,6 +50,16 @@ import java.nio.ByteBuffer; * modify the underlying mesh. */ public final class AiColor { + /** + * Wrapped buffer. + */ + private final ByteBuffer m_buffer; + + /** + * Offset into m_buffer. + */ + private final int m_offset; + /** * Constructor. * @@ -147,16 +157,4 @@ public final class AiColor { return "[" + getRed() + ", " + getGreen() + ", " + getBlue() + ", " + getAlpha() + "]"; } - - - /** - * Wrapped buffer. - */ - private final ByteBuffer m_buffer; - - - /** - * Offset into m_buffer. - */ - private final int m_offset; } diff --git a/port/jassimp/jassimp/src/jassimp/AiMaterial.java b/port/jassimp/jassimp/src/jassimp/AiMaterial.java index 7a9abc0d3..8582d881a 100644 --- a/port/jassimp/jassimp/src/jassimp/AiMaterial.java +++ b/port/jassimp/jassimp/src/jassimp/AiMaterial.java @@ -70,6 +70,17 @@ import java.util.Set; * properties (i.e., properties starting with TEX_). */ public final class AiMaterial { + /** + * List of properties. + */ + private final List m_properties = new ArrayList(); + + /** + * Number of textures for each type. + */ + private final Map m_numTextures = + new EnumMap(AiTextureType.class); + /** * Enumerates all supported material properties. */ @@ -317,7 +328,36 @@ public final class AiMaterial { * properties easily. */ public static final class Property { + /** + * Key. + */ + private final String m_key; + + /** + * Semantic. + */ + private final int m_semantic; + + + /** + * Index. + */ + private final int m_index; + + + /** + * Type. + */ + private final PropertyType m_type; + + + /** + * Data. + */ + private final Object m_data; + + /** * Constructor. * * @param key @@ -417,39 +457,9 @@ public final class AiMaterial { * * @return the data */ - Object getData() { + public Object getData() { return m_data; } - - - /** - * Key. - */ - private final String m_key; - - - /** - * Semantic. - */ - private final int m_semantic; - - - /** - * Index. - */ - private final int m_index; - - - /** - * Type. - */ - private final PropertyType m_type; - - - /** - * Data. - */ - private final Object m_data; } @@ -1185,18 +1195,5 @@ public final class AiMaterial { @SuppressWarnings("unused") private void setTextureNumber(int type, int number) { m_numTextures.put(AiTextureType.fromRawValue(type), number); - } - - - /** - * List of properties. - */ - private final List m_properties = new ArrayList(); - - - /** - * Number of textures for each type. - */ - private final Map m_numTextures = - new EnumMap(AiTextureType.class); + } } diff --git a/port/jassimp/jassimp/src/jassimp/AiMesh.java b/port/jassimp/jassimp/src/jassimp/AiMesh.java index b6a478d18..3f4a29760 100644 --- a/port/jassimp/jassimp/src/jassimp/AiMesh.java +++ b/port/jassimp/jassimp/src/jassimp/AiMesh.java @@ -153,6 +153,89 @@ public final class AiMesh { private final int SIZEOF_V3D = Jassimp.NATIVE_AIVEKTOR3D_SIZE; + /** + * The primitive types used by this mesh. + */ + private final Set m_primitiveTypes = + EnumSet.noneOf(AiPrimitiveType.class); + + + /** + * Number of vertices in this mesh. + */ + private int m_numVertices = 0; + + + /** + * Number of faces in this mesh. + */ + private int m_numFaces = 0; + + /** + * Material used by this mesh. + */ + private int m_materialIndex = -1; + + /** + * The name of the mesh. + */ + private String m_name = ""; + + /** + * Buffer for vertex position data. + */ + private ByteBuffer m_vertices = null; + + /** + * Buffer for faces/ indices. + */ + private ByteBuffer m_faces = null; + + + /** + * Index structure for m_faces.

    + * + * Only used by meshes that are not pure triangular + */ + private ByteBuffer m_faceOffsets = null; + + /** + * Buffer for normals. + */ + private ByteBuffer m_normals = null; + + /** + * Buffer for tangents. + */ + private ByteBuffer m_tangents = null; + + /** + * Buffer for bitangents. + */ + private ByteBuffer m_bitangents = null; + + /** + * Vertex colors. + */ + private ByteBuffer[] m_colorsets = + new ByteBuffer[JassimpConfig.MAX_NUMBER_COLORSETS]; + + /** + * Number of UV components for each texture coordinate set. + */ + private int[] m_numUVComponents = new int[JassimpConfig.MAX_NUMBER_TEXCOORDS]; + + /** + * Texture coordinates. + */ + private ByteBuffer[] m_texcoords = + new ByteBuffer[JassimpConfig.MAX_NUMBER_TEXCOORDS]; + + /** + * Bones. + */ + private final List m_bones = new ArrayList(); + /** * This class is instantiated via JNI, no accessible constructor. */ @@ -1335,99 +1418,4 @@ public final class AiMesh { } } // }} - - - /** - * The primitive types used by this mesh. - */ - private final Set m_primitiveTypes = - EnumSet.noneOf(AiPrimitiveType.class); - - - /** - * Number of vertices in this mesh. - */ - private int m_numVertices = 0; - - - /** - * Number of faces in this mesh. - */ - private int m_numFaces = 0; - - - /** - * Material used by this mesh. - */ - private int m_materialIndex = -1; - - - /** - * The name of the mesh. - */ - private String m_name = ""; - - - /** - * Buffer for vertex position data. - */ - private ByteBuffer m_vertices = null; - - - /** - * Buffer for faces/ indices. - */ - private ByteBuffer m_faces = null; - - - /** - * Index structure for m_faces.

    - * - * Only used by meshes that are not pure triangular - */ - private ByteBuffer m_faceOffsets = null; - - - /** - * Buffer for normals. - */ - private ByteBuffer m_normals = null; - - - /** - * Buffer for tangents. - */ - private ByteBuffer m_tangents = null; - - - /** - * Buffer for bitangents. - */ - private ByteBuffer m_bitangents = null; - - - /** - * Vertex colors. - */ - private ByteBuffer[] m_colorsets = - new ByteBuffer[JassimpConfig.MAX_NUMBER_COLORSETS]; - - - /** - * Number of UV components for each texture coordinate set. - */ - private int[] m_numUVComponents = new int[JassimpConfig.MAX_NUMBER_TEXCOORDS]; - - - /** - * Texture coordinates. - */ - private ByteBuffer[] m_texcoords = - new ByteBuffer[JassimpConfig.MAX_NUMBER_TEXCOORDS]; - - - /** - * Bones. - */ - private final List m_bones = new ArrayList(); } diff --git a/port/jassimp/jassimp/src/jassimp/AiNode.java b/port/jassimp/jassimp/src/jassimp/AiNode.java index 9345b7af4..e585e0449 100644 --- a/port/jassimp/jassimp/src/jassimp/AiNode.java +++ b/port/jassimp/jassimp/src/jassimp/AiNode.java @@ -55,6 +55,34 @@ import java.util.Map; * the imported scene consists of only a single root node without children. */ public final class AiNode { + /** + * Parent node. + */ + private final AiNode m_parent; + + + /** + * Mesh references. + */ + private final int[] m_meshReferences; + + + /** + * List of children. + */ + private final List m_children = new ArrayList(); + + /** + * List of metadata entries. + */ + private final Map m_metaData = new HashMap(); + + + /** + * Buffer for transformation matrix. + */ + private final Object m_transformationMatrix; + /** * Constructor. * @@ -214,34 +242,5 @@ public final class AiNode { /** * Name. */ - private final String m_name; - - - /** - * Parent node. - */ - private final AiNode m_parent; - - - /** - * Mesh references. - */ - private final int[] m_meshReferences; - - - /** - * List of children. - */ - private final List m_children = new ArrayList(); - - /** - * List of metadata entries. - */ - private final Map m_metaData = new HashMap(); - - - /** - * Buffer for transformation matrix. - */ - private final Object m_transformationMatrix; + private final String m_name; } diff --git a/include/assimp/Macros.h b/port/jassimp/jassimp/src/jassimp/AiProgressHandler.java similarity index 84% rename from include/assimp/Macros.h rename to port/jassimp/jassimp/src/jassimp/AiProgressHandler.java index 3aaed4e97..5512942d9 100644 --- a/include/assimp/Macros.h +++ b/port/jassimp/jassimp/src/jassimp/AiProgressHandler.java @@ -1,14 +1,14 @@ /* --------------------------------------------------------------------------- -Open Asset Import Library (assimp) +Open Asset Import Library - Java Binding (jassimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2012, 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 +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 @@ -25,25 +25,22 @@ conditions are met: 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 +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 +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 +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 +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. --------------------------------------------------------------------------- */ +package jassimp; -/* 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 - +public interface AiProgressHandler +{ + boolean update(float percentage); +} \ No newline at end of file diff --git a/port/jassimp/jassimp/src/jassimp/AiQuaternion.java b/port/jassimp/jassimp/src/jassimp/AiQuaternion.java index de162631b..00630e644 100644 --- a/port/jassimp/jassimp/src/jassimp/AiQuaternion.java +++ b/port/jassimp/jassimp/src/jassimp/AiQuaternion.java @@ -50,6 +50,17 @@ import java.nio.ByteBuffer; * modify the underlying mesh/animation. */ public final class AiQuaternion { + /** + * Wrapped buffer. + */ + private final ByteBuffer m_buffer; + + + /** + * Offset into m_buffer. + */ + private final int m_offset; + /** * Constructor. * @@ -150,17 +161,5 @@ public final class AiQuaternion { public String toString() { return "[" + getX() + ", " + getY() + ", " + getZ() + ", " + getW() + "]"; - } - - - /** - * Wrapped buffer. - */ - private final ByteBuffer m_buffer; - - - /** - * Offset into m_buffer. - */ - private final int m_offset; + } } \ No newline at end of file diff --git a/port/jassimp/jassimp/src/jassimp/AiSceneFlag.java b/port/jassimp/jassimp/src/jassimp/AiSceneFlag.java index 7f7e01ea9..af3ee5d5f 100644 --- a/port/jassimp/jassimp/src/jassimp/AiSceneFlag.java +++ b/port/jassimp/jassimp/src/jassimp/AiSceneFlag.java @@ -114,8 +114,12 @@ public enum AiSceneFlag { * you actually need to render it). */ TERRAIN(0x10); - - + + /** + * The mapped c/c++ integer enum value. + */ + private final int m_rawValue; + /** * Utility method for converting from c/c++ based integer enums to java * enums.

    @@ -143,11 +147,5 @@ public enum AiSceneFlag { */ private AiSceneFlag(int rawValue) { m_rawValue = rawValue; - } - - - /** - * The mapped c/c++ integer enum value. - */ - private final int m_rawValue; + } } diff --git a/port/jassimp/jassimp/src/jassimp/Jassimp.java b/port/jassimp/jassimp/src/jassimp/Jassimp.java index d1b4aae4e..c33f95c0a 100644 --- a/port/jassimp/jassimp/src/jassimp/Jassimp.java +++ b/port/jassimp/jassimp/src/jassimp/Jassimp.java @@ -60,6 +60,45 @@ import java.util.Set; */ public final class Jassimp { + /** + * The native interface. + * + * @param filename the file to load + * @param postProcessing post processing flags + * @return the loaded scene, or null if an error occurred + * @throws IOException if an error occurs + */ + private static native AiScene aiImportFile(String filename, + long postProcessing, AiIOSystem ioSystem, + AiProgressHandler progressHandler) throws IOException; + + + /** + * The active wrapper provider. + */ + private static AiWrapperProvider s_wrapperProvider = + new AiBuiltInWrapperProvider(); + + + /** + * The library loader to load the native library. + */ + private static JassimpLibraryLoader s_libraryLoader = + new JassimpLibraryLoader(); + + /** + * Status flag if the library is loaded. + * + * Volatile to avoid problems with double checked locking. + * + */ + private static volatile boolean s_libraryLoaded = false; + + /** + * Lock for library loading. + */ + private static final Object s_libraryLoadingLock = new Object(); + /** * The default wrapper provider using built in types. */ @@ -120,11 +159,26 @@ public final class Jassimp { public static AiScene importFile(String filename, Set postProcessing, AiIOSystem ioSystem) throws IOException { - - loadLibrary(); - + return importFile(filename, postProcessing, ioSystem, null); + } + + /** + * Imports a file via assimp. + * + * @param filename the file to import + * @param postProcessing post processing flags + * @param ioSystem ioSystem to load files, or null for default + * @return the loaded scene, or null if an error occurred + * @throws IOException if an error occurs + */ + public static AiScene importFile(String filename, + Set postProcessing, AiIOSystem ioSystem, + AiProgressHandler progressHandler) throws IOException { + + loadLibrary(); + return aiImportFile(filename, AiPostProcessSteps.toRawValue( - postProcessing), ioSystem); + postProcessing), ioSystem, progressHandler); } @@ -327,48 +381,9 @@ public final class Jassimp { s_libraryLoaded = true; } } - } } - - /** - * The native interface. - * - * @param filename the file to load - * @param postProcessing post processing flags - * @return the loaded scene, or null if an error occurred - * @throws IOException if an error occurs - */ - private static native AiScene aiImportFile(String filename, - long postProcessing, AiIOSystem ioSystem) throws IOException; - - - /** - * The active wrapper provider. - */ - private static AiWrapperProvider s_wrapperProvider = - new AiBuiltInWrapperProvider(); - - - /** - * The library loader to load the native library. - */ - private static JassimpLibraryLoader s_libraryLoader = - new JassimpLibraryLoader(); - - /** - * Status flag if the library is loaded. - * - * Volatile to avoid problems with double checked locking. - * - */ - private static volatile boolean s_libraryLoaded = false; - - /** - * Lock for library loading. - */ - private static final Object s_libraryLoadingLock = new Object(); - + /** * Pure static class, no accessible constructor. */ @@ -384,5 +399,4 @@ public final class Jassimp { public static int NATIVE_UINT_SIZE; public static int NATIVE_DOUBLE_SIZE; public static int NATIVE_LONG_SIZE; - } diff --git a/revision.h.in b/revision.h.in index 87c41fa89..6d09afbc6 100644 --- a/revision.h.in +++ b/revision.h.in @@ -4,4 +4,25 @@ #define GitVersion 0x@GIT_COMMIT_HASH@ #define GitBranch "@GIT_BRANCH@" +#define VER_MAJOR @ASSIMP_VERSION_MAJOR@ +#define VER_MINOR @ASSIMP_VERSION_MINOR@ +#define VER_PATCH @ASSIMP_VERSION_PATCH@ +#define VER_BUILD @ASSIMP_PACKAGE_VERSION@ + +#define STR_HELP(x) #x +#define STR(x) STR_HELP(x) + +#define VER_FILEVERSION VER_MAJOR,VER_MINOR,VER_PATCH,VER_BUILD +#if (GitVersion == 0) +#define VER_FILEVERSION_STR STR(VER_MAJOR) "." STR(VER_MINOR) "." STR(VER_PATCH) "." STR(VER_BUILD) +#else +#define VER_FILEVERSION_STR STR(VER_MAJOR) "." STR(VER_MINOR) "." STR(VER_PATCH) "." STR(VER_BUILD) " (Commit @GIT_COMMIT_HASH@)" +#endif + +#ifdef NDEBUG +#define VER_ORIGINAL_FILENAME_STR "assimp@LIBRARY_SUFFIX@.dll" +#else +#define VER_ORIGINAL_FILENAME_STR "assimp@LIBRARY_SUFFIX@@CMAKE_DEBUG_POSTFIX@.dll" +#endif // NDEBUG + #endif // ASSIMP_REVISION_H_INC diff --git a/samples/DevIL/AUTHORS b/samples/DevIL/AUTHORS deleted file mode 100644 index 0f80b3c4a..000000000 --- a/samples/DevIL/AUTHORS +++ /dev/null @@ -1,4 +0,0 @@ -The main programmer is Denton Woods, but this could not have been possible -without contributions and some pieces of code from other projects. - -For contributors and credits, read the CREDITS file. diff --git a/samples/DevIL/COPYING b/samples/DevIL/COPYING deleted file mode 100644 index 30c8ca213..000000000 --- a/samples/DevIL/COPYING +++ /dev/null @@ -1,506 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - - - diff --git a/samples/DevIL/CREDITS b/samples/DevIL/CREDITS deleted file mode 100644 index b30dc4685..000000000 --- a/samples/DevIL/CREDITS +++ /dev/null @@ -1,264 +0,0 @@ -Credits as of 02/06/2009 ------------------------- - -If I inadvertently omitted anyone's name from this list, please e-mail me at -doomwiz@users.sourceforge.net to remedy the problem. - - -James Joplin, alias jayjay (rjoplin@webzone.net) -for all his invaluable help and encouragement with DevIL. - -Edouard Gomez for his invaluable help. - -All the #flipCode gang for their support. - -All my friends at uni for their support. - -SoftImage .pic support based off of code obtained from -http://www.swin.edu.au/astronomy/pbourke/dataformats/ - -TestPic, used in TestIL -http://www.paintlib.de/paintlib/testpic.zip - -Png Test Images -http://www.schaik.com/pngsuite/pngsuite.html - -John Villar (john.villar@eliaschev.com) for making the suggestion of not -letting the user use ILimage structs but instead binding images like OpenGL. -He also made a suggestion on how to load luminance .jpg images, along with -other suggestions. - -http://www.opengl.org/Coding/KilgardTechniques/oglpitfall/oglpitfall.html -section 6 for the values the NTSC uses, so I could convert from coloured -images to luminance values. - -Kodak Photo CD code from the .pcd link on http://www.wotsit.org. - -Foper (foper@hotmail.com) from #flipCode for supplying the excellent -flipcode.jpg in testil\in. The original can be found at -http://webpatterns.com/flip/flipshow.htm - -Lightman (cdthompson@home.net) from #flipCode for restructuring the project -into /bin, /obj, etc. - -Alexander Blach (alexander@abee.de) from #flipCode for creating the Delphi -headers and test app. He figured out that we needed to use .def files to -prevent name decoration of the dlls. He has contributed multiple ideas and -found flaws. Alexander also created a lovely documentation database to help -with documenting DevIL. - -Randy Heit for finding problems in my Doom texture code. - -Oliver Kurowski (oliver.kurowski@gmx.de) for locating a bug in ilut's -DllMain() and another very harmful bug with ilDeleteImages(). - -Ender Wiggin's article on "Elementary Digital Filtering", -found at http://www.gamedev.net/reference/programming/features/edf/ -for many filters in DevIL. - -SGI's "Graphica Obscura" site at http://www.sgi.com/grafica/matrix/index.html -for several filters in DevIL. - -The http://bae.fse.missouri.edu/luw/course/image/project1/project1.html -page for help in determining filter code for Graphica Obscura's interpolation -article at http://www.sgi.com/grafica/interp/index.html. - -Matt Denham for suggesting optimizations in ilNegativeImage(), -iluEdgeDetectS() and iluEdgeDetectP(). - -Timo Heister (Timo-Heister@gmx.de) from #flipCode for creating the original -Visual Basic headers and test apps for VB. - -The OpenGL SuperBible for code for ilutGetHPal(). - -DJ Luminescent (luminescent@uswest.net) for finding a couple of bugs in the -.bmp-loading code and diligently beta testing. - -Lionel Brits, alias Zaewo from #flipCode for slapping me around and telling -me how Microsoft does their .bmp padding. He then wrote most of the -iluEqualize() code from the base code on -http://www.manning.com/Kabir/Files.html . - -Joel Wilsson, alias Siigron (siigron@hotmail.com) for pointing-out several -design flaws that I (Denton) had introduced and posing very useful -suggestions. - -Sean Montgomery, alias Vapor (sean@astralfx.com) for patiently listening to -my endless drivel about DevIL. - -Perlin Noise site http://freespace.virgin.net/hugo.elias/models/m_perlin.htm -for information on interpolation used in iluScale(). - -Shimon Shvartsbroit, alias MasterBoy (cobra11@netvision.net.il) from #flipCode -for explaining bilinear interpolation to me. - -Lbm source from http://www.wotsit.org - -Eran Kampf, alias ttentacle (ekampf@internet-zahav.net) for giving me -resource-loading code for ilutLoadResource and helping with the Windows -clipboard functions. - -Strumpf from #flipCode for writing a really good DirectDraw class for me to -use in the DDraw test, which is based off of his test, too. - -NullSoft (http://www.nullsoft.com), for their SuperPiMP installer. It is -extremely easy to learn to use and very powerful. - -Serun from #flipCode for noticing that Quake2 .pcx files sometimes don't have -the checksum byte for palette'd .pcx files. - -Conor Stokes, aka DirtyPunk from #flipCode for helping explain several things -to me. - -Half-Life model viewer sources (at http://www.swissquake.ch/chumbalum-soft/) -for specs for the Half-Life model format. - -Rich Schwab, alias endura (endura29@hotmail.com) for contributing -girlfriend.cpp. - -The Djgpp libc sources (http://www.delorie.com/djgpp), from where I copied -several functions. - -Roman Podobedov (romka@ut.ee) of Romka Graphics (http://romka.demonews.com) -for his colour quantization sources, which he was kind enough to let me use. - -Pcx document on http://www.wotsit.org for .pcx saving code. - -http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue2.html#Insight -for iluWave(). - -.lif specs from http://www.infinite-mass.com/bob/files/lifed.zip and - http://www.infinite-mass.com/bob/files/lif.zip - -Rune Kock (rune@vupti.com) for writing the new Visual Basic headers and for -finding a return bug in iluScaleAdvanced. - -Julien Verchere and Xavier Decoret for suggesting that I use const char*'s -instead of char*'s as function parameters. - -Jason Reeve (jason@retribution-entertainment.com) for finding a bug in iluCrop, -several origin-related problems, and helping me bring my targa-loading code up -to spec. - -Darren Adams for telling me the #pragmas to use in MSVC++ to disable the -console window in a "console app". - -David Gould for getting onto me about my crappy Linux support. - -David Galeano for his DX8 Surface to TGA code, modified to save to any texture. -The original can be found at http://rt000s2p.eresmas.net/downloads.htm - -RLE code from TrueVision's TGA sample code available as Tgautils.zip at -ftp://ftp.truevision.com/pub/TGA.File.Format.Spec/PC.Version/ - -Jeroen Janssen for creating a Mandrake RPM patch for DevIL. - -Greg Priem for his help with supporting libungif and some various other things. - -Nelson Rush for SDL surface support and finding several bugs with DevIL. - -George McBay for his wonderful help finding bugs in my mipmapping code. - -Marco Kögler for finding bugs in my .jpg and .png code. - -Falco Kleinschmidt for fixing problems with the Linux makefiles. - -Olivier Bucher for finding a bug in saving 8-bit .bmp files. - -Derek Wills for noticing a problem with ilutGLScreenie when the screen width is -not a multiple of 4. - -Dale Schumacher's "Filtered Image Rescaling" code in Graphic Gems III for some -scaling algorithms in ILU. - -Kevin Park for making some suggestions on the ilImage C++ wrapper. - -Alessandro Pedretti for finding a bug in my TIFF code and making suggestions -about portability issues. - -boostrlns from #flipCode for finding the ilutGLLoadImage bug in the 1.1.5 -release. - -Ismo Kärkkäinen (iak@cs.joensuu.fi) for making some really nice new makefiles -for Linux. - -Kishan (http://www.hackorama.com) for the nice directions on how to compile -the external libraries under Linux. - -Wojciech Sobczuk for creating FreeBSD versions of the makefiles. - -nVidia for code to load .DDS files available at -http://www.nvidia.com/view.asp?IO=dxtc_decompression_code - -PixiGreg for noticing that many viewers don't like .bmp files with negative -heights (flipped), even though the specs say that it is valid. - -Matthias Stiller and Andre Normann for their invaluable help with getting -DevIL to work on Big Endian machines. - -Jean-Francois Richard for the Python bindings of DevIL. - -Nick Marley for post-build information in MSVC++. - -Kenneth Hurley for his help in expanding and fixing my DDS code. - -Mark Callow for EXIF-loading and saving code, along with il[Load/Save]FromJpegStruct - -Sam for several fixes to my .bmp and .jpg loaders. - -chris79 for his help debugging my .psp and .gif code in several versions. - -Nick Marley for his MSVC++ post-build fixes. - -Marc Gregoire for sending images that DevIL would not load. - -Alberto Barbati for noticing that the IL_NEU_QUANT_SAMPLE mode wasn't being used properly. - -Ryan Butterfoss for his contributions to the DDS saving code. - -Computer Graphics (C Version) book by Hearn and Baker for the arbitrary polygon filling code. - -Nicolas Weber - -Meloni Dario - -Erick Tryzelaar - -Matej Tyc for completely redoing the Linux makefile system and rewriting the documentation. - -Matevz Tadel for fixing makefile for Scientific Linux. - -Richard Sim for contributing several fixes, especially for .psd loading - -robin_charlton for contributing a patch for Windows BMP support in ILUT. - -Vincent Richomme for DirectX Mobile support - -Antibyte for DDS save bugfix - -Stefan Cornelius, Secunia Research, for finding some buffer overflow vulnerabilities. - -Nico Golde for finding that my fix for the above vulnerability was not totally complete. - -GAIA (Group for Artificial Intelligence Applications) for contributions including .iff-loading -and redoing the ilutConvertToHBitmap code. Their changes are at -http://gaia.fdi.ucm.es/grupo/projects/javy/devzone.html#DevILNotes. - -Jesse Maurais for support of X11 component - - -Translations: -------------- - -Carlos Aragonés, for Spanish translation - -Bart De Lathouwer, for Danish translation - -Osamu Ohara, for English translation - -Abdullah Alshammari, for Arabic translation - -Osamu Ohara, for Japanese translation - -Andreas Stöckel, for German translation - diff --git a/samples/DevIL/ChangeLog b/samples/DevIL/ChangeLog deleted file mode 100644 index eabed1920..000000000 --- a/samples/DevIL/ChangeLog +++ /dev/null @@ -1,604 +0,0 @@ -2009-03-08 MatÄ›j TÃ½Ä - * docs/Makefile.am: Fixed distcheck by overriding dvi target. - * lib/Makefile.am: Renoved ilu_mipmap.h file - * configure.ac: Added option to disable checks for 'nvidia texture tools' and - 'libsquish' - -2009-03-08 Denton Woods - * il_ilbm.c:410: Changed to IL_BGR from IL_RGB. - * il_iff.c (ilLoadIffF/ilLoadIffL): Changed to call Lbm loading functions - if Iff loading fails, since they both can have the .iff extension. - * il_ilbm.c:416: Added origin reference. - * configure.ac: Added more file formats to the format checks. - * Makefile.am: Removed ilu_mipmap.h. Added ilu_error-french.h. - -2009-03-07 Denton Woods - * Updated version numbers to 1.7.8 project-wide. - * DevIL_manual.texi: Added several file formats to the appendix. - * il_io.c: Updated Doxygen comments for loading/saving functions. - * libraries.txt: Updated with new libraries. - * il_io.c (ilTypeFromExt): Changed return value of FITS files to IL_FITS. - Added DICOM, FTX, Rot and Texture checks. - * il_states.c/.h: Updated with newer file formats. - * il_blp.c:649: Fixed ilNewImageFull call to use color index. - 659: Fixed memcpy from base image to new mipmap. - * il_dcx.c, il_exr.cpp and many more: Checks return value of ilFixImage now. - * il_iff.c:271: Got rid of ilConvertImage call. - -2009-03-06 Denton Woods - * Updated VC8 projects to use il_mp3.c. - * il.h: Added description to IL_WDP. - -2009-03-05 Denton Woods - * il_mp3.c: Added this file. - * il_io.c: Added loading calls for .mp3 files. - * il_internal.h: Added .mp3 loading declarations. - * Makefile.am: Added il_mp3.c to source line. - * il.h: Added IL_MP3 define. - -2009-03-04 Denton Woods - * il_utx.cpp: Started cleanup of file using C++ constructs. - * Updated VC8 projects to use il_utx.cpp. - -2009-03-03 Denton Woods - * ilu_error-french.h: Added French translation of errors. - * ilu.h: Added ILU_FRENCH define. - * Changed il_utx.c to il_utx.cpp. - -2009-03-02 Denton Woods - * il_utx.c: Added DXT1 loading in UTX files. - * il_utx.h: Added this file. - * lib/Makefile.am: Added il_utx.h to include line. - * il_utx.c: Fixed loading of larger images. - * windows_example.rc: Fixed accelerator for menu. - -2009-03-01 Denton Woods - * il_utx.c: Added this file. - * lib/Makefile.am: Added il_utx.c to source line. - * il_internal.h: Added .utx loading declarations. - * il_io.c: Added loading calls for .utx files. - -2009-02-28 Denton Woods - * il_states.c / il_states.h: Added ilVtfCompression to IL_STATES. - * il_vtf.c: Added more formats to saving. - * il.h: Added IL_VTF_COMP define. - * il_io.c: Added saving calls for .vtf files. - * il_dds.c: Added DecompressARGB16 to load a2r10g10b10 and a2b10g10r10 formats. - * il_convbuff (iSwitchTypes): Added several missing break statements. - * il_convbuff:1988: Changed to check types instead of bpc. - -2009-02-27 Denton Woods - * il_dpx.c / il_dpx.h: Got basic dpx loading working. - * WindowsTest.cpp: Fixed memory leak when loading files. - * il_vtf.c (iGetVtfHead): Added support for headers of 64 bytes. - * il_iwi.c (iLoadIwiInternal): Added IL_INVALID_FILE_HEADER error. - * il_vtf.c: Added VTF writing functions. - -2009-02-26 Denton Woods - * configure.ac, lib/Makefile.am, il.h, il_internal.h, il_ilbm.c, il_io.c: Added - patch from Ben Campbell for ILBM files at - https://sourceforge.net/tracker2/index.php?func=detail&aid=2635333&group_id=4470&atid=304470. - * il_dpx.c / il_dpx.h: Added these files. - * lib/Makefile.am: Added il_dpx.c and il_dpx.h to source/include lines. - * il_internal.h: Added .dpx loading declarations. - * il_io.c: Added loading calls for .dpx files. - -2009-02-25 Denton Woods - * il_iwi.c:329: Changed IL_MAX parameter from 16 to 8 (copy+paste error). - * WindowsTest.cpp: Added mipmap functionality to 0-9 keys (0 goes to main image). - -2009-02-24 Denton Woods - * vc9 Unicode projects: Changed settings to use x64 and x86 directories for .obj files. - * test/in: Removed this directory. - * Added "Test Images" to SVN. - * il_dds.c (DecompressFloat): Added proper support for G16B16, G32B32, R16 and R32 images. - -2009-02-23 Denton Woods - * il_pnm.c: Fixed bug at https://sourceforge.net/forum/message.php?msg_id=6491617 - - Changed order of lines 448 and 450. - -2009-02-22 Denton Woods - * il_internal.h: Added IL_NO_EXTLIBS define. - * il_dds-save.c: Removed unused variables. - * ilu_mipmap.c: Finished redoing all mipmap functions. - * ilu_mipmap.h: Removed this file. - -2009-02-21 Denton Woods - * ilu_mipmap.c: Redid mipmap functions to use iluScale functions instead of nearest. - -2009-02-20 MatÄ›j TÃ½Ä - * docs/Makefile.am,docs/Devil_manual.texi: Added new ILU images to the - manual, set the manual license to GFDL. - * testil, ilur: Licensed under GPL v3 - -2009-02-19 Denton Woods - * windows_example\resources: Added DevIL Logo.ico, removed OpenIL Logo.ico. - * windows_example\resource.h: Changed to use DevIL Logo.ico. - * il_io.c (ilSaveL): Fixed bug where return type was cast to 1 byte. - -2009-02-18 Denton Woods - * configure.ac: Added descriptions of more image formats. - * il_ftx.c (iLoadFtxInternal): Changed to load all FTX images as RGBA. - -2009-02-17 Denton Woods - * ilu_mipmap.c: Changed all references of Next to Mipmaps to fix bug noticed at - https://sourceforge.net/forum/message.php?msg_id=6443698. - * Added support for IL_NO_GAMES in il_internal.h. - -2009-02-17 MatÄ›j TÃ½Ä - * configure.ac, m4/devil-definitions.m4 (TEST_FORMAT): Added an option - to describe image formats. - -2009-02-16 MatÄ›j TÃ½Ä - * src-ILU/ilur: Made ilur independent on regex.h - * autogen.sh: Simplified autotools invocation to autoreconf only - * configure.ac: Added support for IL_NO_GAMES if users don't want - support for game formats - * docs/DevIL_manual.texi: Fixed errors causing trouble when making - info files + some minor syntax enhancements. - -2009-02-16 Denton Woods - * il_manip.c (ilGetAlpha): Added IL_ALPHA case. - * il_manip.c (ilSetAlpha): Cleaned up formatting. Added IL_ALPHA case. - Fixed casting issue in integer case. - * il_texture.c: Added this file and the simple .texture loading. - * lib/Makefile.am and src-IL/src/Makefile.am: Added il_texture.c to source line. - * il.h: Added IL_TEXTURE define. - * il_internal.h: Added .texture loading declarations. - * DevIL.nb: Removed the test image from the notebook to drop it from over 9MB to 4.5KB. - -2009-02-15 Denton Woods - * il_blp.c (iLoadBlpInternal): Finished testing and fixed BLP2 RAW with 1-bit alpha. - * il_dicom.c: Added this file. - * config.h.win: Added defines for new image formats. - * il_io.c / il_jp2.c: Added .jpx, .j2k and .j2c extensions for JPEG 2000. - * il_io.c / il_jpeg.c: Added .jif and .jfif extensions for JPEG. - * il_dicom.c: Added DICOM loading for uncompressed formats and little endian data. - * lib/Makefile.am and src-IL/src/Makefile.am: Added il_dicom.c to source line. - * il_dicom.c: Added DICOM support for big endian data. - * test/in/tiff: Removed this directory. - * il_rot.c: Added this file. Added .rot loading. - * lib/Makefile.am and src-IL/src/Makefile.am: Added il_rot.c to source line. - * il.h: Added IL_ROT define. - * il_internal.h: Added Rot loading declarations. - -2009-02-15 MatÄ›j TÃ½Ä - * src-ILU/ilur: Added the ilur - commandline ILU frontend - * bin, examples/Makefile.am: Moved examples's Makefile.am to bin - directory. Added ilur to it. - * docs/DevIL_manual.texi: Made slight syntax corrections, fixed the - sample program and added functions index - -2009-02-14 Denton Woods - * il_blp.c (iLoadBlp1): Support for mipmaps added. - * il_gif.h: Moved iCopyPalette declaration out of here into il_internal.h. - * il_gif.c: Moved iCopyPalette definition out of here into il_pal.c. - * projects/Mathematica: Added this folder. - * il_fits.c (iCheckFits): Implemented this. - * il_fits.c (iLoadFitsInternal): Renormalized float and double data. - * il_blp.c (iLoadBlp1): Added seeks to image data (not necessarily following palette). - * il_blp.c (iLoadBlpInternal): Added loading for BLP2 RAW with 1-bit alpha. - -2009-02-13 Denton Woods - * WindowsTest.cpp: Added slideshow capabilities with Page Up and Page Down. - * il_jpeg.c:357: Added ilFixImage call. - * il_jpeg.c (ilLoadFromJpegStruct): Changed return value to the return of ilFixImage. - * il_blp.c:466-467: Fixed to read these images properly. - * WindowsTest Project: Changed x64 debug to use runtime library debug DLLs. - -2009-02-12 Denton Woods - * il_ftx.c: Added this file. - * lib/Makefile.am and src-IL/src/Makefile.am: Added il_ftx.c to source line. - * il_io.c: Added Ftx loading function calls. - * il_blp.c: Added BLP1-loading functions. - -2009-02-11 Denton Woods - * il_jpeg.c (ilSaveJpegL): Changed the itellw call to after iSetOutputLump - (was returning bad values, since the lump was not set yet). - * il_io.c (ilSaveL): Changed return value to Ret and got rid of IL_FALSE check. - * il_bmp.c, il_dds-save.c, il_hdr.c, il_jp2.c, il_pcx.c, il_png.c, il_pnm.c, il_psd.c, il_raw.c, - il_sgi.c, il_wbmp.c: Fixed same problem that il_jpeg.c had with saving lumps. - * il_sgi.c: Put header on file. - * il_iwi.c:337: Removed this line, which called iread a second time for CompData. - -2009-02-10 Denton Woods - * il_io.c: Added ilLoadBlp calls in il_io.c. - * VC9 projects: Turned off x64 incremental linking to prevent debugging problems described here: - http://stackoverflow.com/questions/218747/msvcr90ddll-not-found-in-debug-mode-with-visual-c-2008 - * il_blp.c: Added code to read BLP2 files. - -2009-02-09 Denton Woods - * ilu_scale2d.c (iluScale2DBilinear_): Started rewrite, since results were really ugly. - * il_iwi.c / il_vtf.c: Changed max references to IL_MAX. - * il_wdp.c: Redid all of the code so that it actually works now. - * il_internal.h:42-46: Added lines to define IL_NO_WDP if not in Windows. - * il_io.c: Added Iwi and Fits loading calls. - * il.h: Added IL_BLP and IL_DICOM. Switched IL_DICOM and IL_IWI defines. - * il_internal.h: Added Blp and Dicom function defines. - * il_blp.c: Added this file and started code. - * lib/Makefile.am and src-IL/src/Makefile.am: Added il_blp.c to source line. - -2009-02-09 MatÄ›j TÃ½Ä - * tests/testil.c: Added checks what IL loading/saving routines ended - * build system: Removed --enable-monolithic option. - -2009-02-07/08 Denton Woods - * il_iwi.c: Added this file and code to load .iwi files. - * il_vtf.c (iLoadVtfInternal): Added checks for CompData == NULL. - * il_dds.c/il_dds.h: Changed CompFormat to a local variable. Renamed Decompress to DdsDecompress. - * ChangeLog (this file): Changed order to newest at the top. - * il.h: Added IL_FITS and IL_IWI defines. - * config.h.win: Added IL_FITS, IL_IWI, IL_SUN and IL_TPL. - * lib/Makefile.am and src-IL/src/Makefile.am: Added il_fits.c and il_iwi.c to source line. - - ---- 1.7.7 release --- - -2009-02-06 MatÄ›j TÃ½Ä - * configure.ac, lib/Makefile.am: Added explicit linking with libm - library + fixed the ilut_x11.c file conditions of compilation - * examples/Makefile.am + IL examples, test/Makefile.am + testil: Added - conditional compilation option when compiling only with IL (without - ILU, iluErrorString() absence workaround) - -2009-02-06 Denton Woods - * README.win and README.unix: Updated with Cygwin/MinGW instructions. - -2009-02-05 Denton Woods - * il_tga.c: Fixed bug loading malformed RLE Targa images. - * il_rle.c:20: Changed size_t cast to ILint to resolve compiler warning. - * il.def: Added definitions. - * Updated version numbers to 1.7.7 everywhere. - -2009-02-04 Denton Woods - * ilut_opengl.c:160: Changed checks to see if less than 0. - * il_fits.c: Got this reading FITS files properly. - -2009-02-04 MatÄ›j TÃ½Ä - * configure.ac: Corrected handling of --enable-debug options, added - working install support for pkg-config - * data/Makefile.am, *.pc.in: Corrected pkg-config files - -2009-02-03 Denton Woods - * il_io.c: Updated Doxygen comments. - * il_fits.c: Added this file (not in any projects yet). - * il_fits.c: Wrote beginning of FITS loading code. - -2009-02-02 Denton Woods - * il_manip.c (ilCopyPixels):311: Added check for destination format of color index. - * il_convbuff.c (ilConvertBuffer): Changed to accept the source image palette. Added code to - convert from buffers that are related to a palette before the large switch. - * il_alloc.c (ifree): Changed so that if Ptr == NULL, it does not try to free the pointer. - * il_nvidia.cpp/il_squish.cpp: Added empty functions if nVidia or libsquish support is not - compiled in. - * test/format_test/testil.c:5: Added _USE_MATH_DEFINES. - -2009-02-01 MatÄ›j TÃ½Ä - * test/format_test: Tweaked the script to use wine if cross-compiling - to run the tests, extended testil capabilities - * m4/devil-definitions.m4: Fixed bugs that caused that you couldn't - disable support for some formats no matter what :-) - * m4/devil-api-checks.m4: Added Xrender build support (by Jesse Maurais) - -2009-02-01 Denton Woods - * devil_internal_exports.h: Commented members of ILimage struct using Doxygen-style comments. - Removed deprecated, commented-out members (NumNext, NumLayers, NumMips). - * Updated several functions with appropriate Doxygen comments. - * il.h: Updated IL_XXX file format defines with Doxygen comments. - * ilu_rotate.c: Changed min/max calls to IL_MIN/IL_MAX. - * ilut_states.c (ilutSetInteger): Fixed ILUT_MAXTEX_DEPTH call and added checks around first - three calls for Param >= 1. - -2009-01-31 Denton Woods - * Added newlines to the end of several files to keep gcc quiet. - * Added new MSVC++ projects for examples. - * il_bmp.c:556: Changed to Header->biWidth from iCurImage->Width. iCurImage->Width was not - updated to the new width at this point. - * il_rotate.c (iluRotate_): Rewrote to fix 1 pixel shifting issue. - * Updated DevIL Manual with new ilSaveL information. - * il_stack.c (ilCloseImage): Added missing delete of Faces member. - * il_dds-save.c (ilCompressDXT): Added this function. - * il.h: Removed ilNVidiaCompressDXT and ilSquishCompressDXT - moved to il_internal.h. - * il_dds-save.c:151: Changed to Faces from Images. - * il_dds-save.c (CompressTo565): Added IL_ALPHA case. - * Updated DevIL Manual with new DXTC information. - -2009-01-30 Denton Woods - * Added DevIL.NET to projects folder. - * il_dds.c: Changed Image->Next code for cubemaps to read Image->Faces. Also changed Image->Next - code for mipmaps to read Image->Mipmaps, even further down the chain. - * il_dds.c (ilTexImageDxtc): Added call to ilCloseImage for Image->Faces. - * il_endian.h:113: Fixed bug #2545848 - inline GCC ASM changed. - * ilut_directx9.c (ilutD3D9CubeTexture): Changed ->Next to ->Faces. - * ilut_directx9.c (iD3D9CreateMipmaps): Changed ->Next to ->Mipmaps. - * il_states.c:605: Changed from ->Next to ->Mipmaps. - * il_states.c (iGetActiveNum): Rewrote to not use ->Next pointer for everything. - * il_vtf.c (VtfInitMipmaps): Changed to reflect the new mipmap arrangement as well. - * il_wal.c:141,142: Changed ->Next to ->Mipmaps. - * il_wal.c: Cleaned up the formatting a bit. - * il_stack.c (ilActiveMipmap): Changed ->Next to ->Mipmaps. - * il_stack.c (ilActiveImage/Mipmap/Face/Layer): Added another check for NULL, changed error. - Changed order of statements in for loop. This leads to much much less in the way of - ilSetError calls, since we do not have iCurImage == NULL. - * il_vtf.h:43: Changed to ILuint from ILint. - * il_vtf.c: Changed VtfInitMipmaps calls to VtfInitFacesMipmaps calls and changed iLoadVtfInternal - to support environment maps. - * il.h:384: Added IL_SPHEREMAP. - * il_hdr.c:467: Changed to char* to get OS X to stop issuing a warning. - * il_size.c:53: Changed return value to ILuint. - * devil_cpp_wrapper.hpp: Removed MSVC++ #pragma at the top for deprecated lib. - -2009-01-28 Denton Woods - * il_tpl.c: Added line 219. - -2009-01-27 Denton Woods - * il_bits.c (bseek): Changed check for return values of iseek. - * il_tpl.c: Added support for many more TPL data formats. - * il_tpl.c: Added support for color indexed data formats. - * il_tpl.c: Added support for multiple images in a file. - * il_sdl.c (ilutConvertToSDLSurface): Overhauled this code. - * ilut_opengl.c: Removed iGLSetMaxW/H/D and MaxTexW/H/D. - * ilut_states.h/ilut_states.c: Added MaxTexW/H/D to ILUT_STATES. - * ilut_states.c (ilutGetIntegerv): Added ILUT_MAXTEX_WIDTH/HEIGHT/DEPTH. - -2009-01-26 Denton Woods - * projects/win mobile: Added Windows Mobile projects. - * Removed .cvsignore files from SVN. - * il_bits.c:65: Commented out icloser call. - * include/IL/DevIL.i: Removed IL/ prefix on header filenames. - * include/IL/build-python and build-lua: Updated paths. - * projects folder: Renamed msvc to msvc9. - * il_tpl.c: Added for TPL support. - * il_io.c: Added function calls for TPL support. - * il_internal.h: Added declarations for TPL support. - -2009-01-25 Denton Woods - * ilut_internal.h:63-67: Redid definitions of IL_TEXT to coincide with il_internal.h. - * il_states.c: Updated _ilLoadExt/_ilSaveExt with all extensions. - * il_states.h: Updated with all extensions. - * All image formats with saving: Changed return values of ilSaveXxxF and ilSaveXxxL to be - an integer stating the number of bytes written. This is what ilSaveF/L have been - trying to return all along. - * il_pal.c:1075: Added error condition. - * lib/Makefile.am: Added il_size.c. - * simple.c: Added iluInit call. - * il_dds-save.c (GetAlphaBlock): Applied code from GetBlock, since it was still reading out of bounds. - * il_psd.c (ParseResources):808: Added check for ResourceSize being too small. - 834-837: Added check to insure that we are not copying from past the end of Resource. - * il_hdr.c:527-528: Changed order so that beg_run+run_count is tested first. - * il_psd.c:829: Subtracted an additional 4 for the Size obtained in the lines before. - * il_jp2.c:792-792: Added cleanup code if failure. 676-680: Added call to jas_init. - Added code throughout to prevent from having to initialize Jasper more than once. - * il_internal.h/il_internal.c: Added strdup for Windows CE. - * il_internal.h:105-107: Added so that we do not try to compile inline ASM with Windows Mobile. - -2009-01-24 Denton Woods - * il_internal.h,il_tiff.c: Changed ilSaveTiffL to void* instead of const void*. - * il_tiff.c: Added _tiffFileReadProcW. Changed _tiffFileSeekProc(W) to return the - result of itellw instead of tOff. This allows us to finally overload the TIFF - writing code. - * il_internal.h: Removed #pragma comments, which were commented out anyway. - * il_io.c (ilSaveL): Added call to ilDetermineSize. - * il_size.c: Added this file. - * il_manip.c:14: Removed #include . - * il_jpeg.c:53: Added check for IL_USE_IJL. - * il_exr.cpp:319,329: Changed to write functions instead of read. - * il_files.c: Added iSetOutputFake. - * il_files.c (iSetOutputLump): Added check for NULL to accommodate ilDetermineSize function. - * il_hdr.c:457: Changed from char* to ILbyte*. - * il_icns.h:24,30: Changed from ILbyte to char. - * il_size.c: Added #ifdefs for when user has declared IL_NO_XXX. Changed error to ENUM instead of PARAM. - * Updated MSVC8 projects with il_size.c. - * src-IL/src/Makefile.am: Added il_size.c. - * il_jp2.c: Added ilIsValidJp2* functions. - * il.h: Added ilDetermineType and ilDetermineTypeL to declarations. - * il_io.c: Changed ilDetermineTypeL to be exported. - * il_pcx.c: Formatting issues fixed. - * il_mdl.c: Added ilIsValidJp2* functions. - * il_io.c: Added JP2, MDL and XPM support to ilDetermineType and ilIsValid functions. - * il_icon.c/il_png.c: Renamed color_type to ico_color_type and png_color_type to avoid name conflicts. - * il_iff.c: Changed all malloc->ialloc and free->ifree. Added checks for ialloc failure. - * il_io.c (ilDetermineTypeL): Changed VTF check to return IL_VTF instead of the miscopied IL_SUN. - * il_size.c (ilDetermineSize): Now calls iTargaSize for Targa files. - * il_tga.c: Added iTargaSize. - -2009-01-22 Denton Woods - * ilut_internal.h:66: Changed to compile under Cygwin. - * ilut_opengl.c:108: Replaced _MSC_VER with _WIN32 and _WIN64. - * il_dds-save.c:343: Fixed bug #1067590 - Removed this line, which caused crashes. - * il_pic.c (iLoadPicInternal): Fixed ilTexImage call, moved it after channel information read. - * il_pic.c (readScanline):294-295: Added check for alpha channel. - * il_pic.c: Added ilSetError calls throughout. - * il_sgi.c (iLoadSgiInternal): Fixed bug #1060946 - Removed IL_LUMINANCE_ALPHA filetype. - * WindowsTest.cpp:52,53: Changed border size to accommodate Windows Vista/7. - * il_endian.h:20: Changed to give __BIG_ENDIAN__ a value of 1. The Google cached page of - http://74.125.47.132/search?q=cache:YfSl36C2pAQJ:patch-tracking.debian.net/patch/series/view/devil/1.7.2-1/00_endian_and_ILvoid_fixes.diff+devil+big+endian&hl=en&ct=clnk&cd=11&gl=us&lr=lang_en - has this patch (Nov. 24, 2008 cache). - * devil_internal_exports.h:34: Uncommented and commented line 30. - -2009-01-20 MatÄ›j TÃ½Ä - * test/format_test: Added a program and script as 'make check' target. - Those will test whether IL is capable of saving and loading images and whether the saved and - loaded image is similar to the original. - * configure.ac, lib/Makefile.am: Added support to IFF compilation. - * docs/DevIL_manual.texi: Added missing documentation about getting - image data + fixed some typos. - * include/IL/devil_cpp_wrapper.hpp: Fixed a typo that caused - compilation error - -2009-01-20 Denton Woods - * ilut_opengl.c (ilutGLScreen): Added glPixelStorei call. - * Added il_iff.c from GAIA. - * Added "x64 DLL Install.exe" to SVN. - * il_internal.h: Renamed ilIsValidJpg* functions to ilIsValidJpeg*. Added Iff functions. - * il_io.c: Added checks for Iff-loading. - * ilut_win32.c (ilutConvertSliceToHBitmap): Added better error handling. - * src-IL/src/Makefile.am: Added il_iff.c. - * ilu_rotate.c (iluRotate_): Changed ilResizeImage call. - * Added ilut_config.h. - * ilut.h: Added reference to ilut_config.h for Windows. - * il_files.c/il_icon.c/il_png.c/il_mng.c: Fixed typecasting warnings. - * il_jp2.c/il_wbmp.c (ilSaveJp2L/ilSaveWbmpL): Removed const qualifier. - -2009-01-19 Denton Woods - * il_hdr.c: Changed line 73 to have space for terminating NULL. - * src-IL/src/Makefile.am: Added il_vtf.c and *.cpp files. - * Fixed the MSVC++ 9 solutions pointing to the MSVC++ 8 project files. - * devil_cpp_wrapper.hpp: Updated to use ILconst_string instead of char*. - * il.h: Changed definition of IL_ALPHA to match OpenGL's GL_ALPHA. - * src-IL/include/Makefile.am: Added il_exr.h. - * il_dds.c/il.h: Readded DXT extension code. - * il_internal.h: Added declaration of ilFixCur. - -2009-01-16 Denton Woods - * Updated x64 projects - -2009-01-15 MatÄ›j TÃ½Ä - * il_io.h, include/IL/il.h, il_states.h: Changed some normal strings to constant - strings (in ilSave, ilIsValid and ilGetString) - * configure.ac, lib/Makefile.am: Added wbmp compilation support - * il_jp2.c, il_wbmp.c: Fixed a typo that prevented compilation - * include/IL/devil_cpp_wrapper.hpp: Added a hopefully harmless solution for - the initialization of DevIL. - -2009-01-15 Denton Woods - * il_manip.c / il.h: Added ilClampNTSC function. - * il_squish.cpp: Added file. - * il_dds-save.c: Added line 688. - * il_states.c: Added lines for libsquish support. - * il_dds-save.c (Compress): Added libsquish compression. - * il_io.c (ilDetermineTypeF/L and ilIsValid/F/L): Added VTF, SUN and EXR. - * il_io.c (ilIsValidF/L): Added TIF - * il_jp2.c:131-137: Added these lines to take care of erroneous error generated by JasPer's buffering. - * il_jp2.c: Added functions to save JPEG 2000 images. - * il_utility.c (ilGetBppFormat): Added IL_ALPHA. - * il_jp2.c (iLoadJp2Internal): Added 1 and 2 channel format loading. - * il_dds-save.c:700-701: Changed to IL_RGBA. - * il_dds-save.c (ChooseEndpoints): Changed to use norm squared instead of a sum of the components. - * il_dds-save.c (GetBlock): Changed to copy adjacent data if it goes beyond the bounds of the image. - * il_icon.c: Removed extra whitespace. - * il_icns.c / il_internal.h: Added ilIsValidIcns*. - * il_icns.h: Changed comments on ICNSDATA. - * il_exr.c: Added ilIsValidExr*. - * il_io.c (ilLoadF): Uncommented ilLoadJp2F. - * il_dds-save.c (CompressTo565): Changed 24-bit to 16-bit code based on Charles Bloom's rant. - * il_dds.c (DxtcReadColor/DxtcReadColors): Changed conversion to copy high bits to lowest bits as well. - * il_io.c: Reenabled PhotoCD support. - * il_pcd.c (iLoadPcdInternal): Added check for end-of-file. - * il_exr.c: Added EXR saving functions. - -2009-01-13 Denton Woods - * Converted source repository to SVN from CVS. - -2009-01-12 Denton Woods - * ilut_directx9.c: Cleared up formatting some. - -2009-01-11 Denton Woods - * MSVC9 Unicode projects: Updated to work better in 64-bit Windows. - * il_vtf.c: Removed commented lines 238-242. - * Created application to copy DLL files to the System32 directory. - -2009-01-10 MatÄ›j TÃ½Ä - * m4/devil-definitions.m4, m4/devil-reports.m4: Added a report saying - what libraries were linked with DevIL (should be helpful to packagers - who need to know DevIL dependencies) - * il_endian.h (iGwapUShort/iSwapUInt): Finished fixing bug #2023453 - (inline GCC asm, there was a typo left) - * src_IL/src/il_tiff.c (ilSaveTiff): Fixed a typo that was causing - conflicting declarations error - * configure.ac:264: Added IL_NO_WBMP since the Wbmp loading functions - that are referenced, but not implemented, caused linking errors - -2009-01-09 Denton Woods - * ilut_opengl.h: Moved ILGLCOMPRESSEDTEXIMAGE2DARBPROC typedef out of #ifdefs. - * ilut_opengl.c: Added ilutGLSetTex2D and ilutGLSetTex3D. Changed ilutGLSetTex to - just call ilutGLSetTex2D. Did the same thing for ilutGLSubTex. Added checks for - volume image extensions. Renamed MakeGLCompliant to MakeGLCompliant2D. Added - MakeGLCompliant3D. - * ilut_opengl.c (ilutGLScreen): Added check for ilTexImage failing. - * il_vtf.c (iLoadVtfInternal): Added BGRA4444 support. - * il_alloc.c / ilu_scale.c: Cleaned up formatting some. - * devil_internal_exports.h: Added Faces member to ILimage. - * il_devil.c (iCopySubImages): Added support for faces. - * il_register.c: Added ilRegisterNumFaces. - * il_convert.c (ilFixImage): Added support for faces. - * il_stack.c: Added ilActiveFace. - * ilut_directx9:63,779: Added ILboolean typecast. - * ilut_win32:102: Added ILboolean typecast. - * il_jpeg.c:987: Commented out pragma warning at the end. - * il_mng.c: Added #pragma warning at the top to get rid of redefinition warning when compiling. - * il_nvidia.cpp (ilNVidiaCompressDXT): Added check for Data being NULL. - * ilut_win32.c (ilutConvertSliceToHBitmap): Fixed bug #2496509 - added line 117 and - added DataSize member. - * il_hdr.c (iGetHdrHead): Fixed bug #2496518 - Added check for count. Changed - sscanf to use %2s format specifier to prevent buffer overruns in x and y. - * il_pnm.c (iGetWord): Fixed bug mentioned in #2496518 - igetc was moved back - into the while loop. Added a check for WordPos to prevent buffer overflow. - Restructured the while loop to work properly. - * il_convert.c (iConvertPalette): Changed references of iCurImage to Image. - * il_gif.c (GifGetData): Added DataPtr and changed line 636 to use Data instead of Image->Data. - * il_gif.c (iGetPalette / GetImages): Changed to better deal with local palettes. - -2009-01-08 MatÄ›j TÃ½Ä - * TODO: Added some tasks that I would like to undertake - * ChangeLog, NEWS: Copied old ChangeLog entries to NEWS file - * lib/Makefile.am: Added two new files to the list of IL sources - (il_sun.c, il_nvidia.cpp) - * examples/iller: Made empty files where the ILU frontend will be in - the future. - * configure.ac, m4/devil-reports.m4: Put the report stage of the - configure script to a separate m4 file. - -2009-01-08 Denton Woods - * opengl_example/gltest.c (main): Added iluInit/ilutInit calls. - * ilut_opengl.c (ilutGLFormat): Added IL_ALPHA support. - * il_bmp.c: Minor formatting issues fixed. - * il.h: Added IL_NVIDIA_COMPRESS #define. - * il_states.h: Added ilUseNVidiaDXT to IL_STATES. - * il_state.c: Added IL_NVIDIA_COMPRESS support. - * il_dds-save.c (Compress): Changed to use NVTT if needed. - * il_nvidia.cpp: Added ilNVidiaCompressDXTFile and Depth parameter to ilNVidiaCompressDXT. - -2009-01-06/07 Denton Woods - * Added il_sun.c (Sun Raster file support) - * ilut_opengl.c (ilutGLInit): Changed Linux ilGLCompressed2D pointer casting - to coincide with the old SVN version. - * il_tiff.c / il_alloc.c: Fixed a few pointer casts that were fixed in SVN. - * test/DDrawTest: Fixed extra whitespace in all files in this project. - * il_endian.h (iGwapUShort/iSwapUInt): Fixed bug #2023453 (inline GCC asm). - * ilut_win32.c (ilutConvertSliceToBitmap): Fixed bug #1775036 (definition of buff). - * il_psd.c (PsdGetData): Fixed bug #2219350 (16-bit luminance images not loading properly). - * il_manip.c: Cleared up some minor formatting issues. - * il_png.c (iSavePngInternal): Fixed bug #1680577 (some metadata not written correctly). - * il_nvidia.cpp (ilnVidiaCompressDXT1): Disabled mipmap generation and added code to - ilOutputHandler constructor to determine the proper size of the buffer. - * il.h: Added IL_DXT1A define for nVidia Texture Tools. - * il_nvidia.cpp: Added DXT1a, DXT3 and DXT5 support. Renamed ilnVidiaCompressDXT to - ilnVidiaCompressDXT and added the DxtType parameter. - * il_internal.c: Cleaned up extra whitespace toward end. - -2009-01-02 MatÄ›j TÃ½Ä - * src-{IL,ILU,ILUT}/src/*_internal.c: Hopefully resolved the - HAVE_CONFIG_H thing once for all :-) - * src-IL/src/il_exr.cpp: Undefined OPENEXR_DLL if we are not on - Windows (=> when HAVE_CONFIG_H is not defined) - * src-IL/src/il_io.c:765: Fixed a typo - * src-IL/src/il_vtf.c: Added min and max macros to the beginning - * docs/Devil_manual.texi: Corrected typos and missing @code and other - formatting stuff, corrected image names and incorrect usage of @xref - etc. that prevented compilation - * build setup (Makefile.am and configure.ac): Added support for - compilation of EXR and WDP formats + various other tweaks. - -Up to 2009-01-02 (since 1.7.5 release) Denton Woods - * Readded EXR code. - * Redefined clamping values in il.h. - * Added 64-bit integer types. - * Fixed bug in iRegisterLoad (https://sourceforge.net/forum/message.php?msg_id=5973761). - * Changed seek functions in il_files.c to return ILint. - * Added rpcsal.h and sal.h #includes to ilut.h for DX10. - * Added IL_MAX_QUANT_INDICES to use instead of IL_MAX_QUANT_INDEXS (misspelled). - * Added WBMP support (loading and saving). - * EXR files can now be loaded as file streams and lumps. - * Changed iNeuQuant to take number of colors in palette. - * Compiled MNG support back in. diff --git a/samples/DevIL/DevIL Website.url b/samples/DevIL/DevIL Website.url deleted file mode 100644 index e002d0636..000000000 --- a/samples/DevIL/DevIL Website.url +++ /dev/null @@ -1,5 +0,0 @@ -[InternetShortcut] -URL=http://openil.sf.net/ -IDList= -[{000214A0-0000-0000-C000-000000000046}] -Prop3=19,2 diff --git a/samples/DevIL/Libraries.txt b/samples/DevIL/Libraries.txt deleted file mode 100644 index 727652ade..000000000 --- a/samples/DevIL/Libraries.txt +++ /dev/null @@ -1,40 +0,0 @@ -Libraries needed to compile DevIL* : ----------------------------------- - -(Most of these are optional) - - -Libpng for .png (and some .ico) support available at http://www.libpng.org/pub/png/libpng.html -ZLib for .png (and some .ico) support available at http://www.gzip.org/zlib/ -Libjpeg for .jpg (and some .blp) support from http://www.ijg.org/ -Libtiff for .tif support from http://www.libtiff.org/ -Libmng for .mng and .jng support from http://www.libmng.com/ -JasPer for .jp2 (and some .icns) support available at http://www.ece.uvic.ca/~mdadams/jasper/ -HD Photo Device Porting Kit for .wdp/.hdp support from http://www.microsoft.com/Downloads/details.aspx?FamilyID=285eeffd-d86c-48c3-ab93-3abd5ee7f1ce&displaylang=en. -Little CMS for color profiles (ILU) from http://www.littlecms.com/ -Colour Picker lib for WindowsTest from http://www.fluidstudios.com/freeware.html -Freeglut (or glut) for GLTest from http://freeglut.sourceforge.net -glext.h from http://oss.sgi.com/projects/ogl-sample/ABI/glext.h (as if using OpenGL) -libsquish for DXT compression from http://code.google.com/p/libsquish/ -nVidia Texture Tools for DXT compression from http://developer.nvidia.com/object/nv_texture_tools.html. - -MSVC++ precompiled versions of libpng, zlib, libjpeg, libtiff, lcms and JasPer can be found -at http://openil.sourceforge.net/libs/LibCompiled-vc8.zip or -http://openil.sourceforge.net/libs/LibCompiled-vc9.zip. - -Sources of libpng, zlib, libjpeg, libmng, libungif, libtiff, lcms and JasPer can be -found at http://openil.sourceforge.net/libs/LibSrc.zip - -Intel Jpeg Library from - http://developer.intel.com/software/products/perflib/ijl/index.htm - - -MAC OS X -These library are not still uploaded! -To learn how to install these libraries, read README.macosx - -Source of external framework, downloaded from the previous sites -http://openil.sourceforge.net/libs/ExternFrameworksSrc.sitx - -Complete Compiled Library -http://openil.sourceforge.net/libs/OpenILBin.sitx \ No newline at end of file diff --git a/samples/DevIL/README b/samples/DevIL/README deleted file mode 100644 index a043a64ee..000000000 --- a/samples/DevIL/README +++ /dev/null @@ -1,176 +0,0 @@ -Developer's Image Library version 1.7.8 Readme, Notes and Quick Use -------------------------------------------------------------------- - - DevIL song: "la la la, a cross-platform image library utilizing a - simple syntax to load, save, convert, manipulate, filter and display - a variety of images with ease, la la la" - - -What is it? ------------ - -DevIL is an Open Source image library whose distribution is done under the -terms of the GNU LGPL license. See the COPYING file for more details. -DevIL offers you a simple way to implement loading, manipulating, filtering, -converting, displaying, saving from/to several different image formats in your -own project. - - -Where can I find it? --------------------- - -DevIL can be found at http://openil.sourceforge.net - - -How do I build and install the 3 libraries ? ------------------------------------------ - -*nix users should read README.unix -VisualC users should read README.win -Cygwin users should read README.cygwin -MacOSX users should read README.macosx - -PS: *nix stands for GNU/Linux, *BSD, SunOS/Solaris and perhaps some more. - - -More Extensive Documentation ----------------------------- - -This file is only a quick guide to point you to more detailed information on -how to use DevIL. More extensive documentation can currently be found on the -DevIL site at http://openil.sf.net and in the /Docs directory in a normal -install. - - -Why the hell another image library? ------------------------------------ - -I have never seen an image library that can do everything DevIL does. Sure, -various different libraries can do part of what DevIL can do as well or even -better, but I wanted a simple to use library that encompassed all of these -features. I also wanted an extremely portable image library that could be used -from a variety of languages and utilized the OpenGL syntax. - - -Basic Readme ------------- - -Most anything stated in this document applies to DevIL as well as DevILU and -DevILUT, unless otherwise stated. (This file is best viewed with word wrap on.) - - -Errors: -------- - -All errors generated inside DevIL, along with illegal parameters passed to -DevIL functions are caught and passed to ilSetError(), an internal library -function. The calling program can call ilGetError() to get the value of the -error generated. Error types are defined in il.h, using the 0x501 - 0x5FF -range. ilGetError() will return 0 (IL_NO_ERROR) if no error has occurred. - - -Basic Usage: ------- - -This demonstrates loading an image through DevIL for OpenGL. Don't forget to -call ilInit before you before you do anything: - -#include -#include -#include - -... - -ILuint devilError; - - -ilInit(); - -devilError = ilGetError(); - -if (devilError != IL_NO_ERROR) { - printf ("Devil Error (ilInit: %s\n", iluGetErrorString (devilError)); - exit (2); -} - -.... - -ILuint devilID; - - -ilGenImages(1, &devilID); -ilBindImage(devilID); -ilLoadImage("default1.tga"); // Loads into the current bound image -devilError = ilGetError(); - -if (devilError != IL_NO_ERROR) { - printf ("Devil Error (ilLoadImage: %s\n", iluGetErrorString (devilError)); - exit (2); -} - -.... - -ilutRenderer(IL_OPENGL); // Switch the renderer - -.... - -GLuint openglID, openglError; - - -openglID = ilutGLBindTexImage(); // This generates the texture for you -devilError = ilGetError(); - -if (devilError != IL_NO_ERROR) { - printf ("Error: %s\n", iluGetErrorString (devilError)); - exit (2); -} - -if (openglError != GL_NO_ERROR) { - printf ("Opengl Error (ilutGLBindTexImage): %s\n", gluGetErrorString (openglError)); - exit (2); -} - - - -// Make sure to close the image when you are done with it (though DevIL -// automatically deletes them when the program exits): - -glDeleteTextures(1, &openglID); -ilDeleteImages (1, &devilID); - - -More Examples: ---------- - -The TestIL project is included to test features of DevIL. - -DevIL includes a project called GLTest. This is a simple test of DevIL's -capabilities. All it does it load any image and displays it in a window -created by FreeGlut, which is available on http://freeglut.sourceforge.net. It -is also included to let the user have an idea of what the library can really -be used for. - -Several other test projects are included to test support with various display -APIs. The WindowsTest project is a basic image program that only runs in -Windows right now but showcases several of DevIL's features through various -menus. - -If you want more in-depth tutorials, you can find them on -http://openil.sf.net, or they may be in your installation under the /examples -directory. Documents are also available in the /docs directory. - - -Additional Reading ------------------- - -All image formats used in DevIL have corresponding documents on -http://www.wotsit.org, under the Graphics Files section. These documents -proved invaluable for the creation of this library when there was no library -already available for that image format. - - -Legalese --------- - -All contents of this file are intellectual property of Denton Woods, -copyright 2001-2008. diff --git a/samples/DevIL/README.win b/samples/DevIL/README.win deleted file mode 100644 index 57e3e90eb..000000000 --- a/samples/DevIL/README.win +++ /dev/null @@ -1,44 +0,0 @@ -Where do I find the project files ? ------------------------------------------ - -MSVC++ projects are in DevIL\projects\vc8 and DevIL\projects\vc9. -If compiling with Cygwin or MinGW, use the instructions in README.unix. - - -The IL_NO_XXX #define's: ------------------------- - -A user can recompile this library without complete image support in it. For -example, if your project does not use .jpg files, you can uncomment -#define IL_NO_JPG at the top of il/il.h, recompile the library, and no .jpg -support will be added, meaning quicker compiles and a smaller library. - - -The ILUT_USE_XXX #define's: ---------------------------- - -To disable support for a specific API, edit IL/ilut.h and comment the -corresponding #define. Per example, to disable OpenGL functions support, - add // in front of the line that reads: - -#define ILUT_USE_OPENGL - - -Libraries needed to compile DevIL* : ------------------------------------ - -Libraries.txt (included with the DevIL distribution) lists all libraries needed -to properly compile DevIL. - -Precompiled versions and sources of all libraries needed to compile DevIL are -available at http://openil.sourceforge.net/libs/LibCompiled.zip and -http://openil.sourceforge.net/libs/LibSrc.zip , respectively. - - -Installation: -------------- - -Just unzip and compile other libs included if needed. - -Please also refer to MSVC++.txt for further instructions if you are using -Microsoft Visual C++. diff --git a/samples/DevIL/include/IL/config.h b/samples/DevIL/include/IL/config.h deleted file mode 100644 index 933759038..000000000 --- a/samples/DevIL/include/IL/config.h +++ /dev/null @@ -1,140 +0,0 @@ -/* include/IL/config.h. Generated by configure. */ -/* include/IL/config.h.in. Generated from configure.in by autoheader. */ -#ifndef __CONFIG_H__ -#define __CONFIG_H__ - -#define IL_USE_PRAGMA_LIBS - -// Supported image formats (IL) - -// #define IL_NO_BLP -// #define IL_NO_BMP -// #define IL_NO_CUT -// #define IL_NO_CHEAD -// #define IL_NO_DCX -// #define IL_NO_DDS -// #define IL_NO_DICOM -// #define IL_NO_DOOM -// #define IL_NO_EXR -// #define IL_NO_FITS -// #define IL_NO_FTX -// #define IL_NO_GIF -// #define IL_NO_HDR -// #define IL_NO_ICO -// #define IL_NO_ICNS -// #define IL_NO_IWI -// #define IL_NO_JP2 -// #define IL_NO_JPG -// #define IL_NO_LCMS -// #define IL_NO_LIF -// #define IL_NO_MDL -// #define IL_NO_MNG -// #define IL_NO_PCD -// #define IL_NO_PCX -// #define IL_NO_PIC -// #define IL_NO_PIX -// #define IL_NO_PNG -// #define IL_NO_PNM -// #define IL_NO_PSD -// #define IL_NO_PSP -// #define IL_NO_PXR -// #define IL_NO_RAW -// #define IL_NO_ROT -// #define IL_NO_SGI -// #define IL_NO_SUN -// #define IL_NO_TGA -// #define IL_NO_TIF -// #define IL_NO_TPL -// #define IL_NO_WAL -// #define IL_NO_WDP -// #define IL_NO_XPM -#define IL_USE_JPEGLIB_UNMODIFIED 1 -//#define IL_USE_DXTC_NVIDIA -#define IL_USE_DXTC_SQUISH - -/* Supported api (ilut) */ - - -// -// sorry just -// can't get this one to work under windows -// have disabled for the now -// -// will look at it some more later -// -// Kriss -// -#undef ILUT_USE_ALLEGRO - -#undef ILUT_USE_DIRECTX8 -//#define ILUT_USE_DIRECTX9 -//#define ILUT_USE_DIRECTX10 -//#define ILUT_USE_OPENGL -//#define ILUT_USE_SDL -//#define ILUT_USE_WIN32 - - -/* Define to 1 if you have the header file. */ -//#define HAVE_DLFCN_H 1 - -/* Define to 1 if you have the header file. */ -//#define HAVE_INTTYPES_H 1 - -/* Define to 1 if you have the header file. */ -//#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the header file. */ -//#define HAVE_STDINT_H 1 - -/* Define to 1 if you have the header file. */ -//#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the header file. */ -//#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the header file. */ -//#define HAVE_STRING_H 1 - -/* Define to 1 if you have the header file. */ -//#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the header file. */ -//#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the header file. */ -//#define HAVE_UNISTD_H 1 - -/* Name of package */ -#define IL_PACKAGE "DevIL" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "" - -/* Define to the full name of this package. */ -#define IL_PACKAGE_NAME "" - -/* Define to the full name and version of this package. */ -#define IL_PACKAGE_STRING "" - -/* Define to the one symbol short name of this package. */ -#define IL_PACKAGE_TARNAME "" - -/* Define to the version of this package. */ -#define IL_PACKAGE_VERSION "" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Version number of package */ -//#define IL_VERSION "1.7.3" - -/* Define to 1 if your processor stores words with the most significant byte - first (like Motorola and SPARC, unlike Intel and VAX). */ -/* #undef WORDS_BIGENDIAN */ - -/* If using Mac OS X uncomment this line */ -/* #include "macconfig.h" */ - -/* Define to 1 if the X Window System is missing or not being used. */ -/* #undef X_DISPLAY_MISSING */ -#endif /* __CONFIG_H__ */ diff --git a/samples/DevIL/include/IL/config.h.win b/samples/DevIL/include/IL/config.h.win deleted file mode 100644 index 0090b9b51..000000000 --- a/samples/DevIL/include/IL/config.h.win +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef __CONFIG_H__ -#define __CONFIG_H__ - -#define IL_USE_PRAGMA_LIBS // Links to only the libraries that are requested. -#define IL_INLINE_ASM 1 // Define if you can support at least some ASM - -// Supported images formats (IL) - -// #define IL_NO_BLP -// #define IL_NO_BMP -// #define IL_NO_CUT -// #define IL_NO_CHEAD -// #define IL_NO_DCX -// #define IL_NO_DDS -// #define IL_NO_DICOM -// #define IL_NO_DOOM -// #define IL_NO_EXR -// #define IL_NO_FITS -// #define IL_NO_FTX -// #define IL_NO_GIF -// #define IL_NO_HDR -// #define IL_NO_ICO -// #define IL_NO_ICNS -// #define IL_NO_IWI -// #define IL_NO_JP2 -// #define IL_NO_JPG -// #define IL_NO_LCMS -// #define IL_NO_LIF -// #define IL_NO_MDL -// #define IL_NO_MNG -// #define IL_NO_PCD -// #define IL_NO_PCX -// #define IL_NO_PIC -// #define IL_NO_PIX -// #define IL_NO_PNG -// #define IL_NO_PNM -// #define IL_NO_PSD -// #define IL_NO_PSP -// #define IL_NO_PXR -// #define IL_NO_RAW -// #define IL_NO_ROT -// #define IL_NO_SGI -// #define IL_NO_SUN -// #define IL_NO_TGA -// #define IL_NO_TIF -// #define IL_NO_TPL -// #define IL_NO_WAL -// #define IL_NO_WDP -// #define IL_NO_XPM - -#define IL_USE_JPEGLIB_UNMODIFIED 1 -#define IL_USE_DXTC_NVIDIA -#define IL_USE_DXTC_SQUISH - -//#define IL_NO_GAMES - -/* Supported api (ilut) */ - - -// -// sorry just -// can't get this one to work under windows -// have disabled for the now -// -// will look at it some more later -// -// Kriss -// -#undef ILUT_USE_ALLEGRO - -#undef ILUT_USE_DIRECTX8 -#define ILUT_USE_DIRECTX9 -#define ILUT_USE_DIRECTX10 -#define ILUT_USE_OPENGL -#define ILUT_USE_SDL -#define ILUT_USE_WIN32 - - -#endif /* __CONFIG_H__ */ diff --git a/samples/DevIL/include/IL/devil_internal_exports.h b/samples/DevIL/include/IL/devil_internal_exports.h deleted file mode 100644 index 30b7aaab4..000000000 --- a/samples/DevIL/include/IL/devil_internal_exports.h +++ /dev/null @@ -1,161 +0,0 @@ -//----------------------------------------------------------------------------- -// -// ImageLib Sources -// Copyright (C) 2000-2009 by Denton Woods -// Last modified: 01/06/2009 -// -// Filename: IL/devil_internal_exports.h -// -// Description: Internal stuff for DevIL (IL, ILU and ILUT) -// -//----------------------------------------------------------------------------- - -#ifndef IL_EXPORTS_H -#define IL_EXPORTS_H - -#include "IL/il.h" - -#ifdef DEBUG - #include -#else - #define assert(x) -#endif - -//#ifndef NOINLINE -#ifndef INLINE -#if defined(__GNUC__) - #define INLINE extern inline -#elif defined(_MSC_VER) //@TODO: Get this working in MSVC++. - // http://www.greenend.org.uk/rjk/2003/03/inline.html - #define NOINLINE - //#define INLINE - /*#ifndef _WIN64 // Cannot use inline assembly in x64 target platform. - #define USE_WIN32_ASM - #endif//_WIN64*/ - #define INLINE __inline -#else - #define INLINE inline -#endif -#endif -//#else -//#define INLINE -//#endif //NOINLINE - -#ifdef __cplusplus -extern "C" { -#endif - -#define IL_MAX(a,b) (((a) > (b)) ? (a) : (b)) -#define IL_MIN(a,b) (((a) < (b)) ? (a) : (b)) - - -//! Basic Palette struct -typedef struct ILpal -{ - ILubyte* Palette; //!< the image palette (if any) - ILuint PalSize; //!< size of the palette (in bytes) - ILenum PalType; //!< the palette types in il.h (0x0500 range) -} ILpal; - - -//! The Fundamental Image structure -/*! Every bit of information about an image is stored in this internal structure.*/ -typedef struct ILimage -{ - ILuint Width; //!< the image's width - ILuint Height; //!< the image's height - ILuint Depth; //!< the image's depth - ILubyte Bpp; //!< bytes per pixel (now number of channels) - ILubyte Bpc; //!< bytes per channel - ILuint Bps; //!< bytes per scanline (components for IL) - ILubyte* Data; //!< the image data - ILuint SizeOfData; //!< the total size of the data (in bytes) - ILuint SizeOfPlane; //!< SizeOfData in a 2d image, size of each plane slice in a 3d image (in bytes) - ILenum Format; //!< image format (in IL enum style) - ILenum Type; //!< image type (in IL enum style) - ILenum Origin; //!< origin of the image - ILpal Pal; //!< palette details - ILuint Duration; //!< length of the time to display this "frame" - ILenum CubeFlags; //!< cube map flags for sides present in chain - struct ILimage* Mipmaps; //!< mipmapped versions of this image terminated by a NULL - usu. NULL - struct ILimage* Next; //!< next image in the chain - usu. NULL - struct ILimage* Faces; //!< next cubemap face in the chain - usu. NULL - struct ILimage* Layers; //!< subsequent layers in the chain - usu. NULL - ILuint* AnimList; //!< animation list - ILuint AnimSize; //!< animation list size - void* Profile; //!< colour profile - ILuint ProfileSize; //!< colour profile size - ILuint OffX; //!< x-offset of the image - ILuint OffY; //!< y-offset of the image - ILubyte* DxtcData; //!< compressed data - ILenum DxtcFormat; //!< compressed data format - ILuint DxtcSize; //!< compressed data size -} ILimage; - - -// Memory functions -ILAPI void* ILAPIENTRY ialloc(const ILsizei Size); -ILAPI void ILAPIENTRY ifree(const void *Ptr); -ILAPI void* ILAPIENTRY icalloc(const ILsizei Size, const ILsizei Num); -#ifdef ALTIVEC_GCC -ILAPI void* ILAPIENTRY ivec_align_buffer(void *buffer, const ILuint size); -#endif - -// Internal library functions in IL -ILAPI ILimage* ILAPIENTRY ilGetCurImage(void); -ILAPI void ILAPIENTRY ilSetCurImage(ILimage *Image); -ILAPI void ILAPIENTRY ilSetError(ILenum Error); -ILAPI void ILAPIENTRY ilSetPal(ILpal *Pal); - -// -// Utility functions -// -ILAPI ILubyte ILAPIENTRY ilGetBppFormat(ILenum Format); -ILAPI ILenum ILAPIENTRY ilGetFormatBpp(ILubyte Bpp); -ILAPI ILubyte ILAPIENTRY ilGetBpcType(ILenum Type); -ILAPI ILenum ILAPIENTRY ilGetTypeBpc(ILubyte Bpc); -ILAPI ILubyte ILAPIENTRY ilGetBppPal(ILenum PalType); -ILAPI ILenum ILAPIENTRY ilGetPalBaseType(ILenum PalType); -ILAPI ILuint ILAPIENTRY ilNextPower2(ILuint Num); -ILAPI ILenum ILAPIENTRY ilTypeFromExt(ILconst_string FileName); -ILAPI void ILAPIENTRY ilReplaceCurImage(ILimage *Image); -ILAPI void ILAPIENTRY iMemSwap(ILubyte *, ILubyte *, const ILuint); - -// -// Image functions -// -ILAPI void ILAPIENTRY iBindImageTemp (void); -ILAPI ILboolean ILAPIENTRY ilClearImage_ (ILimage *Image); -ILAPI void ILAPIENTRY ilCloseImage (ILimage *Image); -ILAPI void ILAPIENTRY ilClosePal (ILpal *Palette); -ILAPI ILpal* ILAPIENTRY iCopyPal (void); -ILAPI ILboolean ILAPIENTRY ilCopyImageAttr (ILimage *Dest, ILimage *Src); -ILAPI ILimage* ILAPIENTRY ilCopyImage_ (ILimage *Src); -ILAPI void ILAPIENTRY ilGetClear (void *Colours, ILenum Format, ILenum Type); -ILAPI ILuint ILAPIENTRY ilGetCurName (void); -ILAPI ILboolean ILAPIENTRY ilIsValidPal (ILpal *Palette); -ILAPI ILimage* ILAPIENTRY ilNewImage (ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILubyte Bpc); -ILAPI ILimage* ILAPIENTRY ilNewImageFull (ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILenum Format, ILenum Type, void *Data); -ILAPI ILboolean ILAPIENTRY ilInitImage (ILimage *Image, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILenum Format, ILenum Type, void *Data); -ILAPI ILboolean ILAPIENTRY ilResizeImage (ILimage *Image, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILubyte Bpc); -ILAPI ILboolean ILAPIENTRY ilTexImage_ (ILimage *Image, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILenum Format, ILenum Type, void *Data); -ILAPI ILboolean ILAPIENTRY ilTexSubImage_ (ILimage *Image, void *Data); -ILAPI void* ILAPIENTRY ilConvertBuffer (ILuint SizeOfData, ILenum SrcFormat, ILenum DestFormat, ILenum SrcType, ILenum DestType, ILpal *SrcPal, void *Buffer); -ILAPI ILimage* ILAPIENTRY iConvertImage (ILimage *Image, ILenum DestFormat, ILenum DestType); -ILAPI ILpal* ILAPIENTRY iConvertPal (ILpal *Pal, ILenum DestFormat); -ILAPI ILubyte* ILAPIENTRY iGetFlipped (ILimage *Image); -ILAPI ILboolean ILAPIENTRY iMirror(); -ILAPI void ILAPIENTRY iFlipBuffer(ILubyte *buff, ILuint depth, ILuint line_size, ILuint line_num); -ILubyte* iFlipNewBuffer(ILubyte *buff, ILuint depth, ILuint line_size, ILuint line_num); -ILAPI void ILAPIENTRY iGetIntegervImage(ILimage *Image, ILenum Mode, ILint *Param); - -// Internal library functions in ILU -ILAPI ILimage* ILAPIENTRY iluRotate_(ILimage *Image, ILfloat Angle); -ILAPI ILimage* ILAPIENTRY iluRotate3D_(ILimage *Image, ILfloat x, ILfloat y, ILfloat z, ILfloat Angle); -ILAPI ILimage* ILAPIENTRY iluScale_(ILimage *Image, ILuint Width, ILuint Height, ILuint Depth); - -#ifdef __cplusplus -} -#endif - -#endif//IL_EXPORTS_H diff --git a/samples/DevIL/include/IL/il.h b/samples/DevIL/include/IL/il.h deleted file mode 100644 index 540a56eb3..000000000 --- a/samples/DevIL/include/IL/il.h +++ /dev/null @@ -1,644 +0,0 @@ -//----------------------------------------------------------------------------- -// -// ImageLib Sources -// Copyright (C) 2000-2009 by Denton Woods -// Last modified: 03/07/2009 -// -// Filename: IL/il.h -// -// Description: The main include file for DevIL -// -//----------------------------------------------------------------------------- - -// Doxygen comment -/*! \file il.h - The main include file for DevIL -*/ - -#ifndef __il_h_ -#ifndef __IL_H__ - -#define __il_h_ -#define __IL_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -//this define controls if floats and doubles are clampled to [0..1] -//during conversion. It takes a little more time, but it is the correct -//way of doing this. If you are sure your floats are always valid, -//you can undefine this value... -#define CLAMP_HALF 1 -#define CLAMP_FLOATS 1 -#define CLAMP_DOUBLES 1 - -/*#ifdef _WIN32_WCE - #define IL_NO_EXR - #define IL_NO_GIF - #define IL_NO_JP2 - #define IL_NO_JPG - #define IL_NO_MNG - #define IL_NO_PNG - #define IL_NO_TIF - #define IL_NO_LCMS -#endif //_WIN32_WCE - -#ifdef DJGPP - #define IL_NO_EXR - #define IL_NO_GIF - #define IL_NO_JP2 - #define IL_NO_JPG - #define IL_NO_MNG - #define IL_NO_PNG - #define IL_NO_TIF - #define IL_NO_LCMS -#endif //DJGPP*/ - -#ifdef _WIN32 - #if (defined(IL_USE_PRAGMA_LIBS)) && (!defined(_IL_BUILD_LIBRARY)) - #if defined(_MSC_VER) || defined(__BORLANDC__) - #pragma comment(lib, "DevIL.lib") - #endif - #endif -#endif - -#ifdef RESTRICT_KEYWORD -#define RESTRICT restrict -#define CONST_RESTRICT const restrict -#else -#define RESTRICT -#define CONST_RESTRICT const -#endif - -#include - -typedef unsigned int ILenum; -typedef unsigned char ILboolean; -typedef unsigned int ILbitfield; -typedef signed char ILbyte; -typedef signed short ILshort; -typedef int ILint; -typedef size_t ILsizei; -typedef unsigned char ILubyte; -typedef unsigned short ILushort; -typedef unsigned int ILuint; -typedef float ILfloat; -typedef float ILclampf; -typedef double ILdouble; -typedef double ILclampd; - -#ifdef _MSC_VER -typedef __int64 ILint64; -typedef unsigned __int64 ILuint64; -#else -typedef long long int ILint64; -typedef long long unsigned int ILuint64; -#endif - - -#include -#ifdef _UNICODE - #ifndef _WIN32_WCE - #include - #endif - //if we use a define instead of a typedef, - //ILconst_string works as intended - #define ILchar wchar_t - #define ILstring wchar_t* - #define ILconst_string wchar_t const * -#else - //if we use a define instead of a typedef, - //ILconst_string works as intended - #define ILchar char - #define ILstring char* - #define ILconst_string char const * -#endif //_UNICODE - -#define IL_FALSE 0 -#define IL_TRUE 1 - -// Matches OpenGL's right now. -//! Data formats \link Formats Formats\endlink -#define IL_COLOUR_INDEX 0x1900 -#define IL_COLOR_INDEX 0x1900 -#define IL_ALPHA 0x1906 -#define IL_RGB 0x1907 -#define IL_RGBA 0x1908 -#define IL_BGR 0x80E0 -#define IL_BGRA 0x80E1 -#define IL_LUMINANCE 0x1909 -#define IL_LUMINANCE_ALPHA 0x190A - -//! Data types \link Types Types\endlink -#define IL_BYTE 0x1400 -#define IL_UNSIGNED_BYTE 0x1401 -#define IL_SHORT 0x1402 -#define IL_UNSIGNED_SHORT 0x1403 -#define IL_INT 0x1404 -#define IL_UNSIGNED_INT 0x1405 -#define IL_FLOAT 0x1406 -#define IL_DOUBLE 0x140A -#define IL_HALF 0x140B - - -#define IL_MAX_BYTE SCHAR_MAX -#define IL_MAX_UNSIGNED_BYTE UCHAR_MAX -#define IL_MAX_SHORT SHRT_MAX -#define IL_MAX_UNSIGNED_SHORT USHRT_MAX -#define IL_MAX_INT INT_MAX -#define IL_MAX_UNSIGNED_INT UINT_MAX - -#define IL_LIMIT(x,m,M) (xM?M:x)) -#define IL_CLAMP(x) IL_LIMIT(x,0,1) - -#define IL_VENDOR 0x1F00 -#define IL_LOAD_EXT 0x1F01 -#define IL_SAVE_EXT 0x1F02 - - -// -// IL-specific #define's -// - -#define IL_VERSION_1_7_8 1 -#define IL_VERSION 178 - - -// Attribute Bits -#define IL_ORIGIN_BIT 0x00000001 -#define IL_FILE_BIT 0x00000002 -#define IL_PAL_BIT 0x00000004 -#define IL_FORMAT_BIT 0x00000008 -#define IL_TYPE_BIT 0x00000010 -#define IL_COMPRESS_BIT 0x00000020 -#define IL_LOADFAIL_BIT 0x00000040 -#define IL_FORMAT_SPECIFIC_BIT 0x00000080 -#define IL_ALL_ATTRIB_BITS 0x000FFFFF - - -// Palette types -#define IL_PAL_NONE 0x0400 -#define IL_PAL_RGB24 0x0401 -#define IL_PAL_RGB32 0x0402 -#define IL_PAL_RGBA32 0x0403 -#define IL_PAL_BGR24 0x0404 -#define IL_PAL_BGR32 0x0405 -#define IL_PAL_BGRA32 0x0406 - - -// Image types -#define IL_TYPE_UNKNOWN 0x0000 -#define IL_BMP 0x0420 //!< Microsoft Windows Bitmap - .bmp extension -#define IL_CUT 0x0421 //!< Dr. Halo - .cut extension -#define IL_DOOM 0x0422 //!< DooM walls - no specific extension -#define IL_DOOM_FLAT 0x0423 //!< DooM flats - no specific extension -#define IL_ICO 0x0424 //!< Microsoft Windows Icons and Cursors - .ico and .cur extensions -#define IL_JPG 0x0425 //!< JPEG - .jpg, .jpe and .jpeg extensions -#define IL_JFIF 0x0425 //!< -#define IL_ILBM 0x0426 //!< Amiga IFF (FORM ILBM) - .iff, .ilbm, .lbm extensions -#define IL_PCD 0x0427 //!< Kodak PhotoCD - .pcd extension -#define IL_PCX 0x0428 //!< ZSoft PCX - .pcx extension -#define IL_PIC 0x0429 //!< PIC - .pic extension -#define IL_PNG 0x042A //!< Portable Network Graphics - .png extension -#define IL_PNM 0x042B //!< Portable Any Map - .pbm, .pgm, .ppm and .pnm extensions -#define IL_SGI 0x042C //!< Silicon Graphics - .sgi, .bw, .rgb and .rgba extensions -#define IL_TGA 0x042D //!< TrueVision Targa File - .tga, .vda, .icb and .vst extensions -#define IL_TIF 0x042E //!< Tagged Image File Format - .tif and .tiff extensions -#define IL_CHEAD 0x042F //!< C-Style Header - .h extension -#define IL_RAW 0x0430 //!< Raw Image Data - any extension -#define IL_MDL 0x0431 //!< Half-Life Model Texture - .mdl extension -#define IL_WAL 0x0432 //!< Quake 2 Texture - .wal extension -#define IL_LIF 0x0434 //!< Homeworld Texture - .lif extension -#define IL_MNG 0x0435 //!< Multiple-image Network Graphics - .mng extension -#define IL_JNG 0x0435 //!< -#define IL_GIF 0x0436 //!< Graphics Interchange Format - .gif extension -#define IL_DDS 0x0437 //!< DirectDraw Surface - .dds extension -#define IL_DCX 0x0438 //!< ZSoft Multi-PCX - .dcx extension -#define IL_PSD 0x0439 //!< Adobe PhotoShop - .psd extension -#define IL_EXIF 0x043A //!< -#define IL_PSP 0x043B //!< PaintShop Pro - .psp extension -#define IL_PIX 0x043C //!< PIX - .pix extension -#define IL_PXR 0x043D //!< Pixar - .pxr extension -#define IL_XPM 0x043E //!< X Pixel Map - .xpm extension -#define IL_HDR 0x043F //!< Radiance High Dynamic Range - .hdr extension -#define IL_ICNS 0x0440 //!< Macintosh Icon - .icns extension -#define IL_JP2 0x0441 //!< Jpeg 2000 - .jp2 extension -#define IL_EXR 0x0442 //!< OpenEXR - .exr extension -#define IL_WDP 0x0443 //!< Microsoft HD Photo - .wdp and .hdp extension -#define IL_VTF 0x0444 //!< Valve Texture Format - .vtf extension -#define IL_WBMP 0x0445 //!< Wireless Bitmap - .wbmp extension -#define IL_SUN 0x0446 //!< Sun Raster - .sun, .ras, .rs, .im1, .im8, .im24 and .im32 extensions -#define IL_IFF 0x0447 //!< Interchange File Format - .iff extension -#define IL_TPL 0x0448 //!< Gamecube Texture - .tpl extension -#define IL_FITS 0x0449 //!< Flexible Image Transport System - .fit and .fits extensions -#define IL_DICOM 0x044A //!< Digital Imaging and Communications in Medicine (DICOM) - .dcm and .dicom extensions -#define IL_IWI 0x044B //!< Call of Duty Infinity Ward Image - .iwi extension -#define IL_BLP 0x044C //!< Blizzard Texture Format - .blp extension -#define IL_FTX 0x044D //!< Heavy Metal: FAKK2 Texture - .ftx extension -#define IL_ROT 0x044E //!< Homeworld 2 - Relic Texture - .rot extension -#define IL_TEXTURE 0x044F //!< Medieval II: Total War Texture - .texture extension -#define IL_DPX 0x0450 //!< Digital Picture Exchange - .dpx extension -#define IL_UTX 0x0451 //!< Unreal (and Unreal Tournament) Texture - .utx extension -#define IL_MP3 0x0452 //!< MPEG-1 Audio Layer 3 - .mp3 extension - - -#define IL_JASC_PAL 0x0475 //!< PaintShop Pro Palette - - -// Error Types -#define IL_NO_ERROR 0x0000 -#define IL_INVALID_ENUM 0x0501 -#define IL_OUT_OF_MEMORY 0x0502 -#define IL_FORMAT_NOT_SUPPORTED 0x0503 -#define IL_INTERNAL_ERROR 0x0504 -#define IL_INVALID_VALUE 0x0505 -#define IL_ILLEGAL_OPERATION 0x0506 -#define IL_ILLEGAL_FILE_VALUE 0x0507 -#define IL_INVALID_FILE_HEADER 0x0508 -#define IL_INVALID_PARAM 0x0509 -#define IL_COULD_NOT_OPEN_FILE 0x050A -#define IL_INVALID_EXTENSION 0x050B -#define IL_FILE_ALREADY_EXISTS 0x050C -#define IL_OUT_FORMAT_SAME 0x050D -#define IL_STACK_OVERFLOW 0x050E -#define IL_STACK_UNDERFLOW 0x050F -#define IL_INVALID_CONVERSION 0x0510 -#define IL_BAD_DIMENSIONS 0x0511 -#define IL_FILE_READ_ERROR 0x0512 // 05/12/2002: Addition by Sam. -#define IL_FILE_WRITE_ERROR 0x0512 - -#define IL_LIB_GIF_ERROR 0x05E1 -#define IL_LIB_JPEG_ERROR 0x05E2 -#define IL_LIB_PNG_ERROR 0x05E3 -#define IL_LIB_TIFF_ERROR 0x05E4 -#define IL_LIB_MNG_ERROR 0x05E5 -#define IL_LIB_JP2_ERROR 0x05E6 -#define IL_LIB_EXR_ERROR 0x05E7 -#define IL_UNKNOWN_ERROR 0x05FF - - -// Origin Definitions -#define IL_ORIGIN_SET 0x0600 -#define IL_ORIGIN_LOWER_LEFT 0x0601 -#define IL_ORIGIN_UPPER_LEFT 0x0602 -#define IL_ORIGIN_MODE 0x0603 - - -// Format and Type Mode Definitions -#define IL_FORMAT_SET 0x0610 -#define IL_FORMAT_MODE 0x0611 -#define IL_TYPE_SET 0x0612 -#define IL_TYPE_MODE 0x0613 - - -// File definitions -#define IL_FILE_OVERWRITE 0x0620 -#define IL_FILE_MODE 0x0621 - - -// Palette definitions -#define IL_CONV_PAL 0x0630 - - -// Load fail definitions -#define IL_DEFAULT_ON_FAIL 0x0632 - - -// Key colour and alpha definitions -#define IL_USE_KEY_COLOUR 0x0635 -#define IL_USE_KEY_COLOR 0x0635 -#define IL_BLIT_BLEND 0x0636 - - -// Interlace definitions -#define IL_SAVE_INTERLACED 0x0639 -#define IL_INTERLACE_MODE 0x063A - - -// Quantization definitions -#define IL_QUANTIZATION_MODE 0x0640 -#define IL_WU_QUANT 0x0641 -#define IL_NEU_QUANT 0x0642 -#define IL_NEU_QUANT_SAMPLE 0x0643 -#define IL_MAX_QUANT_INDEXS 0x0644 //XIX : ILint : Maximum number of colors to reduce to, default of 256. and has a range of 2-256 -#define IL_MAX_QUANT_INDICES 0x0644 // Redefined, since the above #define is misspelled - - -// Hints -#define IL_FASTEST 0x0660 -#define IL_LESS_MEM 0x0661 -#define IL_DONT_CARE 0x0662 -#define IL_MEM_SPEED_HINT 0x0665 -#define IL_USE_COMPRESSION 0x0666 -#define IL_NO_COMPRESSION 0x0667 -#define IL_COMPRESSION_HINT 0x0668 - - -// Compression -#define IL_NVIDIA_COMPRESS 0x0670 -#define IL_SQUISH_COMPRESS 0x0671 - - -// Subimage types -#define IL_SUB_NEXT 0x0680 -#define IL_SUB_MIPMAP 0x0681 -#define IL_SUB_LAYER 0x0682 - - -// Compression definitions -#define IL_COMPRESS_MODE 0x0700 -#define IL_COMPRESS_NONE 0x0701 -#define IL_COMPRESS_RLE 0x0702 -#define IL_COMPRESS_LZO 0x0703 -#define IL_COMPRESS_ZLIB 0x0704 - - -// File format-specific values -#define IL_TGA_CREATE_STAMP 0x0710 -#define IL_JPG_QUALITY 0x0711 -#define IL_PNG_INTERLACE 0x0712 -#define IL_TGA_RLE 0x0713 -#define IL_BMP_RLE 0x0714 -#define IL_SGI_RLE 0x0715 -#define IL_TGA_ID_STRING 0x0717 -#define IL_TGA_AUTHNAME_STRING 0x0718 -#define IL_TGA_AUTHCOMMENT_STRING 0x0719 -#define IL_PNG_AUTHNAME_STRING 0x071A -#define IL_PNG_TITLE_STRING 0x071B -#define IL_PNG_DESCRIPTION_STRING 0x071C -#define IL_TIF_DESCRIPTION_STRING 0x071D -#define IL_TIF_HOSTCOMPUTER_STRING 0x071E -#define IL_TIF_DOCUMENTNAME_STRING 0x071F -#define IL_TIF_AUTHNAME_STRING 0x0720 -#define IL_JPG_SAVE_FORMAT 0x0721 -#define IL_CHEAD_HEADER_STRING 0x0722 -#define IL_PCD_PICNUM 0x0723 -#define IL_PNG_ALPHA_INDEX 0x0724 //XIX : ILint : the color in the palette at this index value (0-255) is considered transparent, -1 for no trasparent color -#define IL_JPG_PROGRESSIVE 0x0725 -#define IL_VTF_COMP 0x0726 - - -// DXTC definitions -#define IL_DXTC_FORMAT 0x0705 -#define IL_DXT1 0x0706 -#define IL_DXT2 0x0707 -#define IL_DXT3 0x0708 -#define IL_DXT4 0x0709 -#define IL_DXT5 0x070A -#define IL_DXT_NO_COMP 0x070B -#define IL_KEEP_DXTC_DATA 0x070C -#define IL_DXTC_DATA_FORMAT 0x070D -#define IL_3DC 0x070E -#define IL_RXGB 0x070F -#define IL_ATI1N 0x0710 -#define IL_DXT1A 0x0711 // Normally the same as IL_DXT1, except for nVidia Texture Tools. - -// Environment map definitions -#define IL_CUBEMAP_POSITIVEX 0x00000400 -#define IL_CUBEMAP_NEGATIVEX 0x00000800 -#define IL_CUBEMAP_POSITIVEY 0x00001000 -#define IL_CUBEMAP_NEGATIVEY 0x00002000 -#define IL_CUBEMAP_POSITIVEZ 0x00004000 -#define IL_CUBEMAP_NEGATIVEZ 0x00008000 -#define IL_SPHEREMAP 0x00010000 - - -// Values -#define IL_VERSION_NUM 0x0DE2 -#define IL_IMAGE_WIDTH 0x0DE4 -#define IL_IMAGE_HEIGHT 0x0DE5 -#define IL_IMAGE_DEPTH 0x0DE6 -#define IL_IMAGE_SIZE_OF_DATA 0x0DE7 -#define IL_IMAGE_BPP 0x0DE8 -#define IL_IMAGE_BYTES_PER_PIXEL 0x0DE8 -#define IL_IMAGE_BPP 0x0DE8 -#define IL_IMAGE_BITS_PER_PIXEL 0x0DE9 -#define IL_IMAGE_FORMAT 0x0DEA -#define IL_IMAGE_TYPE 0x0DEB -#define IL_PALETTE_TYPE 0x0DEC -#define IL_PALETTE_SIZE 0x0DED -#define IL_PALETTE_BPP 0x0DEE -#define IL_PALETTE_NUM_COLS 0x0DEF -#define IL_PALETTE_BASE_TYPE 0x0DF0 -#define IL_NUM_FACES 0x0DE1 -#define IL_NUM_IMAGES 0x0DF1 -#define IL_NUM_MIPMAPS 0x0DF2 -#define IL_NUM_LAYERS 0x0DF3 -#define IL_ACTIVE_IMAGE 0x0DF4 -#define IL_ACTIVE_MIPMAP 0x0DF5 -#define IL_ACTIVE_LAYER 0x0DF6 -#define IL_ACTIVE_FACE 0x0E00 -#define IL_CUR_IMAGE 0x0DF7 -#define IL_IMAGE_DURATION 0x0DF8 -#define IL_IMAGE_PLANESIZE 0x0DF9 -#define IL_IMAGE_BPC 0x0DFA -#define IL_IMAGE_OFFX 0x0DFB -#define IL_IMAGE_OFFY 0x0DFC -#define IL_IMAGE_CUBEFLAGS 0x0DFD -#define IL_IMAGE_ORIGIN 0x0DFE -#define IL_IMAGE_CHANNELS 0x0DFF - -# if defined __GNUC__ && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0)) -// __attribute__((deprecated)) is supported by GCC 3.1 and later. -# define DEPRECATED(D) D __attribute__((deprecated)) -# elif defined _MSC_VER && _MSC_VER >= 1300 -// __declspec(deprecated) is supported by MSVC 7.0 and later. -# define DEPRECATED(D) __declspec(deprecated) D -# else -# define DEPRECATED (D) D -# endif - -// -// Section shamelessly modified from the glut header. -// - -// This is from Win32's -#if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) || defined(__BORLANDC__) || defined(__LCC__) - #define ILAPIENTRY __stdcall - #define IL_PACKSTRUCT -//#elif defined(linux) || defined(MACOSX) || defined(__CYGWIN__) //fix bug 840364 -#elif defined( __GNUC__ ) - // this should work for any of the above commented platforms - // plus any platform using GCC - #ifdef __MINGW32__ - #define ILAPIENTRY __stdcall - #else - #define ILAPIENTRY - #endif - #define IL_PACKSTRUCT __attribute__ ((packed)) -#else - #define ILAPIENTRY - #define IL_PACKSTRUCT -#endif - -// This is from Win32's and -#if defined(__LCC__) - #define ILAPI __stdcall -#elif defined(_WIN32) //changed 20031221 to fix bug 840421 - #ifdef IL_STATIC_LIB - #define ILAPI - #else - #ifdef _IL_BUILD_LIBRARY - #define ILAPI __declspec(dllexport) - #else - #define ILAPI __declspec(dllimport) - #endif - #endif -#elif __APPLE__ - #define ILAPI extern -#else - #define ILAPI -#endif - - -#define IL_SEEK_SET 0 -#define IL_SEEK_CUR 1 -#define IL_SEEK_END 2 -#define IL_EOF -1 - - -// Callback functions for file reading -typedef void* ILHANDLE; -typedef void (ILAPIENTRY *fCloseRProc)(ILHANDLE); -typedef ILboolean (ILAPIENTRY *fEofProc) (ILHANDLE); -typedef ILint (ILAPIENTRY *fGetcProc) (ILHANDLE); -typedef ILHANDLE (ILAPIENTRY *fOpenRProc) (ILconst_string); -typedef ILint (ILAPIENTRY *fReadProc) (void*, ILuint, ILuint, ILHANDLE); -typedef ILint (ILAPIENTRY *fSeekRProc) (ILHANDLE, ILint, ILint); -typedef ILint (ILAPIENTRY *fTellRProc) (ILHANDLE); - -// Callback functions for file writing -typedef void (ILAPIENTRY *fCloseWProc)(ILHANDLE); -typedef ILHANDLE (ILAPIENTRY *fOpenWProc) (ILconst_string); -typedef ILint (ILAPIENTRY *fPutcProc) (ILubyte, ILHANDLE); -typedef ILint (ILAPIENTRY *fSeekWProc) (ILHANDLE, ILint, ILint); -typedef ILint (ILAPIENTRY *fTellWProc) (ILHANDLE); -typedef ILint (ILAPIENTRY *fWriteProc) (const void*, ILuint, ILuint, ILHANDLE); - -// Callback functions for allocation and deallocation -typedef void* (ILAPIENTRY *mAlloc)(const ILsizei); -typedef void (ILAPIENTRY *mFree) (const void* CONST_RESTRICT); - -// Registered format procedures -typedef ILenum (ILAPIENTRY *IL_LOADPROC)(ILconst_string); -typedef ILenum (ILAPIENTRY *IL_SAVEPROC)(ILconst_string); - - -// ImageLib Functions -ILAPI ILboolean ILAPIENTRY ilActiveFace(ILuint Number); -ILAPI ILboolean ILAPIENTRY ilActiveImage(ILuint Number); -ILAPI ILboolean ILAPIENTRY ilActiveLayer(ILuint Number); -ILAPI ILboolean ILAPIENTRY ilActiveMipmap(ILuint Number); -ILAPI ILboolean ILAPIENTRY ilApplyPal(ILconst_string FileName); -ILAPI ILboolean ILAPIENTRY ilApplyProfile(ILstring InProfile, ILstring OutProfile); -ILAPI void ILAPIENTRY ilBindImage(ILuint Image); -ILAPI ILboolean ILAPIENTRY ilBlit(ILuint Source, ILint DestX, ILint DestY, ILint DestZ, ILuint SrcX, ILuint SrcY, ILuint SrcZ, ILuint Width, ILuint Height, ILuint Depth); -ILAPI ILboolean ILAPIENTRY ilClampNTSC(void); -ILAPI void ILAPIENTRY ilClearColour(ILclampf Red, ILclampf Green, ILclampf Blue, ILclampf Alpha); -ILAPI ILboolean ILAPIENTRY ilClearImage(void); -ILAPI ILuint ILAPIENTRY ilCloneCurImage(void); -ILAPI ILubyte* ILAPIENTRY ilCompressDXT(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DXTCFormat, ILuint *DXTCSize); -ILAPI ILboolean ILAPIENTRY ilCompressFunc(ILenum Mode); -ILAPI ILboolean ILAPIENTRY ilConvertImage(ILenum DestFormat, ILenum DestType); -ILAPI ILboolean ILAPIENTRY ilConvertPal(ILenum DestFormat); -ILAPI ILboolean ILAPIENTRY ilCopyImage(ILuint Src); -ILAPI ILuint ILAPIENTRY ilCopyPixels(ILuint XOff, ILuint YOff, ILuint ZOff, ILuint Width, ILuint Height, ILuint Depth, ILenum Format, ILenum Type, void *Data); -ILAPI ILuint ILAPIENTRY ilCreateSubImage(ILenum Type, ILuint Num); -ILAPI ILboolean ILAPIENTRY ilDefaultImage(void); -ILAPI void ILAPIENTRY ilDeleteImage(const ILuint Num); -ILAPI void ILAPIENTRY ilDeleteImages(ILsizei Num, const ILuint *Images); -ILAPI ILenum ILAPIENTRY ilDetermineType(ILconst_string FileName); -ILAPI ILenum ILAPIENTRY ilDetermineTypeF(ILHANDLE File); -ILAPI ILenum ILAPIENTRY ilDetermineTypeL(const void *Lump, ILuint Size); -ILAPI ILboolean ILAPIENTRY ilDisable(ILenum Mode); -ILAPI ILboolean ILAPIENTRY ilDxtcDataToImage(void); -ILAPI ILboolean ILAPIENTRY ilDxtcDataToSurface(void); -ILAPI ILboolean ILAPIENTRY ilEnable(ILenum Mode); -ILAPI void ILAPIENTRY ilFlipSurfaceDxtcData(void); -ILAPI ILboolean ILAPIENTRY ilFormatFunc(ILenum Mode); -ILAPI void ILAPIENTRY ilGenImages(ILsizei Num, ILuint *Images); -ILAPI ILuint ILAPIENTRY ilGenImage(void); -ILAPI ILubyte* ILAPIENTRY ilGetAlpha(ILenum Type); -ILAPI ILboolean ILAPIENTRY ilGetBoolean(ILenum Mode); -ILAPI void ILAPIENTRY ilGetBooleanv(ILenum Mode, ILboolean *Param); -ILAPI ILubyte* ILAPIENTRY ilGetData(void); -ILAPI ILuint ILAPIENTRY ilGetDXTCData(void *Buffer, ILuint BufferSize, ILenum DXTCFormat); -ILAPI ILenum ILAPIENTRY ilGetError(void); -ILAPI ILint ILAPIENTRY ilGetInteger(ILenum Mode); -ILAPI void ILAPIENTRY ilGetIntegerv(ILenum Mode, ILint *Param); -ILAPI ILuint ILAPIENTRY ilGetLumpPos(void); -ILAPI ILubyte* ILAPIENTRY ilGetPalette(void); -ILAPI ILconst_string ILAPIENTRY ilGetString(ILenum StringName); -ILAPI void ILAPIENTRY ilHint(ILenum Target, ILenum Mode); -ILAPI ILboolean ILAPIENTRY ilInvertSurfaceDxtcDataAlpha(void); -ILAPI void ILAPIENTRY ilInit(void); -ILAPI ILboolean ILAPIENTRY ilImageToDxtcData(ILenum Format); -ILAPI ILboolean ILAPIENTRY ilIsDisabled(ILenum Mode); -ILAPI ILboolean ILAPIENTRY ilIsEnabled(ILenum Mode); -ILAPI ILboolean ILAPIENTRY ilIsImage(ILuint Image); -ILAPI ILboolean ILAPIENTRY ilIsValid(ILenum Type, ILconst_string FileName); -ILAPI ILboolean ILAPIENTRY ilIsValidF(ILenum Type, ILHANDLE File); -ILAPI ILboolean ILAPIENTRY ilIsValidL(ILenum Type, void *Lump, ILuint Size); -ILAPI void ILAPIENTRY ilKeyColour(ILclampf Red, ILclampf Green, ILclampf Blue, ILclampf Alpha); -ILAPI ILboolean ILAPIENTRY ilLoad(ILenum Type, ILconst_string FileName); -ILAPI ILboolean ILAPIENTRY ilLoadF(ILenum Type, ILHANDLE File); -ILAPI ILboolean ILAPIENTRY ilLoadImage(ILconst_string FileName); -ILAPI ILboolean ILAPIENTRY ilLoadL(ILenum Type, const void *Lump, ILuint Size); -ILAPI ILboolean ILAPIENTRY ilLoadPal(ILconst_string FileName); -ILAPI void ILAPIENTRY ilModAlpha(ILdouble AlphaValue); -ILAPI ILboolean ILAPIENTRY ilOriginFunc(ILenum Mode); -ILAPI ILboolean ILAPIENTRY ilOverlayImage(ILuint Source, ILint XCoord, ILint YCoord, ILint ZCoord); -ILAPI void ILAPIENTRY ilPopAttrib(void); -ILAPI void ILAPIENTRY ilPushAttrib(ILuint Bits); -ILAPI void ILAPIENTRY ilRegisterFormat(ILenum Format); -ILAPI ILboolean ILAPIENTRY ilRegisterLoad(ILconst_string Ext, IL_LOADPROC Load); -ILAPI ILboolean ILAPIENTRY ilRegisterMipNum(ILuint Num); -ILAPI ILboolean ILAPIENTRY ilRegisterNumFaces(ILuint Num); -ILAPI ILboolean ILAPIENTRY ilRegisterNumImages(ILuint Num); -ILAPI void ILAPIENTRY ilRegisterOrigin(ILenum Origin); -ILAPI void ILAPIENTRY ilRegisterPal(void *Pal, ILuint Size, ILenum Type); -ILAPI ILboolean ILAPIENTRY ilRegisterSave(ILconst_string Ext, IL_SAVEPROC Save); -ILAPI void ILAPIENTRY ilRegisterType(ILenum Type); -ILAPI ILboolean ILAPIENTRY ilRemoveLoad(ILconst_string Ext); -ILAPI ILboolean ILAPIENTRY ilRemoveSave(ILconst_string Ext); -ILAPI void ILAPIENTRY ilResetMemory(void); // Deprecated -ILAPI void ILAPIENTRY ilResetRead(void); -ILAPI void ILAPIENTRY ilResetWrite(void); -ILAPI ILboolean ILAPIENTRY ilSave(ILenum Type, ILconst_string FileName); -ILAPI ILuint ILAPIENTRY ilSaveF(ILenum Type, ILHANDLE File); -ILAPI ILboolean ILAPIENTRY ilSaveImage(ILconst_string FileName); -ILAPI ILuint ILAPIENTRY ilSaveL(ILenum Type, void *Lump, ILuint Size); -ILAPI ILboolean ILAPIENTRY ilSavePal(ILconst_string FileName); -ILAPI ILboolean ILAPIENTRY ilSetAlpha(ILdouble AlphaValue); -ILAPI ILboolean ILAPIENTRY ilSetData(void *Data); -ILAPI ILboolean ILAPIENTRY ilSetDuration(ILuint Duration); -ILAPI void ILAPIENTRY ilSetInteger(ILenum Mode, ILint Param); -ILAPI void ILAPIENTRY ilSetMemory(mAlloc, mFree); -ILAPI void ILAPIENTRY ilSetPixels(ILint XOff, ILint YOff, ILint ZOff, ILuint Width, ILuint Height, ILuint Depth, ILenum Format, ILenum Type, void *Data); -ILAPI void ILAPIENTRY ilSetRead(fOpenRProc, fCloseRProc, fEofProc, fGetcProc, fReadProc, fSeekRProc, fTellRProc); -ILAPI void ILAPIENTRY ilSetString(ILenum Mode, const char *String); -ILAPI void ILAPIENTRY ilSetWrite(fOpenWProc, fCloseWProc, fPutcProc, fSeekWProc, fTellWProc, fWriteProc); -ILAPI void ILAPIENTRY ilShutDown(void); -ILAPI ILboolean ILAPIENTRY ilSurfaceToDxtcData(ILenum Format); -ILAPI ILboolean ILAPIENTRY ilTexImage(ILuint Width, ILuint Height, ILuint Depth, ILubyte NumChannels, ILenum Format, ILenum Type, void *Data); -ILAPI ILboolean ILAPIENTRY ilTexImageDxtc(ILint w, ILint h, ILint d, ILenum DxtFormat, const ILubyte* data); -ILAPI ILenum ILAPIENTRY ilTypeFromExt(ILconst_string FileName); -ILAPI ILboolean ILAPIENTRY ilTypeFunc(ILenum Mode); -ILAPI ILboolean ILAPIENTRY ilLoadData(ILconst_string FileName, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp); -ILAPI ILboolean ILAPIENTRY ilLoadDataF(ILHANDLE File, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp); -ILAPI ILboolean ILAPIENTRY ilLoadDataL(void *Lump, ILuint Size, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp); -ILAPI ILboolean ILAPIENTRY ilSaveData(ILconst_string FileName); - -// For all those weirdos that spell "colour" without the 'u'. -#define ilClearColor ilClearColour -#define ilKeyColor ilKeyColour - -#define imemclear(x,y) memset(x,0,y); - -#ifdef __cplusplus -} -#endif - -#endif // __IL_H__ -#endif // __il_h__ diff --git a/samples/DevIL/include/IL/il_wrap.h b/samples/DevIL/include/IL/il_wrap.h deleted file mode 100644 index 5cf9b0e0a..000000000 --- a/samples/DevIL/include/IL/il_wrap.h +++ /dev/null @@ -1,205 +0,0 @@ -#ifndef WRAPPER_H -#define WRAPPER_H - -/*#include -#include */ -#include // Probably only have to #include this one - -#ifdef _MSC_VER - #ifndef _IL_WRAP_BUILD_LIB - #pragma comment(lib, "il_wrap.lib") - #endif -#endif - -class ilImage -{ -public: - ilImage(); - ilImage(char *); - ilImage(const ilImage &); - virtual ~ilImage(); - - ILboolean Load(char *); - ILboolean Load(char *, ILenum); - ILboolean Save(char *); - ILboolean Save(char *, ILenum); - - - // ImageLib functions - ILboolean ActiveImage(ILuint); - ILboolean ActiveLayer(ILuint); - ILboolean ActiveMipmap(ILuint); - ILboolean Clear(void); - ILvoid ClearColour(ILclampf, ILclampf, ILclampf, ILclampf); - ILboolean Convert(ILenum); - ILboolean Copy(ILuint); - ILboolean Default(void); - ILboolean Flip(void); - ILboolean SwapColours(void); - ILboolean Resize(ILuint, ILuint, ILuint); - ILboolean TexImage(ILuint, ILuint, ILuint, ILubyte, ILenum, ILenum, ILvoid*); - - - // Image handling - ILvoid Bind(void) const; - ILvoid Bind(ILuint); - ILvoid Close(void) { this->Delete(); } - ILvoid Delete(void); - ILvoid iGenBind(); - ILenum PaletteAlphaIndex(); - - // Image characteristics - ILuint Width(void); - ILuint Height(void); - ILuint Depth(void); - ILubyte Bpp(void); - ILubyte Bitpp(void); - ILenum PaletteType(void); - ILenum Format(void); - ILenum Type(void); - ILuint NumImages(void); - ILuint NumMipmaps(void); - ILuint GetId(void) const; - ILenum GetOrigin(void); - ILubyte *GetData(void); - ILubyte *GetPalette(void); - - - // Rendering - ILuint BindImage(void); - ILuint BindImage(ILenum); - - - // Operators - ilImage& operator = (ILuint); - ilImage& operator = (const ilImage &); - - -protected: - ILuint Id; - -private: - ILvoid iStartUp(); - - -}; - - -class ilFilters -{ -public: - static ILboolean Alienify(ilImage &); - static ILboolean BlurAvg(ilImage &, ILuint Iter); - static ILboolean BlurGaussian(ilImage &, ILuint Iter); - static ILboolean Contrast(ilImage &, ILfloat Contrast); - static ILboolean EdgeDetectE(ilImage &); - static ILboolean EdgeDetectP(ilImage &); - static ILboolean EdgeDetectS(ilImage &); - static ILboolean Emboss(ilImage &); - static ILboolean Gamma(ilImage &, ILfloat Gamma); - static ILboolean Negative(ilImage &); - static ILboolean Noisify(ilImage &, ILubyte Factor); - static ILboolean Pixelize(ilImage &, ILuint PixSize); - static ILboolean Saturate(ilImage &, ILfloat Saturation); - static ILboolean Saturate(ilImage &, ILfloat r, ILfloat g, ILfloat b, ILfloat Saturation); - static ILboolean ScaleColours(ilImage &, ILfloat r, ILfloat g, ILfloat b); - static ILboolean Sharpen(ilImage &, ILfloat Factor, ILuint Iter); -}; - - -#ifdef ILUT_USE_OPENGL -class ilOgl -{ -public: - static ILvoid Init(void); - static GLuint BindTex(ilImage &); - static ILboolean Upload(ilImage &, ILuint); - static GLuint Mipmap(ilImage &); - static ILboolean Screen(void); - static ILboolean Screenie(void); -}; -#endif//ILUT_USE_OPENGL - - -#ifdef ILUT_USE_ALLEGRO -class ilAlleg -{ -public: - static ILvoid Init(void); - static BITMAP *Convert(ilImage &); -}; -#endif//ILUT_USE_ALLEGRO - - -#ifdef ILUT_USE_WIN32 -class ilWin32 -{ -public: - static ILvoid Init(void); - static HBITMAP Convert(ilImage &); - static ILboolean GetClipboard(ilImage &); - static ILvoid GetInfo(ilImage &, BITMAPINFO *Info); - static ILubyte *GetPadData(ilImage &); - static HPALETTE GetPal(ilImage &); - static ILboolean GetResource(ilImage &, HINSTANCE hInst, ILint ID, char *ResourceType); - static ILboolean GetResource(ilImage &, HINSTANCE hInst, ILint ID, char *ResourceType, ILenum Type); - static ILboolean SetClipboard(ilImage &); -}; -#endif//ILUT_USE_WIN32 - - -class ilValidate -{ -public: - static ILboolean Valid(ILenum, char *); - static ILboolean Valid(ILenum, FILE *); - static ILboolean Valid(ILenum, ILvoid *, ILuint); - -protected: - -private: - -}; - - -class ilState -{ -public: - static ILboolean Disable(ILenum); - static ILboolean Enable(ILenum); - static ILvoid Get(ILenum, ILboolean &); - static ILvoid Get(ILenum, ILint &); - static ILboolean GetBool(ILenum); - static ILint GetInt(ILenum); - static const char *GetString(ILenum); - static ILboolean IsDisabled(ILenum); - static ILboolean IsEnabled(ILenum); - static ILboolean Origin(ILenum); - static ILvoid Pop(void); - static ILvoid Push(ILuint); - - -protected: - -private: - -}; - - -class ilError -{ -public: - static ILvoid Check(ILvoid (*Callback)(const char*)); - static ILvoid Check(ILvoid (*Callback)(ILenum)); - static ILenum Get(void); - static const char *String(void); - static const char *String(ILenum); - -protected: - -private: - -}; - - -#endif//WRAPPER_H diff --git a/samples/DevIL/include/IL/ilu.h b/samples/DevIL/include/IL/ilu.h deleted file mode 100644 index 49871d79f..000000000 --- a/samples/DevIL/include/IL/ilu.h +++ /dev/null @@ -1,195 +0,0 @@ -//----------------------------------------------------------------------------- -// -// ImageLib Utility Sources -// Copyright (C) 2000-2009 by Denton Woods -// Last modified: 03/07/2009 -// -// Filename: IL/ilu.h -// -// Description: The main include file for ILU -// -//----------------------------------------------------------------------------- - -// Doxygen comment -/*! \file ilu.h - The main include file for ILU -*/ - -#ifndef __ilu_h_ -#ifndef __ILU_H__ - -#define __ilu_h_ -#define __ILU_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -#ifdef _WIN32 - #if (defined(IL_USE_PRAGMA_LIBS)) && (!defined(_IL_BUILD_LIBRARY)) - #if defined(_MSC_VER) || defined(__BORLANDC__) - #pragma comment(lib, "ILU.lib") - #endif - #endif -#endif - - -#define ILU_VERSION_1_7_8 1 -#define ILU_VERSION 178 - - -#define ILU_FILTER 0x2600 -#define ILU_NEAREST 0x2601 -#define ILU_LINEAR 0x2602 -#define ILU_BILINEAR 0x2603 -#define ILU_SCALE_BOX 0x2604 -#define ILU_SCALE_TRIANGLE 0x2605 -#define ILU_SCALE_BELL 0x2606 -#define ILU_SCALE_BSPLINE 0x2607 -#define ILU_SCALE_LANCZOS3 0x2608 -#define ILU_SCALE_MITCHELL 0x2609 - - -// Error types -#define ILU_INVALID_ENUM 0x0501 -#define ILU_OUT_OF_MEMORY 0x0502 -#define ILU_INTERNAL_ERROR 0x0504 -#define ILU_INVALID_VALUE 0x0505 -#define ILU_ILLEGAL_OPERATION 0x0506 -#define ILU_INVALID_PARAM 0x0509 - - -// Values -#define ILU_PLACEMENT 0x0700 -#define ILU_LOWER_LEFT 0x0701 -#define ILU_LOWER_RIGHT 0x0702 -#define ILU_UPPER_LEFT 0x0703 -#define ILU_UPPER_RIGHT 0x0704 -#define ILU_CENTER 0x0705 -#define ILU_CONVOLUTION_MATRIX 0x0710 - -#define ILU_VERSION_NUM IL_VERSION_NUM -#define ILU_VENDOR IL_VENDOR - - -// Languages -#define ILU_ENGLISH 0x0800 -#define ILU_ARABIC 0x0801 -#define ILU_DUTCH 0x0802 -#define ILU_JAPANESE 0x0803 -#define ILU_SPANISH 0x0804 -#define ILU_GERMAN 0x0805 -#define ILU_FRENCH 0x0806 - - -// Filters -/* -#define ILU_FILTER_BLUR 0x0803 -#define ILU_FILTER_GAUSSIAN_3x3 0x0804 -#define ILU_FILTER_GAUSSIAN_5X5 0x0805 -#define ILU_FILTER_EMBOSS1 0x0807 -#define ILU_FILTER_EMBOSS2 0x0808 -#define ILU_FILTER_LAPLACIAN1 0x080A -#define ILU_FILTER_LAPLACIAN2 0x080B -#define ILU_FILTER_LAPLACIAN3 0x080C -#define ILU_FILTER_LAPLACIAN4 0x080D -#define ILU_FILTER_SHARPEN1 0x080E -#define ILU_FILTER_SHARPEN2 0x080F -#define ILU_FILTER_SHARPEN3 0x0810 -*/ - - -typedef struct ILinfo -{ - ILuint Id; // the image's id - ILubyte *Data; // the image's data - ILuint Width; // the image's width - ILuint Height; // the image's height - ILuint Depth; // the image's depth - ILubyte Bpp; // bytes per pixel (not bits) of the image - ILuint SizeOfData; // the total size of the data (in bytes) - ILenum Format; // image format (in IL enum style) - ILenum Type; // image type (in IL enum style) - ILenum Origin; // origin of the image - ILubyte *Palette; // the image's palette - ILenum PalType; // palette type - ILuint PalSize; // palette size - ILenum CubeFlags; // flags for what cube map sides are present - ILuint NumNext; // number of images following - ILuint NumMips; // number of mipmaps - ILuint NumLayers; // number of layers -} ILinfo; - - -typedef struct ILpointf { - ILfloat x; - ILfloat y; -} ILpointf; - -typedef struct ILpointi { - ILint x; - ILint y; -} ILpointi; - -ILAPI ILboolean ILAPIENTRY iluAlienify(void); -ILAPI ILboolean ILAPIENTRY iluBlurAvg(ILuint Iter); -ILAPI ILboolean ILAPIENTRY iluBlurGaussian(ILuint Iter); -ILAPI ILboolean ILAPIENTRY iluBuildMipmaps(void); -ILAPI ILuint ILAPIENTRY iluColoursUsed(void); -ILAPI ILboolean ILAPIENTRY iluCompareImage(ILuint Comp); -ILAPI ILboolean ILAPIENTRY iluContrast(ILfloat Contrast); -ILAPI ILboolean ILAPIENTRY iluCrop(ILuint XOff, ILuint YOff, ILuint ZOff, ILuint Width, ILuint Height, ILuint Depth); -ILAPI void ILAPIENTRY iluDeleteImage(ILuint Id); // Deprecated -ILAPI ILboolean ILAPIENTRY iluEdgeDetectE(void); -ILAPI ILboolean ILAPIENTRY iluEdgeDetectP(void); -ILAPI ILboolean ILAPIENTRY iluEdgeDetectS(void); -ILAPI ILboolean ILAPIENTRY iluEmboss(void); -ILAPI ILboolean ILAPIENTRY iluEnlargeCanvas(ILuint Width, ILuint Height, ILuint Depth); -ILAPI ILboolean ILAPIENTRY iluEnlargeImage(ILfloat XDim, ILfloat YDim, ILfloat ZDim); -ILAPI ILboolean ILAPIENTRY iluEqualize(void); -ILAPI ILconst_string ILAPIENTRY iluErrorString(ILenum Error); -ILAPI ILboolean ILAPIENTRY iluConvolution(ILint *matrix, ILint scale, ILint bias); -ILAPI ILboolean ILAPIENTRY iluFlipImage(void); -ILAPI ILboolean ILAPIENTRY iluGammaCorrect(ILfloat Gamma); -ILAPI ILuint ILAPIENTRY iluGenImage(void); // Deprecated -ILAPI void ILAPIENTRY iluGetImageInfo(ILinfo *Info); -ILAPI ILint ILAPIENTRY iluGetInteger(ILenum Mode); -ILAPI void ILAPIENTRY iluGetIntegerv(ILenum Mode, ILint *Param); -ILAPI ILstring ILAPIENTRY iluGetString(ILenum StringName); -ILAPI void ILAPIENTRY iluImageParameter(ILenum PName, ILenum Param); -ILAPI void ILAPIENTRY iluInit(void); -ILAPI ILboolean ILAPIENTRY iluInvertAlpha(void); -ILAPI ILuint ILAPIENTRY iluLoadImage(ILconst_string FileName); -ILAPI ILboolean ILAPIENTRY iluMirror(void); -ILAPI ILboolean ILAPIENTRY iluNegative(void); -ILAPI ILboolean ILAPIENTRY iluNoisify(ILclampf Tolerance); -ILAPI ILboolean ILAPIENTRY iluPixelize(ILuint PixSize); -ILAPI void ILAPIENTRY iluRegionfv(ILpointf *Points, ILuint n); -ILAPI void ILAPIENTRY iluRegioniv(ILpointi *Points, ILuint n); -ILAPI ILboolean ILAPIENTRY iluReplaceColour(ILubyte Red, ILubyte Green, ILubyte Blue, ILfloat Tolerance); -ILAPI ILboolean ILAPIENTRY iluRotate(ILfloat Angle); -ILAPI ILboolean ILAPIENTRY iluRotate3D(ILfloat x, ILfloat y, ILfloat z, ILfloat Angle); -ILAPI ILboolean ILAPIENTRY iluSaturate1f(ILfloat Saturation); -ILAPI ILboolean ILAPIENTRY iluSaturate4f(ILfloat r, ILfloat g, ILfloat b, ILfloat Saturation); -ILAPI ILboolean ILAPIENTRY iluScale(ILuint Width, ILuint Height, ILuint Depth); -ILAPI ILboolean ILAPIENTRY iluScaleAlpha(ILfloat scale); -ILAPI ILboolean ILAPIENTRY iluScaleColours(ILfloat r, ILfloat g, ILfloat b); -ILAPI ILboolean ILAPIENTRY iluSetLanguage(ILenum Language); -ILAPI ILboolean ILAPIENTRY iluSharpen(ILfloat Factor, ILuint Iter); -ILAPI ILboolean ILAPIENTRY iluSwapColours(void); -ILAPI ILboolean ILAPIENTRY iluWave(ILfloat Angle); - -#define iluColorsUsed iluColoursUsed -#define iluSwapColors iluSwapColours -#define iluReplaceColor iluReplaceColour -#define iluScaleColor iluScaleColour - -#ifdef __cplusplus -} -#endif - -#endif // __ILU_H__ -#endif // __ilu_h_ diff --git a/samples/DevIL/include/IL/ilu_region.h b/samples/DevIL/include/IL/ilu_region.h deleted file mode 100644 index b5b3adc2d..000000000 --- a/samples/DevIL/include/IL/ilu_region.h +++ /dev/null @@ -1,25 +0,0 @@ -//----------------------------------------------------------------------------- -// -// ImageLib Utility Sources -// Copyright (C) 2000-2002 by Denton Woods -// Last modified: 07/09/2002 <--Y2K Compliant! =] -// -// Filename: src-ILU/src/ilu_region.h -// -// Description: Creates an image region. -// -//----------------------------------------------------------------------------- - -#ifndef ILU_REGION_H -#define ILU_REGION_H - -typedef struct Edge -{ - ILint yUpper; - ILfloat xIntersect, dxPerScan; - struct Edge *next; -} Edge; - - -#endif//ILU_REGION_H - diff --git a/samples/DevIL/include/IL/ilut.h b/samples/DevIL/include/IL/ilut.h deleted file mode 100644 index 4a84b845d..000000000 --- a/samples/DevIL/include/IL/ilut.h +++ /dev/null @@ -1,390 +0,0 @@ -//----------------------------------------------------------------------------- -// -// ImageLib Utility Toolkit Sources -// Copyright (C) 2000-2009 by Denton Woods -// Last modified: 03/07/2009 -// -// Filename: IL/ilut.h -// -// Description: The main include file for ILUT -// -//----------------------------------------------------------------------------- - -// Doxygen comment -/*! \file ilut.h - The main include file for ILUT -*/ - -#ifndef __ilut_h_ -#ifndef __ILUT_H__ - -#define __ilut_h_ -#define __ILUT_H__ - -#include -#include - - -//----------------------------------------------------------------------------- -// Defines -//----------------------------------------------------------------------------- - -#define ILUT_VERSION_1_7_8 1 -#define ILUT_VERSION 178 - - -// Attribute Bits -#define ILUT_OPENGL_BIT 0x00000001 -#define ILUT_D3D_BIT 0x00000002 -#define ILUT_ALL_ATTRIB_BITS 0x000FFFFF - - -// Error Types -#define ILUT_INVALID_ENUM 0x0501 -#define ILUT_OUT_OF_MEMORY 0x0502 -#define ILUT_INVALID_VALUE 0x0505 -#define ILUT_ILLEGAL_OPERATION 0x0506 -#define ILUT_INVALID_PARAM 0x0509 -#define ILUT_COULD_NOT_OPEN_FILE 0x050A -#define ILUT_STACK_OVERFLOW 0x050E -#define ILUT_STACK_UNDERFLOW 0x050F -#define ILUT_BAD_DIMENSIONS 0x0511 -#define ILUT_NOT_SUPPORTED 0x0550 - - -// State Definitions -#define ILUT_PALETTE_MODE 0x0600 -#define ILUT_OPENGL_CONV 0x0610 -#define ILUT_D3D_MIPLEVELS 0x0620 -#define ILUT_MAXTEX_WIDTH 0x0630 -#define ILUT_MAXTEX_HEIGHT 0x0631 -#define ILUT_MAXTEX_DEPTH 0x0632 -#define ILUT_GL_USE_S3TC 0x0634 -#define ILUT_D3D_USE_DXTC 0x0634 -#define ILUT_GL_GEN_S3TC 0x0635 -#define ILUT_D3D_GEN_DXTC 0x0635 -#define ILUT_S3TC_FORMAT 0x0705 -#define ILUT_DXTC_FORMAT 0x0705 -#define ILUT_D3D_POOL 0x0706 -#define ILUT_D3D_ALPHA_KEY_COLOR 0x0707 -#define ILUT_D3D_ALPHA_KEY_COLOUR 0x0707 -#define ILUT_FORCE_INTEGER_FORMAT 0x0636 - -//This new state does automatic texture target detection -//if enabled. Currently, only cubemap detection is supported. -//if the current image is no cubemap, the 2d texture is chosen. -#define ILUT_GL_AUTODETECT_TEXTURE_TARGET 0x0807 - - -// Values -#define ILUT_VERSION_NUM IL_VERSION_NUM -#define ILUT_VENDOR IL_VENDOR - -// The different rendering api's...more to be added later? -#define ILUT_OPENGL 0 -#define ILUT_ALLEGRO 1 -#define ILUT_WIN32 2 -#define ILUT_DIRECT3D8 3 -#define ILUT_DIRECT3D9 4 -#define ILUT_X11 5 -#define ILUT_DIRECT3D10 6 - -/* -// Includes specific config -#ifdef DJGPP - #define ILUT_USE_ALLEGRO -#elif _WIN32_WCE - #define ILUT_USE_WIN32 -#elif _WIN32 - //#ifdef __GNUC__ //__CYGWIN32__ (Cygwin seems to not define this with DevIL builds) - #define ILUT_USE_WIN32 - #include "IL/config.h" - - // Temporary fix for the SDL main() linker bug. - //#ifdef ILUT_USE_SDL - //#undef ILUT_USE_SDL - //#endif//ILUT_USE_SDL - - //#else - // #define ILUT_USE_WIN32 - // #define ILUT_USE_OPENGL - // #define ILUT_USE_SDL - // #define ILUT_USE_DIRECTX8 - //#endif -#elif BEOS // Don't know the #define - #define ILUT_USE_BEOS - #define ILUT_USE_OPENGL -#elif MACOSX - #define ILUT_USE_OPENGL -#else - - // We are surely using a *nix so the configure script - // may have written the configured config.h header - #include "IL/config.h" -#endif -*/ - -#if (defined(_WIN32) || defined(_WIN64)) - #if (defined(IL_USE_PRAGMA_LIBS)) && (!defined(_IL_BUILD_LIBRARY)) - #if defined(_MSC_VER) || defined(__BORLANDC__) - #pragma comment(lib, "ILUT.lib") - #endif - #endif - - #include -#endif - - - -//this should remain private and hidden -//#include "IL/config.h" - -////////////// -// OpenGL -////////////// - -#ifdef ILUT_USE_OPENGL - #if defined(_MSC_VER) || defined(_WIN32) - //#define WIN32_LEAN_AND_MEAN - #include - #endif//_MSC_VER - - #ifdef __APPLE__ - #include - #include - #else - #include - #include - #endif//__APPLE__ -#endif - - -#ifdef ILUT_USE_WIN32 - //#define WIN32_LEAN_AND_MEAN - #ifdef _DEBUG - #define _CRTDBG_MAP_ALLOC - #include - #ifndef _WIN32_WCE - #include - #endif - #endif - #include -#endif - - -// -// If we can avoid including these in all cases thing tend to break less -// and we can keep all of them defined as available -// -// Kriss -// - -// ImageLib Utility Toolkit's Allegro Functions -#ifdef ILUT_USE_ALLEGRO -// #include -#endif//ILUT_USE_ALLEGRO - -#ifdef ILUT_USE_SDL -// #include -#endif - -#ifdef ILUT_USE_DIRECTX8 - #include -#endif//ILUT_USE_DIRECTX9 - -#ifdef ILUT_USE_DIRECTX9 - #include -#endif//ILUT_USE_DIRECTX9 - -#ifdef ILUT_USE_DIRECTX10 - #pragma warning(push) - #pragma warning(disable : 4201) // Disables 'nonstandard extension used : nameless struct/union' warning - #include - #include - #include - #pragma warning(pop) -#endif//ILUT_USE_DIRECTX10 - -#ifdef ILUT_USE_X11 - #include - #include -#ifdef ILUT_USE_XSHM - #include - #include - #include -#endif//ILUT_USE_XSHM -#endif//ILUT_USE_X11 - - - -//----------------------------------------------------------------------------- -// Functions -//----------------------------------------------------------------------------- - -#ifdef __cplusplus -extern "C" { -#endif - -// ImageLib Utility Toolkit Functions -ILAPI ILboolean ILAPIENTRY ilutDisable(ILenum Mode); -ILAPI ILboolean ILAPIENTRY ilutEnable(ILenum Mode); -ILAPI ILboolean ILAPIENTRY ilutGetBoolean(ILenum Mode); -ILAPI void ILAPIENTRY ilutGetBooleanv(ILenum Mode, ILboolean *Param); -ILAPI ILint ILAPIENTRY ilutGetInteger(ILenum Mode); -ILAPI void ILAPIENTRY ilutGetIntegerv(ILenum Mode, ILint *Param); -ILAPI ILstring ILAPIENTRY ilutGetString(ILenum StringName); -ILAPI void ILAPIENTRY ilutInit(void); -ILAPI ILboolean ILAPIENTRY ilutIsDisabled(ILenum Mode); -ILAPI ILboolean ILAPIENTRY ilutIsEnabled(ILenum Mode); -ILAPI void ILAPIENTRY ilutPopAttrib(void); -ILAPI void ILAPIENTRY ilutPushAttrib(ILuint Bits); -ILAPI void ILAPIENTRY ilutSetInteger(ILenum Mode, ILint Param); - -ILAPI ILboolean ILAPIENTRY ilutRenderer(ILenum Renderer); - - -// ImageLib Utility Toolkit's OpenGL Functions -#ifdef ILUT_USE_OPENGL - ILAPI GLuint ILAPIENTRY ilutGLBindTexImage(); - ILAPI GLuint ILAPIENTRY ilutGLBindMipmaps(void); - ILAPI ILboolean ILAPIENTRY ilutGLBuildMipmaps(void); - ILAPI GLuint ILAPIENTRY ilutGLLoadImage(ILstring FileName); - ILAPI ILboolean ILAPIENTRY ilutGLScreen(void); - ILAPI ILboolean ILAPIENTRY ilutGLScreenie(void); - ILAPI ILboolean ILAPIENTRY ilutGLSaveImage(ILstring FileName, GLuint TexID); - ILAPI ILboolean ILAPIENTRY ilutGLSubTex2D(GLuint TexID, ILuint XOff, ILuint YOff); - ILAPI ILboolean ILAPIENTRY ilutGLSubTex3D(GLuint TexID, ILuint XOff, ILuint YOff, ILuint ZOff); - ILAPI ILboolean ILAPIENTRY ilutGLSetTex2D(GLuint TexID); - ILAPI ILboolean ILAPIENTRY ilutGLSetTex3D(GLuint TexID); - ILAPI ILboolean ILAPIENTRY ilutGLTexImage(GLuint Level); - ILAPI ILboolean ILAPIENTRY ilutGLSubTex(GLuint TexID, ILuint XOff, ILuint YOff); - - ILAPI ILboolean ILAPIENTRY ilutGLSetTex(GLuint TexID); // Deprecated - use ilutGLSetTex2D. - ILAPI ILboolean ILAPIENTRY ilutGLSubTex(GLuint TexID, ILuint XOff, ILuint YOff); // Use ilutGLSubTex2D. -#endif//ILUT_USE_OPENGL - - -// ImageLib Utility Toolkit's Allegro Functions -#ifdef ILUT_USE_ALLEGRO - #ifdef __cplusplus - extern "C" { - #endif - #include - #ifdef __cplusplus - } - #endif - - ILAPI BITMAP* ILAPIENTRY ilutAllegLoadImage(ILstring FileName); - ILAPI BITMAP* ILAPIENTRY ilutConvertToAlleg(PALETTE Pal); -#endif//ILUT_USE_ALLEGRO - - -// ImageLib Utility Toolkit's SDL Functions -#ifdef ILUT_USE_SDL - ILAPI struct SDL_Surface* ILAPIENTRY ilutConvertToSDLSurface(unsigned int flags); - ILAPI struct SDL_Surface* ILAPIENTRY ilutSDLSurfaceLoadImage(ILstring FileName); - ILAPI ILboolean ILAPIENTRY ilutSDLSurfaceFromBitmap(struct SDL_Surface *Bitmap); -#endif//ILUT_USE_SDL - - -// ImageLib Utility Toolkit's BeOS Functions -#ifdef ILUT_USE_BEOS - ILAPI BBitmap ILAPIENTRY ilutConvertToBBitmap(void); -#endif//ILUT_USE_BEOS - - -// ImageLib Utility Toolkit's Win32 GDI Functions -#ifdef ILUT_USE_WIN32 - ILAPI HBITMAP ILAPIENTRY ilutConvertToHBitmap(HDC hDC); - ILAPI HBITMAP ILAPIENTRY ilutConvertSliceToHBitmap(HDC hDC, ILuint slice); - ILAPI void ILAPIENTRY ilutFreePaddedData(ILubyte *Data); - ILAPI void ILAPIENTRY ilutGetBmpInfo(BITMAPINFO *Info); - ILAPI HPALETTE ILAPIENTRY ilutGetHPal(void); - ILAPI ILubyte* ILAPIENTRY ilutGetPaddedData(void); - ILAPI ILboolean ILAPIENTRY ilutGetWinClipboard(void); - ILAPI ILboolean ILAPIENTRY ilutLoadResource(HINSTANCE hInst, ILint ID, ILstring ResourceType, ILenum Type); - ILAPI ILboolean ILAPIENTRY ilutSetHBitmap(HBITMAP Bitmap); - ILAPI ILboolean ILAPIENTRY ilutSetHPal(HPALETTE Pal); - ILAPI ILboolean ILAPIENTRY ilutSetWinClipboard(void); - ILAPI HBITMAP ILAPIENTRY ilutWinLoadImage(ILstring FileName, HDC hDC); - ILAPI ILboolean ILAPIENTRY ilutWinLoadUrl(ILstring Url); - ILAPI ILboolean ILAPIENTRY ilutWinPrint(ILuint XPos, ILuint YPos, ILuint Width, ILuint Height, HDC hDC); - ILAPI ILboolean ILAPIENTRY ilutWinSaveImage(ILstring FileName, HBITMAP Bitmap); -#endif//ILUT_USE_WIN32 - -// ImageLib Utility Toolkit's DirectX 8 Functions -#ifdef ILUT_USE_DIRECTX8 -// ILAPI void ILAPIENTRY ilutD3D8MipFunc(ILuint NumLevels); - ILAPI struct IDirect3DTexture8* ILAPIENTRY ilutD3D8Texture(struct IDirect3DDevice8 *Device); - ILAPI struct IDirect3DVolumeTexture8* ILAPIENTRY ilutD3D8VolumeTexture(struct IDirect3DDevice8 *Device); - ILAPI ILboolean ILAPIENTRY ilutD3D8TexFromFile(struct IDirect3DDevice8 *Device, char *FileName, struct IDirect3DTexture8 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D8VolTexFromFile(struct IDirect3DDevice8 *Device, char *FileName, struct IDirect3DVolumeTexture8 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D8TexFromFileInMemory(struct IDirect3DDevice8 *Device, void *Lump, ILuint Size, struct IDirect3DTexture8 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D8VolTexFromFileInMemory(struct IDirect3DDevice8 *Device, void *Lump, ILuint Size, struct IDirect3DVolumeTexture8 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D8TexFromFileHandle(struct IDirect3DDevice8 *Device, ILHANDLE File, struct IDirect3DTexture8 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D8VolTexFromFileHandle(struct IDirect3DDevice8 *Device, ILHANDLE File, struct IDirect3DVolumeTexture8 **Texture); - // These two are not tested yet. - ILAPI ILboolean ILAPIENTRY ilutD3D8TexFromResource(struct IDirect3DDevice8 *Device, HMODULE SrcModule, char *SrcResource, struct IDirect3DTexture8 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D8VolTexFromResource(struct IDirect3DDevice8 *Device, HMODULE SrcModule, char *SrcResource, struct IDirect3DVolumeTexture8 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D8LoadSurface(struct IDirect3DDevice8 *Device, struct IDirect3DSurface8 *Surface); -#endif//ILUT_USE_DIRECTX8 - -#ifdef ILUT_USE_DIRECTX9 - #pragma warning(push) - #pragma warning(disable : 4115) // Disables 'named type definition in parentheses' warning -// ILAPI void ILAPIENTRY ilutD3D9MipFunc(ILuint NumLevels); - ILAPI struct IDirect3DTexture9* ILAPIENTRY ilutD3D9Texture (struct IDirect3DDevice9* Device); - ILAPI struct IDirect3DVolumeTexture9* ILAPIENTRY ilutD3D9VolumeTexture (struct IDirect3DDevice9* Device); - ILAPI struct IDirect3DCubeTexture9* ILAPIENTRY ilutD3D9CubeTexture (struct IDirect3DDevice9* Device); - - ILAPI ILboolean ILAPIENTRY ilutD3D9CubeTexFromFile(struct IDirect3DDevice9 *Device, ILconst_string FileName, struct IDirect3DCubeTexture9 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D9CubeTexFromFileInMemory(struct IDirect3DDevice9 *Device, void *Lump, ILuint Size, struct IDirect3DCubeTexture9 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D9CubeTexFromFileHandle(struct IDirect3DDevice9 *Device, ILHANDLE File, struct IDirect3DCubeTexture9 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D9CubeTexFromResource(struct IDirect3DDevice9 *Device, HMODULE SrcModule, ILconst_string SrcResource, struct IDirect3DCubeTexture9 **Texture); - - ILAPI ILboolean ILAPIENTRY ilutD3D9TexFromFile(struct IDirect3DDevice9 *Device, ILconst_string FileName, struct IDirect3DTexture9 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D9VolTexFromFile(struct IDirect3DDevice9 *Device, ILconst_string FileName, struct IDirect3DVolumeTexture9 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D9TexFromFileInMemory(struct IDirect3DDevice9 *Device, void *Lump, ILuint Size, struct IDirect3DTexture9 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D9VolTexFromFileInMemory(struct IDirect3DDevice9 *Device, void *Lump, ILuint Size, struct IDirect3DVolumeTexture9 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D9TexFromFileHandle(struct IDirect3DDevice9 *Device, ILHANDLE File, struct IDirect3DTexture9 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D9VolTexFromFileHandle(struct IDirect3DDevice9 *Device, ILHANDLE File, struct IDirect3DVolumeTexture9 **Texture); - - // These three are not tested yet. - ILAPI ILboolean ILAPIENTRY ilutD3D9TexFromResource(struct IDirect3DDevice9 *Device, HMODULE SrcModule, ILconst_string SrcResource, struct IDirect3DTexture9 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D9VolTexFromResource(struct IDirect3DDevice9 *Device, HMODULE SrcModule, ILconst_string SrcResource, struct IDirect3DVolumeTexture9 **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D9LoadSurface(struct IDirect3DDevice9 *Device, struct IDirect3DSurface9 *Surface); - #pragma warning(pop) -#endif//ILUT_USE_DIRECTX9 - -#ifdef ILUT_USE_DIRECTX10 - ILAPI ID3D10Texture2D* ILAPIENTRY ilutD3D10Texture(ID3D10Device *Device); - ILAPI ILboolean ILAPIENTRY ilutD3D10TexFromFile(ID3D10Device *Device, ILconst_string FileName, ID3D10Texture2D **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D10TexFromFileInMemory(ID3D10Device *Device, void *Lump, ILuint Size, ID3D10Texture2D **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D10TexFromResource(ID3D10Device *Device, HMODULE SrcModule, ILconst_string SrcResource, ID3D10Texture2D **Texture); - ILAPI ILboolean ILAPIENTRY ilutD3D10TexFromFileHandle(ID3D10Device *Device, ILHANDLE File, ID3D10Texture2D **Texture); -#endif//ILUT_USE_DIRECTX10 - - - -#ifdef ILUT_USE_X11 - ILAPI XImage * ILAPIENTRY ilutXCreateImage( Display* ); - ILAPI Pixmap ILAPIENTRY ilutXCreatePixmap( Display*,Drawable ); - ILAPI XImage * ILAPIENTRY ilutXLoadImage( Display*,char* ); - ILAPI Pixmap ILAPIENTRY ilutXLoadPixmap( Display*,Drawable,char* ); -#ifdef ILUT_USE_XSHM - ILAPI XImage * ILAPIENTRY ilutXShmCreateImage( Display*,XShmSegmentInfo* ); - ILAPI void ILAPIENTRY ilutXShmDestroyImage( Display*,XImage*,XShmSegmentInfo* ); - ILAPI Pixmap ILAPIENTRY ilutXShmCreatePixmap( Display*,Drawable,XShmSegmentInfo* ); - ILAPI void ILAPIENTRY ilutXShmFreePixmap( Display*,Pixmap,XShmSegmentInfo* ); - ILAPI XImage * ILAPIENTRY ilutXShmLoadImage( Display*,char*,XShmSegmentInfo* ); - ILAPI Pixmap ILAPIENTRY ilutXShmLoadPixmap( Display*,Drawable,char*,XShmSegmentInfo* ); -#endif//ILUT_USE_XSHM -#endif//ILUT_USE_X11 - - -#ifdef __cplusplus -} -#endif - -#endif // __ILUT_H__ -#endif // __ilut_h_ diff --git a/samples/DevIL/include/IL/ilut_config.h b/samples/DevIL/include/IL/ilut_config.h deleted file mode 100644 index bd9cbc694..000000000 --- a/samples/DevIL/include/IL/ilut_config.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef __ILUT_CONFIG_H__ -#define __ILUT_CONFIG_H__ - -#define IL_USE_PRAGMA_LIBS - -// Supported APIs (ILUT) - -// -// sorry just -// can't get this one to work under windows -// have disabled for the now -// -// will look at it some more later -// -// Kriss -// -#undef ILUT_USE_ALLEGRO - -#undef ILUT_USE_DIRECTX8 -//#define ILUT_USE_DIRECTX9 -//#define ILUT_USE_DIRECTX10 -#define ILUT_USE_OPENGL -//#define ILUT_USE_SDL -#define ILUT_USE_WIN32 - -#endif//__ILUT_CONFIG_H__ diff --git a/samples/DevIL/lib/DevIL.lib b/samples/DevIL/lib/DevIL.lib deleted file mode 100644 index 1aa82d047..000000000 Binary files a/samples/DevIL/lib/DevIL.lib and /dev/null differ diff --git a/samples/DevIL/lib/ILU.lib b/samples/DevIL/lib/ILU.lib deleted file mode 100644 index 5124172e2..000000000 Binary files a/samples/DevIL/lib/ILU.lib and /dev/null differ diff --git a/samples/DevIL/lib/ILUT.lib b/samples/DevIL/lib/ILUT.lib deleted file mode 100644 index 99bfb6124..000000000 Binary files a/samples/DevIL/lib/ILUT.lib and /dev/null differ diff --git a/samples/README b/samples/README index 995a84f0c..a9f44cec2 100644 --- a/samples/README +++ b/samples/README @@ -12,22 +12,25 @@ use in various real-world environments. Workspaces to build the samples can be found in the respective directories. The VC workspaces copy the created executables to the ./bin directory. -All GL-based samples depend on GLUT, some on DevIL. For convenience, -these libraries are included in the repository in their respective - Windows/x86 prebuilt versions. To build on linux, install the - required packages using the package manager of your choice. +All GL-based samples depend on FreeGLUT, the image loading will be done +by a header-only library. For convenience, these libraries are included +in the repository in their respective Windows/x86 prebuilt versions. +To build on linux, install freeglut using the package manager of your +choice. For instance on Ubuntu to install freeglut you can use the following +command: -Also note that the VS workspaces link against the DLL version of the -Assimp library, thus you need to build it in the first place ( -assimp-release-dll build configuration). The Assimp DLL needs to be -copied to ./bin as well (the VS workspaces will try to do this -automatically). +> sudo apt install freeglut + +All samples will be placed at + +Win32: //bin + +or Linux : /bin 2. List of samples ------------------ - SimpleOpenGL A very simple and straightforward OpenGL sample. It loads a diff --git a/samples/SimpleOpenGL/CMakeLists.txt b/samples/SimpleOpenGL/CMakeLists.txt index 455cbd8ca..93f389741 100644 --- a/samples/SimpleOpenGL/CMakeLists.txt +++ b/samples/SimpleOpenGL/CMakeLists.txt @@ -9,8 +9,8 @@ ENDIF ( MSVC ) IF ( NOT GLUT_FOUND ) IF ( MSVC ) SET ( GLUT_FOUND 1 ) - SET ( GLUT_INCLUDE_DIR ${Assimp_SOURCE_DIR}/samples/glut/ ) - SET ( GLUT_LIBRARIES ${Assimp_SOURCE_DIR}/samples/glut/glut32.lib ) + SET ( GLUT_INCLUDE_DIR ${Assimp_SOURCE_DIR}/samples/freeglut/ ) + SET ( GLUT_LIBRARIES ${Assimp_SOURCE_DIR}/samples/freeglut/lib/freeglut.lib ) ELSE ( MSVC ) MESSAGE( WARNING "Please install glut." ) ENDIF ( MSVC ) @@ -26,6 +26,7 @@ INCLUDE_DIRECTORIES( ${Assimp_SOURCE_DIR}/code ${OPENGL_INCLUDE_DIR} ${GLUT_INCLUDE_DIR} + ${Assimp_SOURCE_DIR}/samples/freeglut/include ) LINK_DIRECTORIES( diff --git a/samples/SimpleOpenGL/Sample_SimpleOpenGL.c b/samples/SimpleOpenGL/Sample_SimpleOpenGL.c index 2dec5bc01..a8a3532cf 100644 --- a/samples/SimpleOpenGL/Sample_SimpleOpenGL.c +++ b/samples/SimpleOpenGL/Sample_SimpleOpenGL.c @@ -26,9 +26,9 @@ #include /* the global Assimp scene object */ -const struct aiScene* scene = NULL; +const C_STRUCT aiScene* scene = NULL; GLuint scene_list = 0; -struct aiVector3D scene_min, scene_max, scene_center; +C_STRUCT aiVector3D scene_min, scene_max, scene_center; /* current rotation angle */ static float angle = 0.f; @@ -49,22 +49,22 @@ void reshape(int width, int height) } /* ---------------------------------------------------------------------------- */ -void get_bounding_box_for_node (const struct aiNode* nd, - struct aiVector3D* min, - struct aiVector3D* max, - struct aiMatrix4x4* trafo +void get_bounding_box_for_node (const C_STRUCT aiNode* nd, + C_STRUCT aiVector3D* min, + C_STRUCT aiVector3D* max, + C_STRUCT aiMatrix4x4* trafo ){ - struct aiMatrix4x4 prev; + C_STRUCT aiMatrix4x4 prev; unsigned int n = 0, t; prev = *trafo; aiMultiplyMatrix4(trafo,&nd->mTransformation); for (; n < nd->mNumMeshes; ++n) { - const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; + const C_STRUCT aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; for (t = 0; t < mesh->mNumVertices; ++t) { - struct aiVector3D tmp = mesh->mVertices[t]; + C_STRUCT aiVector3D tmp = mesh->mVertices[t]; aiTransformVecByMatrix4(&tmp,trafo); min->x = aisgl_min(min->x,tmp.x); @@ -84,9 +84,9 @@ void get_bounding_box_for_node (const struct aiNode* nd, } /* ---------------------------------------------------------------------------- */ -void get_bounding_box (struct aiVector3D* min, struct aiVector3D* max) +void get_bounding_box(C_STRUCT aiVector3D* min, C_STRUCT aiVector3D* max) { - struct aiMatrix4x4 trafo; + C_STRUCT aiMatrix4x4 trafo; aiIdentityMatrix4(&trafo); min->x = min->y = min->z = 1e10f; @@ -95,7 +95,7 @@ void get_bounding_box (struct aiVector3D* min, struct aiVector3D* max) } /* ---------------------------------------------------------------------------- */ -void color4_to_float4(const struct aiColor4D *c, float f[4]) +void color4_to_float4(const C_STRUCT aiColor4D *c, float f[4]) { f[0] = c->r; f[1] = c->g; @@ -113,16 +113,16 @@ void set_float4(float f[4], float a, float b, float c, float d) } /* ---------------------------------------------------------------------------- */ -void apply_material(const struct aiMaterial *mtl) +void apply_material(const C_STRUCT aiMaterial *mtl) { float c[4]; GLenum fill_mode; int ret1, ret2; - struct aiColor4D diffuse; - struct aiColor4D specular; - struct aiColor4D ambient; - struct aiColor4D emission; + C_STRUCT aiColor4D diffuse; + C_STRUCT aiColor4D specular; + C_STRUCT aiColor4D ambient; + C_STRUCT aiColor4D emission; ai_real shininess, strength; int two_sided; int wireframe; @@ -179,11 +179,11 @@ void apply_material(const struct aiMaterial *mtl) } /* ---------------------------------------------------------------------------- */ -void recursive_render (const struct aiScene *sc, const struct aiNode* nd) +void recursive_render (const C_STRUCT aiScene *sc, const C_STRUCT aiNode* nd) { unsigned int i; unsigned int n = 0, t; - struct aiMatrix4x4 m = nd->mTransformation; + C_STRUCT aiMatrix4x4 m = nd->mTransformation; /* update transform */ aiTransposeMatrix4(&m); @@ -192,7 +192,7 @@ void recursive_render (const struct aiScene *sc, const struct aiNode* nd) /* draw all meshes assigned to this node */ for (; n < nd->mNumMeshes; ++n) { - const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; + const C_STRUCT aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; apply_material(sc->mMaterials[mesh->mMaterialIndex]); @@ -203,7 +203,7 @@ void recursive_render (const struct aiScene *sc, const struct aiNode* nd) } for (t = 0; t < mesh->mNumFaces; ++t) { - const struct aiFace* face = &mesh->mFaces[t]; + const C_STRUCT aiFace* face = &mesh->mFaces[t]; GLenum face_mode; switch(face->mNumIndices) { @@ -324,7 +324,7 @@ int loadasset (const char* path) /* ---------------------------------------------------------------------------- */ int main(int argc, char **argv) { - struct aiLogStream stream; + C_STRUCT aiLogStream stream; glutInitWindowSize(900,600); glutInitWindowPosition(100,100); diff --git a/samples/SimpleTexturedOpenGL/CMakeLists.txt b/samples/SimpleTexturedOpenGL/CMakeLists.txt index 1b206af50..40138c49b 100644 --- a/samples/SimpleTexturedOpenGL/CMakeLists.txt +++ b/samples/SimpleTexturedOpenGL/CMakeLists.txt @@ -4,8 +4,8 @@ FIND_PACKAGE(GLUT) IF ( NOT GLUT_FOUND ) IF ( MSVC ) SET ( GLUT_FOUND 1 ) - SET ( GLUT_INCLUDE_DIR ${Assimp_SOURCE_DIR}/samples/glut/ ) - SET ( GLUT_LIBRARIES ${Assimp_SOURCE_DIR}/samples/glut/glut32.lib ) + SET ( GLUT_INCLUDE_DIR ${Assimp_SOURCE_DIR}/samples/freeglut/ ) + SET ( GLUT_LIBRARIES ${Assimp_SOURCE_DIR}/samples/freeglut/lib/freeglut.lib ) ELSE ( MSVC ) MESSAGE( WARNING "Please install glut." ) ENDIF ( MSVC ) @@ -21,13 +21,11 @@ INCLUDE_DIRECTORIES( ${Assimp_SOURCE_DIR}/code ${OPENGL_INCLUDE_DIR} ${GLUT_INCLUDE_DIR} - ${Assimp_SOURCE_DIR}/samples/DevIL/include/ ) LINK_DIRECTORIES( ${Assimp_BINARY_DIR} ${Assimp_BINARY_DIR}/lib/ - ${Assimp_SOURCE_DIR}/samples/DevIL/lib/ ) ADD_EXECUTABLE( assimp_simpletexturedogl WIN32 diff --git a/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp b/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp index df05b56c4..8d25aaaed 100644 --- a/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp +++ b/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp @@ -17,7 +17,9 @@ #include #include #include -#include + +#define STB_IMAGE_IMPLEMENTATION +#include "contrib/stb_image/stb_image.h" #include @@ -25,19 +27,17 @@ #include #include - // assimp include files. These three are usually needed. -#include "assimp/Importer.hpp" //OO version Header! -#include "assimp/postprocess.h" -#include "assimp/scene.h" -#include "assimp/DefaultLogger.hpp" -#include "assimp/LogStream.hpp" +#include +#include +#include +#include +#include // The default hard-coded path. Can be overridden by supplying a path through the command line. static std::string modelpath = "../../test/models/OBJ/spider.obj"; - HGLRC hRC=NULL; // Permanent Rendering Context HDC hDC=NULL; // Private GDI Device Context HWND hWnd=NULL; // Holds Window Handle @@ -75,7 +75,6 @@ GLuint* textureIds; // pointer to texture Array // Create an instance of the Importer class Assimp::Importer importer; - void createAILogger() { // Change this line to normal if you not want to analyse the import process @@ -173,21 +172,22 @@ std::string getBasePath(const std::string& path) int LoadGLTextures(const aiScene* scene) { - ILboolean success; + //ILboolean success; /* Before calling ilInit() version should be checked. */ - if (ilGetInteger(IL_VERSION_NUM) < IL_VERSION) + /*if (ilGetInteger(IL_VERSION_NUM) < IL_VERSION) { /// wrong DevIL version /// std::string err_msg = "Wrong DevIL version. Old devil.dll in system32/SysWow64?"; char* cErr_msg = (char *) err_msg.c_str(); abortGLInit(cErr_msg); return -1; - } + }*/ - ilInit(); /* Initialization of DevIL */ + //ilInit(); /* Initialization of DevIL */ - if (scene->HasTextures()) abortGLInit("Support for meshes with embedded textures is not implemented"); + if (scene->HasTextures()) return 1; + //abortGLInit("Support for meshes with embedded textures is not implemented"); /* getTexture Filenames and Numb of Textures */ for (unsigned int m=0; mmNumMaterials; m++) @@ -207,12 +207,13 @@ int LoadGLTextures(const aiScene* scene) int numTextures = textureIdMap.size(); + /* array with DevIL image IDs */ - ILuint* imageIds = NULL; - imageIds = new ILuint[numTextures]; + //ILuint* imageIds = NULL; +// imageIds = new ILuint[numTextures]; /* generate DevIL Image IDs */ - ilGenImages(numTextures, imageIds); /* Generation of numTextures image names */ +// ilGenImages(numTextures, imageIds); /* Generation of numTextures image names */ /* create and fill array with GL texture ids */ textureIds = new GLuint[numTextures]; @@ -231,21 +232,22 @@ int LoadGLTextures(const aiScene* scene) itr++; // next texture - ilBindImage(imageIds[i]); /* Binding of DevIL image name */ + //ilBindImage(imageIds[i]); /* Binding of DevIL image name */ std::string fileloc = basepath + filename; /* Loading of image */ - success = ilLoadImage(fileloc.c_str()); + //success = ilLoadImage(fileloc.c_str()); + int x, y, n; + unsigned char *data = stbi_load(fileloc.c_str(), &x, &y, &n, STBI_rgb_alpha); - if (success) /* If no error occurred: */ + if (nullptr != data ) { // Convert every colour component into unsigned byte.If your image contains // alpha channel you can replace IL_RGB with IL_RGBA - success = ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE); - if (!success) + //success = ilConvertImage(IL_RGB, IL_UNSIGNED_BYTE); + /*if (!success) { - /* Error occurred */ abortGLInit("Couldn't convert image"); return -1; - } + }*/ // Binding of texture name glBindTexture(GL_TEXTURE_2D, textureIds[i]); // redefine standard texture values @@ -254,15 +256,15 @@ int LoadGLTextures(const aiScene* scene) // We will use linear interpolation for minifying filter glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); // Texture specification - glTexImage2D(GL_TEXTURE_2D, 0, ilGetInteger(IL_IMAGE_BPP), ilGetInteger(IL_IMAGE_WIDTH), - ilGetInteger(IL_IMAGE_HEIGHT), 0, ilGetInteger(IL_IMAGE_FORMAT), GL_UNSIGNED_BYTE, - ilGetData()); + glTexImage2D(GL_TEXTURE_2D, 0, n, x, y, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);// Texture specification. + // we also want to be able to deal with odd texture dimensions glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 ); glPixelStorei( GL_UNPACK_SKIP_PIXELS, 0 ); glPixelStorei( GL_UNPACK_SKIP_ROWS, 0 ); - } + stbi_image_free(data); + } else { /* Error occurred */ @@ -270,11 +272,11 @@ int LoadGLTextures(const aiScene* scene) } } // Because we have already copied image data into texture data we can release memory used by image. - ilDeleteImages(numTextures, imageIds); +// ilDeleteImages(numTextures, imageIds); // Cleanup - delete [] imageIds; - imageIds = NULL; + //delete [] imageIds; + //imageIds = NULL; return TRUE; } diff --git a/samples/bin/DevIL.dll b/samples/bin/DevIL.dll deleted file mode 100644 index 689b3d4de..000000000 Binary files a/samples/bin/DevIL.dll and /dev/null differ diff --git a/samples/bin/ILU.dll b/samples/bin/ILU.dll deleted file mode 100644 index ed44744e6..000000000 Binary files a/samples/bin/ILU.dll and /dev/null differ diff --git a/samples/bin/ILUT.dll b/samples/bin/ILUT.dll deleted file mode 100644 index 8b274b351..000000000 Binary files a/samples/bin/ILUT.dll and /dev/null differ diff --git a/samples/bin/ShowDwarf.bat b/samples/bin/ShowDwarf.bat deleted file mode 100644 index 935343fb0..000000000 --- a/samples/bin/ShowDwarf.bat +++ /dev/null @@ -1 +0,0 @@ -SimpleOpenGL.exe ..\..\test\models-nonbsd\X\dwarf.X \ No newline at end of file diff --git a/samples/bin/ShowWuson.bat b/samples/bin/ShowWuson.bat deleted file mode 100644 index 9eb879dde..000000000 --- a/samples/bin/ShowWuson.bat +++ /dev/null @@ -1 +0,0 @@ -SimpleOpenGL.exe ..\..\test\models\X\Testwuson.X \ No newline at end of file diff --git a/samples/bin/glut32.dll b/samples/bin/glut32.dll deleted file mode 100644 index 196ba78a9..000000000 Binary files a/samples/bin/glut32.dll and /dev/null differ diff --git a/samples/glut/GL/glut.h b/samples/glut/GL/glut.h deleted file mode 100644 index 86aa5c423..000000000 --- a/samples/glut/GL/glut.h +++ /dev/null @@ -1,716 +0,0 @@ -#ifndef __glut_h__ -#define __glut_h__ - -/* Copyright (c) Mark J. Kilgard, 1994, 1995, 1996, 1998. */ - -/* This program is freely distributable without licensing fees and is - provided without guarantee or warrantee expressed or implied. This - program is -not- in the public domain. */ - -#if defined(_WIN32) - -/* GLUT 3.7 now tries to avoid including - to avoid name space pollution, but Win32's - needs APIENTRY and WINGDIAPI defined properly. */ -# if 0 - /* This would put tons of macros and crap in our clean name space. */ -# define WIN32_LEAN_AND_MEAN -# include -# else - /* XXX This is from Win32's */ -# ifndef APIENTRY -# define GLUT_APIENTRY_DEFINED -# if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) || defined(__BORLANDC__) || defined(__LCC__) -# define APIENTRY __stdcall -# else -# define APIENTRY -# endif -# endif - /* XXX This is from Win32's */ -# ifndef CALLBACK -# if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) || defined(__LCC__) -# define CALLBACK __stdcall -# else -# define CALLBACK -# endif -# endif - /* XXX Hack for lcc compiler. It doesn't support __declspec(dllimport), just __stdcall. */ -# if defined( __LCC__ ) -# undef WINGDIAPI -# define WINGDIAPI __stdcall -# else - /* XXX This is from Win32's and */ -# ifndef WINGDIAPI -# define GLUT_WINGDIAPI_DEFINED -# define WINGDIAPI __declspec(dllimport) -# endif -# endif - /* XXX This is from Win32's */ -# ifndef _WCHAR_T_DEFINED -typedef unsigned short wchar_t; -# define _WCHAR_T_DEFINED -# endif -# endif - -/* To disable automatic library usage for GLUT, define GLUT_NO_LIB_PRAGMA - in your compile preprocessor options. */ -# if !defined(GLUT_BUILDING_LIB) && !defined(GLUT_NO_LIB_PRAGMA) -# pragma comment (lib, "winmm.lib") /* link with Windows MultiMedia lib */ -/* To enable automatic SGI OpenGL for Windows library usage for GLUT, - define GLUT_USE_SGI_OPENGL in your compile preprocessor options. */ -# ifdef GLUT_USE_SGI_OPENGL -# pragma comment (lib, "opengl.lib") /* link with SGI OpenGL for Windows lib */ -# pragma comment (lib, "glu.lib") /* link with SGI OpenGL Utility lib */ -# pragma comment (lib, "glut.lib") /* link with Win32 GLUT for SGI OpenGL lib */ -# else -# pragma comment (lib, "opengl32.lib") /* link with Microsoft OpenGL lib */ -# pragma comment (lib, "glu32.lib") /* link with Microsoft OpenGL Utility lib */ -# pragma comment (lib, "glut32.lib") /* link with Win32 GLUT lib */ -# endif -# endif - -/* To disable supression of annoying warnings about floats being promoted - to doubles, define GLUT_NO_WARNING_DISABLE in your compile preprocessor - options. */ -# ifndef GLUT_NO_WARNING_DISABLE -# pragma warning (disable:4244) /* Disable bogus VC++ 4.2 conversion warnings. */ -# pragma warning (disable:4305) /* VC++ 5.0 version of above warning. */ -# endif - -/* Win32 has an annoying issue where there are multiple C run-time - libraries (CRTs). If the executable is linked with a different CRT - from the GLUT DLL, the GLUT DLL will not share the same CRT static - data seen by the executable. In particular, atexit callbacks registered - in the executable will not be called if GLUT calls its (different) - exit routine). GLUT is typically built with the - "/MD" option (the CRT with multithreading DLL support), but the Visual - C++ linker default is "/ML" (the single threaded CRT). - - One workaround to this issue is requiring users to always link with - the same CRT as GLUT is compiled with. That requires users supply a - non-standard option. GLUT 3.7 has its own built-in workaround where - the executable's "exit" function pointer is covertly passed to GLUT. - GLUT then calls the executable's exit function pointer to ensure that - any "atexit" calls registered by the application are called if GLUT - needs to exit. - - Note that the __glut*WithExit routines should NEVER be called directly. - To avoid the atexit workaround, #define GLUT_DISABLE_ATEXIT_HACK. */ - -/* XXX This is from Win32's */ -# if !defined(_MSC_VER) && !defined(__cdecl) - /* Define __cdecl for non-Microsoft compilers. */ -# define __cdecl -# define GLUT_DEFINED___CDECL -# endif -# ifndef _CRTIMP -# ifdef _NTSDK - /* Definition compatible with NT SDK */ -# define _CRTIMP -# else - /* Current definition */ -# ifdef _DLL -# define _CRTIMP __declspec(dllimport) -# else -# define _CRTIMP -# endif -# endif -# define GLUT_DEFINED__CRTIMP -# endif - -/* GLUT API entry point declarations for Win32. */ -# ifdef GLUT_BUILDING_LIB -# define GLUTAPI __declspec(dllexport) -# else -# ifdef _DLL -# define GLUTAPI __declspec(dllimport) -# else -# define GLUTAPI extern -# endif -# endif - -/* GLUT callback calling convention for Win32. */ -# define GLUTCALLBACK __cdecl - -#endif /* _WIN32 */ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#if defined(_WIN32) -# ifndef GLUT_BUILDING_LIB -extern _CRTIMP void __cdecl exit(int); -# endif -#else -/* non-Win32 case. */ -/* Define APIENTRY and CALLBACK to nothing if we aren't on Win32. */ -# define APIENTRY -# define GLUT_APIENTRY_DEFINED -# define CALLBACK -/* Define GLUTAPI and GLUTCALLBACK as below if we aren't on Win32. */ -# define GLUTAPI extern -# define GLUTCALLBACK -/* Prototype exit for the non-Win32 case (see above). */ -extern void exit(int); -#endif - -/** - GLUT API revision history: - - GLUT_API_VERSION is updated to reflect incompatible GLUT - API changes (interface changes, semantic changes, deletions, - or additions). - - GLUT_API_VERSION=1 First public release of GLUT. 11/29/94 - - GLUT_API_VERSION=2 Added support for OpenGL/GLX multisampling, - extension. Supports new input devices like tablet, dial and button - box, and Spaceball. Easy to query OpenGL extensions. - - GLUT_API_VERSION=3 glutMenuStatus added. - - GLUT_API_VERSION=4 glutInitDisplayString, glutWarpPointer, - glutBitmapLength, glutStrokeLength, glutWindowStatusFunc, dynamic - video resize subAPI, glutPostWindowRedisplay, glutKeyboardUpFunc, - glutSpecialUpFunc, glutIgnoreKeyRepeat, glutSetKeyRepeat, - glutJoystickFunc, glutForceJoystickFunc (NOT FINALIZED!). -**/ -#ifndef GLUT_API_VERSION /* allow this to be overridden */ -#define GLUT_API_VERSION 3 -#endif - -/** - GLUT implementation revision history: - - GLUT_XLIB_IMPLEMENTATION is updated to reflect both GLUT - API revisions and implementation revisions (ie, bug fixes). - - GLUT_XLIB_IMPLEMENTATION=1 mjk's first public release of - GLUT Xlib-based implementation. 11/29/94 - - GLUT_XLIB_IMPLEMENTATION=2 mjk's second public release of - GLUT Xlib-based implementation providing GLUT version 2 - interfaces. - - GLUT_XLIB_IMPLEMENTATION=3 mjk's GLUT 2.2 images. 4/17/95 - - GLUT_XLIB_IMPLEMENTATION=4 mjk's GLUT 2.3 images. 6/?/95 - - GLUT_XLIB_IMPLEMENTATION=5 mjk's GLUT 3.0 images. 10/?/95 - - GLUT_XLIB_IMPLEMENTATION=7 mjk's GLUT 3.1+ with glutWarpPoitner. 7/24/96 - - GLUT_XLIB_IMPLEMENTATION=8 mjk's GLUT 3.1+ with glutWarpPoitner - and video resize. 1/3/97 - - GLUT_XLIB_IMPLEMENTATION=9 mjk's GLUT 3.4 release with early GLUT 4 routines. - - GLUT_XLIB_IMPLEMENTATION=11 Mesa 2.5's GLUT 3.6 release. - - GLUT_XLIB_IMPLEMENTATION=12 mjk's GLUT 3.6 release with early GLUT 4 routines + signal handling. - - GLUT_XLIB_IMPLEMENTATION=13 mjk's GLUT 3.7 beta with GameGLUT support. - - GLUT_XLIB_IMPLEMENTATION=14 mjk's GLUT 3.7 beta with f90gl friend interface. - - GLUT_XLIB_IMPLEMENTATION=15 mjk's GLUT 3.7 beta sync'ed with Mesa -**/ -#ifndef GLUT_XLIB_IMPLEMENTATION /* Allow this to be overridden. */ -#define GLUT_XLIB_IMPLEMENTATION 15 -#endif - -/* Display mode bit masks. */ -#define GLUT_RGB 0 -#define GLUT_RGBA GLUT_RGB -#define GLUT_INDEX 1 -#define GLUT_SINGLE 0 -#define GLUT_DOUBLE 2 -#define GLUT_ACCUM 4 -#define GLUT_ALPHA 8 -#define GLUT_DEPTH 16 -#define GLUT_STENCIL 32 -#if (GLUT_API_VERSION >= 2) -#define GLUT_MULTISAMPLE 128 -#define GLUT_STEREO 256 -#endif -#if (GLUT_API_VERSION >= 3) -#define GLUT_LUMINANCE 512 -#endif - -/* Mouse buttons. */ -#define GLUT_LEFT_BUTTON 0 -#define GLUT_MIDDLE_BUTTON 1 -#define GLUT_RIGHT_BUTTON 2 - -/* Mouse button state. */ -#define GLUT_DOWN 0 -#define GLUT_UP 1 - -#if (GLUT_API_VERSION >= 2) -/* function keys */ -#define GLUT_KEY_F1 1 -#define GLUT_KEY_F2 2 -#define GLUT_KEY_F3 3 -#define GLUT_KEY_F4 4 -#define GLUT_KEY_F5 5 -#define GLUT_KEY_F6 6 -#define GLUT_KEY_F7 7 -#define GLUT_KEY_F8 8 -#define GLUT_KEY_F9 9 -#define GLUT_KEY_F10 10 -#define GLUT_KEY_F11 11 -#define GLUT_KEY_F12 12 -/* directional keys */ -#define GLUT_KEY_LEFT 100 -#define GLUT_KEY_UP 101 -#define GLUT_KEY_RIGHT 102 -#define GLUT_KEY_DOWN 103 -#define GLUT_KEY_PAGE_UP 104 -#define GLUT_KEY_PAGE_DOWN 105 -#define GLUT_KEY_HOME 106 -#define GLUT_KEY_END 107 -#define GLUT_KEY_INSERT 108 -#endif - -/* Entry/exit state. */ -#define GLUT_LEFT 0 -#define GLUT_ENTERED 1 - -/* Menu usage state. */ -#define GLUT_MENU_NOT_IN_USE 0 -#define GLUT_MENU_IN_USE 1 - -/* Visibility state. */ -#define GLUT_NOT_VISIBLE 0 -#define GLUT_VISIBLE 1 - -/* Window status state. */ -#define GLUT_HIDDEN 0 -#define GLUT_FULLY_RETAINED 1 -#define GLUT_PARTIALLY_RETAINED 2 -#define GLUT_FULLY_COVERED 3 - -/* Color index component selection values. */ -#define GLUT_RED 0 -#define GLUT_GREEN 1 -#define GLUT_BLUE 2 - -#if defined(_WIN32) -/* Stroke font constants (use these in GLUT program). */ -#define GLUT_STROKE_ROMAN ((void*)0) -#define GLUT_STROKE_MONO_ROMAN ((void*)1) - -/* Bitmap font constants (use these in GLUT program). */ -#define GLUT_BITMAP_9_BY_15 ((void*)2) -#define GLUT_BITMAP_8_BY_13 ((void*)3) -#define GLUT_BITMAP_TIMES_ROMAN_10 ((void*)4) -#define GLUT_BITMAP_TIMES_ROMAN_24 ((void*)5) -#if (GLUT_API_VERSION >= 3) -#define GLUT_BITMAP_HELVETICA_10 ((void*)6) -#define GLUT_BITMAP_HELVETICA_12 ((void*)7) -#define GLUT_BITMAP_HELVETICA_18 ((void*)8) -#endif -#else -/* Stroke font opaque addresses (use constants instead in source code). */ -GLUTAPI void *glutStrokeRoman; -GLUTAPI void *glutStrokeMonoRoman; - -/* Stroke font constants (use these in GLUT program). */ -#define GLUT_STROKE_ROMAN (&glutStrokeRoman) -#define GLUT_STROKE_MONO_ROMAN (&glutStrokeMonoRoman) - -/* Bitmap font opaque addresses (use constants instead in source code). */ -GLUTAPI void *glutBitmap9By15; -GLUTAPI void *glutBitmap8By13; -GLUTAPI void *glutBitmapTimesRoman10; -GLUTAPI void *glutBitmapTimesRoman24; -GLUTAPI void *glutBitmapHelvetica10; -GLUTAPI void *glutBitmapHelvetica12; -GLUTAPI void *glutBitmapHelvetica18; - -/* Bitmap font constants (use these in GLUT program). */ -#define GLUT_BITMAP_9_BY_15 (&glutBitmap9By15) -#define GLUT_BITMAP_8_BY_13 (&glutBitmap8By13) -#define GLUT_BITMAP_TIMES_ROMAN_10 (&glutBitmapTimesRoman10) -#define GLUT_BITMAP_TIMES_ROMAN_24 (&glutBitmapTimesRoman24) -#if (GLUT_API_VERSION >= 3) -#define GLUT_BITMAP_HELVETICA_10 (&glutBitmapHelvetica10) -#define GLUT_BITMAP_HELVETICA_12 (&glutBitmapHelvetica12) -#define GLUT_BITMAP_HELVETICA_18 (&glutBitmapHelvetica18) -#endif -#endif - -/* glutGet parameters. */ -#define GLUT_WINDOW_X ((GLenum) 100) -#define GLUT_WINDOW_Y ((GLenum) 101) -#define GLUT_WINDOW_WIDTH ((GLenum) 102) -#define GLUT_WINDOW_HEIGHT ((GLenum) 103) -#define GLUT_WINDOW_BUFFER_SIZE ((GLenum) 104) -#define GLUT_WINDOW_STENCIL_SIZE ((GLenum) 105) -#define GLUT_WINDOW_DEPTH_SIZE ((GLenum) 106) -#define GLUT_WINDOW_RED_SIZE ((GLenum) 107) -#define GLUT_WINDOW_GREEN_SIZE ((GLenum) 108) -#define GLUT_WINDOW_BLUE_SIZE ((GLenum) 109) -#define GLUT_WINDOW_ALPHA_SIZE ((GLenum) 110) -#define GLUT_WINDOW_ACCUM_RED_SIZE ((GLenum) 111) -#define GLUT_WINDOW_ACCUM_GREEN_SIZE ((GLenum) 112) -#define GLUT_WINDOW_ACCUM_BLUE_SIZE ((GLenum) 113) -#define GLUT_WINDOW_ACCUM_ALPHA_SIZE ((GLenum) 114) -#define GLUT_WINDOW_DOUBLEBUFFER ((GLenum) 115) -#define GLUT_WINDOW_RGBA ((GLenum) 116) -#define GLUT_WINDOW_PARENT ((GLenum) 117) -#define GLUT_WINDOW_NUM_CHILDREN ((GLenum) 118) -#define GLUT_WINDOW_COLORMAP_SIZE ((GLenum) 119) -#if (GLUT_API_VERSION >= 2) -#define GLUT_WINDOW_NUM_SAMPLES ((GLenum) 120) -#define GLUT_WINDOW_STEREO ((GLenum) 121) -#endif -#if (GLUT_API_VERSION >= 3) -#define GLUT_WINDOW_CURSOR ((GLenum) 122) -#endif -#define GLUT_SCREEN_WIDTH ((GLenum) 200) -#define GLUT_SCREEN_HEIGHT ((GLenum) 201) -#define GLUT_SCREEN_WIDTH_MM ((GLenum) 202) -#define GLUT_SCREEN_HEIGHT_MM ((GLenum) 203) -#define GLUT_MENU_NUM_ITEMS ((GLenum) 300) -#define GLUT_DISPLAY_MODE_POSSIBLE ((GLenum) 400) -#define GLUT_INIT_WINDOW_X ((GLenum) 500) -#define GLUT_INIT_WINDOW_Y ((GLenum) 501) -#define GLUT_INIT_WINDOW_WIDTH ((GLenum) 502) -#define GLUT_INIT_WINDOW_HEIGHT ((GLenum) 503) -#define GLUT_INIT_DISPLAY_MODE ((GLenum) 504) -#if (GLUT_API_VERSION >= 2) -#define GLUT_ELAPSED_TIME ((GLenum) 700) -#endif -#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) -#define GLUT_WINDOW_FORMAT_ID ((GLenum) 123) -#endif - -#if (GLUT_API_VERSION >= 2) -/* glutDeviceGet parameters. */ -#define GLUT_HAS_KEYBOARD ((GLenum) 600) -#define GLUT_HAS_MOUSE ((GLenum) 601) -#define GLUT_HAS_SPACEBALL ((GLenum) 602) -#define GLUT_HAS_DIAL_AND_BUTTON_BOX ((GLenum) 603) -#define GLUT_HAS_TABLET ((GLenum) 604) -#define GLUT_NUM_MOUSE_BUTTONS ((GLenum) 605) -#define GLUT_NUM_SPACEBALL_BUTTONS ((GLenum) 606) -#define GLUT_NUM_BUTTON_BOX_BUTTONS ((GLenum) 607) -#define GLUT_NUM_DIALS ((GLenum) 608) -#define GLUT_NUM_TABLET_BUTTONS ((GLenum) 609) -#endif -#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) -#define GLUT_DEVICE_IGNORE_KEY_REPEAT ((GLenum) 610) -#define GLUT_DEVICE_KEY_REPEAT ((GLenum) 611) -#define GLUT_HAS_JOYSTICK ((GLenum) 612) -#define GLUT_OWNS_JOYSTICK ((GLenum) 613) -#define GLUT_JOYSTICK_BUTTONS ((GLenum) 614) -#define GLUT_JOYSTICK_AXES ((GLenum) 615) -#define GLUT_JOYSTICK_POLL_RATE ((GLenum) 616) -#endif - -#if (GLUT_API_VERSION >= 3) -/* glutLayerGet parameters. */ -#define GLUT_OVERLAY_POSSIBLE ((GLenum) 800) -#define GLUT_LAYER_IN_USE ((GLenum) 801) -#define GLUT_HAS_OVERLAY ((GLenum) 802) -#define GLUT_TRANSPARENT_INDEX ((GLenum) 803) -#define GLUT_NORMAL_DAMAGED ((GLenum) 804) -#define GLUT_OVERLAY_DAMAGED ((GLenum) 805) - -#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) -/* glutVideoResizeGet parameters. */ -#define GLUT_VIDEO_RESIZE_POSSIBLE ((GLenum) 900) -#define GLUT_VIDEO_RESIZE_IN_USE ((GLenum) 901) -#define GLUT_VIDEO_RESIZE_X_DELTA ((GLenum) 902) -#define GLUT_VIDEO_RESIZE_Y_DELTA ((GLenum) 903) -#define GLUT_VIDEO_RESIZE_WIDTH_DELTA ((GLenum) 904) -#define GLUT_VIDEO_RESIZE_HEIGHT_DELTA ((GLenum) 905) -#define GLUT_VIDEO_RESIZE_X ((GLenum) 906) -#define GLUT_VIDEO_RESIZE_Y ((GLenum) 907) -#define GLUT_VIDEO_RESIZE_WIDTH ((GLenum) 908) -#define GLUT_VIDEO_RESIZE_HEIGHT ((GLenum) 909) -#endif - -/* glutUseLayer parameters. */ -#define GLUT_NORMAL ((GLenum) 0) -#define GLUT_OVERLAY ((GLenum) 1) - -/* glutGetModifiers return mask. */ -#define GLUT_ACTIVE_SHIFT 1 -#define GLUT_ACTIVE_CTRL 2 -#define GLUT_ACTIVE_ALT 4 - -/* glutSetCursor parameters. */ -/* Basic arrows. */ -#define GLUT_CURSOR_RIGHT_ARROW 0 -#define GLUT_CURSOR_LEFT_ARROW 1 -/* Symbolic cursor shapes. */ -#define GLUT_CURSOR_INFO 2 -#define GLUT_CURSOR_DESTROY 3 -#define GLUT_CURSOR_HELP 4 -#define GLUT_CURSOR_CYCLE 5 -#define GLUT_CURSOR_SPRAY 6 -#define GLUT_CURSOR_WAIT 7 -#define GLUT_CURSOR_TEXT 8 -#define GLUT_CURSOR_CROSSHAIR 9 -/* Directional cursors. */ -#define GLUT_CURSOR_UP_DOWN 10 -#define GLUT_CURSOR_LEFT_RIGHT 11 -/* Sizing cursors. */ -#define GLUT_CURSOR_TOP_SIDE 12 -#define GLUT_CURSOR_BOTTOM_SIDE 13 -#define GLUT_CURSOR_LEFT_SIDE 14 -#define GLUT_CURSOR_RIGHT_SIDE 15 -#define GLUT_CURSOR_TOP_LEFT_CORNER 16 -#define GLUT_CURSOR_TOP_RIGHT_CORNER 17 -#define GLUT_CURSOR_BOTTOM_RIGHT_CORNER 18 -#define GLUT_CURSOR_BOTTOM_LEFT_CORNER 19 -/* Inherit from parent window. */ -#define GLUT_CURSOR_INHERIT 100 -/* Blank cursor. */ -#define GLUT_CURSOR_NONE 101 -/* Fullscreen crosshair (if available). */ -#define GLUT_CURSOR_FULL_CROSSHAIR 102 -#endif - -/* GLUT initialization sub-API. */ -GLUTAPI void APIENTRY glutInit(int *argcp, char **argv); -#if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) -GLUTAPI void APIENTRY __glutInitWithExit(int *argcp, char **argv, void (__cdecl *exitfunc)(int)); -#ifndef GLUT_BUILDING_LIB -static void APIENTRY glutInit_ATEXIT_HACK(int *argcp, char **argv) { __glutInitWithExit(argcp, argv, exit); } -#define glutInit glutInit_ATEXIT_HACK -#endif -#endif -GLUTAPI void APIENTRY glutInitDisplayMode(unsigned int mode); -#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) -GLUTAPI void APIENTRY glutInitDisplayString(const char *string); -#endif -GLUTAPI void APIENTRY glutInitWindowPosition(int x, int y); -GLUTAPI void APIENTRY glutInitWindowSize(int width, int height); -GLUTAPI void APIENTRY glutMainLoop(void); - -/* GLUT window sub-API. */ -GLUTAPI int APIENTRY glutCreateWindow(const char *title); -#if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) -GLUTAPI int APIENTRY __glutCreateWindowWithExit(const char *title, void (__cdecl *exitfunc)(int)); -#ifndef GLUT_BUILDING_LIB -static int APIENTRY glutCreateWindow_ATEXIT_HACK(const char *title) { return __glutCreateWindowWithExit(title, exit); } -#define glutCreateWindow glutCreateWindow_ATEXIT_HACK -#endif -#endif -GLUTAPI int APIENTRY glutCreateSubWindow(int win, int x, int y, int width, int height); -GLUTAPI void APIENTRY glutDestroyWindow(int win); -GLUTAPI void APIENTRY glutPostRedisplay(void); -#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 11) -GLUTAPI void APIENTRY glutPostWindowRedisplay(int win); -#endif -GLUTAPI void APIENTRY glutSwapBuffers(void); -GLUTAPI int APIENTRY glutGetWindow(void); -GLUTAPI void APIENTRY glutSetWindow(int win); -GLUTAPI void APIENTRY glutSetWindowTitle(const char *title); -GLUTAPI void APIENTRY glutSetIconTitle(const char *title); -GLUTAPI void APIENTRY glutPositionWindow(int x, int y); -GLUTAPI void APIENTRY glutReshapeWindow(int width, int height); -GLUTAPI void APIENTRY glutPopWindow(void); -GLUTAPI void APIENTRY glutPushWindow(void); -GLUTAPI void APIENTRY glutIconifyWindow(void); -GLUTAPI void APIENTRY glutShowWindow(void); -GLUTAPI void APIENTRY glutHideWindow(void); -#if (GLUT_API_VERSION >= 3) -GLUTAPI void APIENTRY glutFullScreen(void); -GLUTAPI void APIENTRY glutSetCursor(int cursor); -#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) -GLUTAPI void APIENTRY glutWarpPointer(int x, int y); -#endif - -/* GLUT overlay sub-API. */ -GLUTAPI void APIENTRY glutEstablishOverlay(void); -GLUTAPI void APIENTRY glutRemoveOverlay(void); -GLUTAPI void APIENTRY glutUseLayer(GLenum layer); -GLUTAPI void APIENTRY glutPostOverlayRedisplay(void); -#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 11) -GLUTAPI void APIENTRY glutPostWindowOverlayRedisplay(int win); -#endif -GLUTAPI void APIENTRY glutShowOverlay(void); -GLUTAPI void APIENTRY glutHideOverlay(void); -#endif - -/* GLUT menu sub-API. */ -GLUTAPI int APIENTRY glutCreateMenu(void (GLUTCALLBACK *func)(int)); -#if defined(_WIN32) && !defined(GLUT_DISABLE_ATEXIT_HACK) -GLUTAPI int APIENTRY __glutCreateMenuWithExit(void (GLUTCALLBACK *func)(int), void (__cdecl *exitfunc)(int)); -#ifndef GLUT_BUILDING_LIB -static int APIENTRY glutCreateMenu_ATEXIT_HACK(void (GLUTCALLBACK *func)(int)) { return __glutCreateMenuWithExit(func, exit); } -#define glutCreateMenu glutCreateMenu_ATEXIT_HACK -#endif -#endif -GLUTAPI void APIENTRY glutDestroyMenu(int menu); -GLUTAPI int APIENTRY glutGetMenu(void); -GLUTAPI void APIENTRY glutSetMenu(int menu); -GLUTAPI void APIENTRY glutAddMenuEntry(const char *label, int value); -GLUTAPI void APIENTRY glutAddSubMenu(const char *label, int submenu); -GLUTAPI void APIENTRY glutChangeToMenuEntry(int item, const char *label, int value); -GLUTAPI void APIENTRY glutChangeToSubMenu(int item, const char *label, int submenu); -GLUTAPI void APIENTRY glutRemoveMenuItem(int item); -GLUTAPI void APIENTRY glutAttachMenu(int button); -GLUTAPI void APIENTRY glutDetachMenu(int button); - -/* GLUT window callback sub-API. */ -GLUTAPI void APIENTRY glutDisplayFunc(void (GLUTCALLBACK *func)(void)); -GLUTAPI void APIENTRY glutReshapeFunc(void (GLUTCALLBACK *func)(int width, int height)); -GLUTAPI void APIENTRY glutKeyboardFunc(void (GLUTCALLBACK *func)(unsigned char key, int x, int y)); -GLUTAPI void APIENTRY glutMouseFunc(void (GLUTCALLBACK *func)(int button, int state, int x, int y)); -GLUTAPI void APIENTRY glutMotionFunc(void (GLUTCALLBACK *func)(int x, int y)); -GLUTAPI void APIENTRY glutPassiveMotionFunc(void (GLUTCALLBACK *func)(int x, int y)); -GLUTAPI void APIENTRY glutEntryFunc(void (GLUTCALLBACK *func)(int state)); -GLUTAPI void APIENTRY glutVisibilityFunc(void (GLUTCALLBACK *func)(int state)); -GLUTAPI void APIENTRY glutIdleFunc(void (GLUTCALLBACK *func)(void)); -GLUTAPI void APIENTRY glutTimerFunc(unsigned int millis, void (GLUTCALLBACK *func)(int value), int value); -GLUTAPI void APIENTRY glutMenuStateFunc(void (GLUTCALLBACK *func)(int state)); -#if (GLUT_API_VERSION >= 2) -GLUTAPI void APIENTRY glutSpecialFunc(void (GLUTCALLBACK *func)(int key, int x, int y)); -GLUTAPI void APIENTRY glutSpaceballMotionFunc(void (GLUTCALLBACK *func)(int x, int y, int z)); -GLUTAPI void APIENTRY glutSpaceballRotateFunc(void (GLUTCALLBACK *func)(int x, int y, int z)); -GLUTAPI void APIENTRY glutSpaceballButtonFunc(void (GLUTCALLBACK *func)(int button, int state)); -GLUTAPI void APIENTRY glutButtonBoxFunc(void (GLUTCALLBACK *func)(int button, int state)); -GLUTAPI void APIENTRY glutDialsFunc(void (GLUTCALLBACK *func)(int dial, int value)); -GLUTAPI void APIENTRY glutTabletMotionFunc(void (GLUTCALLBACK *func)(int x, int y)); -GLUTAPI void APIENTRY glutTabletButtonFunc(void (GLUTCALLBACK *func)(int button, int state, int x, int y)); -#if (GLUT_API_VERSION >= 3) -GLUTAPI void APIENTRY glutMenuStatusFunc(void (GLUTCALLBACK *func)(int status, int x, int y)); -GLUTAPI void APIENTRY glutOverlayDisplayFunc(void (GLUTCALLBACK *func)(void)); -#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) -GLUTAPI void APIENTRY glutWindowStatusFunc(void (GLUTCALLBACK *func)(int state)); -#endif -#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) -GLUTAPI void APIENTRY glutKeyboardUpFunc(void (GLUTCALLBACK *func)(unsigned char key, int x, int y)); -GLUTAPI void APIENTRY glutSpecialUpFunc(void (GLUTCALLBACK *func)(int key, int x, int y)); -GLUTAPI void APIENTRY glutJoystickFunc(void (GLUTCALLBACK *func)(unsigned int buttonMask, int x, int y, int z), int pollInterval); -#endif -#endif -#endif - -/* GLUT color index sub-API. */ -GLUTAPI void APIENTRY glutSetColor(int, GLfloat red, GLfloat green, GLfloat blue); -GLUTAPI GLfloat APIENTRY glutGetColor(int ndx, int component); -GLUTAPI void APIENTRY glutCopyColormap(int win); - -/* GLUT state retrieval sub-API. */ -GLUTAPI int APIENTRY glutGet(GLenum type); -GLUTAPI int APIENTRY glutDeviceGet(GLenum type); -#if (GLUT_API_VERSION >= 2) -/* GLUT extension support sub-API */ -GLUTAPI int APIENTRY glutExtensionSupported(const char *name); -#endif -#if (GLUT_API_VERSION >= 3) -GLUTAPI int APIENTRY glutGetModifiers(void); -GLUTAPI int APIENTRY glutLayerGet(GLenum type); -#endif - -/* GLUT font sub-API */ -GLUTAPI void APIENTRY glutBitmapCharacter(void *font, int character); -GLUTAPI int APIENTRY glutBitmapWidth(void *font, int character); -GLUTAPI void APIENTRY glutStrokeCharacter(void *font, int character); -GLUTAPI int APIENTRY glutStrokeWidth(void *font, int character); -#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) -GLUTAPI int APIENTRY glutBitmapLength(void *font, const unsigned char *string); -GLUTAPI int APIENTRY glutStrokeLength(void *font, const unsigned char *string); -#endif - -/* GLUT pre-built models sub-API */ -GLUTAPI void APIENTRY glutWireSphere(GLdouble radius, GLint slices, GLint stacks); -GLUTAPI void APIENTRY glutSolidSphere(GLdouble radius, GLint slices, GLint stacks); -GLUTAPI void APIENTRY glutWireCone(GLdouble base, GLdouble height, GLint slices, GLint stacks); -GLUTAPI void APIENTRY glutSolidCone(GLdouble base, GLdouble height, GLint slices, GLint stacks); -GLUTAPI void APIENTRY glutWireCube(GLdouble size); -GLUTAPI void APIENTRY glutSolidCube(GLdouble size); -GLUTAPI void APIENTRY glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings); -GLUTAPI void APIENTRY glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings); -GLUTAPI void APIENTRY glutWireDodecahedron(void); -GLUTAPI void APIENTRY glutSolidDodecahedron(void); -GLUTAPI void APIENTRY glutWireTeapot(GLdouble size); -GLUTAPI void APIENTRY glutSolidTeapot(GLdouble size); -GLUTAPI void APIENTRY glutWireOctahedron(void); -GLUTAPI void APIENTRY glutSolidOctahedron(void); -GLUTAPI void APIENTRY glutWireTetrahedron(void); -GLUTAPI void APIENTRY glutSolidTetrahedron(void); -GLUTAPI void APIENTRY glutWireIcosahedron(void); -GLUTAPI void APIENTRY glutSolidIcosahedron(void); - -#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 9) -/* GLUT video resize sub-API. */ -GLUTAPI int APIENTRY glutVideoResizeGet(GLenum param); -GLUTAPI void APIENTRY glutSetupVideoResizing(void); -GLUTAPI void APIENTRY glutStopVideoResizing(void); -GLUTAPI void APIENTRY glutVideoResize(int x, int y, int width, int height); -GLUTAPI void APIENTRY glutVideoPan(int x, int y, int width, int height); - -/* GLUT debugging sub-API. */ -GLUTAPI void APIENTRY glutReportErrors(void); -#endif - -#if (GLUT_API_VERSION >= 4 || GLUT_XLIB_IMPLEMENTATION >= 13) -/* GLUT device control sub-API. */ -/* glutSetKeyRepeat modes. */ -#define GLUT_KEY_REPEAT_OFF 0 -#define GLUT_KEY_REPEAT_ON 1 -#define GLUT_KEY_REPEAT_DEFAULT 2 - -/* Joystick button masks. */ -#define GLUT_JOYSTICK_BUTTON_A 1 -#define GLUT_JOYSTICK_BUTTON_B 2 -#define GLUT_JOYSTICK_BUTTON_C 4 -#define GLUT_JOYSTICK_BUTTON_D 8 - -GLUTAPI void APIENTRY glutIgnoreKeyRepeat(int ignore); -GLUTAPI void APIENTRY glutSetKeyRepeat(int repeatMode); -GLUTAPI void APIENTRY glutForceJoystickFunc(void); - -/* GLUT game mode sub-API. */ -/* glutGameModeGet. */ -#define GLUT_GAME_MODE_ACTIVE ((GLenum) 0) -#define GLUT_GAME_MODE_POSSIBLE ((GLenum) 1) -#define GLUT_GAME_MODE_WIDTH ((GLenum) 2) -#define GLUT_GAME_MODE_HEIGHT ((GLenum) 3) -#define GLUT_GAME_MODE_PIXEL_DEPTH ((GLenum) 4) -#define GLUT_GAME_MODE_REFRESH_RATE ((GLenum) 5) -#define GLUT_GAME_MODE_DISPLAY_CHANGED ((GLenum) 6) - -GLUTAPI void APIENTRY glutGameModeString(const char *string); -GLUTAPI int APIENTRY glutEnterGameMode(void); -GLUTAPI void APIENTRY glutLeaveGameMode(void); -GLUTAPI int APIENTRY glutGameModeGet(GLenum mode); -#endif - -#ifdef __cplusplus -} - -#endif - -#ifdef GLUT_APIENTRY_DEFINED -# undef GLUT_APIENTRY_DEFINED -# undef APIENTRY -#endif - -#ifdef GLUT_WINGDIAPI_DEFINED -# undef GLUT_WINGDIAPI_DEFINED -# undef WINGDIAPI -#endif - -#ifdef GLUT_DEFINED___CDECL -# undef GLUT_DEFINED___CDECL -# undef __cdecl -#endif - -#ifdef GLUT_DEFINED__CRTIMP -# undef GLUT_DEFINED__CRTIMP -# undef _CRTIMP -#endif - -#endif /* __glut_h__ */ diff --git a/samples/glut/README-win32.txt b/samples/glut/README-win32.txt deleted file mode 100644 index 59bd9504e..000000000 --- a/samples/glut/README-win32.txt +++ /dev/null @@ -1,613 +0,0 @@ - - - GLUT for Win32 README - --------------------- - - -VERSION/INFO: - - This is GLUT for Win32 version 3.7.6 as of Nov 8th 2001. - See the COPYRIGHT section for distribution and copyright notices. - Send all bug reports and questions for this version of GLUT to - Nate Robins [nate@pobox.com]. - - For more information about GLUT for Win32, see the web page: - www.pobox.com/~nate/glut.html or subscribe to the GLUT for Win32 - mailing list by sending e-mail to majordomo@perp.com with - "subscribe glut" in the body of the message. - - For general information about GLUT, see the GLUT web page: - http://reality.sgi.com/opengl/glut3/glut3.html and be sure to - check the GLUT FAQ first for any questions that you may have: - http://reality.sgi.com/opengl/glut3/glut-faq.html - - -COMPILING/INSTALLATION: - - o Precompiled versions of the DLL and import library can be - found on the GLUT for Win32 web page mentioned above. - - o Microsoft Developer Studio 6 workspace and project files have - been included in the source code distribution. - - To build the glut dll: - First, open Microsoft Developer Studio. - Then, select File -> Open Workspace and find the glut.dsw file - in the file dialog and double-click on it. - Finally, select Build -> Build glut32.dll. - When the build is finished, it will copy: - glut32.dll to %WinDir%\System, - glut32.lib to $(MSDevDir)\..\..\VC98\lib, and - glut.h to $(MSDevDir)\..\..\VC98\include\GL. - - Additional workspace files have been included in the progs, test - and lib directories to build the progs, tests and libs respectively. - - -BORLAND NOTES: - - From what I understand, Borland supplies a utility that - converts Microsoft Visual C++ .libs into Borland compatible - files. Therefore, the best method for Borland users is - probably to get the precompiled versions of the library and - convert the library. To create an import library for Borland - from the DLLs, use the following command (from a command prompt): - IMPLIB glut32.lib glut32.dll - If IMPLIB crashes when called this way, try - IMPLIB glut32.lib glut32.def - using the glut32.def file in this distribution. - - -FORTRAN NOTES: - - Bill Mitchell [william.mitchell@nist.gov] has put considerable - effort into getting GLUT to work with different compilers for - Fortran 90. He indicates that you should copy the f90glut.h - file to your $(MSDevDir)\..\..\VC98\include\GL directory. - Then, just build GLUT as usual. The Fortran 90 interface, f90gl, - can be obtained at http://math.nist.gov/f90gl and contains - installation instructions and usage examples. - - -MISC NOTES: - - o Overlay support is not implemented, nor are there any plans to - implement it in the near future. - - o To customize the windows icon, you can use the resource name - GLUT_ICON. For example, create an icon named "glut.ico", and - create a file called glut.rc that contains the following: - GLUT_ICON ICON glut.ico - then compile the glut.rc file with the following: - rc /r glut - and link the resulting glut.res file into your executable - (just like you would an object file). - Alternatively, you can simply add the glut.rc file to your - project if you are using Microsoft Developer Studio. - - -IMPLEMENTATION DEPENDENT DIFFERENCES: - - There are a few differences between the Win32 version of GLUT - and the X11 version of GLUT. Those are outlined here. Note - that MOST of these differences are allowed by the GLUT - specification. Bugs and unsupported features are outlined in - the UNSUPPORTED/BUGS section. - - o glutInit: - The following command line options have no meaning (and are - ignored) in GLUT for Win32: - -display, -indirect, -direct, -sync. - - o glutInitWindowPosition, glutPositionWindow: - Win32 has two different coordinate systems for windows. - One is in terms of client space and the other is the whole - window space (including the decorations). If you - glutPositionWindow(0, 0), GLUT for Win32 will place the - window CLIENT area at 0, 0. This will cause the window - decorations (title bar and left edge) to be OFF-SCREEN, but - it gives the user the most flexibility in positioning. - HOWEVER, if the user specifies glutInitWindowPosition(0, 0), - the window is placed relative to window space at 0, 0. - This will cause the window to be opened in the upper left - corner with all the decorations showing. This behaviour is - acceptable under the current GLUT specification. - - o glutSetIconTitle, glutSetWindowTitle: - There is no separation between Icon title and Window title - in Win32. Therefore, setting an icon title in Win32 has - no effect. - - o glutSetCursor: - As indicated in the GLUT specification, cursors may be - different on different platforms. This is the case in GLUT - for Win32. For the most part, the cursors will match the - meaning, but not necessarily the shape. Notable exceptions - are the GLUT_CURSOR_INFO & GLUT_CURSOR_SPRAY which use the - crosshair cursor and the GLUT_CURSOR_CYCLE which uses the - 'no' or 'destroy' cursor in Win32. - - o glutVisibilityFunc: - Win32 seems to be unable to determine if a window is fully - obscured. Therefore, the visibility of a GLUT window is - only reflected by its Iconic, Hidden or Shown state. That - is, even if a window is fully obscured, in GLUT for Win32, - it is still "visible". - - o glutEntryFunc: - Window Focus is handled differently in Win32 and X. - Specifically, the "window manager" in Win32 uses a "click to - focus" policy. That is, in order for a window to receive - focus, a mouse button must be clicked in it. Likewise, in - order for a window to lose focus, a mouse button must be - clicked outside the window (or in another window). - Therefore, the Enter and Leave notification provided by GLUT - may behave differently in the Win32 and in X11 versions. - There is a viable workaround for this. A program called - "Tweak UI" is provided by Microsoft which can be used to - change the focus policy in Win32 to "focus follows mouse". - It is available from the Microsoft Web Pages: - http://www.microsoft.com/windows/software/PowerToy.htm - - o glutCopyColormap: - GLUT for Win32 always copies the colormap. There is never - any sharing of colormaps. This is probably okay, since - Win32 merges the logical palette and the physical palette - anyway, so even if there are two windows with totally - different colors in their colormaps, Win32 will find a - (hopefully) good match between them. - - o glutIdleFunc + menus: - The glut idle function will NOT be called when a menu is - active. This causes all animation to stop when a menu is - active (in general, this is probably okay). Timer - functions will still fire, however. If the timer callback - draws into the rendering context, the drawing will not show - up until after the menu has finished, though. - - -UNSUPPORTED/BUGS: - - o glutAttachMenu: - Win32 only likes to work with left and right mouse buttons. - Especially so with popup menus. Therefore, when attaching - the menu to the middle mouse button, the LEFT mouse button - must be used to select from the menu. - - o glutSpaceball*, glutButtonBox*, glutTablet*, glutDials*: - None of the special input devices are supported at this - time. - - o When resizing or moving a GLUT for Win32 window, no updating - is performed. This causes the window to leave "tracks" on - the screen when getting bigger or when previously obscured - parts are being revealed. I put in a bit of a kludgy - workaround for those that absolutely can't have the weird - lines. The reshape callback is called multiple times for - reshapes. Therefore, in the reshape callback, some drawing - can be done. It should probably be limited to a color buffer - clear. - - o The video resizing capabilities of GLUT 3.3+ for X11 is - currently unimplemented (this is probably ok, since it - really isn't part of the spec until 4.0). I doubt that - this will ever be part of GLUT for Win32, since there is no - hardware to support it. A hack could simply change the - resolution of the desktop. - - -CHANGES/FIXES: - - (Nov 8, '01) - x Released 3.7.6 - - (Nov 8, '01) - x Changed fullscreen mode from TOPMOST back to simply TOP, since - (it turns out) many people use windows atop a GLUT window. - - (Nov 8, '01) - x Added code to prevent CPU spiking when no idle function is - registered. Otherwise, if an idle function is registered, spike - CPU so that the idle function gets all the attention it needs and - if this is a problem on the program side, the user can stick a - sleep() in their idle function. I believe that this strikes the - best balance betweeen GLUT being fast, and also being "nice" to - other processes. Thanks to James Wright for reporting this bug. - - (Nov 8, '01) - x Fixed bug in motion callback handler which wasn't setting the - current window, so multiple window apps (e.g., any GLUI app) - wouldn't get the callback correctly. - - (Oct 4, '01) - x Fixed bug in glutEnterGameMode() that caused new windows to not - be in "fullscreen" mode, so they got window decorations. - - (Oct 4, '01) - x Fixed bug in glutEnterGameMode() that caused new windows to not - be in "fullscreen" mode, so they got window decorations. - - (Oct 3, '01) - x Fixed bug in getVisualInfoFromString(): visuals not reloaded on - display mode change. Reload visuals each time they are queried. - This fixes a problem with Win32 because the list of available Visuals - (Pixelformats) changes after a change in displaymode. The problem - occurs when switching to gamemode and back. Thanks to Michael - Wimmer for pointing this out & providing the fix. - - (Oct 3, '01) - x Fixed bug in XGetVisualInfo(): pixelformats enumerated incorrectly. - Passing 0 as a pixelformat index to DescribePixelFormat gives - unpredictible results (e.g., this fails on the Voodoo opengl32.dll - and always reports 0 as the last available pixelformat index). - Thanks to Michael Wimmer for pointing this out & providing the fix. - - (Oct 3, '01) - x Fixed bug in glXGetConfig(): pixelformats enumerated incorrectly. The - test was OpenGL support OR draw to window, but should be AND. Thanks - to Michael Wimmer for pointing this out & providing the fix. - - (Sep 28, '01) - x Fixed glutChangeToSubMenu()/glutChangeToMenuEntry() bug where if you - went back and forth between a submenu and a plain entry, the submenu - wouldn't be updated properly. - - (Sep 28, '01) - x glutSetIconTitle() is now a nop. - - (Sep 28, '01) - x glutFullScreen() now sets the window as TOPMOST, therefore, the - window will always be on top (this essentially disables alt-tabbing). - - (Sep 28, '01) - x The key repeat ignore flag is now honored correctly. - - (Sep 28, '01) - x Key presses are now reported more accurately and fully, in - particular, modified up events (i.e., SHIFT-2) are now reported - correctly. - - (Sep 28, '01) - x Subwindows nested arbitrarily deep get their keyboard callbacks - correctly now. - - (Sep 28, '01) - x Major rewrite of the window procedure code to clean it up and make - way for other bug fixes. - - (Sep 23, '01) - x Fixed noof example program to use RAND_MAX instead of assumed - max of 2147483647.0. (Now it looks _much_ better!) - - (Sep 22, '01) - x Fixed sunlight example program. globe.raw data file was corrupt, - added a new one. - - (Sep 22, '01) - x Fixed zcomposite example program to print message if overlay - support is not found (instead of crashing). - - (Jan 22, '01) - x Fixed malloc(0) bug in Win32 version of XGetVisualInfo. Thanks - to Kekoa Proudfoot for bringing this to my attention. - - (Dec 12, '00) - x Added data files for the advanced & advanced97 programs. - - (Dec 12, '00) - x Added Developer Studio 6 project and workspace files for pretty - much everything (the stuff left out was usually unix specific). - - (Dec 7, '00) - x Fixed several compilation problems & corrupt files. Thanks to - Alexander Stohr for bringing these to my attention and providing - detailed fixes. - - (Dec 6, '00) - x Fixed compiler support for lcc. Thanks to Gordon for bringing - this to my attention and debugging fixes. - - (Nov 8, '00) - x Fixed submenu problem (sometimes the menu callback was not - called for valid items). Thanks to Michael Keeley. - - (Oct 16, '00) - x Corrected corrupt duck.iv file. Thanks to Jon Willeke for finding - this problem. - - (Sept 27, '00) - x Fixed bug in processWorkList that could cause a hang. Thanks to - Bill Volz & Daniel Azuma. - - (Sept 26, '00) - x Added mui DLL project file (thanks to DMWeldy@ugsolutions.com). - - (Sept 9, '00) - x Fixed Delete key bug (crash when no keyboard callback was - registered, but a special key callback was). Thanks to - Kent Bowling (kent_bowling@hotmail.com) for finding this bug. - - (May 18, '00) - x Fixed subwindow keyboard callbacks. - - (May 22, '97) - o Menus don't work under Windows 95 - x Fixed! Added a unique identifier to each menu item, and a - search function to grab a menu item given the unique identifier. - - (May 21, '97) - o A few minor bug fixes here and there. - x Thanks to Bruce Silberman and Chris Vale for their help with - this. We now have a DLL! - - (Apr 25, '97) - o DLL version of the library is coming (as soon as I figure out - how to do it -- if you know, let me know). - x Thanks to Bruce Silberman and Chris Vale for their help with - this. We now have a DLL! - - (Apr 24, '97) - x Added returns to KEY_DOWN etc messages so that the F10 key - doesn't toggle the system menu anymore. - - (Apr 7, '97) - o Palette is incorrect for modes other than TrueColor. - x Fixed this by forcing a default palette in modes that aren't - Truecolor in order to 'simulate' it. The applications - program shouldn't have to do this IMHO, but I guess we - can't argue with Microsoft (well, we can, but what good - will it do?). - - (Apr 2, '97) - x Added glut.ide file for Borland users. - - (Apr 2, '97) - x Fixed a bug in the WM_QUERYNEWPALETTE message. Wasn't - checking for a null colormap, then de-ref'd it. Oops. - - (Mar 13, '97) - o glutTimerFunc: - Currently, GLUT for Win32 programs busy waits when there is - an outstanding timer event (i.e., there is no select() - call). I haven't found this to be a problem, but I plan to - fix it just because I can't bear the thought of a busy wait. - x Added a timer event and a wait in the main loop. This fixes - the CPU spike. - - (Mar 11, '97) - x Fixed subwindow visibility. The visibility callback of - subwindows wasn't being called, now it is. - - (Mar 11, '97) - o glutGetHDC, glutGetHWND: - In order to support additional dialog boxes, wgl fonts, and - a host of other Win32 dependent structures, two functions - have been added that operate on the current window in GLUT. - The first (glutGetHDC) returns a handle to the current - windows device context. The second (glutGetHWND) returns - handle to the current window. - x Took these out to preserve GLUT portability. - - (Mar 11, '97) - x Fixed the glutWarpPointer() coordinates. Were relative to - the screen, now relative to window (client area) origin - (which is what they're supposed to be). - - (Mar 11, '97) - o glutCreateMenu, glutIdleFunc: - Menu's are modal in Win32. That is, they don't allow any - messages to be processed while they are up. Therefore, if - an idle function exists, it will not be called while - processing a menu. - x Fixed! I've put in a timer function that fires every - millisecond while a menu is up. The timer function handles - idle and timer events only (which should be the only - functions that are firing when a menu is up anyway). - - (Mar 7 '97) - x Fixed minor bugs tracked down by the example programs. - - (Mar 6, '97) - x Merged 3.3 GLUT for X11 into 3.2 GLUT for Win32. New code - structure allows for EASY merging! - - o In Win32, the parent gets the right to set the cursor of - any of its children. Therefore, a child windows cursor - will 'blink' between its cursor and its parent. - x Fixed this by checking whether the cursor is in a child - window or not. - - (Feb 28 '97) - o On initial bringup apps are getting 2 display callbacks. - x Fixed by the Fev 28 re-write. - - o Some multiple window (not subwindow) functionality is messed up. - See the sphere.exe program. - x Fixed by the Feb 28 re-write. - - o GLUT for Win32 supports color index mode ONLY in a paletted - display mode (i.e., 256 or 16 color mode). - x Fixed this in the re-write. If you can get a color index - visual (pixel format) you can use color index mode. - - (Feb 28 '97) - o Quite a few bugs (and incompatibilities) were being caused - by the structure that I used in the previous port of GLUT. - Therefore I decided that it would be best to "get back to - the roots". I re-implemented most of glut trying to stick - with the structure laid out by Mark. The result is a much - more stable version that passes ALL (!) (except overlay) - the tests provided by Mark. In addition, this new - structure will allow future enhancements by Mark to be - integrated much more quickly into the Win32 version. Also, - I'm now ordering the bugs in reverse, so that the most - recently fixed appear at the top of the list. - - (9/8/96) - o Changed the glutGetModifiers code to produce an error if not - called in the core input callbacks. - - (9/11/96) - o If the alt key is pressed with more than one other modifier key - it acts as if it is stuck -- it stays selected until pressed - and released again. - x Fixed. - - (9/12/96) - o When a submenu is attached to a menu, sometimes a GPF occurs. - Fixed. Needed to set the submenu before referencing it's members. - - o Kenny: Also, one little problem, I attached the menu to the - right-button, but when the left-button is pressed I detach - it to give the right-button new meaning; if I pop-up the menu and I - don't want to select anything, like most users, I click off of the - menu to make it disappear. When I do this, I get a GLUT error and - the program terminates because I am altering the menu attachment - from within the button press while the menu is active. - x Fixed. Needed to finish the menu when the user presses the button, - not just when a button is released. - - o GLUT for Win32 emulates a middle mouse button by checking if - both mouse buttons are down. This causes a lot of problems with - the menu and other multiple mouse button things. - x Fixed. No more middle mouse button emulation. Perhaps it would - be a good idea to emulate the middle mouse button (if not present) - with a key? - - (9/15/96) - o Added code to accept a user defined icon. If no icon is provided, - a default icon is loaded. - - (9/19/96) - o Shane: Command line options seem to be screwed up. (9/13) - x Fixed. The geometry command line was broken, and so was the - gldebug command line. - - o Fixed a bug in the default glut reshape. It was looking for the - parent of the current window and GPF'ing if there wasn't a parent. - Put in a check for a parent, and if none is there, use the - child. - - o Idle function sucks up all processor cycles. (9/8/96) - x I don't know if this is avoidable. If you have a tight rendering - loop, it may be that the processor time is going to be sucked up - no matter what. You can add a sleep() to the end of your render - loop if you would like to yield to other processes and you don't - care too much about the speed of your rendering loop. If you have - Hardware that supports OpenGL (like a 3Dpro card, or GLint card) - then this should be less of a problem, since it won't be rendering - in software. (9/11/96) - - o If a window is fully obscured by another window, the visibility - callback is NOT called. As far as I can tell, this is a limitation - of the Win32 api, but a workaround is being searched for. (9/8/96) - x Limitation of the Win32 API - - o Fixed the entry functions. They only work if the keyboard focus - changes. Therefore, in most Win32 systems, the mouse must be - pressed outside of the window to get a GLUT_LEFT message and - then pressed inside the window for a GLUT_ENTERED message. - - o Alt modifier key doesn't work with keyboard callback. (9/8/96) - x Probably okay, because the glut spec says that these keys can - be intercepted by the system (which the alt key is...) (9/11/96) - - (11/17/96) - o glutRemoveMenuItem() not working properly. - x Thanks to Gary (grc@maple.civeng.rutgers.edu) for the fix to - this one. - - o Timer functions are messed up. - x Thanks to Joseph Galbraith for the fix to this one. - - (12/9/96) - o One (minor) difference came up between the X version of glut - and the nt one which you should know about. It is not a new - problem, and it concerns co-ords returned to the pointer - callbacks. (glutMotionFunc, glutMouseFunc) - Under X, you get co-ords in the range 0 +/- 2^15, under NT - you get 0..2^16. This is only really a problem when moving - above or to the left of the window. - eg dragging one pixel ABOVE the window will give :- - under x11 : y = -1 - under nt : y = 2^16 -1 - x Put in fix provided by Shane Clauson. - - (12/17/96) - o Idle functions not working properly for multiple windows. - x Fixed this by posting an idle message to every window in the - window list when idle. - - (12/18/96) - o glutSetCursor() was misbehaving (lthomas@cco.caltech.edu). - x Win32 requires that the hCursor member of the window class - be set to NULL when the class is registered or whenever the - mouse is moved, the original cursor is replaced (go - figure!). Now sets the cursor whenever a WM_MOUSEMOVE message - is received, because the WM_SETCURSOR event resets the cursor - even when in the decoration area. - - o Geometry is not being handled quite right. The numbers don't - take into account the window decorations. That is, if I say - make a window 100x100, then the WHOLE window (not just the - client area) is 100x100. Therefore, the client (opengl) area - is smaller than 100x100. (9/8/96) - x Fixed. Added code to subtract the decoration size on glutGet() - and add the decoration size on glutReshapeWindow(). - - o Multiple glutPostRedisplay() calls are NOT being combined. - To get round the "coalesce" problem on glutPostRedisplay, - the easiest solution is to roll-your-own coalesce by - keeping a global "dirty" flag in the app (eg replace all - calls to glutPostRedisplay with image_dirty=TRUE;), and to - handle image_dirty with a single glutPostRedisplay in the - idle callback when required. (erk - but increases - performance for my particular app (a rendering engine on - the end of a pipleine with a stream of graphics updates) by - a couple of orders of magnitude ! ) (9/8/96) - x Added code to coalesce redisplays. Every idle cycle, a - check is made to see which windows need redisplay, if they - need it, a redisplay is posted. The glutPostRedisplay() - call is just a stub that sets a flag. - - -THANKS: - - Special thanks to the following people for extensive testing, - suggestions, fixes and help: - - Alexander Stohr - Shane Clauson - Kenny Hoff - Richard Readings - Paul McQuesten - Philip Winston - JaeWoo Ahn - Joseph Galbraith - Paula Higgins - Sam Fortin - Chris Vale - Bill Mitchell - - and of course, the original author of GLUT: - Mark Kilgard. - - and many others... - - -COPYRIGHT: - -The OpenGL Utility Toolkit distribution for Win32 (Windows NT & -Windows 95) contains source code modified from the original source -code for GLUT version 3.3 which was developed by Mark J. Kilgard. The -original source code for GLUT is Copyright 1997 by Mark J. Kilgard. -GLUT for Win32 is Copyright 1997 by Nate Robins and is not in the -public domain, but it is freely distributable without licensing fees. -It is provided without guarantee or warrantee expressed or implied. -It was ported with the permission of Mark J. Kilgard by Nate Robins. - -THIS SOURCE CODE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER -EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OR MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. - -OpenGL (R) is a registered trademark of Silicon Graphics, Inc. diff --git a/samples/glut/glut.def b/samples/glut/glut.def deleted file mode 100644 index d7d0240fc..000000000 --- a/samples/glut/glut.def +++ /dev/null @@ -1,126 +0,0 @@ -DESCRIPTION 'OpenGL Utility Toolkit for Win32' - -VERSION 3.7 - -EXPORTS - - glutAddMenuEntry - glutAddSubMenu - glutAttachMenu - glutBitmapCharacter - glutBitmapLength - glutBitmapWidth - glutButtonBoxFunc - glutChangeToMenuEntry - glutChangeToSubMenu - glutCopyColormap - glutCreateMenu - __glutCreateMenuWithExit - glutCreateSubWindow - glutCreateWindow - __glutCreateWindowWithExit - glutDestroyMenu - glutDestroyWindow - glutDetachMenu - glutDeviceGet - glutDialsFunc - glutDisplayFunc - glutEnterGameMode - glutEntryFunc - glutEstablishOverlay - glutExtensionSupported - glutForceJoystickFunc - glutFullScreen - glutGameModeGet - glutGameModeString - glutGet - glutGetColor - glutGetMenu - glutGetModifiers - glutGetWindow - glutHideOverlay - glutHideWindow - glutIconifyWindow - glutIdleFunc - glutIgnoreKeyRepeat - glutInit - __glutInitWithExit - glutInitDisplayMode - glutInitDisplayString - glutInitWindowPosition - glutInitWindowSize - glutJoystickFunc - glutKeyboardFunc - glutKeyboardUpFunc - glutLayerGet - glutLeaveGameMode - glutMainLoop - glutMenuStateFunc - glutMenuStatusFunc - glutMotionFunc - glutMouseFunc - glutOverlayDisplayFunc - glutPassiveMotionFunc - glutPopWindow - glutPositionWindow - glutPostOverlayRedisplay - glutPostRedisplay - glutPostWindowOverlayRedisplay - glutPostWindowRedisplay - glutPushWindow - glutRemoveMenuItem - glutRemoveOverlay - glutReportErrors - glutReshapeFunc - glutReshapeWindow - glutSetColor - glutSetCursor - glutSetIconTitle - glutSetKeyRepeat - glutSetMenu - glutSetWindow - glutSetWindowTitle - glutSetupVideoResizing - glutShowOverlay - glutShowWindow - glutSolidCone - glutSolidCube - glutSolidDodecahedron - glutSolidIcosahedron - glutSolidOctahedron - glutSolidSphere - glutSolidTeapot - glutSolidTetrahedron - glutSolidTorus - glutSpaceballButtonFunc - glutSpaceballMotionFunc - glutSpaceballRotateFunc - glutSpecialFunc - glutSpecialUpFunc - glutStopVideoResizing - glutStrokeCharacter - glutStrokeLength - glutStrokeWidth - glutSwapBuffers - glutTabletButtonFunc - glutTabletMotionFunc - glutTimerFunc - glutUseLayer - glutVideoPan - glutVideoResize - glutVideoResizeGet - glutVisibilityFunc - glutWarpPointer - glutWindowStatusFunc - glutWireCone - glutWireCube - glutWireDodecahedron - glutWireIcosahedron - glutWireOctahedron - glutWireSphere - glutWireTeapot - glutWireTetrahedron - glutWireTorus -; __glutSetFCB -; __glutGetFCB - diff --git a/samples/glut/glut32.lib b/samples/glut/glut32.lib deleted file mode 100644 index c25583d44..000000000 Binary files a/samples/glut/glut32.lib and /dev/null differ diff --git a/scripts/BlenderImporter/genblenddna.py b/scripts/BlenderImporter/genblenddna.py index caa58ded7..cca595eca 100644 --- a/scripts/BlenderImporter/genblenddna.py +++ b/scripts/BlenderImporter/genblenddna.py @@ -291,7 +291,9 @@ def main(): #s += "#endif\n" output.write(templt.replace("",s)) - + + # we got here, so no error + return 0 if __name__ == "__main__": sys.exit(main()) diff --git a/scripts/StepImporter/CppGenerator.py b/scripts/StepImporter/CppGenerator.py index 156f19523..b9dba9902 100644 --- a/scripts/StepImporter/CppGenerator.py +++ b/scripts/StepImporter/CppGenerator.py @@ -52,8 +52,8 @@ use_ifc_template = False input_step_template_h = 'StepReaderGen.h.template' input_step_template_cpp = 'StepReaderGen.cpp.template' -input_ifc_template_h = 'IFCReaderGen.h.template' -input_ifc_template_cpp = 'IFCReaderGen.cpp.template' +input_ifc_template_h = 'IFCReaderGen.h.template' +input_ifc_template_cpp = 'IFCReaderGen.cpp.template' cpp_keywords = "class" @@ -87,7 +87,7 @@ template_type = r""" template_stub_decl = '\tDECL_CONV_STUB({type});\n' template_schema = '\t\tSchemaEntry("{normalized_name}",&STEP::ObjectHelper<{type},{argcnt}>::Construct )\n' -template_schema_type = '\t\tSchemaEntry("{normalized_name}",NULL )\n' +template_schema_type = '\t\tSchemaEntry("{normalized_name}",nullptr )\n' template_converter = r""" // ----------------------------------------------------------------------------------------------------------- template <> size_t GenericFill<{type}>(const DB& db, const LIST& params, {type}* in) @@ -99,7 +99,7 @@ template_converter_prologue_a = '\tsize_t base = GenericFill(db,params,static_ca template_converter_prologue_b = '\tsize_t base = 0;\n' template_converter_check_argcnt = '\tif (params.GetSize() < {max_arg}) {{ throw STEP::TypeError("expected {max_arg} arguments to {name}"); }}' template_converter_code_per_field = r""" do {{ // convert the '{fieldname}' argument - boost::shared_ptr arg = params[base++];{handle_unset}{convert} + std::shared_ptr arg = params[base++];{handle_unset}{convert} }} while(0); """ template_allow_optional = r""" @@ -151,11 +151,8 @@ def handle_unset_args(field,entity,schema,argnum): return n+template_allow_optional.format() def get_single_conversion(field,schema,argnum=0,classname='?'): - typen = field.type name = field.name - if field.collection: - typen = 'LIST' - return template_convert_single.format(type=typen,name=name,argnum=argnum,classname=classname,full_type=field.fullspec) + return template_convert_single.format(name=name,argnum=argnum,classname=classname,full_type=field.fullspec) def count_args_up(entity,schema): return len(entity.members) + (count_args_up(schema.entities[entity.parent],schema) if entity.parent else 0) @@ -218,7 +215,7 @@ def get_derived(e,schema): return res def get_hierarchy(e,schema): - return get_derived(e.schema)+[e.name]+get_base_classes(e,schema) + return get_derived(e, schema)+[e.name]+get_base_classes(e,schema) def sort_entity_list(schema): deps = [] @@ -300,5 +297,8 @@ def work(filename): with open(output_file_cpp,'wt') as outp: outp.write(inp.read().replace('{schema-static-table}',schema_table).replace('{converter-impl}',converters)) + # Finished without error, so return 0 + return 0 + if __name__ == "__main__": sys.exit(work(sys.argv[1] if len(sys.argv)>1 else 'schema.exp')) diff --git a/scripts/StepImporter/ExpressReader.py b/scripts/StepImporter/ExpressReader.py index 84aaadbdc..c2a39e70b 100644 --- a/scripts/StepImporter/ExpressReader.py +++ b/scripts/StepImporter/ExpressReader.py @@ -43,7 +43,8 @@ """Parse an EXPRESS file and extract basic information on all entities and data types contained""" -import sys, os, re +import sys +import re from collections import OrderedDict re_match_entity = re.compile(r""" diff --git a/scripts/StepImporter/StepReaderGen.cpp.template b/scripts/StepImporter/StepReaderGen.cpp.template index 343c43019..f3240c099 100644 --- a/scripts/StepImporter/StepReaderGen.cpp.template +++ b/scripts/StepImporter/StepReaderGen.cpp.template @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, ASSIMP Development Team +Copyright (c) 2006-2019, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -40,7 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /** MACHINE-GENERATED by scripts/ICFImporter/CppGenerator.py */ -#ifndef ASSIMP_BUILD_NO_STEPFILE_IMPORTER +#ifndef ASSIMP_BUILD_NO_STEP_IMPORTER #include "code/Importer/StepFile/StepReaderGen.h" @@ -66,7 +66,7 @@ namespace STEP { // ----------------------------------------------------------------------------------------------------------- template <> size_t GenericFill(const STEP::DB& db, const LIST& params, NotImplemented* in) { - return 0; + return 0u; } diff --git a/scripts/StepImporter/StepReaderGen.h.template b/scripts/StepImporter/StepReaderGen.h.template index 5f9a2fd5d..7d4d77ef4 100644 --- a/scripts/StepImporter/StepReaderGen.h.template +++ b/scripts/StepImporter/StepReaderGen.h.template @@ -2,7 +2,7 @@ Open Asset Import Library (ASSIMP) ---------------------------------------------------------------------- -Copyright (c) 2006-2018, ASSIMP Development Team +Copyright (c) 2006-2019, ASSIMP Development Team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -47,25 +47,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { namespace StepFile { - using namespace STEP; - using namespace STEP::EXPRESS; - - - struct NotImplemented : public ObjectHelper { - - }; - - // ****************************************************************************** - // StepFile Custom data types - // ****************************************************************************** +using namespace STEP; +using namespace STEP::EXPRESS; + +struct NotImplemented : public ObjectHelper { + +}; + +// ****************************************************************************** +// StepFile Custom data types +// ****************************************************************************** {types} - - // ****************************************************************************** - // StepFile Entities - // ****************************************************************************** +// ****************************************************************************** +// StepFile Entities +// ****************************************************************************** {predefs} {entities} @@ -73,11 +71,12 @@ namespace StepFile { void GetSchema(EXPRESS::ConversionSchema& out); } //! StepFile + namespace STEP { - // ****************************************************************************** - // Converter stubs - // ****************************************************************************** +// ****************************************************************************** +// Converter stubs +// ****************************************************************************** #define DECL_CONV_STUB(type) template <> size_t GenericFill(const STEP::DB& db, const EXPRESS::LIST& params, IFC::type* in) diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 000000000..b652d6aae --- /dev/null +++ b/test/.gitignore @@ -0,0 +1,3 @@ +# Ignore Unit Test Output files + +*_out.* diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7e2aec270..913813c3b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,7 +1,7 @@ # Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # -# Copyright (c) 2006-2018, assimp team +# Copyright (c) 2006-2019, assimp team # All rights reserved. @@ -37,7 +37,7 @@ # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # #---------------------------------------------------------------------- -cmake_minimum_required( VERSION 2.6 ) +cmake_minimum_required( VERSION 3.0 ) INCLUDE_DIRECTORIES( ${Assimp_SOURCE_DIR}/contrib/gtest/include @@ -81,6 +81,7 @@ SET( COMMON SET( IMPORTERS unit/utLWSImportExport.cpp + unit/utLWOImportExport.cpp unit/utSMDImportExport.cpp unit/utglTFImportExport.cpp unit/utglTF2ImportExport.cpp @@ -119,10 +120,13 @@ SET( IMPORTERS unit/utB3DImportExport.cpp unit/utMDCImportExport.cpp unit/utAssbinImportExport.cpp + unit/ImportExport/utAssjsonImportExport.cpp unit/ImportExport/utCOBImportExport.cpp unit/ImportExport/utOgreImportExport.cpp unit/ImportExport/utQ3BSPFileImportExport.cpp unit/ImportExport/utOFFImportExport.cpp + unit/ImportExport/utNFFImportExport.cpp + unit/ImportExport/utXGLImportExport.cpp ) SET( MATERIAL @@ -158,20 +162,21 @@ SET( POST_PROCESSES unit/utTargetAnimation.cpp unit/utSortByPType.cpp unit/utSceneCombiner.cpp + unit/utGenBoundingBoxesProcess.cpp ) SOURCE_GROUP( UnitTests\\Compiler FILES unit/CCompilerTest.c ) -SOURCE_GROUP( UnitTests\\Common FILES ${COMMON} ) -SOURCE_GROUP( UnitTests\\Importers FILES ${IMPORTERS} ) -SOURCE_GROUP( UnitTests\\Material FILES ${MATERIAL} ) -SOURCE_GROUP( UnitTests\\Math FILES ${MATH} ) -SOURCE_GROUP( UnitTests\\PostProcess FILES ${POST_PROCESSES}) +SOURCE_GROUP( UnitTests\\Common FILES ${COMMON} ) +SOURCE_GROUP( UnitTests\\ImportExport FILES ${IMPORTERS} ) +SOURCE_GROUP( UnitTests\\Material FILES ${MATERIAL} ) +SOURCE_GROUP( UnitTests\\Math FILES ${MATH} ) +SOURCE_GROUP( UnitTests\\PostProcess FILES ${POST_PROCESSES}) add_executable( unit ../contrib/gtest/src/gtest-all.cc unit/CCompilerTest.c unit/Main.cpp - ../code/Version.cpp + ../code/Common/Version.cpp ${COMMON} ${IMPORTERS} ${MATERIAL} diff --git a/test/models/Collada/duck.zae b/test/models/Collada/duck.zae new file mode 100644 index 000000000..978235355 Binary files /dev/null and b/test/models/Collada/duck.zae differ diff --git a/test/models/Collada/duck_nomanifest.zae b/test/models/Collada/duck_nomanifest.zae new file mode 100644 index 000000000..d5559ccb2 Binary files /dev/null and b/test/models/Collada/duck_nomanifest.zae differ diff --git a/test/models/FBX/boxWithCompressedCTypeArray.FBX b/test/models/FBX/boxWithCompressedCTypeArray.FBX new file mode 100644 index 000000000..2f71bc7ee Binary files /dev/null and b/test/models/FBX/boxWithCompressedCTypeArray.FBX differ diff --git a/test/models/FBX/boxWithUncompressedCTypeArray.FBX b/test/models/FBX/boxWithUncompressedCTypeArray.FBX new file mode 100644 index 000000000..2ec3d77d7 Binary files /dev/null and b/test/models/FBX/boxWithUncompressedCTypeArray.FBX differ diff --git a/test/models/FBX/close_to_identity_transforms.fbx b/test/models/FBX/close_to_identity_transforms.fbx new file mode 100644 index 000000000..c0b990282 --- /dev/null +++ b/test/models/FBX/close_to_identity_transforms.fbx @@ -0,0 +1,855 @@ +; FBX 7.5.0 project file +; ---------------------------------------------------- + +FBXHeaderExtension: { + FBXHeaderVersion: 1003 + FBXVersion: 7500 + CreationTimeStamp: { + Version: 1000 + Year: 2019 + Month: 5 + Day: 14 + Hour: 17 + Minute: 27 + Second: 42 + Millisecond: 70 + } + Creator: "FBX SDK/FBX Plugins version 2018.1.1" + SceneInfo: "SceneInfo::GlobalInfo", "UserData" { + Type: "UserData" + Version: 100 + MetaData: { + Version: 100 + Title: "" + Subject: "" + Author: "" + Keywords: "" + Revision: "" + Comment: "" + } + Properties70: { + P: "DocumentUrl", "KString", "Url", "", "U:\Some\Absolute\Path\cubes_with_mirroring_and_pivot.fbx" + P: "SrcDocumentUrl", "KString", "Url", "", "U:\Some\Absolute\Path\cubes_with_mirroring_and_pivot.fbx" + P: "Original", "Compound", "", "" + P: "Original|ApplicationVendor", "KString", "", "", "Autodesk" + P: "Original|ApplicationName", "KString", "", "", "Maya" + P: "Original|ApplicationVersion", "KString", "", "", "201800" + P: "Original|DateTime_GMT", "DateTime", "", "", "14/05/2019 16:27:42.070" + P: "Original|FileName", "KString", "", "", "U:\Some\Absolute\Path\cubes_with_mirroring_and_pivot.fbx" + P: "LastSaved", "Compound", "", "" + P: "LastSaved|ApplicationVendor", "KString", "", "", "Autodesk" + P: "LastSaved|ApplicationName", "KString", "", "", "Maya" + P: "LastSaved|ApplicationVersion", "KString", "", "", "201800" + P: "LastSaved|DateTime_GMT", "DateTime", "", "", "14/05/2019 16:27:42.070" + P: "Original|ApplicationActiveProject", "KString", "", "", "U:\Some\Absolute\Path" + } + } +} +GlobalSettings: { + Version: 1000 + Properties70: { + P: "UpAxis", "int", "Integer", "",1 + P: "UpAxisSign", "int", "Integer", "",1 + P: "FrontAxis", "int", "Integer", "",2 + P: "FrontAxisSign", "int", "Integer", "",1 + P: "CoordAxis", "int", "Integer", "",0 + P: "CoordAxisSign", "int", "Integer", "",1 + P: "OriginalUpAxis", "int", "Integer", "",1 + P: "OriginalUpAxisSign", "int", "Integer", "",1 + P: "UnitScaleFactor", "double", "Number", "",100 + P: "OriginalUnitScaleFactor", "double", "Number", "",1 + P: "AmbientColor", "ColorRGB", "Color", "",0,0,0 + P: "DefaultCamera", "KString", "", "", "Producer Perspective" + P: "TimeMode", "enum", "", "",11 + P: "TimeProtocol", "enum", "", "",2 + P: "SnapOnFrameMode", "enum", "", "",0 + P: "TimeSpanStart", "KTime", "Time", "",1924423250 + P: "TimeSpanStop", "KTime", "Time", "",384884650000 + P: "CustomFrameRate", "double", "Number", "",-1 + P: "TimeMarker", "Compound", "", "" + P: "CurrentTimeMarker", "int", "Integer", "",-1 + } +} + +; Documents Description +;------------------------------------------------------------------ + +Documents: { + Count: 1 + Document: 1827132552544, "", "Scene" { + Properties70: { + P: "SourceObject", "object", "", "" + P: "ActiveAnimStackName", "KString", "", "", "Take 001" + } + RootNode: 0 + } +} + +; Document References +;------------------------------------------------------------------ + +References: { +} + +; Object definitions +;------------------------------------------------------------------ + +Definitions: { + Version: 100 + Count: 13 + ObjectType: "GlobalSettings" { + Count: 1 + } + ObjectType: "AnimationStack" { + Count: 1 + PropertyTemplate: "FbxAnimStack" { + Properties70: { + P: "Description", "KString", "", "", "" + P: "LocalStart", "KTime", "Time", "",0 + P: "LocalStop", "KTime", "Time", "",0 + P: "ReferenceStart", "KTime", "Time", "",0 + P: "ReferenceStop", "KTime", "Time", "",0 + } + } + } + ObjectType: "AnimationLayer" { + Count: 1 + PropertyTemplate: "FbxAnimLayer" { + Properties70: { + P: "Weight", "Number", "", "A",100 + P: "Mute", "bool", "", "",0 + P: "Solo", "bool", "", "",0 + P: "Lock", "bool", "", "",0 + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "BlendMode", "enum", "", "",0 + P: "RotationAccumulationMode", "enum", "", "",0 + P: "ScaleAccumulationMode", "enum", "", "",0 + P: "BlendModeBypass", "ULongLong", "", "",0 + } + } + } + ObjectType: "Geometry" { + Count: 4 + PropertyTemplate: "FbxMesh" { + Properties70: { + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "BBoxMin", "Vector3D", "Vector", "",0,0,0 + P: "BBoxMax", "Vector3D", "Vector", "",0,0,0 + P: "Primary Visibility", "bool", "", "",1 + P: "Casts Shadows", "bool", "", "",1 + P: "Receive Shadows", "bool", "", "",1 + } + } + } + ObjectType: "Material" { + Count: 2 + PropertyTemplate: "FbxSurfaceLambert" { + Properties70: { + P: "ShadingModel", "KString", "", "", "Lambert" + P: "MultiLayer", "bool", "", "",0 + P: "EmissiveColor", "Color", "", "A",0,0,0 + P: "EmissiveFactor", "Number", "", "A",1 + P: "AmbientColor", "Color", "", "A",0.2,0.2,0.2 + P: "AmbientFactor", "Number", "", "A",1 + P: "DiffuseColor", "Color", "", "A",0.8,0.8,0.8 + P: "DiffuseFactor", "Number", "", "A",1 + P: "Bump", "Vector3D", "Vector", "",0,0,0 + P: "NormalMap", "Vector3D", "Vector", "",0,0,0 + P: "BumpFactor", "double", "Number", "",1 + P: "TransparentColor", "Color", "", "A",0,0,0 + P: "TransparencyFactor", "Number", "", "A",0 + P: "DisplacementColor", "ColorRGB", "Color", "",0,0,0 + P: "DisplacementFactor", "double", "Number", "",1 + P: "VectorDisplacementColor", "ColorRGB", "Color", "",0,0,0 + P: "VectorDisplacementFactor", "double", "Number", "",1 + } + } + } + ObjectType: "Model" { + Count: 4 + PropertyTemplate: "FbxNode" { + Properties70: { + P: "QuaternionInterpolate", "enum", "", "",0 + P: "RotationOffset", "Vector3D", "Vector", "",0,0,0 + P: "RotationPivot", "Vector3D", "Vector", "",0,0,0 + P: "ScalingOffset", "Vector3D", "Vector", "",0,0,0 + P: "ScalingPivot", "Vector3D", "Vector", "",0,0,0 + P: "TranslationActive", "bool", "", "",0 + P: "TranslationMin", "Vector3D", "Vector", "",0,0,0 + P: "TranslationMax", "Vector3D", "Vector", "",0,0,0 + P: "TranslationMinX", "bool", "", "",0 + P: "TranslationMinY", "bool", "", "",0 + P: "TranslationMinZ", "bool", "", "",0 + P: "TranslationMaxX", "bool", "", "",0 + P: "TranslationMaxY", "bool", "", "",0 + P: "TranslationMaxZ", "bool", "", "",0 + P: "RotationOrder", "enum", "", "",0 + P: "RotationSpaceForLimitOnly", "bool", "", "",0 + P: "RotationStiffnessX", "double", "Number", "",0 + P: "RotationStiffnessY", "double", "Number", "",0 + P: "RotationStiffnessZ", "double", "Number", "",0 + P: "AxisLen", "double", "Number", "",10 + P: "PreRotation", "Vector3D", "Vector", "",0,0,0 + P: "PostRotation", "Vector3D", "Vector", "",0,0,0 + P: "RotationActive", "bool", "", "",0 + P: "RotationMin", "Vector3D", "Vector", "",0,0,0 + P: "RotationMax", "Vector3D", "Vector", "",0,0,0 + P: "RotationMinX", "bool", "", "",0 + P: "RotationMinY", "bool", "", "",0 + P: "RotationMinZ", "bool", "", "",0 + P: "RotationMaxX", "bool", "", "",0 + P: "RotationMaxY", "bool", "", "",0 + P: "RotationMaxZ", "bool", "", "",0 + P: "InheritType", "enum", "", "",0 + P: "ScalingActive", "bool", "", "",0 + P: "ScalingMin", "Vector3D", "Vector", "",0,0,0 + P: "ScalingMax", "Vector3D", "Vector", "",1,1,1 + P: "ScalingMinX", "bool", "", "",0 + P: "ScalingMinY", "bool", "", "",0 + P: "ScalingMinZ", "bool", "", "",0 + P: "ScalingMaxX", "bool", "", "",0 + P: "ScalingMaxY", "bool", "", "",0 + P: "ScalingMaxZ", "bool", "", "",0 + P: "GeometricTranslation", "Vector3D", "Vector", "",0,0,0 + P: "GeometricRotation", "Vector3D", "Vector", "",0,0,0 + P: "GeometricScaling", "Vector3D", "Vector", "",1,1,1 + P: "MinDampRangeX", "double", "Number", "",0 + P: "MinDampRangeY", "double", "Number", "",0 + P: "MinDampRangeZ", "double", "Number", "",0 + P: "MaxDampRangeX", "double", "Number", "",0 + P: "MaxDampRangeY", "double", "Number", "",0 + P: "MaxDampRangeZ", "double", "Number", "",0 + P: "MinDampStrengthX", "double", "Number", "",0 + P: "MinDampStrengthY", "double", "Number", "",0 + P: "MinDampStrengthZ", "double", "Number", "",0 + P: "MaxDampStrengthX", "double", "Number", "",0 + P: "MaxDampStrengthY", "double", "Number", "",0 + P: "MaxDampStrengthZ", "double", "Number", "",0 + P: "PreferedAngleX", "double", "Number", "",0 + P: "PreferedAngleY", "double", "Number", "",0 + P: "PreferedAngleZ", "double", "Number", "",0 + P: "LookAtProperty", "object", "", "" + P: "UpVectorProperty", "object", "", "" + P: "Show", "bool", "", "",1 + P: "NegativePercentShapeSupport", "bool", "", "",1 + P: "DefaultAttributeIndex", "int", "Integer", "",-1 + P: "Freeze", "bool", "", "",0 + P: "LODBox", "bool", "", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",0,0,0 + P: "Lcl Rotation", "Lcl Rotation", "", "A",0,0,0 + P: "Lcl Scaling", "Lcl Scaling", "", "A",1,1,1 + P: "Visibility", "Visibility", "", "A",1 + P: "Visibility Inheritance", "Visibility Inheritance", "", "",1 + } + } + } +} + +; Object properties +;------------------------------------------------------------------ + +Objects: { + Geometry: 1827080157856, "Geometry::", "Mesh" { + Vertices: *24 { + a: -0.5,-0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,-0.5,-0.5,-0.5,-0.5,0.5,-0.5,-0.5 + } + PolygonVertexIndex: *24 { + a: 0,1,3,-3,2,3,5,-5,4,5,7,-7,6,7,1,-1,1,7,5,-4,6,0,2,-5 + } + Edges: *12 { + a: 0,1,2,3,5,6,7,9,10,11,13,15 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *72 { + a: 0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 + } + NormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *72 { + a: 0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,-0,1,0,-0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0 + } + BinormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *72 { + a: 1,-0,-0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0,-0,1,0,-0,1,0,-0,1,0,-0,1 + } + TangentsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *28 { + a: 0.375,0,0.625,0,0.375,0.25,0.625,0.25,0.375,0.5,0.625,0.5,0.375,0.75,0.625,0.75,0.375,1,0.625,1,0.875,0,0.875,0.25,0.125,0,0.125,0.25 + } + UVIndex: *24 { + a: 0,1,3,2,2,3,5,4,4,5,7,6,6,7,9,8,1,10,11,3,12,0,2,13 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *12 { + a: 0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Geometry: 1827080155296, "Geometry::", "Mesh" { + Vertices: *24 { + a: -0.5,-0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,-0.5,-0.5,-0.5,-0.5,0.5,-0.5,-0.5 + } + PolygonVertexIndex: *24 { + a: 0,1,3,-3,2,3,5,-5,4,5,7,-7,6,7,1,-1,1,7,5,-4,6,0,2,-5 + } + Edges: *12 { + a: 0,1,2,3,5,6,7,9,10,11,13,15 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *72 { + a: 0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 + } + NormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *72 { + a: 0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,-0,1,0,-0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0 + } + BinormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *72 { + a: 1,-0,-0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0,-0,1,0,-0,1,0,-0,1,0,-0,1 + } + TangentsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *28 { + a: 0.375,0,0.625,0,0.375,0.25,0.625,0.25,0.375,0.5,0.625,0.5,0.375,0.75,0.625,0.75,0.375,1,0.625,1,0.875,0,0.875,0.25,0.125,0,0.125,0.25 + } + UVIndex: *24 { + a: 0,1,3,2,2,3,5,4,4,5,7,6,6,7,9,8,1,10,11,3,12,0,2,13 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *12 { + a: 0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Geometry: 1827080156320, "Geometry::", "Mesh" { + Vertices: *24 { + a: -0.5,-0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,-0.5,-0.5,-0.5,-0.5,0.5,-0.5,-0.5 + } + PolygonVertexIndex: *24 { + a: 0,1,3,-3,2,3,5,-5,4,5,7,-7,6,7,1,-1,1,7,5,-4,6,0,2,-5 + } + Edges: *12 { + a: 0,1,2,3,5,6,7,9,10,11,13,15 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *72 { + a: 0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 + } + NormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *72 { + a: 0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,-0,1,0,-0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0 + } + BinormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *72 { + a: 1,-0,-0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0,-0,1,0,-0,1,0,-0,1,0,-0,1 + } + TangentsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *28 { + a: 0.375,0,0.625,0,0.375,0.25,0.625,0.25,0.375,0.5,0.625,0.5,0.375,0.75,0.625,0.75,0.375,1,0.625,1,0.875,0,0.875,0.25,0.125,0,0.125,0.25 + } + UVIndex: *24 { + a: 0,1,3,2,2,3,5,4,4,5,7,6,6,7,9,8,1,10,11,3,12,0,2,13 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *12 { + a: 0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Geometry: 1827080139424, "Geometry::", "Mesh" { + Vertices: *588 { + a: -0.499999970197678,-0.5,0.5,0.500000059604645,-0.5,0.5,-0.499999970197678,0.5,0.5,0.500000059604645,0.5,0.5,-0.499999970197678,0.5,-0.49999988079071,0.500000059604645,0.5,-0.49999988079071,-0.499999970197678,-0.5,-0.49999988079071,0.500000059604645,-0.5,-0.49999988079071,0,0,0.5,0,-0.5,0.5,0.500000059604645,0,0.5,0,0.5,0.5,-0.499999970197678,0,0.5,0,0.5,1.19209289550781e-07,0.500000059604645,0.5,1.19209289550781e-07,0,0.5,-0.49999988079071,-0.499999970197678,0.5,1.19209289550781e-07,0,0,-0.49999988079071,0.500000059604645,0,-0.49999988079071,0,-0.5,-0.49999988079071,-0.499999970197678,0,-0.49999988079071,0,-0.5,1.19209289550781e-07,0.500000059604645,-0.5,1.19209289550781e-07,-0.499999970197678,-0.5,1.19209289550781e-07,0.500000059604645,0,1.19209289550781e-07,-0.499999970197678,0,1.19209289550781e-07,-0.25,-0.25,0.5,-0.499999970197678,-0.25,0.5,-0.25,-0.5,0.5,0,-0.25,0.5,-0.25,0,0.5,-0.25,0.5,0.25,-0.499999970197678,0.5,0.25,-0.25,0.5,0.5,0,0.5,0.25,-0.25,0.5,1.19209289550781e-07,-0.25,0.25,-0.49999988079071,-0.499999970197678,0.25,-0.49999988079071,-0.25,0.5,-0.49999988079071,0,0.25,-0.49999988079071,-0.25,0,-0.49999988079071,-0.25,-0.5,-0.24999988079071,-0.499999970197678,-0.5,-0.24999988079071,-0.25,-0.5,-0.49999988079071,0,-0.5,-0.24999988079071,-0.25,-0.5,1.19209289550781e-07,0.500000059604645,-0.25,0.25,0.500000059604645,-0.25,0.5,0.500000059604645,-0.5,0.25,0.500000059604645,-0.25,1.19209289550781e-07,0.500000059604645,0,0.25,-0.499999970197678,-0.25,-0.24999988079071,-0.499999970197678,-0.25,-0.49999988079071,-0.499999970197678,-0.25,1.19209289550781e-07,-0.499999970197678,0,-0.24999988079071,0.250000059604645,-0.25,0.5,0.250000059604645,-0.5,0.5,0.250000059604645,0,0.5,0.250000059604645,0.25,0.5,0.500000059604645,0.25,0.5,0.250000059604645,0.5,0.5,0,0.25,0.5,-0.25,0.25,0.5,-0.499999970197678,0.25,0.5,0.250000059604645,0.5,0.25,0.500000059604645,0.5,0.25,0.250000059604645,0.5,1.19209289550781e-07,0.250000059604645,0.5,-0.24999988079071,0.500000059604645,0.5,-0.24999988079071,0.250000059604645,0.5,-0.49999988079071, +0,0.5,-0.24999988079071,-0.25,0.5,-0.24999988079071,-0.499999970197678,0.5,-0.24999988079071,0.250000059604645,0.25,-0.49999988079071,0.500000059604645,0.25,-0.49999988079071,0.250000059604645,0,-0.49999988079071,0.250000059604645,-0.25,-0.49999988079071,0.500000059604645,-0.25,-0.49999988079071,0.250000059604645,-0.5,-0.49999988079071,0,-0.25,-0.49999988079071,-0.25,-0.25,-0.49999988079071,0.250000059604645,-0.5,-0.24999988079071,0.500000059604645,-0.5,-0.24999988079071,0.250000059604645,-0.5,1.19209289550781e-07,0.250000059604645,-0.5,0.25,0,-0.5,0.25,-0.25,-0.5,0.25,-0.499999970197678,-0.5,0.25,0.500000059604645,-0.25,-0.24999988079071,0.500000059604645,0,-0.24999988079071,0.500000059604645,0.25,-0.24999988079071,0.500000059604645,0.25,1.19209289550781e-07,0.500000059604645,0.25,0.25,-0.499999970197678,-0.25,0.25,-0.499999970197678,0,0.25,-0.499999970197678,0.25,0.25,-0.499999970197678,0.25,1.19209289550781e-07,-0.499999970197678,0.25,-0.24999988079071,-0.594913899898529,0,0.594913899898529,-0.152911216020584,0,0.714658200740814,-0.594913899898529,-0.152911216020584,0.594913899898529,-0.152911216020584,-0.152911216020584,0.714658200740814,-0.594913899898529,0.594913899898529,7.29137497046395e-08,-0.152911216020584,0.714658200740814,7.29137497046395e-08,-0.594913899898529,0.594913899898529,0.152911216020584,-0.152911216020584,0.714658200740814,0.152911216020584,-0.594913899898529,0,-0.594913899898529,-0.152911216020584,0,-0.714658200740814,-0.594913899898529,0.152911216020584,-0.594913899898529,-0.152911216020584,0.152911216020584,-0.714658200740814,-0.594913899898529,-0.594913899898529,7.29137497046395e-08,-0.152911216020584,-0.714658200740814,7.29137497046395e-08,-0.594913899898529,-0.594913899898529,-0.152911216020584,-0.152911216020584,-0.714658200740814,-0.152911216020584,0.594913899898529,0,0.594913899898529,0.714658200740814,0,0.152911216020584,0.594913899898529,-0.152911216020584,0.594913899898529,0.714658200740814,-0.152911216020584,0.152911216020584,-0.714658200740814,0,-0.152911216020584,-0.594913899898529,-0.152911216020584,-0.594913899898529, +-0.714658200740814,-0.152911216020584,-0.152911216020584,8.62321627254444e-17,-0.594913899898529,0.594913899898529,8.62321627254444e-17,-0.152911216020584,0.714658200740814,0.152911230921745,-0.594913899898529,0.594913899898529,0.152911230921745,-0.152911216020584,0.714658200740814,0.152911230921745,0,0.714658200740814,0.594913899898529,0.152911216020584,0.594913899898529,0.152911230921745,0.152911216020584,0.714658200740814,8.62321627254444e-17,0.594913899898529,0.594913899898529,8.62321627254444e-17,0.152911216020584,0.714658200740814,-0.152911216020584,0.594913899898529,0.594913899898529,-0.152911216020584,0.152911216020584,0.714658200740814,8.62321627254444e-17,0.714658200740814,0.152911216020584,0.152911230921745,0.594913899898529,0.594913899898529,0.152911230921745,0.714658200740814,0.152911216020584,0.594913899898529,0.594913899898529,7.29137497046395e-08,0.152911230921745,0.714658200740814,7.29137497046395e-08,0.594913899898529,0.594913899898529,-0.152911216020584,0.152911230921745,0.714658200740814,-0.152911216020584,8.62321627254444e-17,0.594913899898529,-0.594913899898529,8.62321627254444e-17,0.714658200740814,-0.152911216020584,-0.152911216020584,0.594913899898529,-0.594913899898529,-0.152911216020584,0.714658200740814,-0.152911216020584,8.62321627254444e-17,0.152911216020584,-0.714658200740814,0.152911230921745,0.594913899898529,-0.594913899898529,0.152911230921745,0.152911216020584,-0.714658200740814,0.594913899898529,0,-0.594913899898529,0.152911230921745,0,-0.714658200740814,0.594913899898529,-0.152911216020584,-0.594913899898529,0.152911230921745,-0.152911216020584,-0.714658200740814,8.62321627254444e-17,-0.594913899898529,-0.594913899898529,8.62321627254444e-17,-0.152911216020584,-0.714658200740814,-0.152911216020584,-0.594913899898529,-0.594913899898529,-0.152911216020584,-0.152911216020584,-0.714658200740814,8.62321627254444e-17,-0.714658200740814,-0.152911216020584,0.152911230921745,-0.594913899898529,-0.594913899898529,0.152911230921745,-0.714658200740814,-0.152911216020584,0.594913899898529,-0.594913899898529,7.29137497046395e-08, +0.152911230921745,-0.714658200740814,7.29137497046395e-08,0.594913899898529,-0.594913899898529,0.152911216020584,0.152911230921745,-0.714658200740814,0.152911216020584,8.62321627254444e-17,-0.714658200740814,0.152911216020584,-0.152911216020584,-0.594913899898529,0.594913899898529,-0.152911216020584,-0.714658200740814,0.152911216020584,0.714658200740814,-0.152911216020584,7.29137497046395e-08,0.594913899898529,-0.594913899898529,-0.152911216020584,0.714658200740814,-0.152911216020584,-0.152911216020584,0.714658200740814,0,-0.152911216020584,0.594913899898529,0.152911216020584,-0.594913899898529,0.714658200740814,0.152911216020584,-0.152911216020584,0.714658200740814,0.152911216020584,7.29137497046395e-08,0.594913899898529,0.594913899898529,0.152911216020584,0.714658200740814,0.152911216020584,0.152911216020584,-0.714658200740814,-0.152911216020584,7.29137497046395e-08,-0.594913899898529,-0.594913899898529,0.152911216020584,-0.714658200740814,-0.152911216020584,0.152911216020584,-0.714658200740814,0,0.152911216020584,-0.594913899898529,0.152911216020584,0.594913899898529,-0.714658200740814,0.152911216020584,0.152911216020584,-0.714658200740814,0.152911216020584,7.29137497046395e-08,-0.594913899898529,0.594913899898529,-0.152911216020584,-0.714658200740814,0.152911216020584,-0.152911216020584,-0.541863918304443,-0.541864037513733,0.541863918304443,8.62321627254444e-17,0,0.714658200740814,-0.541863918304443,0.541863918304443,0.541863918304443,8.62321627254444e-17,0.714658200740814,7.29137497046395e-08,-0.541863918304443,0.541863918304443,-0.541863799095154,8.62321627254444e-17,0,-0.714658200740814,-0.541863918304443,-0.541864037513733,-0.541863799095154,8.62321627254444e-17,-0.714658200740814,7.29137497046395e-08,0.541863977909088,-0.541864037513733,0.541863918304443,0.714658200740814,0,7.29137497046395e-08,-0.714658200740814,0,7.29137497046395e-08,0.541863977909088,0.541863918304443,0.541863918304443,0.541863977909088,0.541863918304443,-0.541863799095154,0.541863977909088,-0.541864037513733,-0.541863799095154 + } + PolygonVertexIndex: *768 { + a: 99,98,100,-102,103,102,104,-106,107,106,108,-110,111,110,112,-114,115,114,116,-118,118,106,119,-121,122,121,123,-125,125,114,126,-128,129,128,130,-132,132,128,133,-135,136,135,137,-139,140,139,141,-143,143,139,144,-146,147,146,148,-150,151,150,152,-154,154,150,155,-157,158,157,159,-161,161,121,162,-164,164,157,165,-167,167,146,168,-170,170,135,171,-173,173,110,174,-176,176,98,177,-179,179,102,180,-182,100,182,162,-102,162,121,122,-102,122,183,99,-102,104,184,130,-106,130,128,132,-106,132,185,103,-106,108,186,141,-110,141,139,143,-110,143,187,107,-110,112,188,152,-114,152,150,154,-114,154,189,111,-114,116,190,159,-118,159,157,164,-118,164,191,115,-118,119,188,112,-121,112,110,173,-121,173,192,118,-121,123,190,116,-125,116,114,125,-125,125,183,122,-125,126,193,133,-128,133,128,129,-128,129,183,125,-128,130,184,177,-132,177,98,99,-132,99,183,129,-132,133,193,171,-135,171,135,136,-135,136,185,132,-135,137,194,144,-139,144,139,140,-139,140,185,136,-139,141,186,180,-143,180,102,103,-143,103,185,140,-143,144,194,168,-146,168,146,147,-146,147,187,143,-146,148,195,155,-150,155,150,151,-150,151,187,147,-150,152,188,119,-154,119,106,107,-154,107,187,151,-154,155,195,165,-157,165,157,158,-157,158,189,154,-157,159,190,123,-161,123,121,161,-161,161,189,158,-161,162,182,174,-164,174,110,111,-164,111,189,161,-164,165,195,148,-167,148,146,167,-167,167,191,164,-167,168,194,137,-170,137,135,170,-170,170,191,167,-170,171,193,126,-173,126,114,115,-173,115,191,170,-173,174,182,100,-176,100,98,176,-176,176,192,173,-176,177,184,104,-179,104,102,179,-179,179,192,176,-179,180,186,108,-182,108,106,118,-182,118,192,179,-182,30,26,27,-13,35,31,32,-17,40,36,37,-21,45,41,42,-24,50,46,47,-11,54,51,52,-21,29,55,56,-10,57,58,59,-11,61,62,33,-12,34,64,60,-12,66,67,68,-15,70,71,38,-16,39,73,69,-16,75,76,77,-19,79,80,43,-20,44,81,78,-20,83,84,48,-23,85,86,28,-10,49,88,82,-23,89,90,74,-19,91,92,65,-15,53,93,87,-24,94,95,63,-13,96,97,72,-17,27,26,28,-1,28,26,29,-10,29,26,30,-9,32,31,33,-3,33,31,34,-12,34,31,35,-14,37,36,38,-5,38,36,39, +-16,39,36,40,-18,42,41,43,-7,43,41,44,-20,44,41,45,-22,47,46,48,-2,48,46,49,-23,49,46,50,-25,52,51,42,-7,42,51,53,-24,53,51,54,-26,56,55,47,-2,47,55,57,-11,57,55,29,-9,59,58,60,-4,60,58,61,-12,61,58,57,-9,33,62,63,-3,63,62,30,-13,30,62,61,-9,60,64,65,-4,65,64,66,-15,66,64,34,-14,68,67,69,-6,69,67,70,-16,70,67,66,-14,38,71,72,-5,72,71,35,-17,35,71,70,-14,69,73,74,-6,74,73,75,-19,75,73,39,-18,77,76,78,-8,78,76,79,-20,79,76,75,-18,43,80,52,-7,52,80,40,-21,40,80,79,-18,78,81,82,-8,82,81,83,-23,83,81,44,-22,48,84,56,-2,56,84,85,-10,85,84,83,-22,28,86,87,-1,87,86,45,-24,45,86,85,-22,82,88,77,-8,77,88,89,-19,89,88,49,-25,74,90,68,-6,68,90,91,-15,91,90,89,-25,65,92,59,-4,59,92,50,-11,50,92,91,-25,87,93,27,-1,27,93,94,-13,94,93,53,-26,63,95,32,-3,32,95,96,-17,96,95,94,-26,72,97,37,-5,37,97,54,-21,54,97,96,-26 + } + Edges: *384 { + a: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,102,104,105,108,109,110,114,116,117,120,121,122,126,128,129,132,133,134,138,140,141,144,145,146,150,152,153,156,158,162,164,165,168,170,174,176,180,181,182,186,188,193,194,198,205,206,210,212,216,217,218,222,224,229,230,234,241,242,246,248,252,253,254,258,260,266,270,277,278,282,284,290,294,296,301,302,306,314,318,320,326,330,332,338,342,350,354,356,362,366,368,374,378,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,481,482,483,485,490,491,493,494,495,497,502,503,505,506,507,509,514,515,517,518,519,521,526,527,529,530,531,533,538,539,541,543,545,550,551,553,555,557,563,565,566,567,569,575,577,578,581,589,590,593,599,601,602,603,605,611,613,614,617,625,626,629,635,637,638,639,641,647,649,653,661,662,665,671,673,677,683,685,686,689,697,701,707,709,713,719,721,725,733,737,743,745,749,755,757,761 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *2304 { + a: -0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487185955048,0.965206921100616,0,-0.261487185955048,0.965206921100616,0,-0.261487185955048,0.965206921100616,0,-0.261487185955048,0.965206921100616,0,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,0,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.965206921100616,0.261487156152725,0,0.965206921100616,0.261487156152725,0,0.965206921100616,0.261487156152725,0,0.965206921100616,0.261487156152725,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0.261487126350403,0,-0.965206980705261, +0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.965206921100616,-0.261487156152725,0,-0.965206921100616,-0.261487156152725,0,-0.965206921100616,-0.261487156152725,0,-0.965206921100616,-0.261487156152725,0.261487185955048,-0.965206921100616,0,0.261487185955048,-0.965206921100616,0,0.261487185955048,-0.965206921100616,0,0.261487185955048,-0.965206921100616,0,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0.965206980705261,-0.261487066745758,0,0.965206980705261,-0.261487066745758,0,0.965206980705261,-0.261487066745758,0,0.965206980705261,-0.261487066745758,0,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0.261487066745758,0,-0.965206980705261,0.261487066745758,0,-0.965206980705261,0.261487066745758,0,-0.965206980705261,0.261487066745758,0,-0.211917281150818,-0.211917445063591,0.954034626483917,0,0,1,-0.211917281150818,-0.21191743016243,0.954034626483917,-0.211917266249657,-0.211917445063591,0.954034626483917,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,-0.211917445063591,0.954034626483917,0.211917281150818, +0,1,0,-0.211917445063591,0.954034626483917,0.211917281150818,-0.211917445063591,0.954034626483917,0.211917266249657,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,1,0,0,1,0,0,1,0,0,1,0,-0.211917594075203,0.211917579174042,-0.954034507274628,0,0,-1,-0.211917594075203,0.211917579174042,-0.954034507274628,-0.211917594075203,0.211917564272881,-0.954034507274628,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.211917325854301,-0.954034626483917,-0.211917325854301,0,-1,0,-0.211917325854301,-0.954034686088562,-0.211917325854301,-0.211917355656624,-0.954034686088562,-0.211917355656624,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0.954034626483917,-0.211917251348495,0.21191731095314,1,0,0,0.954034626483917,-0.211917251348495,0.211917340755463,0.954034745693207,-0.211917266249657,0.211917325854301,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,1,0,0,1,0,0,1,0,0,1,0,0,-0.954034686088562,-0.211917355656624,-0.211917459964752,-1,0,0,-0.954034626483917,-0.211917325854301,-0.211917445063591,-0.954034686088562,-0.211917355656624,-0.211917474865913,-0.965206980705261,-0.261487066745758,0,-0.965206980705261,-0.261487066745758,0,-0.965206980705261,-0.261487066745758,0,-0.965206980705261,-0.261487066745758,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0.211917281150818,-0.211917400360107,0.954034626483917,0,0,1,0.211917266249657,-0.211917415261269,0.954034626483917,0.211917266249657,-0.211917415261269,0.954034626483917,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261, +0,0,1,0,0,1,0,0,1,0,0,1,0.211917296051979,0.211917415261269,0.954034626483917,0,0,1,0.211917296051979,0.211917415261269,0.954034626483917,0.211917281150818,0.211917415261269,0.954034626483917,0,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0,1,0,0,1,0,0,1,0,0,1,-0.211917281150818,0.211917445063591,0.954034626483917,0,0,1,-0.211917281150818,0.211917445063591,0.954034626483917,-0.211917266249657,0.211917445063591,0.954034626483917,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,0.211917445063591,0.954034626483917,0.211917445063591,0,1,0,0.211917415261269,0.954034566879272,0.211917415261269,0.211917445063591,0.954034626483917,0.211917445063591,0.261487185955048,0.965206921100616,0,0.261487185955048,0.965206921100616,0,0.261487185955048,0.965206921100616,0,0.261487185955048,0.965206921100616,0,0,1,0,0,1,0,0,1,0,0,1,0,0.211917445063591,0.954034626483917,-0.211917489767075,0,1,0,0.21191743016243,0.954034566879272,-0.211917489767075,0.211917445063591,0.954034566879272,-0.211917474865913,0,0.965206921100616,-0.261487156152725,0,0.965206921100616,-0.261487156152725,0,0.965206921100616,-0.261487156152725,0,0.965206921100616,-0.261487156152725,0,1,0,0,1,0,0,1,0,0,1,0,-0.211917459964752,0.954034686088562,-0.211917340755463,0,1,0,-0.211917445063591,0.954034626483917,-0.21191731095314,-0.211917489767075,0.954034686088562,-0.211917355656624,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0,0,1,0,0,1,0,0,1,0,0,1,0,0.211917608976364,0.211917579174042,-0.954034507274628,0,0,-1,0.211917608976364,0.211917564272881,-0.954034566879272,0.211917594075203,0.211917579174042,-0.954034507274628,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261, +0.261487126350403,0,-0.965206980705261,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0.211917579174042,-0.211917534470558,-0.954034507274628,0,0,-1,0.211917594075203,-0.211917549371719,-0.954034507274628,0.211917594075203,-0.211917519569397,-0.954034507274628,0,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.211917594075203,-0.211917549371719,-0.954034507274628,0,0,-1,-0.211917579174042,-0.211917534470558,-0.954034566879272,-0.211917594075203,-0.211917519569397,-0.954034507274628,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0.211917340755463,-0.954034686088562,-0.211917519569397,0,-1,0,0.211917325854301,-0.954034626483917,-0.211917489767075,0.211917325854301,-0.954034686088562,-0.211917489767075,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0.211917281150818,-0.954034626483917,0.211917445063591,0,-1,0,0.211917296051979,-0.954034626483917,0.211917445063591,0.211917266249657,-0.954034626483917,0.211917445063591,0,-0.965206921100616,0.261487156152725,0,-0.965206921100616,0.261487156152725,0,-0.965206921100616,0.261487156152725,0,-0.965206921100616,0.261487156152725,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0.211917296051979,-0.954034626483917,0.211917296051979,0,-1,0,-0.211917296051979,-0.954034626483917,0.211917296051979,-0.211917281150818,-0.954034686088562,0.211917281150818,-0.261487185955048,-0.965206921100616,0,-0.261487185955048,-0.965206921100616,0,-0.261487185955048,-0.965206921100616,0,-0.261487185955048,-0.965206921100616,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0.954034626483917,-0.211917325854301,-0.211917400360107,1,0,0,0.954034686088562,-0.211917340755463,-0.211917400360107,0.954034686088562,-0.211917355656624,-0.21191743016243,0.965206980705261,0,-0.261487185955048, +0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,1,0,0,1,0,0,1,0,0,1,0,0,0.954034686088562,0.211917370557785,-0.211917489767075,1,0,0,0.954034686088562,0.211917355656624,-0.211917445063591,0.954034626483917,0.211917355656624,-0.211917445063591,0.965206980705261,0.261487066745758,0,0.965206980705261,0.261487066745758,0,0.965206980705261,0.261487066745758,0,0.965206980705261,0.261487066745758,0,1,0,0,1,0,0,1,0,0,1,0,0,0.954034626483917,0.211917296051979,0.211917385458946,1,0,0,0.954034626483917,0.211917296051979,0.211917385458946,0.954034626483917,0.211917266249657,0.211917355656624,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,1,0,0,1,0,0,1,0,0,1,0,0,-0.954034626483917,-0.211917251348495,0.211917400360107,-1,0,0,-0.954034626483917,-0.211917266249657,0.211917400360107,-0.954034626483917,-0.211917251348495,0.211917400360107,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-0.954034626483917,0.211917281150818,0.211917445063591,-1,0,0,-0.954034626483917,0.211917281150818,0.211917445063591,-0.954034626483917,0.211917266249657,0.211917445063591,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-0.954034566879272,0.211917355656624,-0.211917519569397,-1,0,0,-0.954034686088562,0.211917370557785,-0.211917534470558,-0.954034626483917,0.211917355656624,-0.211917504668236,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0, +1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0, +-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0 + } + NormalsW: *768 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *2304 { + a: 0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0.965207040309906,0.261487185955048,0,0.965207040309906,0.261487185955048,0,0.965207040309906,0.261487185955048,0,0.965207040309906,0.261487185955048,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,0.965206980705261,-0.261487185955048,0,0.965206980705261,-0.261487185955048,0,0.965206980705261,-0.261487185955048,0,0.965206980705261,-0.261487185955048,0,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0.261487126350403,-0.965206980705261,0,-0.261487126350403,-0.965206980705261,0,-0.261487126350403,-0.965206980705261,0,-0.261487126350403,-0.965206980705261,0,-0.965207040309906,-0.261487185955048,0,-0.965207040309906,-0.261487185955048,0,-0.965207040309906,-0.261487185955048,0,-0.965207040309906,-0.261487185955048,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-0.965206980705261,0.261487185955048,0,-0.965206980705261,0.261487185955048,0,-0.965206980705261,0.261487185955048,0,-0.965206980705261,0.261487185955048,0,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0,0,1,0,0,1,0,0,1,0,0,1,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,0,1,0,0,1,0,0,1,0, +0,1,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,-0.0554696954786777,0.977241098880768,0.204750895500183,0.0677256807684898,0.997704029083252,-0,0.0995207726955414,0.966452240943909,0.236782029271126,0.022095151245594,0.974918127059937,0.221464186906815,0,0.965206980705261,0.261487185955048,0,0.965206980705261,0.261487185955048,0,0.965206980705261,0.261487185955048,0,0.965206980705261,0.261487185955048,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0.0554696545004845,0.204750746488571,-0.977241158485413,0.0677258297801018,0,-0.997703969478607,0.0995210781693459,0.23678195476532,-0.966452240943909,0.0220953319221735,0.221464082598686,-0.974918246269226,0,0.261487126350403,-0.965206980705261,0,0.261487126350403,-0.965206980705261,0,0.261487126350403,-0.965206980705261,0,0.261487126350403,-0.965206980705261,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.055469736456871,-0.977241158485413,-0.204751059412956,0.0677258297801018,-0.997703969478607,0,0.0995209664106369,-0.966452121734619,-0.236782252788544,0.0220952294766903,-0.974918127059937,-0.221464350819588,0,-0.965206980705261,-0.261487185955048,0,-0.965206980705261,-0.261487185955048,0,-0.965206980705261,-0.261487185955048,0,-0.965206980705261,-0.261487185955048,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,-0,-0.0554696694016457,-0.204750820994377,0.977241218090057,0.0677259787917137,0,0.997703969478607,0.0995214134454727,-0.236782014369965,0.966452121734619,0.0220954976975918,-0.221464157104492,0.974918186664581,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,0.204750746488571,0.977241218090057,0.0554696507751942,0,0.997704029083252,-0.0677256807684898,0.236781880259514,0.966452300548553,-0.0995208472013474,0.221463993191719,0.974918186664581,-0.0220952127128839,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0, +-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0.204750791192055,0.977241098880768,-0.0554696619510651,0,0.997704029083252,0.0677257031202316,-0.236781939864159,0.966452240943909,0.099520817399025,-0.221464112401009,0.974918246269226,0.022095188498497,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,0,-0.099520780146122,0.966452240943909,0.236781999468803,-0.0677256733179092,0.997704029083252,0,0.0554696880280972,0.977241098880768,0.204750865697861,-0.022095151245594,0.974918127059937,0.221464157104492,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0.0554696880280972,0.977241098880768,-0.204750865697861,0.0677258223295212,0.997703969478607,-0,0.0995210558176041,0.966452181339264,-0.236782059073448,0.0220952890813351,0.974918246269226,-0.221464201807976,0,0.965207040309906,-0.261487185955048,0,0.965207040309906,-0.261487185955048,0,0.965207040309906,-0.261487185955048,0,0.965207040309906,-0.261487185955048,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0.0995210707187653,0.966452240943909,-0.236782118678093,-0.0677258297801018,0.997703969478607,0,0.0554696954786777,0.977241098880768,-0.204750895500183,-0.0220952928066254,0.974918186664581,-0.221464231610298,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0.0995210558176041,0.236782118678093,-0.966452240943909,-0.0677258223295212,0,-0.997703969478607,0.0554696917533875,0.204750880599022,-0.977241098880768,-0.0220952853560448,0.221464216709137,-0.974918127059937,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.0554697066545486,-0.204750955104828,-0.977241158485413,0.0677259713411331,0,-0.997703969478607,0.0995213314890862,-0.236782237887383,-0.966452181339264,0.0220954213291407,-0.221464306116104,-0.974918186664581,0,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.0995213687419891,-0.236782059073448,-0.966452181339264, +-0.0677259787917137,0,-0.997703969478607,0.0554696545004845,-0.204750776290894,-0.977241158485413,-0.0220954604446888,-0.221464172005653,-0.974918246269226,0,0,-1,0,0,-1,-0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.0995209515094757,-0.966452121734619,-0.236782252788544,-0.0677258223295212,-0.997703969478607,-0,0.0554697290062904,-0.977241098880768,-0.204751014709473,-0.0220952183008194,-0.974918127059937,-0.221464365720749,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,-0,-0.0554697290062904,-0.977241158485413,0.204751014709473,0.0677256733179092,-0.997704029083252,0,0.099520668387413,-0.966452181339264,0.236782178282738,0.022095087915659,-0.974918127059937,0.221464276313782,0,-0.965207040309906,0.261487185955048,0,-0.965207040309906,0.261487185955048,0,-0.965207040309906,0.261487185955048,0,-0.965207040309906,0.261487185955048,0,-1,0,0,-1,0,0,-1,-0,0,-1,0,-0.0995206907391548,-0.966452181339264,0.236782178282738,-0.0677256807684898,-0.997704029083252,-0,0.0554697178304195,-0.977241098880768,0.20475098490715,-0.0220951028168201,-0.974918127059937,0.221464276313782,0,-1,-0,0,-1,-0,-0,-1,0,0,-1,-0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0.0995213836431503,-0.23678220808506,0.966452121734619,-0.0677259713411331,0,0.997703969478607,0.0554697066545486,-0.204750940203667,0.977241098880768,-0.0220954623073339,-0.221464291214943,0.974918186664581,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0.0554696954786777,0.204750895500183,0.977241098880768,0.0677258223295212,0,0.997703969478607,0.0995211154222488,0.236782103776932,0.966452181339264,0.0220953226089478,0.221464246511459,0.974918186664581,0,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0,1,0,0,1,0,0,1,0,0,1,-0.0995211601257324,0.23678195476532,0.966452181339264,-0.0677258297801018,0,0.997703969478607,0.0554696619510651,0.204750776290894,0.977241218090057,-0.022095363587141,0.221464082598686,0.974918246269226,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0.236781939864159,0.966452240943909,0.0995208621025085, +-0,0.997704029083252,0.0677257031202316,0.204750806093216,0.977241158485413,-0.0554696656763554,0.221464112401009,0.974918186664581,0.0220951996743679,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0.204750806093216,0.977241098880768,0.0554696694016457,0,0.997703969478607,-0.0677258521318436,-0.236782044172287,0.966452240943909,-0.0995211452245712,-0.221464172005653,0.974918246269226,-0.0220953542739153,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,0,1,-0,-0,1,0,-0,1,0,-0,1,0,-0.236781984567642,0.966452300548553,0.09952113032341,-0,0.997703969478607,0.0677258297801018,-0.204750761389732,0.977241158485413,-0.0554696582257748,-0.221464067697525,0.974918246269226,0.022095350548625,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,-0,-0,1,0,-0.236781880259514,0.966452360153198,-0.0995208248496056,0,0.997704029083252,-0.0677256807684898,-0.20475073158741,0.977241158485413,0.0554696470499039,-0.221464022994041,0.974918246269226,-0.0220951903611422,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0.204750746488571,0.977241158485413,-0.0554696545004845,0,0.997703969478607,0.0677258297801018,0.23678195476532,0.966452240943909,0.0995210781693459,0.221464082598686,0.974918246269226,0.0220953319221735,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,0,0.236782059073448,0.966452240943909,-0.0995211154222488,0,0.997703969478607,-0.0677258521318436,0.204750806093216,0.977241098880768,0.0554696656763554,0.221464142203331,0.974918186664581,-0.0220953188836575,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,-0,-1,0,-0,-1, +0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1, +-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0 + } + BinormalsW: *768 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *2304 { + a: 0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965207040309906,0.26148721575737,0,0.965207040309906,0.26148721575737,0,0.965207040309906,0.26148721575737,0,0.965207040309906,0.26148721575737,0,0.965206980705261,-0,-0.261487126350403,0.965206980705261,-0,-0.261487126350403,0.965206980705261,-0,-0.261487126350403,0.965206980705261,-0,-0.261487126350403,0.965206980705261,-0.261487156152725,-0,0.965206980705261,-0.261487156152725,-0,0.965206980705261,-0.261487156152725,-0,0.965206980705261,-0.261487156152725,-0,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,0.965206980705261,-0.261487156152725,0,0.965206980705261,-0.261487156152725,0,0.965206980705261,-0.261487156152725,0,0.965206980705261,-0.261487156152725,0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,-0,0,1,0,0,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,-0,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0.26148721575737,-0,0.965207040309906, +0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0.97571212053299,0.00952975451946259,0.218849271535873,0.997704029083252,-0.0677256807684898,0,0.972207129001617,-0.145124465227127,0.183717742562294,0.977037787437439,-0.0680116266012192,0.201919630169868,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0.97571212053299,0.218849420547485,-0.0095297135412693,0.997703969478607,0,0.0677258297801018,0.972207069396973,0.183717846870422,0.145124778151512,0.977037727832794,0.20191977918148,0.0680118054151535,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0.975712060928345,-0.00952968932688236,-0.21884959936142,0.997703969478607,0.0677258297801018,0,0.972207009792328,0.145124763250351,-0.183717966079712,0.977037727832794,0.0680118054151535,-0.201919928193092,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0.97571212053299,-0.218849316239357,0.00952973961830139,0.997703969478607,0,-0.0677259787917137,0.972207069396973,-0.183717638254166,-0.145125105977058,0.977037727832794,-0.201919630169868,-0.068011961877346,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0.218849301338196,0.00952973961830139,-0.97571212053299,0,-0.0677256807684898,-0.997704029083252,0.1837178170681,-0.145124509930611,-0.972207069396973,0.201919689774513,-0.0680116564035416,-0.977037787437439,-0,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.218849420547485,0.0095297172665596,0.97571212053299,0,-0.0677257031202316,0.997704029083252,-0.183717906475067,-0.145124524831772,0.972207069396973,-0.201919823884964,-0.068011686205864,0.977037727832794,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0.972207129001617,0.145124465227127,-0.183717742562294,0.997704029083252,0.0677256733179092,0,0.97571212053299,-0.00952975824475288,-0.218849256634712,0.977037787437439,0.0680116191506386,-0.201919630169868,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403, +1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0.97571212053299,0.00952975172549486,-0.218849286437035,0.997703969478607,-0.0677258223295212,0,0.972207069396973,-0.14512474834919,-0.183717682957649,0.977037847042084,-0.0680117681622505,-0.20191964507103,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,0.972207069396973,0.14512474834919,0.183717668056488,0.997703969478607,0.0677258297801018,0,0.97571212053299,-0.00952975451946259,0.218849271535873,0.977037847042084,0.0680117756128311,0.201919630169868,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,1,-0,-0,1,-0,0,1,-0,0,1,-0,0,0.972207069396973,-0.183717831969261,-0.145124778151512,0.997703969478607,0,-0.0677258223295212,0.97571212053299,-0.218849420547485,0.00952972378581762,0.977037727832794,-0.20191977918148,-0.0680117979645729,0.965207040309906,-0.26148721575737,-0,0.965207040309906,-0.26148721575737,-0,0.965207040309906,-0.26148721575737,-0,0.965207040309906,-0.26148721575737,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0.97571212053299,-0.218849420547485,-0.0095297247171402,0.997703969478607,0,0.0677259713411331,0.972207009792328,-0.183717742562294,0.145125061273575,0.977037727832794,-0.201919749379158,0.0680119395256042,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,-0,-0,1,0,0,0.972207009792328,0.183717772364616,-0.145125061273575,0.997703969478607,0,-0.0677259787917137,0.97571212053299,0.218849420547485,0.00952971447259188,0.977037727832794,0.20191977918148,-0.0680119544267654,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,-0,0.965206980705261,0.261487156152725,0,1,-0,0,1,0,0,1,0,0,1,0,0,0.972207009792328,-0.14512474834919,0.183717995882034,0.997703969478607,-0.0677258223295212,0,0.975712060928345,0.00952969118952751,0.218849584460258,0.977037727832794,-0.0680117979645729,0.201919928193092,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403, +1,-0,0,1,-0,0,1,-0,0,1,-0,0,0.975712060928345,-0.00952969212085009,0.218849584460258,0.997704029083252,0.0677256733179092,0,0.972207069396973,0.145124465227127,0.183718055486679,0.977037727832794,0.0680116564035416,0.201919972896576,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,0.972207069396973,-0.145124480128288,-0.183718040585518,0.997704029083252,-0.0677256807684898,0,0.975712060928345,0.00952969398349524,-0.218849569559097,0.977037727832794,-0.0680116713047028,-0.201919972896576,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,-0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,1,0,0,1,0,0,1,0,0,1,0,0,0.972207069396973,0.183717623353004,0.145125105977058,0.997703969478607,0,0.0677259713411331,0.97571212053299,0.218849316239357,-0.00952974893152714,0.977037847042084,0.201919630169868,0.0680119544267654,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0.97571212053299,0.218849271535873,0.00952975638210773,0.997703969478607,0,-0.0677258223295212,0.972207069396973,0.183717668056488,-0.145124807953835,0.977037847042084,0.201919630169868,-0.0680118054151535,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0.972207069396973,-0.183717682957649,0.145124822854996,0.997703969478607,0,0.0677258297801018,0.97571212053299,-0.218849286437035,-0.00952974427491426,0.977037847042084,-0.201919630169868,0.0680118054151535,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,-0.183717846870422,0.145124554634094,-0.972207069396973,0,0.0677257031202316,-0.997704029083252,-0.218849360942841,-0.0095297284424305,-0.97571212053299,-0.20191977918148,0.068011686205864,-0.977037727832794,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906, +0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.218849450349808,0.00952971167862415,-0.97571212053299,0,-0.0677258521318436,-0.997703969478607,-0.1837178170681,-0.145124852657318,-0.972207069396973,-0.201919764280319,-0.0680118426680565,-0.977037727832794,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0,0,-1,0,0,-1,0.183717772364616,0.145124807953835,-0.972207069396973,0,0.0677258297801018,-0.997703969478607,0.218849375844002,-0.00952972657978535,-0.97571212053299,0.201919689774513,0.0680118054151535,-0.977037727832794,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0.183717876672745,0.145124495029449,0.972207069396973,0,0.0677256807684898,0.997704029083252,0.218849375844002,-0.00952972192317247,0.97571212053299,0.20191977918148,0.0680116564035416,0.977037727832794,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0.218849420547485,0.0095297135412693,0.97571212053299,0,-0.0677258297801018,0.997703969478607,0.183717846870422,-0.145124778151512,0.972207069396973,0.20191977918148,-0.0680118054151535,0.977037727832794,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,-0.183717906475067,0.145124837756157,0.972207009792328,0,0.0677258521318436,0.997703969478607,-0.21884948015213,-0.00952970236539841,0.97571212053299,-0.201919838786125,0.0680118277668953,0.977037727832794,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,0,-0,1,0,-0,1,0,-0,1,0,-0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,0,1,0,0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0,0,1,0,0,1,0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0, +1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1, +0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1 + } + TangentsW: *768 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *542 { + a: 0.375,0,0.625,0,0.375,0.25,0.625,0.25,0.375,0.5,0.625,0.5,0.375,0.75,0.625,0.75,0.375,1,0.625,1,0.875,0,0.875,0.25,0.125,0,0.125,0.25,0.5,0.125,0.5,0,0.5,1,0.625,0.125,0.5,0.25,0.375,0.125,0.5,0.375,0.625,0.375,0.75,0.25,0.5,0.5,0.375,0.375,0.25,0.25,0.5,0.625,0.625,0.625,0.875,0.125,0.5,0.75,0.375,0.625,0.125,0.125,0.5,0.875,0.625,0.875,0.75,0,0.5,1,0.375,0.875,0.25,0,0.75,0.125,0.75,0,0.875,0.125,0.75,0.25,0.25,0.125,0.25,0,0.25,0.25,0.125,0.125,0.4375,0.0625,0.375,0.0625,0.4375,0,0.4375,1,0.5,0.0625,0.4375,0.125,0.4375,0.3125,0.375,0.3125,0.3125,0.25,0.4375,0.25,0.5,0.3125,0.4375,0.375,0.4375,0.5625,0.375,0.5625,0.125,0.1875,0.4375,0.5,0.5,0.5625,0.4375,0.625,0.4375,0.8125,0.375,0.8125,0.1875,0,0.4375,0.75,0.5,0.8125,0.4375,0.875,0.6875,0.0625,0.625,0.0625,0.625,0.9375,0.6875,0,0.75,0.0625,0.6875,0.125,0.1875,0.0625,0.375,0.6875,0.125,0.0625,0.1875,0,0.25,0.0625,0.1875,0.125,0.5625,0.0625,0.5625,0,0.5625,1,0.5625,0.125,0.5625,0.1875,0.625,0.1875,0.5625,0.25,0.5,0.1875,0.4375,0.1875,0.375,0.1875,0.5625,0.3125,0.625,0.3125,0.6875,0.25,0.5625,0.375,0.5625,0.4375,0.625,0.4375,0.8125,0.25,0.5625,0.5,0.5,0.4375,0.4375,0.4375,0.375,0.4375,0.1875,0.25,0.5625,0.5625,0.625,0.5625,0.875,0.1875,0.5625,0.625,0.5625,0.6875,0.625,0.6875,0.875,0.0625,0.5625,0.75,0.5,0.6875,0.4375,0.6875,0.375,0.6875,0.5625,0.8125,0.625,0.8125,0.8125,0,0.5625,0.875,0.5625,0.9375,0.625,0.9375,0.5625,1,0.5,0.9375,0.4375,0.9375,0.4375,1,0.375,0.9375,0.3125,0,0.8125,0.0625,0.8125,0,0.875,0.0625,0.8125,0.125,0.8125,0.1875,0.875,0.1875,0.8125,0.25,0.75,0.1875,0.6875,0.1875,0.6875,0.25,0.3125,0.0625,0.3125,0,0.3125,0.125,0.3125,0.1875,0.3125,0.25,0.25,0.1875,0.1875,0.1875,0.1875,0.25,0.125,0.1875,0.4375,0.125,0.375,0.125,0.375,0.0625,0.4375,0.0625,0.4375,0.375,0.375,0.375,0.375,0.3125,0.4375,0.3125,0.4375,0.625,0.375,0.625,0.375,0.5625,0.4375,0.5625,0.4375,0.875,0.375,0.875,0.375,0.8125,0.4375,0.8125,0.6875,0.125,0.625,0.125,0.625,0.0625,0.6875,0.0625,0.1875,0.125,0.125,0.125,0.125,0.0625,0.1875,0.0625,0.5,0.0625,0.5,0,0.5625,0, +0.5625,0.0625,0.5625,0.125,0.625,0.1875,0.5625,0.1875,0.5,0.1875,0.5,0.25,0.4375,0.25,0.4375,0.1875,0.5,0.3125,0.5625,0.25,0.5625,0.3125,0.5625,0.375,0.625,0.375,0.625,0.4375,0.5625,0.4375,0.5,0.4375,0.5,0.5,0.4375,0.5,0.4375,0.4375,0.5,0.5625,0.5625,0.5,0.5625,0.5625,0.5625,0.625,0.625,0.625,0.625,0.6875,0.5625,0.6875,0.5,0.6875,0.5,0.75,0.4375,0.75,0.4375,0.6875,0.5,0.8125,0.5625,0.75,0.5625,0.8125,0.5625,0.875,0.625,0.875,0.625,0.9375,0.5625,0.9375,0.5,0.9375,0.5,1,0.4375,1,0.4375,0.9375,0.75,0.0625,0.75,0,0.8125,0,0.8125,0.0625,0.8125,0.125,0.875,0.125,0.875,0.1875,0.8125,0.1875,0.75,0.1875,0.75,0.25,0.6875,0.25,0.6875,0.1875,0.25,0.0625,0.25,0,0.3125,0,0.3125,0.0625,0.3125,0.125,0.375,0.1875,0.3125,0.1875,0.25,0.1875,0.25,0.25,0.1875,0.25,0.1875,0.1875,0.375,0,0.4375,0,0.5,0.125,0.375,0.25,0.5,0.375,0.375,0.5,0.5,0.625,0.375,0.75,0.5,0.875,0.625,0,0.6875,0,0.75,0.125,0.125,0,0.1875,0,0.25,0.125,0.625,0.25,0.625,0.3125,0.625,0.5,0.375,0.4375,0.625,0.5625,0.625,0.75,0.375,0.6875,0.625,0.8125,0.625,1,0.5625,1,0.375,1,0.375,0.9375,0.875,0,0.875,0.0625,0.875,0.25,0.8125,0.25,0.3125,0.25,0.125,0.25,0.125,0.1875 + } + UVIndex: *768 { + a: 51,19,47,46,57,24,53,52,63,30,59,58,69,36,65,64,75,17,71,70,81,45,78,76,50,15,83,82,85,17,87,86,89,18,55,90,56,18,88,92,95,21,97,96,100,23,61,101,62,23,99,104,107,27,109,108,112,29,67,113,68,29,111,115,118,33,120,119,122,35,124,123,74,39,128,127,130,40,132,131,134,41,136,135,80,43,138,137,139,19,91,140,142,44,144,143,47,0,48,46,48,15,50,46,50,14,51,46,53,2,55,52,55,18,56,52,56,20,57,52,59,4,61,58,61,23,62,58,62,26,63,58,65,6,67,64,67,29,68,64,68,32,69,64,71,1,73,70,73,39,74,70,74,38,75,70,78,12,79,76,79,43,80,76,80,42,81,76,83,1,71,82,71,17,85,82,85,14,50,82,87,3,88,86,88,18,89,86,89,14,85,86,55,2,91,90,91,19,51,90,51,14,89,90,88,3,93,92,93,21,95,92,95,20,56,92,97,5,99,96,99,23,100,96,100,20,95,96,61,4,102,101,102,24,57,101,57,20,100,101,99,5,105,104,105,27,107,104,107,26,62,104,109,7,111,108,111,29,112,108,112,26,107,108,67,6,114,113,114,30,63,113,63,26,112,113,111,7,116,115,116,33,118,115,118,32,68,115,120,9,121,119,121,35,122,119,122,32,118,119,124,8,125,123,125,36,69,123,69,32,122,123,128,10,129,127,129,40,130,127,130,38,74,127,132,11,133,131,133,41,134,131,134,38,130,131,136,3,87,135,87,17,75,135,75,38,134,135,138,0,47,137,47,19,139,137,139,42,80,137,91,2,141,140,141,44,142,140,142,42,139,140,144,13,145,143,145,45,81,143,81,42,142,143,146,149,148,147,150,153,152,151,154,157,156,155,158,161,160,159,162,165,164,163,166,169,168,167,170,173,172,171,174,176,175,163,177,180,179,178,181,183,182,178,184,187,186,185,188,191,190,189,192,194,193,189,195,198,197,196,199,202,201,200,203,205,204,200,206,209,208,207,210,213,212,211,214,217,216,215,218,221,220,219,222,225,224,223,226,229,228,227,230,232,231,147,233,236,235,234,148,149,238,237,238,149,170,171,170,149,146,239,152,153,179,240,179,153,181,178,181,153,150,241,156,157,190,242,190,157,192,189,192,157,154,243,160,161,201,244,201,161,203,200,203,161,158,245,164,165,247,246,247,165,214,215,214,165,162,248,168,169,250,249,250,169,226,227,226,169,166,251,172,173,164,246,164,173,174,163,174,173,170,239,175,176,182,252,182,176,177,178,177,176,174,239, +179,180,231,240,231,180,146,147,146,180,177,239,182,183,253,252,253,183,184,185,184,183,181,241,186,187,193,254,193,187,188,189,188,187,184,241,190,191,255,242,255,191,150,151,150,191,188,241,193,194,256,254,256,194,195,196,195,194,192,243,197,198,204,257,204,198,199,200,199,198,195,243,201,202,258,244,258,202,154,155,154,202,199,243,204,205,259,257,259,205,206,207,206,205,203,245,208,209,261,260,261,209,210,211,210,209,206,245,212,213,263,262,263,213,158,159,158,213,210,245,216,217,265,264,265,217,218,219,218,217,214,248,220,221,267,266,267,221,222,223,222,221,218,248,224,225,175,252,175,225,162,163,162,225,222,248,228,229,148,237,148,229,230,147,230,229,226,251,231,232,268,240,268,232,233,234,233,232,230,251,235,236,270,269,270,236,166,167,166,236,233,251 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *384 { + a: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Model: 1827098352032, "Model::Cube2", "Mesh" { + Version: 232 + Properties70: { + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",-0.0104023897647858,0.00998288810253143,-0.0104375958442688 + P: "Lcl Scaling", "Lcl Scaling", "", "A",0.1,-0.1,0.1 + P: "currentUVSet", "KString", "", "U", "map1" + } + Shading: T + Culling: "CullingOff" + } + Model: 1827098379872, "Model::Cube1", "Mesh" { + Version: 232 + Properties70: { + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",1.04023897647858,-0.998288810253143,1.04375958442688 + P: "currentUVSet", "KString", "", "U", "map1" + } + Shading: T + Culling: "CullingOff" + } + Model: 1827098382192, "Model::Cube3", "Mesh" { + Version: 232 + Properties70: { + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",-0.0106711769104004,0.00998288810253143,0.0939023494720459 + P: "Lcl Scaling", "Lcl Scaling", "", "A",0.1,0.1,0.1 + P: "currentUVSet", "KString", "", "U", "map1" + } + Shading: T + Culling: "CullingOff" + } + Model: 1827098384512, "Model::Cube1", "Mesh" { + Version: 232 + Properties70: { + P: "RotationPivot", "Vector3D", "Vector", "",0.0,0.0019,0.0 + P: "ScalingOffset", "Vector3D", "Vector", "",0.0,0.0019,0.0 + P: "ScalingPivot", "Vector3D", "Vector", "",0.0,0.0019,0.0 + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",0.0,0.0019,0.0 + P: "Lcl Scaling", "Lcl Scaling", "", "A",1.0,1.0019,1.0 + P: "currentUVSet", "KString", "", "U", "map1" + } + Shading: T + Culling: "CullingOff" + } + Material: 1827074508720, "Material::Mat_Green", "" { + Version: 102 + ShadingModel: "lambert" + MultiLayer: 0 + Properties70: { + P: "AmbientColor", "Color", "", "A",0,0,0 + P: "DiffuseColor", "Color", "", "A",0,1,0 + P: "DiffuseFactor", "Number", "", "A",0.800000011920929 + P: "TransparencyFactor", "Number", "", "A",1 + P: "Emissive", "Vector3D", "Vector", "",0,0,0 + P: "Ambient", "Vector3D", "Vector", "",0,0,0 + P: "Diffuse", "Vector3D", "Vector", "",0,0.800000011920929,0 + P: "Opacity", "double", "Number", "",1 + } + } + Material: 1827074501920, "Material::Mat_Red", "" { + Version: 102 + ShadingModel: "lambert" + MultiLayer: 0 + Properties70: { + P: "AmbientColor", "Color", "", "A",0,0,0 + P: "DiffuseColor", "Color", "", "A",1,0,0 + P: "DiffuseFactor", "Number", "", "A",0.800000011920929 + P: "TransparencyFactor", "Number", "", "A",1 + P: "Emissive", "Vector3D", "Vector", "",0,0,0 + P: "Ambient", "Vector3D", "Vector", "",0,0,0 + P: "Diffuse", "Vector3D", "Vector", "",0.800000011920929,0,0 + P: "Opacity", "double", "Number", "",1 + } + } + AnimationStack: 1825586153728, "AnimStack::Take 001", "" { + Properties70: { + P: "LocalStart", "KTime", "Time", "",1924423250 + P: "LocalStop", "KTime", "Time", "",230930790000 + P: "ReferenceStart", "KTime", "Time", "",1924423250 + P: "ReferenceStop", "KTime", "Time", "",230930790000 + } + } + AnimationLayer: 1827070038960, "AnimLayer::BaseLayer", "" { + } +} + +; Object connections +;------------------------------------------------------------------ + +Connections: { + + ;Model::Cube2, Model::RootNode + C: "OO",1827098352032,0 + + ;Model::Cube3, Model::RootNode + C: "OO",1827098382192,0 + + ;AnimLayer::BaseLayer, AnimStack::Take 001 + C: "OO",1827070038960,1825586153728 + + ;Geometry::, Model::Cube2 + C: "OO",1827080157856,1827098352032 + + ;Material::Mat_Green, Model::Cube2 + C: "OO",1827074508720,1827098352032 + + ;Model::Cube1, Model::Cube2 + C: "OO",1827098379872,1827098352032 + + ;Geometry::, Model::Cube1 + C: "OO",1827080155296,1827098379872 + + ;Material::Mat_Green, Model::Cube1 + C: "OO",1827074508720,1827098379872 + + ;Geometry::, Model::Cube3 + C: "OO",1827080156320,1827098382192 + + ;Material::Mat_Red, Model::Cube3 + C: "OO",1827074501920,1827098382192 + + ;Model::Cube1, Model::Cube3 + C: "OO",1827098384512,1827098382192 + + ;Geometry::, Model::Cube1 + C: "OO",1827080139424,1827098384512 + + ;Material::Mat_Red, Model::Cube1 + C: "OO",1827074501920,1827098384512 +} +;Takes section +;---------------------------------------------------- + +Takes: { + Current: "Take 001" + Take: "Take 001" { + FileName: "Take_001.tak" + LocalTime: 1924423250,230930790000 + ReferenceTime: 1924423250,230930790000 + } +} diff --git a/test/models/FBX/cubes_nonames.fbx b/test/models/FBX/cubes_nonames.fbx new file mode 100644 index 000000000..810657aff --- /dev/null +++ b/test/models/FBX/cubes_nonames.fbx @@ -0,0 +1,852 @@ +; FBX 7.5.0 project file +; ---------------------------------------------------- + +FBXHeaderExtension: { + FBXHeaderVersion: 1003 + FBXVersion: 7500 + CreationTimeStamp: { + Version: 1000 + Year: 2019 + Month: 1 + Day: 7 + Hour: 16 + Minute: 17 + Second: 31 + Millisecond: 730 + } + Creator: "FBX SDK/FBX Plugins version 2018.1.1" + SceneInfo: "SceneInfo::GlobalInfo", "UserData" { + Type: "UserData" + Version: 100 + MetaData: { + Version: 100 + Title: "" + Subject: "" + Author: "" + Keywords: "" + Revision: "" + Comment: "" + } + Properties70: { + P: "DocumentUrl", "KString", "Url", "", "U:\Some\Absolute\Path\cubes_noname.fbx" + P: "SrcDocumentUrl", "KString", "Url", "", "U:\Some\Absolute\Path\cubes_noname.fbx" + P: "Original", "Compound", "", "" + P: "Original|ApplicationVendor", "KString", "", "", "Autodesk" + P: "Original|ApplicationName", "KString", "", "", "Maya" + P: "Original|ApplicationVersion", "KString", "", "", "201800" + P: "Original|DateTime_GMT", "DateTime", "", "", "07/01/2019 16:17:31.730" + P: "Original|FileName", "KString", "", "", "U:\Some\Absolute\Path\cubes_noname.fbx" + P: "LastSaved", "Compound", "", "" + P: "LastSaved|ApplicationVendor", "KString", "", "", "Autodesk" + P: "LastSaved|ApplicationName", "KString", "", "", "Maya" + P: "LastSaved|ApplicationVersion", "KString", "", "", "201800" + P: "LastSaved|DateTime_GMT", "DateTime", "", "", "07/01/2019 16:17:31.730" + P: "Original|ApplicationActiveProject", "KString", "", "", "U:\Some\Absolute\Path" + } + } +} +GlobalSettings: { + Version: 1000 + Properties70: { + P: "UpAxis", "int", "Integer", "",1 + P: "UpAxisSign", "int", "Integer", "",1 + P: "FrontAxis", "int", "Integer", "",2 + P: "FrontAxisSign", "int", "Integer", "",1 + P: "CoordAxis", "int", "Integer", "",0 + P: "CoordAxisSign", "int", "Integer", "",1 + P: "OriginalUpAxis", "int", "Integer", "",1 + P: "OriginalUpAxisSign", "int", "Integer", "",1 + P: "UnitScaleFactor", "double", "Number", "",1 + P: "OriginalUnitScaleFactor", "double", "Number", "",1 + P: "AmbientColor", "ColorRGB", "Color", "",0,0,0 + P: "DefaultCamera", "KString", "", "", "Producer Perspective" + P: "TimeMode", "enum", "", "",11 + P: "TimeProtocol", "enum", "", "",2 + P: "SnapOnFrameMode", "enum", "", "",0 + P: "TimeSpanStart", "KTime", "Time", "",1924423250 + P: "TimeSpanStop", "KTime", "Time", "",384884650000 + P: "CustomFrameRate", "double", "Number", "",-1 + P: "TimeMarker", "Compound", "", "" + P: "CurrentTimeMarker", "int", "Integer", "",-1 + } +} + +; Documents Description +;------------------------------------------------------------------ + +Documents: { + Count: 1 + Document: 2359325563280, "", "Scene" { + Properties70: { + P: "SourceObject", "object", "", "" + P: "ActiveAnimStackName", "KString", "", "", "Take 001" + } + RootNode: 0 + } +} + +; Document References +;------------------------------------------------------------------ + +References: { +} + +; Object definitions +;------------------------------------------------------------------ + +Definitions: { + Version: 100 + Count: 13 + ObjectType: "GlobalSettings" { + Count: 1 + } + ObjectType: "AnimationStack" { + Count: 1 + PropertyTemplate: "FbxAnimStack" { + Properties70: { + P: "Description", "KString", "", "", "" + P: "LocalStart", "KTime", "Time", "",0 + P: "LocalStop", "KTime", "Time", "",0 + P: "ReferenceStart", "KTime", "Time", "",0 + P: "ReferenceStop", "KTime", "Time", "",0 + } + } + } + ObjectType: "AnimationLayer" { + Count: 1 + PropertyTemplate: "FbxAnimLayer" { + Properties70: { + P: "Weight", "Number", "", "A",100 + P: "Mute", "bool", "", "",0 + P: "Solo", "bool", "", "",0 + P: "Lock", "bool", "", "",0 + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "BlendMode", "enum", "", "",0 + P: "RotationAccumulationMode", "enum", "", "",0 + P: "ScaleAccumulationMode", "enum", "", "",0 + P: "BlendModeBypass", "ULongLong", "", "",0 + } + } + } + ObjectType: "Geometry" { + Count: 4 + PropertyTemplate: "FbxMesh" { + Properties70: { + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "BBoxMin", "Vector3D", "Vector", "",0,0,0 + P: "BBoxMax", "Vector3D", "Vector", "",0,0,0 + P: "Primary Visibility", "bool", "", "",1 + P: "Casts Shadows", "bool", "", "",1 + P: "Receive Shadows", "bool", "", "",1 + } + } + } + ObjectType: "Material" { + Count: 2 + PropertyTemplate: "FbxSurfaceLambert" { + Properties70: { + P: "ShadingModel", "KString", "", "", "Lambert" + P: "MultiLayer", "bool", "", "",0 + P: "EmissiveColor", "Color", "", "A",0,0,0 + P: "EmissiveFactor", "Number", "", "A",1 + P: "AmbientColor", "Color", "", "A",0.2,0.2,0.2 + P: "AmbientFactor", "Number", "", "A",1 + P: "DiffuseColor", "Color", "", "A",0.8,0.8,0.8 + P: "DiffuseFactor", "Number", "", "A",1 + P: "Bump", "Vector3D", "Vector", "",0,0,0 + P: "NormalMap", "Vector3D", "Vector", "",0,0,0 + P: "BumpFactor", "double", "Number", "",1 + P: "TransparentColor", "Color", "", "A",0,0,0 + P: "TransparencyFactor", "Number", "", "A",0 + P: "DisplacementColor", "ColorRGB", "Color", "",0,0,0 + P: "DisplacementFactor", "double", "Number", "",1 + P: "VectorDisplacementColor", "ColorRGB", "Color", "",0,0,0 + P: "VectorDisplacementFactor", "double", "Number", "",1 + } + } + } + ObjectType: "Model" { + Count: 4 + PropertyTemplate: "FbxNode" { + Properties70: { + P: "QuaternionInterpolate", "enum", "", "",0 + P: "RotationOffset", "Vector3D", "Vector", "",0,0,0 + P: "RotationPivot", "Vector3D", "Vector", "",0,0,0 + P: "ScalingOffset", "Vector3D", "Vector", "",0,0,0 + P: "ScalingPivot", "Vector3D", "Vector", "",0,0,0 + P: "TranslationActive", "bool", "", "",0 + P: "TranslationMin", "Vector3D", "Vector", "",0,0,0 + P: "TranslationMax", "Vector3D", "Vector", "",0,0,0 + P: "TranslationMinX", "bool", "", "",0 + P: "TranslationMinY", "bool", "", "",0 + P: "TranslationMinZ", "bool", "", "",0 + P: "TranslationMaxX", "bool", "", "",0 + P: "TranslationMaxY", "bool", "", "",0 + P: "TranslationMaxZ", "bool", "", "",0 + P: "RotationOrder", "enum", "", "",0 + P: "RotationSpaceForLimitOnly", "bool", "", "",0 + P: "RotationStiffnessX", "double", "Number", "",0 + P: "RotationStiffnessY", "double", "Number", "",0 + P: "RotationStiffnessZ", "double", "Number", "",0 + P: "AxisLen", "double", "Number", "",10 + P: "PreRotation", "Vector3D", "Vector", "",0,0,0 + P: "PostRotation", "Vector3D", "Vector", "",0,0,0 + P: "RotationActive", "bool", "", "",0 + P: "RotationMin", "Vector3D", "Vector", "",0,0,0 + P: "RotationMax", "Vector3D", "Vector", "",0,0,0 + P: "RotationMinX", "bool", "", "",0 + P: "RotationMinY", "bool", "", "",0 + P: "RotationMinZ", "bool", "", "",0 + P: "RotationMaxX", "bool", "", "",0 + P: "RotationMaxY", "bool", "", "",0 + P: "RotationMaxZ", "bool", "", "",0 + P: "InheritType", "enum", "", "",0 + P: "ScalingActive", "bool", "", "",0 + P: "ScalingMin", "Vector3D", "Vector", "",0,0,0 + P: "ScalingMax", "Vector3D", "Vector", "",1,1,1 + P: "ScalingMinX", "bool", "", "",0 + P: "ScalingMinY", "bool", "", "",0 + P: "ScalingMinZ", "bool", "", "",0 + P: "ScalingMaxX", "bool", "", "",0 + P: "ScalingMaxY", "bool", "", "",0 + P: "ScalingMaxZ", "bool", "", "",0 + P: "GeometricTranslation", "Vector3D", "Vector", "",0,0,0 + P: "GeometricRotation", "Vector3D", "Vector", "",0,0,0 + P: "GeometricScaling", "Vector3D", "Vector", "",1,1,1 + P: "MinDampRangeX", "double", "Number", "",0 + P: "MinDampRangeY", "double", "Number", "",0 + P: "MinDampRangeZ", "double", "Number", "",0 + P: "MaxDampRangeX", "double", "Number", "",0 + P: "MaxDampRangeY", "double", "Number", "",0 + P: "MaxDampRangeZ", "double", "Number", "",0 + P: "MinDampStrengthX", "double", "Number", "",0 + P: "MinDampStrengthY", "double", "Number", "",0 + P: "MinDampStrengthZ", "double", "Number", "",0 + P: "MaxDampStrengthX", "double", "Number", "",0 + P: "MaxDampStrengthY", "double", "Number", "",0 + P: "MaxDampStrengthZ", "double", "Number", "",0 + P: "PreferedAngleX", "double", "Number", "",0 + P: "PreferedAngleY", "double", "Number", "",0 + P: "PreferedAngleZ", "double", "Number", "",0 + P: "LookAtProperty", "object", "", "" + P: "UpVectorProperty", "object", "", "" + P: "Show", "bool", "", "",1 + P: "NegativePercentShapeSupport", "bool", "", "",1 + P: "DefaultAttributeIndex", "int", "Integer", "",-1 + P: "Freeze", "bool", "", "",0 + P: "LODBox", "bool", "", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",0,0,0 + P: "Lcl Rotation", "Lcl Rotation", "", "A",0,0,0 + P: "Lcl Scaling", "Lcl Scaling", "", "A",1,1,1 + P: "Visibility", "Visibility", "", "A",1 + P: "Visibility Inheritance", "Visibility Inheritance", "", "",1 + } + } + } +} + +; Object properties +;------------------------------------------------------------------ + +Objects: { + Geometry: 2358377979296, "Geometry::", "Mesh" { + Vertices: *24 { + a: -0.5,-0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,-0.5,-0.5,-0.5,-0.5,0.5,-0.5,-0.5 + } + PolygonVertexIndex: *24 { + a: 0,1,3,-3,2,3,5,-5,4,5,7,-7,6,7,1,-1,1,7,5,-4,6,0,2,-5 + } + Edges: *12 { + a: 0,1,2,3,5,6,7,9,10,11,13,15 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *72 { + a: 0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 + } + NormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *72 { + a: 0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,-0,1,0,-0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0 + } + BinormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *72 { + a: 1,-0,-0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0,-0,1,0,-0,1,0,-0,1,0,-0,1 + } + TangentsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *28 { + a: 0.375,0,0.625,0,0.375,0.25,0.625,0.25,0.375,0.5,0.625,0.5,0.375,0.75,0.625,0.75,0.375,1,0.625,1,0.875,0,0.875,0.25,0.125,0,0.125,0.25 + } + UVIndex: *24 { + a: 0,1,3,2,2,3,5,4,4,5,7,6,6,7,9,8,1,10,11,3,12,0,2,13 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *12 { + a: 0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Geometry: 2358377961872, "Geometry::", "Mesh" { + Vertices: *24 { + a: -0.5,-0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,-0.5,-0.5,-0.5,-0.5,0.5,-0.5,-0.5 + } + PolygonVertexIndex: *24 { + a: 0,1,3,-3,2,3,5,-5,4,5,7,-7,6,7,1,-1,1,7,5,-4,6,0,2,-5 + } + Edges: *12 { + a: 0,1,2,3,5,6,7,9,10,11,13,15 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *72 { + a: 0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 + } + NormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *72 { + a: 0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,-0,1,0,-0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0 + } + BinormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *72 { + a: 1,-0,-0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0,-0,1,0,-0,1,0,-0,1,0,-0,1 + } + TangentsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *28 { + a: 0.375,0,0.625,0,0.375,0.25,0.625,0.25,0.375,0.5,0.625,0.5,0.375,0.75,0.625,0.75,0.375,1,0.625,1,0.875,0,0.875,0.25,0.125,0,0.125,0.25 + } + UVIndex: *24 { + a: 0,1,3,2,2,3,5,4,4,5,7,6,6,7,9,8,1,10,11,3,12,0,2,13 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *12 { + a: 0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Geometry: 2358377982464, "Geometry::", "Mesh" { + Vertices: *24 { + a: -0.5,-0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,-0.5,-0.5,-0.5,-0.5,0.5,-0.5,-0.5 + } + PolygonVertexIndex: *24 { + a: 0,1,3,-3,2,3,5,-5,4,5,7,-7,6,7,1,-1,1,7,5,-4,6,0,2,-5 + } + Edges: *12 { + a: 0,1,2,3,5,6,7,9,10,11,13,15 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *72 { + a: 0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 + } + NormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *72 { + a: 0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,-0,1,0,-0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0 + } + BinormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *72 { + a: 1,-0,-0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0,-0,1,0,-0,1,0,-0,1,0,-0,1 + } + TangentsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *28 { + a: 0.375,0,0.625,0,0.375,0.25,0.625,0.25,0.375,0.5,0.625,0.5,0.375,0.75,0.625,0.75,0.375,1,0.625,1,0.875,0,0.875,0.25,0.125,0,0.125,0.25 + } + UVIndex: *24 { + a: 0,1,3,2,2,3,5,4,4,5,7,6,6,7,9,8,1,10,11,3,12,0,2,13 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *12 { + a: 0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Geometry: 2358377979824, "Geometry::", "Mesh" { + Vertices: *588 { + a: -0.499999970197678,-0.5,0.5,0.500000059604645,-0.5,0.5,-0.499999970197678,0.5,0.5,0.500000059604645,0.5,0.5,-0.499999970197678,0.5,-0.49999988079071,0.500000059604645,0.5,-0.49999988079071,-0.499999970197678,-0.5,-0.49999988079071,0.500000059604645,-0.5,-0.49999988079071,0,0,0.5,0,-0.5,0.5,0.500000059604645,0,0.5,0,0.5,0.5,-0.499999970197678,0,0.5,0,0.5,1.19209289550781e-07,0.500000059604645,0.5,1.19209289550781e-07,0,0.5,-0.49999988079071,-0.499999970197678,0.5,1.19209289550781e-07,0,0,-0.49999988079071,0.500000059604645,0,-0.49999988079071,0,-0.5,-0.49999988079071,-0.499999970197678,0,-0.49999988079071,0,-0.5,1.19209289550781e-07,0.500000059604645,-0.5,1.19209289550781e-07,-0.499999970197678,-0.5,1.19209289550781e-07,0.500000059604645,0,1.19209289550781e-07,-0.499999970197678,0,1.19209289550781e-07,-0.25,-0.25,0.5,-0.499999970197678,-0.25,0.5,-0.25,-0.5,0.5,0,-0.25,0.5,-0.25,0,0.5,-0.25,0.5,0.25,-0.499999970197678,0.5,0.25,-0.25,0.5,0.5,0,0.5,0.25,-0.25,0.5,1.19209289550781e-07,-0.25,0.25,-0.49999988079071,-0.499999970197678,0.25,-0.49999988079071,-0.25,0.5,-0.49999988079071,0,0.25,-0.49999988079071,-0.25,0,-0.49999988079071,-0.25,-0.5,-0.24999988079071,-0.499999970197678,-0.5,-0.24999988079071,-0.25,-0.5,-0.49999988079071,0,-0.5,-0.24999988079071,-0.25,-0.5,1.19209289550781e-07,0.500000059604645,-0.25,0.25,0.500000059604645,-0.25,0.5,0.500000059604645,-0.5,0.25,0.500000059604645,-0.25,1.19209289550781e-07,0.500000059604645,0,0.25,-0.499999970197678,-0.25,-0.24999988079071,-0.499999970197678,-0.25,-0.49999988079071,-0.499999970197678,-0.25,1.19209289550781e-07,-0.499999970197678,0,-0.24999988079071,0.250000059604645,-0.25,0.5,0.250000059604645,-0.5,0.5,0.250000059604645,0,0.5,0.250000059604645,0.25,0.5,0.500000059604645,0.25,0.5,0.250000059604645,0.5,0.5,0,0.25,0.5,-0.25,0.25,0.5,-0.499999970197678,0.25,0.5,0.250000059604645,0.5,0.25,0.500000059604645,0.5,0.25,0.250000059604645,0.5,1.19209289550781e-07,0.250000059604645,0.5,-0.24999988079071,0.500000059604645,0.5,-0.24999988079071,0.250000059604645,0.5,-0.49999988079071, +0,0.5,-0.24999988079071,-0.25,0.5,-0.24999988079071,-0.499999970197678,0.5,-0.24999988079071,0.250000059604645,0.25,-0.49999988079071,0.500000059604645,0.25,-0.49999988079071,0.250000059604645,0,-0.49999988079071,0.250000059604645,-0.25,-0.49999988079071,0.500000059604645,-0.25,-0.49999988079071,0.250000059604645,-0.5,-0.49999988079071,0,-0.25,-0.49999988079071,-0.25,-0.25,-0.49999988079071,0.250000059604645,-0.5,-0.24999988079071,0.500000059604645,-0.5,-0.24999988079071,0.250000059604645,-0.5,1.19209289550781e-07,0.250000059604645,-0.5,0.25,0,-0.5,0.25,-0.25,-0.5,0.25,-0.499999970197678,-0.5,0.25,0.500000059604645,-0.25,-0.24999988079071,0.500000059604645,0,-0.24999988079071,0.500000059604645,0.25,-0.24999988079071,0.500000059604645,0.25,1.19209289550781e-07,0.500000059604645,0.25,0.25,-0.499999970197678,-0.25,0.25,-0.499999970197678,0,0.25,-0.499999970197678,0.25,0.25,-0.499999970197678,0.25,1.19209289550781e-07,-0.499999970197678,0.25,-0.24999988079071,-0.594913899898529,0,0.594913899898529,-0.152911216020584,0,0.714658200740814,-0.594913899898529,-0.152911216020584,0.594913899898529,-0.152911216020584,-0.152911216020584,0.714658200740814,-0.594913899898529,0.594913899898529,7.29137497046395e-08,-0.152911216020584,0.714658200740814,7.29137497046395e-08,-0.594913899898529,0.594913899898529,0.152911216020584,-0.152911216020584,0.714658200740814,0.152911216020584,-0.594913899898529,0,-0.594913899898529,-0.152911216020584,0,-0.714658200740814,-0.594913899898529,0.152911216020584,-0.594913899898529,-0.152911216020584,0.152911216020584,-0.714658200740814,-0.594913899898529,-0.594913899898529,7.29137497046395e-08,-0.152911216020584,-0.714658200740814,7.29137497046395e-08,-0.594913899898529,-0.594913899898529,-0.152911216020584,-0.152911216020584,-0.714658200740814,-0.152911216020584,0.594913899898529,0,0.594913899898529,0.714658200740814,0,0.152911216020584,0.594913899898529,-0.152911216020584,0.594913899898529,0.714658200740814,-0.152911216020584,0.152911216020584,-0.714658200740814,0,-0.152911216020584,-0.594913899898529,-0.152911216020584,-0.594913899898529, +-0.714658200740814,-0.152911216020584,-0.152911216020584,8.62321627254444e-17,-0.594913899898529,0.594913899898529,8.62321627254444e-17,-0.152911216020584,0.714658200740814,0.152911230921745,-0.594913899898529,0.594913899898529,0.152911230921745,-0.152911216020584,0.714658200740814,0.152911230921745,0,0.714658200740814,0.594913899898529,0.152911216020584,0.594913899898529,0.152911230921745,0.152911216020584,0.714658200740814,8.62321627254444e-17,0.594913899898529,0.594913899898529,8.62321627254444e-17,0.152911216020584,0.714658200740814,-0.152911216020584,0.594913899898529,0.594913899898529,-0.152911216020584,0.152911216020584,0.714658200740814,8.62321627254444e-17,0.714658200740814,0.152911216020584,0.152911230921745,0.594913899898529,0.594913899898529,0.152911230921745,0.714658200740814,0.152911216020584,0.594913899898529,0.594913899898529,7.29137497046395e-08,0.152911230921745,0.714658200740814,7.29137497046395e-08,0.594913899898529,0.594913899898529,-0.152911216020584,0.152911230921745,0.714658200740814,-0.152911216020584,8.62321627254444e-17,0.594913899898529,-0.594913899898529,8.62321627254444e-17,0.714658200740814,-0.152911216020584,-0.152911216020584,0.594913899898529,-0.594913899898529,-0.152911216020584,0.714658200740814,-0.152911216020584,8.62321627254444e-17,0.152911216020584,-0.714658200740814,0.152911230921745,0.594913899898529,-0.594913899898529,0.152911230921745,0.152911216020584,-0.714658200740814,0.594913899898529,0,-0.594913899898529,0.152911230921745,0,-0.714658200740814,0.594913899898529,-0.152911216020584,-0.594913899898529,0.152911230921745,-0.152911216020584,-0.714658200740814,8.62321627254444e-17,-0.594913899898529,-0.594913899898529,8.62321627254444e-17,-0.152911216020584,-0.714658200740814,-0.152911216020584,-0.594913899898529,-0.594913899898529,-0.152911216020584,-0.152911216020584,-0.714658200740814,8.62321627254444e-17,-0.714658200740814,-0.152911216020584,0.152911230921745,-0.594913899898529,-0.594913899898529,0.152911230921745,-0.714658200740814,-0.152911216020584,0.594913899898529,-0.594913899898529,7.29137497046395e-08, +0.152911230921745,-0.714658200740814,7.29137497046395e-08,0.594913899898529,-0.594913899898529,0.152911216020584,0.152911230921745,-0.714658200740814,0.152911216020584,8.62321627254444e-17,-0.714658200740814,0.152911216020584,-0.152911216020584,-0.594913899898529,0.594913899898529,-0.152911216020584,-0.714658200740814,0.152911216020584,0.714658200740814,-0.152911216020584,7.29137497046395e-08,0.594913899898529,-0.594913899898529,-0.152911216020584,0.714658200740814,-0.152911216020584,-0.152911216020584,0.714658200740814,0,-0.152911216020584,0.594913899898529,0.152911216020584,-0.594913899898529,0.714658200740814,0.152911216020584,-0.152911216020584,0.714658200740814,0.152911216020584,7.29137497046395e-08,0.594913899898529,0.594913899898529,0.152911216020584,0.714658200740814,0.152911216020584,0.152911216020584,-0.714658200740814,-0.152911216020584,7.29137497046395e-08,-0.594913899898529,-0.594913899898529,0.152911216020584,-0.714658200740814,-0.152911216020584,0.152911216020584,-0.714658200740814,0,0.152911216020584,-0.594913899898529,0.152911216020584,0.594913899898529,-0.714658200740814,0.152911216020584,0.152911216020584,-0.714658200740814,0.152911216020584,7.29137497046395e-08,-0.594913899898529,0.594913899898529,-0.152911216020584,-0.714658200740814,0.152911216020584,-0.152911216020584,-0.541863918304443,-0.541864037513733,0.541863918304443,8.62321627254444e-17,0,0.714658200740814,-0.541863918304443,0.541863918304443,0.541863918304443,8.62321627254444e-17,0.714658200740814,7.29137497046395e-08,-0.541863918304443,0.541863918304443,-0.541863799095154,8.62321627254444e-17,0,-0.714658200740814,-0.541863918304443,-0.541864037513733,-0.541863799095154,8.62321627254444e-17,-0.714658200740814,7.29137497046395e-08,0.541863977909088,-0.541864037513733,0.541863918304443,0.714658200740814,0,7.29137497046395e-08,-0.714658200740814,0,7.29137497046395e-08,0.541863977909088,0.541863918304443,0.541863918304443,0.541863977909088,0.541863918304443,-0.541863799095154,0.541863977909088,-0.541864037513733,-0.541863799095154 + } + PolygonVertexIndex: *768 { + a: 99,98,100,-102,103,102,104,-106,107,106,108,-110,111,110,112,-114,115,114,116,-118,118,106,119,-121,122,121,123,-125,125,114,126,-128,129,128,130,-132,132,128,133,-135,136,135,137,-139,140,139,141,-143,143,139,144,-146,147,146,148,-150,151,150,152,-154,154,150,155,-157,158,157,159,-161,161,121,162,-164,164,157,165,-167,167,146,168,-170,170,135,171,-173,173,110,174,-176,176,98,177,-179,179,102,180,-182,100,182,162,-102,162,121,122,-102,122,183,99,-102,104,184,130,-106,130,128,132,-106,132,185,103,-106,108,186,141,-110,141,139,143,-110,143,187,107,-110,112,188,152,-114,152,150,154,-114,154,189,111,-114,116,190,159,-118,159,157,164,-118,164,191,115,-118,119,188,112,-121,112,110,173,-121,173,192,118,-121,123,190,116,-125,116,114,125,-125,125,183,122,-125,126,193,133,-128,133,128,129,-128,129,183,125,-128,130,184,177,-132,177,98,99,-132,99,183,129,-132,133,193,171,-135,171,135,136,-135,136,185,132,-135,137,194,144,-139,144,139,140,-139,140,185,136,-139,141,186,180,-143,180,102,103,-143,103,185,140,-143,144,194,168,-146,168,146,147,-146,147,187,143,-146,148,195,155,-150,155,150,151,-150,151,187,147,-150,152,188,119,-154,119,106,107,-154,107,187,151,-154,155,195,165,-157,165,157,158,-157,158,189,154,-157,159,190,123,-161,123,121,161,-161,161,189,158,-161,162,182,174,-164,174,110,111,-164,111,189,161,-164,165,195,148,-167,148,146,167,-167,167,191,164,-167,168,194,137,-170,137,135,170,-170,170,191,167,-170,171,193,126,-173,126,114,115,-173,115,191,170,-173,174,182,100,-176,100,98,176,-176,176,192,173,-176,177,184,104,-179,104,102,179,-179,179,192,176,-179,180,186,108,-182,108,106,118,-182,118,192,179,-182,30,26,27,-13,35,31,32,-17,40,36,37,-21,45,41,42,-24,50,46,47,-11,54,51,52,-21,29,55,56,-10,57,58,59,-11,61,62,33,-12,34,64,60,-12,66,67,68,-15,70,71,38,-16,39,73,69,-16,75,76,77,-19,79,80,43,-20,44,81,78,-20,83,84,48,-23,85,86,28,-10,49,88,82,-23,89,90,74,-19,91,92,65,-15,53,93,87,-24,94,95,63,-13,96,97,72,-17,27,26,28,-1,28,26,29,-10,29,26,30,-9,32,31,33,-3,33,31,34,-12,34,31,35,-14,37,36,38,-5,38,36,39, +-16,39,36,40,-18,42,41,43,-7,43,41,44,-20,44,41,45,-22,47,46,48,-2,48,46,49,-23,49,46,50,-25,52,51,42,-7,42,51,53,-24,53,51,54,-26,56,55,47,-2,47,55,57,-11,57,55,29,-9,59,58,60,-4,60,58,61,-12,61,58,57,-9,33,62,63,-3,63,62,30,-13,30,62,61,-9,60,64,65,-4,65,64,66,-15,66,64,34,-14,68,67,69,-6,69,67,70,-16,70,67,66,-14,38,71,72,-5,72,71,35,-17,35,71,70,-14,69,73,74,-6,74,73,75,-19,75,73,39,-18,77,76,78,-8,78,76,79,-20,79,76,75,-18,43,80,52,-7,52,80,40,-21,40,80,79,-18,78,81,82,-8,82,81,83,-23,83,81,44,-22,48,84,56,-2,56,84,85,-10,85,84,83,-22,28,86,87,-1,87,86,45,-24,45,86,85,-22,82,88,77,-8,77,88,89,-19,89,88,49,-25,74,90,68,-6,68,90,91,-15,91,90,89,-25,65,92,59,-4,59,92,50,-11,50,92,91,-25,87,93,27,-1,27,93,94,-13,94,93,53,-26,63,95,32,-3,32,95,96,-17,96,95,94,-26,72,97,37,-5,37,97,54,-21,54,97,96,-26 + } + Edges: *384 { + a: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,102,104,105,108,109,110,114,116,117,120,121,122,126,128,129,132,133,134,138,140,141,144,145,146,150,152,153,156,158,162,164,165,168,170,174,176,180,181,182,186,188,193,194,198,205,206,210,212,216,217,218,222,224,229,230,234,241,242,246,248,252,253,254,258,260,266,270,277,278,282,284,290,294,296,301,302,306,314,318,320,326,330,332,338,342,350,354,356,362,366,368,374,378,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,481,482,483,485,490,491,493,494,495,497,502,503,505,506,507,509,514,515,517,518,519,521,526,527,529,530,531,533,538,539,541,543,545,550,551,553,555,557,563,565,566,567,569,575,577,578,581,589,590,593,599,601,602,603,605,611,613,614,617,625,626,629,635,637,638,639,641,647,649,653,661,662,665,671,673,677,683,685,686,689,697,701,707,709,713,719,721,725,733,737,743,745,749,755,757,761 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *2304 { + a: -0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.26148721575737,0.965207040309906,0,-0.26148721575737,0.965207040309906,0,-0.26148721575737,0.965207040309906,0,-0.26148721575737,0.965207040309906,0,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,0,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.965207040309906,0.261487185955048,0,0.965207040309906,0.261487185955048,0,0.965207040309906,0.261487185955048,0,0.965207040309906,0.261487185955048,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0.261487126350403,0,-0.965206980705261, +0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.965207040309906,-0.261487185955048,0,-0.965207040309906,-0.261487185955048,0,-0.965207040309906,-0.261487185955048,0,-0.965207040309906,-0.261487185955048,0.26148721575737,-0.965207040309906,0,0.26148721575737,-0.965207040309906,0,0.26148721575737,-0.965207040309906,0,0.26148721575737,-0.965207040309906,0,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0.965206980705261,-0.261487066745758,0,0.965206980705261,-0.261487066745758,0,0.965206980705261,-0.261487066745758,0,0.965206980705261,-0.261487066745758,0,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0.261487066745758,0,-0.965206980705261,0.261487066745758,0,-0.965206980705261,0.261487066745758,0,-0.965206980705261,0.261487066745758,0,-0.211917281150818,-0.211917445063591,0.954034626483917,0,0,1,-0.211917281150818,-0.21191743016243,0.954034626483917,-0.211917266249657,-0.211917445063591,0.954034626483917,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,-0.211917445063591,0.954034626483917,0.211917281150818, +0,1,0,-0.211917445063591,0.954034626483917,0.211917281150818,-0.211917445063591,0.954034626483917,0.211917266249657,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,1,0,0,1,0,0,1,0,0,1,0,-0.211917623877525,0.211917608976364,-0.954034626483917,0,0,-1,-0.211917623877525,0.211917608976364,-0.954034626483917,-0.211917623877525,0.211917594075203,-0.954034626483917,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.211917355656624,-0.954034745693207,-0.211917355656624,0,-1,0,-0.211917325854301,-0.954034686088562,-0.211917325854301,-0.211917355656624,-0.954034686088562,-0.211917355656624,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0.954034745693207,-0.211917281150818,0.211917340755463,1,0,0,0.954034745693207,-0.211917281150818,0.211917370557785,0.954034626483917,-0.211917236447334,0.211917296051979,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,1,0,0,1,0,0,1,0,0,1,0,0,-0.954034686088562,-0.211917355656624,-0.211917459964752,-1,0,0,-0.954034626483917,-0.211917325854301,-0.211917445063591,-0.954034686088562,-0.211917355656624,-0.211917474865913,-0.965206980705261,-0.261487066745758,0,-0.965206980705261,-0.261487066745758,0,-0.965206980705261,-0.261487066745758,0,-0.965206980705261,-0.261487066745758,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0.211917281150818,-0.211917400360107,0.954034626483917,0,0,1,0.211917266249657,-0.211917415261269,0.954034626483917,0.211917266249657,-0.211917415261269,0.954034626483917,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261, +0,0,1,0,0,1,0,0,1,0,0,1,0.211917296051979,0.211917415261269,0.954034626483917,0,0,1,0.211917296051979,0.211917415261269,0.954034626483917,0.211917281150818,0.211917415261269,0.954034626483917,0,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0,1,0,0,1,0,0,1,0,0,1,-0.211917281150818,0.211917445063591,0.954034626483917,0,0,1,-0.211917281150818,0.211917445063591,0.954034626483917,-0.211917266249657,0.211917445063591,0.954034626483917,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,0.211917445063591,0.954034626483917,0.211917445063591,0,1,0,0.211917445063591,0.954034686088562,0.211917445063591,0.211917445063591,0.954034626483917,0.211917445063591,0.26148721575737,0.965207040309906,0,0.26148721575737,0.965207040309906,0,0.26148721575737,0.965207040309906,0,0.26148721575737,0.965207040309906,0,0,1,0,0,1,0,0,1,0,0,1,0,0.211917445063591,0.954034626483917,-0.211917489767075,0,1,0,0.211917459964752,0.954034686088562,-0.211917519569397,0.211917474865913,0.954034686088562,-0.211917504668236,0,0.965207040309906,-0.261487185955048,0,0.965207040309906,-0.261487185955048,0,0.965207040309906,-0.261487185955048,0,0.965207040309906,-0.261487185955048,0,1,0,0,1,0,0,1,0,0,1,0,-0.211917459964752,0.954034686088562,-0.211917340755463,0,1,0,-0.211917445063591,0.954034626483917,-0.21191731095314,-0.211917489767075,0.954034686088562,-0.211917355656624,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0,0,1,0,0,1,0,0,1,0,0,1,0,0.211917638778687,0.211917608976364,-0.954034626483917,0,0,-1,0.211917608976364,0.211917564272881,-0.954034566879272,0.211917623877525,0.211917608976364,-0.954034626483917,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261, +0.261487126350403,0,-0.965206980705261,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0.211917608976364,-0.211917564272881,-0.954034626483917,0,0,-1,0.211917623877525,-0.211917579174042,-0.954034626483917,0.211917623877525,-0.211917549371719,-0.954034626483917,0,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.211917623877525,-0.211917579174042,-0.954034626483917,0,0,-1,-0.211917579174042,-0.211917534470558,-0.954034566879272,-0.211917623877525,-0.211917549371719,-0.954034626483917,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0.211917340755463,-0.954034686088562,-0.211917519569397,0,-1,0,0.211917325854301,-0.954034626483917,-0.211917489767075,0.211917325854301,-0.954034686088562,-0.211917489767075,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0.211917281150818,-0.954034626483917,0.211917445063591,0,-1,0,0.211917296051979,-0.954034626483917,0.211917445063591,0.211917266249657,-0.954034626483917,0.211917445063591,0,-0.965207040309906,0.261487185955048,0,-0.965207040309906,0.261487185955048,0,-0.965207040309906,0.261487185955048,0,-0.965207040309906,0.261487185955048,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0.211917325854301,-0.954034745693207,0.211917325854301,0,-1,0,-0.211917325854301,-0.954034745693207,0.211917325854301,-0.211917281150818,-0.954034686088562,0.211917281150818,-0.26148721575737,-0.965207040309906,0,-0.26148721575737,-0.965207040309906,0,-0.26148721575737,-0.965207040309906,0,-0.26148721575737,-0.965207040309906,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0.954034626483917,-0.211917325854301,-0.211917400360107,1,0,0,0.954034686088562,-0.211917340755463,-0.211917400360107,0.954034686088562,-0.211917355656624,-0.21191743016243,0.965206980705261,0,-0.261487185955048, +0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,1,0,0,1,0,0,1,0,0,1,0,0,0.954034686088562,0.211917370557785,-0.211917489767075,1,0,0,0.954034686088562,0.211917355656624,-0.211917445063591,0.954034626483917,0.211917355656624,-0.211917445063591,0.965206980705261,0.261487066745758,0,0.965206980705261,0.261487066745758,0,0.965206980705261,0.261487066745758,0,0.965206980705261,0.261487066745758,0,1,0,0,1,0,0,1,0,0,1,0,0,0.954034626483917,0.211917296051979,0.211917385458946,1,0,0,0.954034626483917,0.211917296051979,0.211917385458946,0.954034745693207,0.211917296051979,0.211917385458946,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,1,0,0,1,0,0,1,0,0,1,0,0,-0.954034626483917,-0.211917251348495,0.211917400360107,-1,0,0,-0.954034626483917,-0.211917266249657,0.211917400360107,-0.954034626483917,-0.211917251348495,0.211917400360107,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-0.954034626483917,0.211917281150818,0.211917445063591,-1,0,0,-0.954034626483917,0.211917281150818,0.211917445063591,-0.954034626483917,0.211917266249657,0.211917445063591,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-0.954034686088562,0.211917385458946,-0.211917549371719,-1,0,0,-0.954034686088562,0.211917370557785,-0.211917534470558,-0.954034626483917,0.211917355656624,-0.211917504668236,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0, +1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0, +-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0 + } + NormalsW: *768 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *2304 { + a: 0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0.965206921100616,0.261487156152725,0,0.965206921100616,0.261487156152725,0,0.965206921100616,0.261487156152725,0,0.965206921100616,0.261487156152725,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,0.965206980705261,-0.261487185955048,0,0.965206980705261,-0.261487185955048,0,0.965206980705261,-0.261487185955048,0,0.965206980705261,-0.261487185955048,0,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0.261487126350403,-0.965206980705261,0,-0.261487126350403,-0.965206980705261,0,-0.261487126350403,-0.965206980705261,0,-0.261487126350403,-0.965206980705261,0,-0.965206921100616,-0.261487156152725,0,-0.965206921100616,-0.261487156152725,0,-0.965206921100616,-0.261487156152725,0,-0.965206921100616,-0.261487156152725,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-0.965206980705261,0.261487185955048,0,-0.965206980705261,0.261487185955048,0,-0.965206980705261,0.261487185955048,0,-0.965206980705261,0.261487185955048,0,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0,0,1,0,0,1,0,0,1,0,0,1,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,0,1,0,0,1,0,0,1,0, +0,1,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,-0.0554696954786777,0.977241098880768,0.204750895500183,0.0677256807684898,0.997704029083252,-0,0.0995207726955414,0.966452240943909,0.236782029271126,0.022095151245594,0.974918127059937,0.221464186906815,0,0.965206980705261,0.261487185955048,0,0.965206980705261,0.261487185955048,0,0.965206980705261,0.261487185955048,0,0.965206980705261,0.261487185955048,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0.0554696545004845,0.204750746488571,-0.977241158485413,0.0677258297801018,0,-0.997703969478607,0.0995210781693459,0.23678195476532,-0.966452240943909,0.0220953319221735,0.221464082598686,-0.974918246269226,0,0.261487126350403,-0.965206980705261,0,0.261487126350403,-0.965206980705261,0,0.261487126350403,-0.965206980705261,0,0.261487126350403,-0.965206980705261,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.0554697290062904,-0.977241039276123,-0.204751029610634,0.0677258297801018,-0.997703969478607,0,0.0995209515094757,-0.966452121734619,-0.236782252788544,0.0220952276140451,-0.974918127059937,-0.221464350819588,0,-0.965206980705261,-0.261487185955048,0,-0.965206980705261,-0.261487185955048,0,-0.965206980705261,-0.261487185955048,0,-0.965206980705261,-0.261487185955048,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,-0,-0.0554696619510651,-0.204750776290894,0.977241098880768,0.0677259787917137,0,0.997703969478607,0.0995214134454727,-0.236782014369965,0.966452121734619,0.0220954976975918,-0.221464157104492,0.974918186664581,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,0.20475073158741,0.977241218090057,0.0554696507751942,0,0.997704029083252,-0.0677256807684898,0.236781880259514,0.966452300548553,-0.0995208472013474,0.221463993191719,0.974918186664581,-0.0220952145755291,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0, +-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0.204750791192055,0.977241098880768,-0.0554696619510651,0,0.997704029083252,0.0677257031202316,-0.236781939864159,0.966452240943909,0.099520817399025,-0.221464112401009,0.974918246269226,0.022095188498497,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,0,-0.099520780146122,0.966452240943909,0.236781999468803,-0.0677256733179092,0.997704029083252,0,0.0554696880280972,0.977241098880768,0.204750865697861,-0.022095151245594,0.974918127059937,0.221464157104492,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0.0554696880280972,0.977241098880768,-0.204750865697861,0.0677258223295212,0.997703969478607,-0,0.0995210558176041,0.966452181339264,-0.236782059073448,0.0220952890813351,0.974918246269226,-0.221464201807976,0,0.965206921100616,-0.261487156152725,0,0.965206921100616,-0.261487156152725,0,0.965206921100616,-0.261487156152725,0,0.965206921100616,-0.261487156152725,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0.0995210707187653,0.966452240943909,-0.236782118678093,-0.0677258297801018,0.997703969478607,0,0.0554696954786777,0.977241098880768,-0.204750895500183,-0.0220952928066254,0.974918186664581,-0.221464231610298,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0.0995210558176041,0.236782118678093,-0.966452240943909,-0.0677258223295212,0,-0.997703969478607,0.0554696880280972,0.204750880599022,-0.977241098880768,-0.0220952853560448,0.221464216709137,-0.974918127059937,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.0554697066545486,-0.204750955104828,-0.977241158485413,0.0677259713411331,0,-0.997703969478607,0.0995213389396667,-0.236782237887383,-0.966452181339264,0.0220954176038504,-0.221464291214943,-0.974918127059937,0,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.0995213687419891,-0.236782059073448,-0.966452181339264, +-0.0677259787917137,0,-0.997703969478607,0.0554696545004845,-0.204750776290894,-0.977241158485413,-0.0220954604446888,-0.221464172005653,-0.974918246269226,0,0,-1,0,0,-1,-0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.0995209366083145,-0.966452121734619,-0.236782252788544,-0.0677258223295212,-0.997703969478607,-0,0.0554697290062904,-0.977241098880768,-0.204751014709473,-0.0220952201634645,-0.974918127059937,-0.221464365720749,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,-0,-0.0554697252810001,-0.977241158485413,0.204751014709473,0.0677256733179092,-0.997704029083252,0,0.099520668387413,-0.966452181339264,0.236782178282738,0.0220950860530138,-0.974918127059937,0.221464276313782,0,-0.965206921100616,0.261487156152725,0,-0.965206921100616,0.261487156152725,0,-0.965206921100616,0.261487156152725,0,-0.965206921100616,0.261487156152725,0,-1,0,0,-1,0,0,-1,-0,0,-1,0,-0.0995206832885742,-0.966452181339264,0.236782178282738,-0.0677256807684898,-0.997704029083252,-0,0.0554697178304195,-0.977241098880768,0.20475098490715,-0.0220950935035944,-0.974918127059937,0.221464276313782,0,-1,-0,0,-1,-0,-0,-1,0,0,-1,-0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0.0995213836431503,-0.23678220808506,0.966452121734619,-0.0677259713411331,0,0.997703969478607,0.0554697066545486,-0.204750940203667,0.977241098880768,-0.0220954623073339,-0.221464291214943,0.974918186664581,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0.0554696954786777,0.204750895500183,0.977241098880768,0.0677258223295212,0,0.997703969478607,0.0995211154222488,0.236782103776932,0.966452181339264,0.0220953226089478,0.221464246511459,0.974918186664581,0,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0,1,0,0,1,0,0,1,0,0,1,-0.0995211452245712,0.23678195476532,0.966452181339264,-0.0677258297801018,0,0.997703969478607,0.0554696656763554,0.204750776290894,0.977241218090057,-0.022095363587141,0.221464082598686,0.974918246269226,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0.236781939864159,0.966452240943909,0.0995208621025085, +-0,0.997704029083252,0.0677257031202316,0.204750806093216,0.977241158485413,-0.0554696656763554,0.221464112401009,0.974918186664581,0.0220951996743679,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0.204750806093216,0.977241098880768,0.0554696694016457,0,0.997703969478607,-0.0677258521318436,-0.236782044172287,0.966452240943909,-0.0995211452245712,-0.221464172005653,0.974918246269226,-0.0220953542739153,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,0,1,-0,-0,1,0,-0,1,0,-0,1,0,-0.236781984567642,0.966452300548553,0.09952113032341,-0,0.997703969478607,0.0677258297801018,-0.204750761389732,0.977241158485413,-0.0554696582257748,-0.221464067697525,0.974918246269226,0.0220953486859798,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,-0,-0,1,0,-0.236781880259514,0.966452360153198,-0.0995208248496056,0,0.997704029083252,-0.0677256807684898,-0.20475073158741,0.977241158485413,0.0554696470499039,-0.221464022994041,0.974918246269226,-0.0220951903611422,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0.204750746488571,0.977241158485413,-0.0554696545004845,0,0.997703969478607,0.0677258297801018,0.23678195476532,0.966452240943909,0.0995210781693459,0.221464082598686,0.974918246269226,0.0220953319221735,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,0,0.236782073974609,0.966452240943909,-0.0995211005210876,0,0.997703969478607,-0.0677258521318436,0.204750806093216,0.977241098880768,0.0554696656763554,0.221464142203331,0.974918186664581,-0.0220953188836575,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,-0,-1,0,-0,-1, +0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1, +-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0 + } + BinormalsW: *768 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *2304 { + a: 0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965207040309906,0.26148721575737,0,0.965207040309906,0.26148721575737,0,0.965207040309906,0.26148721575737,0,0.965207040309906,0.26148721575737,0,0.965206980705261,-0,-0.261487126350403,0.965206980705261,-0,-0.261487126350403,0.965206980705261,-0,-0.261487126350403,0.965206980705261,-0,-0.261487126350403,0.965206980705261,-0.261487156152725,-0,0.965206980705261,-0.261487156152725,-0,0.965206980705261,-0.261487156152725,-0,0.965206980705261,-0.261487156152725,-0,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,0.965206980705261,-0.261487156152725,0,0.965206980705261,-0.261487156152725,0,0.965206980705261,-0.261487156152725,0,0.965206980705261,-0.261487156152725,0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,-0,0,1,0,0,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,-0,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0.26148721575737,-0,0.965207040309906, +0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0.97571212053299,0.00952975451946259,0.218849271535873,0.997704029083252,-0.0677256807684898,0,0.972207129001617,-0.145124465227127,0.183717742562294,0.977037787437439,-0.0680116266012192,0.201919630169868,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0.97571212053299,0.218849420547485,-0.0095297135412693,0.997703969478607,0,0.0677258297801018,0.972207069396973,0.183717846870422,0.145124778151512,0.977037727832794,0.20191977918148,0.0680118054151535,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0.975712060928345,-0.00952969118952751,-0.218849584460258,0.997703969478607,0.0677258297801018,0,0.972207009792328,0.145124763250351,-0.183717995882034,0.977037727832794,0.0680118054151535,-0.201919928193092,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0.97571212053299,-0.218849301338196,0.00952974148094654,0.997703969478607,0,-0.0677259787917137,0.972207069396973,-0.183717638254166,-0.145125105977058,0.977037727832794,-0.201919630169868,-0.068011961877346,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0.218849286437035,0.00952974148094654,-0.97571212053299,0,-0.0677256807684898,-0.997704029083252,0.183717831969261,-0.145124509930611,-0.972207069396973,0.201919674873352,-0.0680116564035416,-0.977037787437439,-0,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.218849420547485,0.0095297172665596,0.97571212053299,0,-0.0677257031202316,0.997704029083252,-0.183717906475067,-0.145124524831772,0.972207069396973,-0.201919823884964,-0.068011686205864,0.977037727832794,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0.972207129001617,0.145124465227127,-0.183717742562294,0.997704029083252,0.0677256733179092,0,0.97571212053299,-0.00952975824475288,-0.218849256634712,0.977037787437439,0.0680116191506386,-0.201919630169868,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403, +1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0.97571212053299,0.00952975172549486,-0.218849286437035,0.997703969478607,-0.0677258223295212,0,0.972207069396973,-0.14512474834919,-0.183717682957649,0.977037847042084,-0.0680117681622505,-0.20191964507103,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,0.972207069396973,0.14512474834919,0.183717668056488,0.997703969478607,0.0677258297801018,0,0.97571212053299,-0.00952975451946259,0.218849271535873,0.977037847042084,0.0680117756128311,0.201919630169868,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,1,-0,-0,1,-0,0,1,-0,0,1,-0,0,0.972207069396973,-0.183717831969261,-0.145124778151512,0.997703969478607,0,-0.0677258223295212,0.97571212053299,-0.218849405646324,0.00952972564846277,0.977037727832794,-0.20191977918148,-0.0680117979645729,0.965207040309906,-0.26148721575737,-0,0.965207040309906,-0.26148721575737,-0,0.965207040309906,-0.26148721575737,-0,0.965207040309906,-0.26148721575737,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0.97571212053299,-0.218849420547485,-0.0095297247171402,0.997703969478607,0,0.0677259713411331,0.972207009792328,-0.183717757463455,0.145125061273575,0.977037727832794,-0.201919749379158,0.0680119395256042,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,-0,-0,1,0,0,0.972207009792328,0.183717772364616,-0.145125061273575,0.997703969478607,0,-0.0677259787917137,0.97571212053299,0.218849420547485,0.00952971447259188,0.977037727832794,0.20191977918148,-0.0680119544267654,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,-0,0.965206980705261,0.261487156152725,0,1,-0,0,1,0,0,1,0,0,1,0,0,0.972207009792328,-0.14512474834919,0.183718010783195,0.997703969478607,-0.0677258223295212,0,0.975712060928345,0.00952969118952751,0.218849584460258,0.977037727832794,-0.0680117979645729,0.201919928193092,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403, +1,-0,0,1,-0,0,1,-0,0,1,-0,0,0.975712060928345,-0.00952969398349524,0.218849569559097,0.997704029083252,0.0677256733179092,0,0.972207069396973,0.145124465227127,0.18371807038784,0.977037727832794,0.0680116564035416,0.201919972896576,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,0.972207069396973,-0.145124480128288,-0.183718055486679,0.997704029083252,-0.0677256807684898,0,0.975712060928345,0.00952969398349524,-0.218849569559097,0.977037727832794,-0.0680116638541222,-0.201919972896576,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,-0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,1,0,0,1,0,0,1,0,0,1,0,0,0.972207069396973,0.183717623353004,0.145125105977058,0.997703969478607,0,0.0677259713411331,0.97571212053299,0.218849316239357,-0.00952974893152714,0.977037847042084,0.201919630169868,0.0680119544267654,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0.97571212053299,0.218849271535873,0.00952975638210773,0.997703969478607,0,-0.0677258223295212,0.972207069396973,0.183717668056488,-0.145124807953835,0.977037847042084,0.201919630169868,-0.0680118054151535,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0.972207069396973,-0.18371769785881,0.145124822854996,0.997703969478607,0,0.0677258297801018,0.97571212053299,-0.218849286437035,-0.00952974613755941,0.977037847042084,-0.201919630169868,0.0680118054151535,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,-0.183717846870422,0.145124554634094,-0.972207069396973,0,0.0677257031202316,-0.997704029083252,-0.218849360942841,-0.0095297284424305,-0.97571212053299,-0.20191977918148,0.068011686205864,-0.977037727832794,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906, +0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.218849450349808,0.00952971167862415,-0.97571212053299,0,-0.0677258521318436,-0.997703969478607,-0.1837178170681,-0.145124852657318,-0.972207069396973,-0.201919764280319,-0.0680118426680565,-0.977037727832794,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0,0,-1,0,0,-1,0.183717772364616,0.145124807953835,-0.972207069396973,0,0.0677258297801018,-0.997703969478607,0.218849375844002,-0.00952972657978535,-0.97571212053299,0.201919689774513,0.0680118054151535,-0.977037727832794,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0.183717876672745,0.145124495029449,0.972207069396973,0,0.0677256807684898,0.997704029083252,0.218849375844002,-0.00952972192317247,0.97571212053299,0.20191977918148,0.0680116564035416,0.977037727832794,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0.218849420547485,0.0095297135412693,0.97571212053299,0,-0.0677258297801018,0.997703969478607,0.183717846870422,-0.145124778151512,0.972207069396973,0.20191977918148,-0.0680118054151535,0.977037727832794,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,-0.183717921376228,0.145124837756157,0.972207009792328,0,0.0677258521318436,0.997703969478607,-0.21884948015213,-0.00952970236539841,0.97571212053299,-0.201919838786125,0.0680118277668953,0.977037727832794,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,0,-0,1,0,-0,1,0,-0,1,0,-0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,0,1,0,0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0,0,1,0,0,1,0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0, +1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1, +0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1 + } + TangentsW: *768 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *542 { + a: 0.375,0,0.625,0,0.375,0.25,0.625,0.25,0.375,0.5,0.625,0.5,0.375,0.75,0.625,0.75,0.375,1,0.625,1,0.875,0,0.875,0.25,0.125,0,0.125,0.25,0.5,0.125,0.5,0,0.5,1,0.625,0.125,0.5,0.25,0.375,0.125,0.5,0.375,0.625,0.375,0.75,0.25,0.5,0.5,0.375,0.375,0.25,0.25,0.5,0.625,0.625,0.625,0.875,0.125,0.5,0.75,0.375,0.625,0.125,0.125,0.5,0.875,0.625,0.875,0.75,0,0.5,1,0.375,0.875,0.25,0,0.75,0.125,0.75,0,0.875,0.125,0.75,0.25,0.25,0.125,0.25,0,0.25,0.25,0.125,0.125,0.4375,0.0625,0.375,0.0625,0.4375,0,0.4375,1,0.5,0.0625,0.4375,0.125,0.4375,0.3125,0.375,0.3125,0.3125,0.25,0.4375,0.25,0.5,0.3125,0.4375,0.375,0.4375,0.5625,0.375,0.5625,0.125,0.1875,0.4375,0.5,0.5,0.5625,0.4375,0.625,0.4375,0.8125,0.375,0.8125,0.1875,0,0.4375,0.75,0.5,0.8125,0.4375,0.875,0.6875,0.0625,0.625,0.0625,0.625,0.9375,0.6875,0,0.75,0.0625,0.6875,0.125,0.1875,0.0625,0.375,0.6875,0.125,0.0625,0.1875,0,0.25,0.0625,0.1875,0.125,0.5625,0.0625,0.5625,0,0.5625,1,0.5625,0.125,0.5625,0.1875,0.625,0.1875,0.5625,0.25,0.5,0.1875,0.4375,0.1875,0.375,0.1875,0.5625,0.3125,0.625,0.3125,0.6875,0.25,0.5625,0.375,0.5625,0.4375,0.625,0.4375,0.8125,0.25,0.5625,0.5,0.5,0.4375,0.4375,0.4375,0.375,0.4375,0.1875,0.25,0.5625,0.5625,0.625,0.5625,0.875,0.1875,0.5625,0.625,0.5625,0.6875,0.625,0.6875,0.875,0.0625,0.5625,0.75,0.5,0.6875,0.4375,0.6875,0.375,0.6875,0.5625,0.8125,0.625,0.8125,0.8125,0,0.5625,0.875,0.5625,0.9375,0.625,0.9375,0.5625,1,0.5,0.9375,0.4375,0.9375,0.4375,1,0.375,0.9375,0.3125,0,0.8125,0.0625,0.8125,0,0.875,0.0625,0.8125,0.125,0.8125,0.1875,0.875,0.1875,0.8125,0.25,0.75,0.1875,0.6875,0.1875,0.6875,0.25,0.3125,0.0625,0.3125,0,0.3125,0.125,0.3125,0.1875,0.3125,0.25,0.25,0.1875,0.1875,0.1875,0.1875,0.25,0.125,0.1875,0.4375,0.125,0.375,0.125,0.375,0.0625,0.4375,0.0625,0.4375,0.375,0.375,0.375,0.375,0.3125,0.4375,0.3125,0.4375,0.625,0.375,0.625,0.375,0.5625,0.4375,0.5625,0.4375,0.875,0.375,0.875,0.375,0.8125,0.4375,0.8125,0.6875,0.125,0.625,0.125,0.625,0.0625,0.6875,0.0625,0.1875,0.125,0.125,0.125,0.125,0.0625,0.1875,0.0625,0.5,0.0625,0.5,0,0.5625,0, +0.5625,0.0625,0.5625,0.125,0.625,0.1875,0.5625,0.1875,0.5,0.1875,0.5,0.25,0.4375,0.25,0.4375,0.1875,0.5,0.3125,0.5625,0.25,0.5625,0.3125,0.5625,0.375,0.625,0.375,0.625,0.4375,0.5625,0.4375,0.5,0.4375,0.5,0.5,0.4375,0.5,0.4375,0.4375,0.5,0.5625,0.5625,0.5,0.5625,0.5625,0.5625,0.625,0.625,0.625,0.625,0.6875,0.5625,0.6875,0.5,0.6875,0.5,0.75,0.4375,0.75,0.4375,0.6875,0.5,0.8125,0.5625,0.75,0.5625,0.8125,0.5625,0.875,0.625,0.875,0.625,0.9375,0.5625,0.9375,0.5,0.9375,0.5,1,0.4375,1,0.4375,0.9375,0.75,0.0625,0.75,0,0.8125,0,0.8125,0.0625,0.8125,0.125,0.875,0.125,0.875,0.1875,0.8125,0.1875,0.75,0.1875,0.75,0.25,0.6875,0.25,0.6875,0.1875,0.25,0.0625,0.25,0,0.3125,0,0.3125,0.0625,0.3125,0.125,0.375,0.1875,0.3125,0.1875,0.25,0.1875,0.25,0.25,0.1875,0.25,0.1875,0.1875,0.375,0,0.4375,0,0.5,0.125,0.375,0.25,0.5,0.375,0.375,0.5,0.5,0.625,0.375,0.75,0.5,0.875,0.625,0,0.6875,0,0.75,0.125,0.125,0,0.1875,0,0.25,0.125,0.625,0.25,0.625,0.3125,0.625,0.5,0.375,0.4375,0.625,0.5625,0.625,0.75,0.375,0.6875,0.625,0.8125,0.625,1,0.5625,1,0.375,1,0.375,0.9375,0.875,0,0.875,0.0625,0.875,0.25,0.8125,0.25,0.3125,0.25,0.125,0.25,0.125,0.1875 + } + UVIndex: *768 { + a: 51,19,47,46,57,24,53,52,63,30,59,58,69,36,65,64,75,17,71,70,81,45,78,76,50,15,83,82,85,17,87,86,89,18,55,90,56,18,88,92,95,21,97,96,100,23,61,101,62,23,99,104,107,27,109,108,112,29,67,113,68,29,111,115,118,33,120,119,122,35,124,123,74,39,128,127,130,40,132,131,134,41,136,135,80,43,138,137,139,19,91,140,142,44,144,143,47,0,48,46,48,15,50,46,50,14,51,46,53,2,55,52,55,18,56,52,56,20,57,52,59,4,61,58,61,23,62,58,62,26,63,58,65,6,67,64,67,29,68,64,68,32,69,64,71,1,73,70,73,39,74,70,74,38,75,70,78,12,79,76,79,43,80,76,80,42,81,76,83,1,71,82,71,17,85,82,85,14,50,82,87,3,88,86,88,18,89,86,89,14,85,86,55,2,91,90,91,19,51,90,51,14,89,90,88,3,93,92,93,21,95,92,95,20,56,92,97,5,99,96,99,23,100,96,100,20,95,96,61,4,102,101,102,24,57,101,57,20,100,101,99,5,105,104,105,27,107,104,107,26,62,104,109,7,111,108,111,29,112,108,112,26,107,108,67,6,114,113,114,30,63,113,63,26,112,113,111,7,116,115,116,33,118,115,118,32,68,115,120,9,121,119,121,35,122,119,122,32,118,119,124,8,125,123,125,36,69,123,69,32,122,123,128,10,129,127,129,40,130,127,130,38,74,127,132,11,133,131,133,41,134,131,134,38,130,131,136,3,87,135,87,17,75,135,75,38,134,135,138,0,47,137,47,19,139,137,139,42,80,137,91,2,141,140,141,44,142,140,142,42,139,140,144,13,145,143,145,45,81,143,81,42,142,143,146,149,148,147,150,153,152,151,154,157,156,155,158,161,160,159,162,165,164,163,166,169,168,167,170,173,172,171,174,176,175,163,177,180,179,178,181,183,182,178,184,187,186,185,188,191,190,189,192,194,193,189,195,198,197,196,199,202,201,200,203,205,204,200,206,209,208,207,210,213,212,211,214,217,216,215,218,221,220,219,222,225,224,223,226,229,228,227,230,232,231,147,233,236,235,234,148,149,238,237,238,149,170,171,170,149,146,239,152,153,179,240,179,153,181,178,181,153,150,241,156,157,190,242,190,157,192,189,192,157,154,243,160,161,201,244,201,161,203,200,203,161,158,245,164,165,247,246,247,165,214,215,214,165,162,248,168,169,250,249,250,169,226,227,226,169,166,251,172,173,164,246,164,173,174,163,174,173,170,239,175,176,182,252,182,176,177,178,177,176,174,239, +179,180,231,240,231,180,146,147,146,180,177,239,182,183,253,252,253,183,184,185,184,183,181,241,186,187,193,254,193,187,188,189,188,187,184,241,190,191,255,242,255,191,150,151,150,191,188,241,193,194,256,254,256,194,195,196,195,194,192,243,197,198,204,257,204,198,199,200,199,198,195,243,201,202,258,244,258,202,154,155,154,202,199,243,204,205,259,257,259,205,206,207,206,205,203,245,208,209,261,260,261,209,210,211,210,209,206,245,212,213,263,262,263,213,158,159,158,213,210,245,216,217,265,264,265,217,218,219,218,217,214,248,220,221,267,266,267,221,222,223,222,221,218,248,224,225,175,252,175,225,162,163,162,225,222,248,228,229,148,237,148,229,230,147,230,229,226,251,231,232,268,240,268,232,233,234,233,232,230,251,235,236,270,269,270,236,166,167,166,236,233,251 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *384 { + a: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Model: 2359439406816, "Model::", "Mesh" { + Version: 232 + Properties70: { + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",-1.04023893373156,0.998288783259251,-1.04375962988677 + P: "Lcl Scaling", "Lcl Scaling", "", "A",10,10,10 + P: "currentUVSet", "KString", "", "U", "map1" + } + Shading: T + Culling: "CullingOff" + } + Model: 2359439411456, "Model::", "Mesh" { + Version: 232 + Properties70: { + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",1.04023893373156,-0.998288783259251,1.04375962988677 + P: "currentUVSet", "KString", "", "U", "map1" + } + Shading: T + Culling: "CullingOff" + } + Model: 2359439409136, "Model::", "Mesh" { + Version: 232 + Properties70: { + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",-1.0671176743957,0.998288783259251,9.39023469168045 + P: "Lcl Scaling", "Lcl Scaling", "", "A",10,10,10 + P: "currentUVSet", "KString", "", "U", "map1" + } + Shading: T + Culling: "CullingOff" + } + Model: 2359439416096, "Model::", "Mesh" { + Version: 232 + Properties70: { + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",1.04023893373156,-0.998288783259251,1.1806740271636 + P: "Lcl Scaling", "Lcl Scaling", "", "A",0.77384837213491,0.77384837213491,0.77384837213491 + P: "currentUVSet", "KString", "", "U", "map1" + } + Shading: T + Culling: "CullingOff" + } + Material: 2359823919504, "Material::Mat_Green", "" { + Version: 102 + ShadingModel: "lambert" + MultiLayer: 0 + Properties70: { + P: "AmbientColor", "Color", "", "A",0,0,0 + P: "DiffuseColor", "Color", "", "A",0,1,0 + P: "DiffuseFactor", "Number", "", "A",0.800000011920929 + P: "TransparencyFactor", "Number", "", "A",1 + P: "Emissive", "Vector3D", "Vector", "",0,0,0 + P: "Ambient", "Vector3D", "Vector", "",0,0,0 + P: "Diffuse", "Vector3D", "Vector", "",0,0.800000011920929,0 + P: "Opacity", "double", "Number", "",1 + } + } + Material: 2359823921584, "Material::Mat_Red", "" { + Version: 102 + ShadingModel: "lambert" + MultiLayer: 0 + Properties70: { + P: "AmbientColor", "Color", "", "A",0,0,0 + P: "DiffuseColor", "Color", "", "A",1,0,0 + P: "DiffuseFactor", "Number", "", "A",0.800000011920929 + P: "TransparencyFactor", "Number", "", "A",1 + P: "Emissive", "Vector3D", "Vector", "",0,0,0 + P: "Ambient", "Vector3D", "Vector", "",0,0,0 + P: "Diffuse", "Vector3D", "Vector", "",0.800000011920929,0,0 + P: "Opacity", "double", "Number", "",1 + } + } + AnimationStack: 2359349464816, "AnimStack::Take 001", "" { + Properties70: { + P: "LocalStart", "KTime", "Time", "",1924423250 + P: "LocalStop", "KTime", "Time", "",230930790000 + P: "ReferenceStart", "KTime", "Time", "",1924423250 + P: "ReferenceStop", "KTime", "Time", "",230930790000 + } + } + AnimationLayer: 2359327403664, "AnimLayer::BaseLayer", "" { + } +} + +; Object connections +;------------------------------------------------------------------ + +Connections: { + + ;Model::, Model::RootNode + C: "OO",2359439406816,0 + + ;Model::, Model::RootNode + C: "OO",2359439409136,0 + + ;AnimLayer::BaseLayer, AnimStack::Take 001 + C: "OO",2359327403664,2359349464816 + + ;Geometry::, Model:: + C: "OO",2358377979296,2359439406816 + + ;Material::Mat_Green, Model:: + C: "OO",2359823919504,2359439406816 + + ;Model::, Model:: + C: "OO",2359439411456,2359439406816 + + ;Geometry::, Model:: + C: "OO",2358377961872,2359439411456 + + ;Material::Mat_Green, Model:: + C: "OO",2359823919504,2359439411456 + + ;Geometry::, Model:: + C: "OO",2358377982464,2359439409136 + + ;Material::Mat_Red, Model:: + C: "OO",2359823921584,2359439409136 + + ;Model::, Model:: + C: "OO",2359439416096,2359439409136 + + ;Geometry::, Model:: + C: "OO",2358377979824,2359439416096 + + ;Material::Mat_Red, Model:: + C: "OO",2359823921584,2359439416096 +} +;Takes section +;---------------------------------------------------- + +Takes: { + Current: "Take 001" + Take: "Take 001" { + FileName: "Take_001.tak" + LocalTime: 1924423250,230930790000 + ReferenceTime: 1924423250,230930790000 + } +} diff --git a/test/models/FBX/cubes_with_mirroring_and_pivot.fbx b/test/models/FBX/cubes_with_mirroring_and_pivot.fbx new file mode 100644 index 000000000..172bf2cb5 --- /dev/null +++ b/test/models/FBX/cubes_with_mirroring_and_pivot.fbx @@ -0,0 +1,855 @@ +; FBX 7.5.0 project file +; ---------------------------------------------------- + +FBXHeaderExtension: { + FBXHeaderVersion: 1003 + FBXVersion: 7500 + CreationTimeStamp: { + Version: 1000 + Year: 2019 + Month: 5 + Day: 14 + Hour: 17 + Minute: 27 + Second: 42 + Millisecond: 70 + } + Creator: "FBX SDK/FBX Plugins version 2018.1.1" + SceneInfo: "SceneInfo::GlobalInfo", "UserData" { + Type: "UserData" + Version: 100 + MetaData: { + Version: 100 + Title: "" + Subject: "" + Author: "" + Keywords: "" + Revision: "" + Comment: "" + } + Properties70: { + P: "DocumentUrl", "KString", "Url", "", "U:\Some\Absolute\Path\cubes_with_mirroring_and_pivot.fbx" + P: "SrcDocumentUrl", "KString", "Url", "", "U:\Some\Absolute\Path\cubes_with_mirroring_and_pivot.fbx" + P: "Original", "Compound", "", "" + P: "Original|ApplicationVendor", "KString", "", "", "Autodesk" + P: "Original|ApplicationName", "KString", "", "", "Maya" + P: "Original|ApplicationVersion", "KString", "", "", "201800" + P: "Original|DateTime_GMT", "DateTime", "", "", "14/05/2019 16:27:42.070" + P: "Original|FileName", "KString", "", "", "U:\Some\Absolute\Path\cubes_with_mirroring_and_pivot.fbx" + P: "LastSaved", "Compound", "", "" + P: "LastSaved|ApplicationVendor", "KString", "", "", "Autodesk" + P: "LastSaved|ApplicationName", "KString", "", "", "Maya" + P: "LastSaved|ApplicationVersion", "KString", "", "", "201800" + P: "LastSaved|DateTime_GMT", "DateTime", "", "", "14/05/2019 16:27:42.070" + P: "Original|ApplicationActiveProject", "KString", "", "", "U:\Some\Absolute\Path" + } + } +} +GlobalSettings: { + Version: 1000 + Properties70: { + P: "UpAxis", "int", "Integer", "",1 + P: "UpAxisSign", "int", "Integer", "",1 + P: "FrontAxis", "int", "Integer", "",2 + P: "FrontAxisSign", "int", "Integer", "",1 + P: "CoordAxis", "int", "Integer", "",0 + P: "CoordAxisSign", "int", "Integer", "",1 + P: "OriginalUpAxis", "int", "Integer", "",1 + P: "OriginalUpAxisSign", "int", "Integer", "",1 + P: "UnitScaleFactor", "double", "Number", "",100 + P: "OriginalUnitScaleFactor", "double", "Number", "",1 + P: "AmbientColor", "ColorRGB", "Color", "",0,0,0 + P: "DefaultCamera", "KString", "", "", "Producer Perspective" + P: "TimeMode", "enum", "", "",11 + P: "TimeProtocol", "enum", "", "",2 + P: "SnapOnFrameMode", "enum", "", "",0 + P: "TimeSpanStart", "KTime", "Time", "",1924423250 + P: "TimeSpanStop", "KTime", "Time", "",384884650000 + P: "CustomFrameRate", "double", "Number", "",-1 + P: "TimeMarker", "Compound", "", "" + P: "CurrentTimeMarker", "int", "Integer", "",-1 + } +} + +; Documents Description +;------------------------------------------------------------------ + +Documents: { + Count: 1 + Document: 1827132552544, "", "Scene" { + Properties70: { + P: "SourceObject", "object", "", "" + P: "ActiveAnimStackName", "KString", "", "", "Take 001" + } + RootNode: 0 + } +} + +; Document References +;------------------------------------------------------------------ + +References: { +} + +; Object definitions +;------------------------------------------------------------------ + +Definitions: { + Version: 100 + Count: 13 + ObjectType: "GlobalSettings" { + Count: 1 + } + ObjectType: "AnimationStack" { + Count: 1 + PropertyTemplate: "FbxAnimStack" { + Properties70: { + P: "Description", "KString", "", "", "" + P: "LocalStart", "KTime", "Time", "",0 + P: "LocalStop", "KTime", "Time", "",0 + P: "ReferenceStart", "KTime", "Time", "",0 + P: "ReferenceStop", "KTime", "Time", "",0 + } + } + } + ObjectType: "AnimationLayer" { + Count: 1 + PropertyTemplate: "FbxAnimLayer" { + Properties70: { + P: "Weight", "Number", "", "A",100 + P: "Mute", "bool", "", "",0 + P: "Solo", "bool", "", "",0 + P: "Lock", "bool", "", "",0 + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "BlendMode", "enum", "", "",0 + P: "RotationAccumulationMode", "enum", "", "",0 + P: "ScaleAccumulationMode", "enum", "", "",0 + P: "BlendModeBypass", "ULongLong", "", "",0 + } + } + } + ObjectType: "Geometry" { + Count: 4 + PropertyTemplate: "FbxMesh" { + Properties70: { + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "BBoxMin", "Vector3D", "Vector", "",0,0,0 + P: "BBoxMax", "Vector3D", "Vector", "",0,0,0 + P: "Primary Visibility", "bool", "", "",1 + P: "Casts Shadows", "bool", "", "",1 + P: "Receive Shadows", "bool", "", "",1 + } + } + } + ObjectType: "Material" { + Count: 2 + PropertyTemplate: "FbxSurfaceLambert" { + Properties70: { + P: "ShadingModel", "KString", "", "", "Lambert" + P: "MultiLayer", "bool", "", "",0 + P: "EmissiveColor", "Color", "", "A",0,0,0 + P: "EmissiveFactor", "Number", "", "A",1 + P: "AmbientColor", "Color", "", "A",0.2,0.2,0.2 + P: "AmbientFactor", "Number", "", "A",1 + P: "DiffuseColor", "Color", "", "A",0.8,0.8,0.8 + P: "DiffuseFactor", "Number", "", "A",1 + P: "Bump", "Vector3D", "Vector", "",0,0,0 + P: "NormalMap", "Vector3D", "Vector", "",0,0,0 + P: "BumpFactor", "double", "Number", "",1 + P: "TransparentColor", "Color", "", "A",0,0,0 + P: "TransparencyFactor", "Number", "", "A",0 + P: "DisplacementColor", "ColorRGB", "Color", "",0,0,0 + P: "DisplacementFactor", "double", "Number", "",1 + P: "VectorDisplacementColor", "ColorRGB", "Color", "",0,0,0 + P: "VectorDisplacementFactor", "double", "Number", "",1 + } + } + } + ObjectType: "Model" { + Count: 4 + PropertyTemplate: "FbxNode" { + Properties70: { + P: "QuaternionInterpolate", "enum", "", "",0 + P: "RotationOffset", "Vector3D", "Vector", "",0,0,0 + P: "RotationPivot", "Vector3D", "Vector", "",0,0,0 + P: "ScalingOffset", "Vector3D", "Vector", "",0,0,0 + P: "ScalingPivot", "Vector3D", "Vector", "",0,0,0 + P: "TranslationActive", "bool", "", "",0 + P: "TranslationMin", "Vector3D", "Vector", "",0,0,0 + P: "TranslationMax", "Vector3D", "Vector", "",0,0,0 + P: "TranslationMinX", "bool", "", "",0 + P: "TranslationMinY", "bool", "", "",0 + P: "TranslationMinZ", "bool", "", "",0 + P: "TranslationMaxX", "bool", "", "",0 + P: "TranslationMaxY", "bool", "", "",0 + P: "TranslationMaxZ", "bool", "", "",0 + P: "RotationOrder", "enum", "", "",0 + P: "RotationSpaceForLimitOnly", "bool", "", "",0 + P: "RotationStiffnessX", "double", "Number", "",0 + P: "RotationStiffnessY", "double", "Number", "",0 + P: "RotationStiffnessZ", "double", "Number", "",0 + P: "AxisLen", "double", "Number", "",10 + P: "PreRotation", "Vector3D", "Vector", "",0,0,0 + P: "PostRotation", "Vector3D", "Vector", "",0,0,0 + P: "RotationActive", "bool", "", "",0 + P: "RotationMin", "Vector3D", "Vector", "",0,0,0 + P: "RotationMax", "Vector3D", "Vector", "",0,0,0 + P: "RotationMinX", "bool", "", "",0 + P: "RotationMinY", "bool", "", "",0 + P: "RotationMinZ", "bool", "", "",0 + P: "RotationMaxX", "bool", "", "",0 + P: "RotationMaxY", "bool", "", "",0 + P: "RotationMaxZ", "bool", "", "",0 + P: "InheritType", "enum", "", "",0 + P: "ScalingActive", "bool", "", "",0 + P: "ScalingMin", "Vector3D", "Vector", "",0,0,0 + P: "ScalingMax", "Vector3D", "Vector", "",1,1,1 + P: "ScalingMinX", "bool", "", "",0 + P: "ScalingMinY", "bool", "", "",0 + P: "ScalingMinZ", "bool", "", "",0 + P: "ScalingMaxX", "bool", "", "",0 + P: "ScalingMaxY", "bool", "", "",0 + P: "ScalingMaxZ", "bool", "", "",0 + P: "GeometricTranslation", "Vector3D", "Vector", "",0,0,0 + P: "GeometricRotation", "Vector3D", "Vector", "",0,0,0 + P: "GeometricScaling", "Vector3D", "Vector", "",1,1,1 + P: "MinDampRangeX", "double", "Number", "",0 + P: "MinDampRangeY", "double", "Number", "",0 + P: "MinDampRangeZ", "double", "Number", "",0 + P: "MaxDampRangeX", "double", "Number", "",0 + P: "MaxDampRangeY", "double", "Number", "",0 + P: "MaxDampRangeZ", "double", "Number", "",0 + P: "MinDampStrengthX", "double", "Number", "",0 + P: "MinDampStrengthY", "double", "Number", "",0 + P: "MinDampStrengthZ", "double", "Number", "",0 + P: "MaxDampStrengthX", "double", "Number", "",0 + P: "MaxDampStrengthY", "double", "Number", "",0 + P: "MaxDampStrengthZ", "double", "Number", "",0 + P: "PreferedAngleX", "double", "Number", "",0 + P: "PreferedAngleY", "double", "Number", "",0 + P: "PreferedAngleZ", "double", "Number", "",0 + P: "LookAtProperty", "object", "", "" + P: "UpVectorProperty", "object", "", "" + P: "Show", "bool", "", "",1 + P: "NegativePercentShapeSupport", "bool", "", "",1 + P: "DefaultAttributeIndex", "int", "Integer", "",-1 + P: "Freeze", "bool", "", "",0 + P: "LODBox", "bool", "", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",0,0,0 + P: "Lcl Rotation", "Lcl Rotation", "", "A",0,0,0 + P: "Lcl Scaling", "Lcl Scaling", "", "A",1,1,1 + P: "Visibility", "Visibility", "", "A",1 + P: "Visibility Inheritance", "Visibility Inheritance", "", "",1 + } + } + } +} + +; Object properties +;------------------------------------------------------------------ + +Objects: { + Geometry: 1827080157856, "Geometry::", "Mesh" { + Vertices: *24 { + a: -0.5,-0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,-0.5,-0.5,-0.5,-0.5,0.5,-0.5,-0.5 + } + PolygonVertexIndex: *24 { + a: 0,1,3,-3,2,3,5,-5,4,5,7,-7,6,7,1,-1,1,7,5,-4,6,0,2,-5 + } + Edges: *12 { + a: 0,1,2,3,5,6,7,9,10,11,13,15 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *72 { + a: 0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 + } + NormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *72 { + a: 0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,-0,1,0,-0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0 + } + BinormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *72 { + a: 1,-0,-0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0,-0,1,0,-0,1,0,-0,1,0,-0,1 + } + TangentsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *28 { + a: 0.375,0,0.625,0,0.375,0.25,0.625,0.25,0.375,0.5,0.625,0.5,0.375,0.75,0.625,0.75,0.375,1,0.625,1,0.875,0,0.875,0.25,0.125,0,0.125,0.25 + } + UVIndex: *24 { + a: 0,1,3,2,2,3,5,4,4,5,7,6,6,7,9,8,1,10,11,3,12,0,2,13 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *12 { + a: 0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Geometry: 1827080155296, "Geometry::", "Mesh" { + Vertices: *24 { + a: -0.5,-0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,-0.5,-0.5,-0.5,-0.5,0.5,-0.5,-0.5 + } + PolygonVertexIndex: *24 { + a: 0,1,3,-3,2,3,5,-5,4,5,7,-7,6,7,1,-1,1,7,5,-4,6,0,2,-5 + } + Edges: *12 { + a: 0,1,2,3,5,6,7,9,10,11,13,15 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *72 { + a: 0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 + } + NormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *72 { + a: 0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,-0,1,0,-0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0 + } + BinormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *72 { + a: 1,-0,-0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0,-0,1,0,-0,1,0,-0,1,0,-0,1 + } + TangentsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *28 { + a: 0.375,0,0.625,0,0.375,0.25,0.625,0.25,0.375,0.5,0.625,0.5,0.375,0.75,0.625,0.75,0.375,1,0.625,1,0.875,0,0.875,0.25,0.125,0,0.125,0.25 + } + UVIndex: *24 { + a: 0,1,3,2,2,3,5,4,4,5,7,6,6,7,9,8,1,10,11,3,12,0,2,13 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *12 { + a: 0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Geometry: 1827080156320, "Geometry::", "Mesh" { + Vertices: *24 { + a: -0.5,-0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,-0.5,-0.5,-0.5,-0.5,0.5,-0.5,-0.5 + } + PolygonVertexIndex: *24 { + a: 0,1,3,-3,2,3,5,-5,4,5,7,-7,6,7,1,-1,1,7,5,-4,6,0,2,-5 + } + Edges: *12 { + a: 0,1,2,3,5,6,7,9,10,11,13,15 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *72 { + a: 0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 + } + NormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *72 { + a: 0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,-0,1,0,-0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0 + } + BinormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *72 { + a: 1,-0,-0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0,-0,1,0,-0,1,0,-0,1,0,-0,1 + } + TangentsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *28 { + a: 0.375,0,0.625,0,0.375,0.25,0.625,0.25,0.375,0.5,0.625,0.5,0.375,0.75,0.625,0.75,0.375,1,0.625,1,0.875,0,0.875,0.25,0.125,0,0.125,0.25 + } + UVIndex: *24 { + a: 0,1,3,2,2,3,5,4,4,5,7,6,6,7,9,8,1,10,11,3,12,0,2,13 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *12 { + a: 0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Geometry: 1827080139424, "Geometry::", "Mesh" { + Vertices: *588 { + a: -0.499999970197678,-0.5,0.5,0.500000059604645,-0.5,0.5,-0.499999970197678,0.5,0.5,0.500000059604645,0.5,0.5,-0.499999970197678,0.5,-0.49999988079071,0.500000059604645,0.5,-0.49999988079071,-0.499999970197678,-0.5,-0.49999988079071,0.500000059604645,-0.5,-0.49999988079071,0,0,0.5,0,-0.5,0.5,0.500000059604645,0,0.5,0,0.5,0.5,-0.499999970197678,0,0.5,0,0.5,1.19209289550781e-07,0.500000059604645,0.5,1.19209289550781e-07,0,0.5,-0.49999988079071,-0.499999970197678,0.5,1.19209289550781e-07,0,0,-0.49999988079071,0.500000059604645,0,-0.49999988079071,0,-0.5,-0.49999988079071,-0.499999970197678,0,-0.49999988079071,0,-0.5,1.19209289550781e-07,0.500000059604645,-0.5,1.19209289550781e-07,-0.499999970197678,-0.5,1.19209289550781e-07,0.500000059604645,0,1.19209289550781e-07,-0.499999970197678,0,1.19209289550781e-07,-0.25,-0.25,0.5,-0.499999970197678,-0.25,0.5,-0.25,-0.5,0.5,0,-0.25,0.5,-0.25,0,0.5,-0.25,0.5,0.25,-0.499999970197678,0.5,0.25,-0.25,0.5,0.5,0,0.5,0.25,-0.25,0.5,1.19209289550781e-07,-0.25,0.25,-0.49999988079071,-0.499999970197678,0.25,-0.49999988079071,-0.25,0.5,-0.49999988079071,0,0.25,-0.49999988079071,-0.25,0,-0.49999988079071,-0.25,-0.5,-0.24999988079071,-0.499999970197678,-0.5,-0.24999988079071,-0.25,-0.5,-0.49999988079071,0,-0.5,-0.24999988079071,-0.25,-0.5,1.19209289550781e-07,0.500000059604645,-0.25,0.25,0.500000059604645,-0.25,0.5,0.500000059604645,-0.5,0.25,0.500000059604645,-0.25,1.19209289550781e-07,0.500000059604645,0,0.25,-0.499999970197678,-0.25,-0.24999988079071,-0.499999970197678,-0.25,-0.49999988079071,-0.499999970197678,-0.25,1.19209289550781e-07,-0.499999970197678,0,-0.24999988079071,0.250000059604645,-0.25,0.5,0.250000059604645,-0.5,0.5,0.250000059604645,0,0.5,0.250000059604645,0.25,0.5,0.500000059604645,0.25,0.5,0.250000059604645,0.5,0.5,0,0.25,0.5,-0.25,0.25,0.5,-0.499999970197678,0.25,0.5,0.250000059604645,0.5,0.25,0.500000059604645,0.5,0.25,0.250000059604645,0.5,1.19209289550781e-07,0.250000059604645,0.5,-0.24999988079071,0.500000059604645,0.5,-0.24999988079071,0.250000059604645,0.5,-0.49999988079071, +0,0.5,-0.24999988079071,-0.25,0.5,-0.24999988079071,-0.499999970197678,0.5,-0.24999988079071,0.250000059604645,0.25,-0.49999988079071,0.500000059604645,0.25,-0.49999988079071,0.250000059604645,0,-0.49999988079071,0.250000059604645,-0.25,-0.49999988079071,0.500000059604645,-0.25,-0.49999988079071,0.250000059604645,-0.5,-0.49999988079071,0,-0.25,-0.49999988079071,-0.25,-0.25,-0.49999988079071,0.250000059604645,-0.5,-0.24999988079071,0.500000059604645,-0.5,-0.24999988079071,0.250000059604645,-0.5,1.19209289550781e-07,0.250000059604645,-0.5,0.25,0,-0.5,0.25,-0.25,-0.5,0.25,-0.499999970197678,-0.5,0.25,0.500000059604645,-0.25,-0.24999988079071,0.500000059604645,0,-0.24999988079071,0.500000059604645,0.25,-0.24999988079071,0.500000059604645,0.25,1.19209289550781e-07,0.500000059604645,0.25,0.25,-0.499999970197678,-0.25,0.25,-0.499999970197678,0,0.25,-0.499999970197678,0.25,0.25,-0.499999970197678,0.25,1.19209289550781e-07,-0.499999970197678,0.25,-0.24999988079071,-0.594913899898529,0,0.594913899898529,-0.152911216020584,0,0.714658200740814,-0.594913899898529,-0.152911216020584,0.594913899898529,-0.152911216020584,-0.152911216020584,0.714658200740814,-0.594913899898529,0.594913899898529,7.29137497046395e-08,-0.152911216020584,0.714658200740814,7.29137497046395e-08,-0.594913899898529,0.594913899898529,0.152911216020584,-0.152911216020584,0.714658200740814,0.152911216020584,-0.594913899898529,0,-0.594913899898529,-0.152911216020584,0,-0.714658200740814,-0.594913899898529,0.152911216020584,-0.594913899898529,-0.152911216020584,0.152911216020584,-0.714658200740814,-0.594913899898529,-0.594913899898529,7.29137497046395e-08,-0.152911216020584,-0.714658200740814,7.29137497046395e-08,-0.594913899898529,-0.594913899898529,-0.152911216020584,-0.152911216020584,-0.714658200740814,-0.152911216020584,0.594913899898529,0,0.594913899898529,0.714658200740814,0,0.152911216020584,0.594913899898529,-0.152911216020584,0.594913899898529,0.714658200740814,-0.152911216020584,0.152911216020584,-0.714658200740814,0,-0.152911216020584,-0.594913899898529,-0.152911216020584,-0.594913899898529, +-0.714658200740814,-0.152911216020584,-0.152911216020584,8.62321627254444e-17,-0.594913899898529,0.594913899898529,8.62321627254444e-17,-0.152911216020584,0.714658200740814,0.152911230921745,-0.594913899898529,0.594913899898529,0.152911230921745,-0.152911216020584,0.714658200740814,0.152911230921745,0,0.714658200740814,0.594913899898529,0.152911216020584,0.594913899898529,0.152911230921745,0.152911216020584,0.714658200740814,8.62321627254444e-17,0.594913899898529,0.594913899898529,8.62321627254444e-17,0.152911216020584,0.714658200740814,-0.152911216020584,0.594913899898529,0.594913899898529,-0.152911216020584,0.152911216020584,0.714658200740814,8.62321627254444e-17,0.714658200740814,0.152911216020584,0.152911230921745,0.594913899898529,0.594913899898529,0.152911230921745,0.714658200740814,0.152911216020584,0.594913899898529,0.594913899898529,7.29137497046395e-08,0.152911230921745,0.714658200740814,7.29137497046395e-08,0.594913899898529,0.594913899898529,-0.152911216020584,0.152911230921745,0.714658200740814,-0.152911216020584,8.62321627254444e-17,0.594913899898529,-0.594913899898529,8.62321627254444e-17,0.714658200740814,-0.152911216020584,-0.152911216020584,0.594913899898529,-0.594913899898529,-0.152911216020584,0.714658200740814,-0.152911216020584,8.62321627254444e-17,0.152911216020584,-0.714658200740814,0.152911230921745,0.594913899898529,-0.594913899898529,0.152911230921745,0.152911216020584,-0.714658200740814,0.594913899898529,0,-0.594913899898529,0.152911230921745,0,-0.714658200740814,0.594913899898529,-0.152911216020584,-0.594913899898529,0.152911230921745,-0.152911216020584,-0.714658200740814,8.62321627254444e-17,-0.594913899898529,-0.594913899898529,8.62321627254444e-17,-0.152911216020584,-0.714658200740814,-0.152911216020584,-0.594913899898529,-0.594913899898529,-0.152911216020584,-0.152911216020584,-0.714658200740814,8.62321627254444e-17,-0.714658200740814,-0.152911216020584,0.152911230921745,-0.594913899898529,-0.594913899898529,0.152911230921745,-0.714658200740814,-0.152911216020584,0.594913899898529,-0.594913899898529,7.29137497046395e-08, +0.152911230921745,-0.714658200740814,7.29137497046395e-08,0.594913899898529,-0.594913899898529,0.152911216020584,0.152911230921745,-0.714658200740814,0.152911216020584,8.62321627254444e-17,-0.714658200740814,0.152911216020584,-0.152911216020584,-0.594913899898529,0.594913899898529,-0.152911216020584,-0.714658200740814,0.152911216020584,0.714658200740814,-0.152911216020584,7.29137497046395e-08,0.594913899898529,-0.594913899898529,-0.152911216020584,0.714658200740814,-0.152911216020584,-0.152911216020584,0.714658200740814,0,-0.152911216020584,0.594913899898529,0.152911216020584,-0.594913899898529,0.714658200740814,0.152911216020584,-0.152911216020584,0.714658200740814,0.152911216020584,7.29137497046395e-08,0.594913899898529,0.594913899898529,0.152911216020584,0.714658200740814,0.152911216020584,0.152911216020584,-0.714658200740814,-0.152911216020584,7.29137497046395e-08,-0.594913899898529,-0.594913899898529,0.152911216020584,-0.714658200740814,-0.152911216020584,0.152911216020584,-0.714658200740814,0,0.152911216020584,-0.594913899898529,0.152911216020584,0.594913899898529,-0.714658200740814,0.152911216020584,0.152911216020584,-0.714658200740814,0.152911216020584,7.29137497046395e-08,-0.594913899898529,0.594913899898529,-0.152911216020584,-0.714658200740814,0.152911216020584,-0.152911216020584,-0.541863918304443,-0.541864037513733,0.541863918304443,8.62321627254444e-17,0,0.714658200740814,-0.541863918304443,0.541863918304443,0.541863918304443,8.62321627254444e-17,0.714658200740814,7.29137497046395e-08,-0.541863918304443,0.541863918304443,-0.541863799095154,8.62321627254444e-17,0,-0.714658200740814,-0.541863918304443,-0.541864037513733,-0.541863799095154,8.62321627254444e-17,-0.714658200740814,7.29137497046395e-08,0.541863977909088,-0.541864037513733,0.541863918304443,0.714658200740814,0,7.29137497046395e-08,-0.714658200740814,0,7.29137497046395e-08,0.541863977909088,0.541863918304443,0.541863918304443,0.541863977909088,0.541863918304443,-0.541863799095154,0.541863977909088,-0.541864037513733,-0.541863799095154 + } + PolygonVertexIndex: *768 { + a: 99,98,100,-102,103,102,104,-106,107,106,108,-110,111,110,112,-114,115,114,116,-118,118,106,119,-121,122,121,123,-125,125,114,126,-128,129,128,130,-132,132,128,133,-135,136,135,137,-139,140,139,141,-143,143,139,144,-146,147,146,148,-150,151,150,152,-154,154,150,155,-157,158,157,159,-161,161,121,162,-164,164,157,165,-167,167,146,168,-170,170,135,171,-173,173,110,174,-176,176,98,177,-179,179,102,180,-182,100,182,162,-102,162,121,122,-102,122,183,99,-102,104,184,130,-106,130,128,132,-106,132,185,103,-106,108,186,141,-110,141,139,143,-110,143,187,107,-110,112,188,152,-114,152,150,154,-114,154,189,111,-114,116,190,159,-118,159,157,164,-118,164,191,115,-118,119,188,112,-121,112,110,173,-121,173,192,118,-121,123,190,116,-125,116,114,125,-125,125,183,122,-125,126,193,133,-128,133,128,129,-128,129,183,125,-128,130,184,177,-132,177,98,99,-132,99,183,129,-132,133,193,171,-135,171,135,136,-135,136,185,132,-135,137,194,144,-139,144,139,140,-139,140,185,136,-139,141,186,180,-143,180,102,103,-143,103,185,140,-143,144,194,168,-146,168,146,147,-146,147,187,143,-146,148,195,155,-150,155,150,151,-150,151,187,147,-150,152,188,119,-154,119,106,107,-154,107,187,151,-154,155,195,165,-157,165,157,158,-157,158,189,154,-157,159,190,123,-161,123,121,161,-161,161,189,158,-161,162,182,174,-164,174,110,111,-164,111,189,161,-164,165,195,148,-167,148,146,167,-167,167,191,164,-167,168,194,137,-170,137,135,170,-170,170,191,167,-170,171,193,126,-173,126,114,115,-173,115,191,170,-173,174,182,100,-176,100,98,176,-176,176,192,173,-176,177,184,104,-179,104,102,179,-179,179,192,176,-179,180,186,108,-182,108,106,118,-182,118,192,179,-182,30,26,27,-13,35,31,32,-17,40,36,37,-21,45,41,42,-24,50,46,47,-11,54,51,52,-21,29,55,56,-10,57,58,59,-11,61,62,33,-12,34,64,60,-12,66,67,68,-15,70,71,38,-16,39,73,69,-16,75,76,77,-19,79,80,43,-20,44,81,78,-20,83,84,48,-23,85,86,28,-10,49,88,82,-23,89,90,74,-19,91,92,65,-15,53,93,87,-24,94,95,63,-13,96,97,72,-17,27,26,28,-1,28,26,29,-10,29,26,30,-9,32,31,33,-3,33,31,34,-12,34,31,35,-14,37,36,38,-5,38,36,39, +-16,39,36,40,-18,42,41,43,-7,43,41,44,-20,44,41,45,-22,47,46,48,-2,48,46,49,-23,49,46,50,-25,52,51,42,-7,42,51,53,-24,53,51,54,-26,56,55,47,-2,47,55,57,-11,57,55,29,-9,59,58,60,-4,60,58,61,-12,61,58,57,-9,33,62,63,-3,63,62,30,-13,30,62,61,-9,60,64,65,-4,65,64,66,-15,66,64,34,-14,68,67,69,-6,69,67,70,-16,70,67,66,-14,38,71,72,-5,72,71,35,-17,35,71,70,-14,69,73,74,-6,74,73,75,-19,75,73,39,-18,77,76,78,-8,78,76,79,-20,79,76,75,-18,43,80,52,-7,52,80,40,-21,40,80,79,-18,78,81,82,-8,82,81,83,-23,83,81,44,-22,48,84,56,-2,56,84,85,-10,85,84,83,-22,28,86,87,-1,87,86,45,-24,45,86,85,-22,82,88,77,-8,77,88,89,-19,89,88,49,-25,74,90,68,-6,68,90,91,-15,91,90,89,-25,65,92,59,-4,59,92,50,-11,50,92,91,-25,87,93,27,-1,27,93,94,-13,94,93,53,-26,63,95,32,-3,32,95,96,-17,96,95,94,-26,72,97,37,-5,37,97,54,-21,54,97,96,-26 + } + Edges: *384 { + a: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,102,104,105,108,109,110,114,116,117,120,121,122,126,128,129,132,133,134,138,140,141,144,145,146,150,152,153,156,158,162,164,165,168,170,174,176,180,181,182,186,188,193,194,198,205,206,210,212,216,217,218,222,224,229,230,234,241,242,246,248,252,253,254,258,260,266,270,277,278,282,284,290,294,296,301,302,306,314,318,320,326,330,332,338,342,350,354,356,362,366,368,374,378,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,481,482,483,485,490,491,493,494,495,497,502,503,505,506,507,509,514,515,517,518,519,521,526,527,529,530,531,533,538,539,541,543,545,550,551,553,555,557,563,565,566,567,569,575,577,578,581,589,590,593,599,601,602,603,605,611,613,614,617,625,626,629,635,637,638,639,641,647,649,653,661,662,665,671,673,677,683,685,686,689,697,701,707,709,713,719,721,725,733,737,743,745,749,755,757,761 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *2304 { + a: -0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487185955048,0.965206921100616,0,-0.261487185955048,0.965206921100616,0,-0.261487185955048,0.965206921100616,0,-0.261487185955048,0.965206921100616,0,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,0,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.965206921100616,0.261487156152725,0,0.965206921100616,0.261487156152725,0,0.965206921100616,0.261487156152725,0,0.965206921100616,0.261487156152725,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0.261487126350403,0,-0.965206980705261, +0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.965206921100616,-0.261487156152725,0,-0.965206921100616,-0.261487156152725,0,-0.965206921100616,-0.261487156152725,0,-0.965206921100616,-0.261487156152725,0.261487185955048,-0.965206921100616,0,0.261487185955048,-0.965206921100616,0,0.261487185955048,-0.965206921100616,0,0.261487185955048,-0.965206921100616,0,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0.965206980705261,-0.261487066745758,0,0.965206980705261,-0.261487066745758,0,0.965206980705261,-0.261487066745758,0,0.965206980705261,-0.261487066745758,0,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0.261487066745758,0,-0.965206980705261,0.261487066745758,0,-0.965206980705261,0.261487066745758,0,-0.965206980705261,0.261487066745758,0,-0.211917281150818,-0.211917445063591,0.954034626483917,0,0,1,-0.211917281150818,-0.21191743016243,0.954034626483917,-0.211917266249657,-0.211917445063591,0.954034626483917,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,-0.211917445063591,0.954034626483917,0.211917281150818, +0,1,0,-0.211917445063591,0.954034626483917,0.211917281150818,-0.211917445063591,0.954034626483917,0.211917266249657,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,1,0,0,1,0,0,1,0,0,1,0,-0.211917594075203,0.211917579174042,-0.954034507274628,0,0,-1,-0.211917594075203,0.211917579174042,-0.954034507274628,-0.211917594075203,0.211917564272881,-0.954034507274628,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.211917325854301,-0.954034626483917,-0.211917325854301,0,-1,0,-0.211917325854301,-0.954034686088562,-0.211917325854301,-0.211917355656624,-0.954034686088562,-0.211917355656624,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0.954034626483917,-0.211917251348495,0.21191731095314,1,0,0,0.954034626483917,-0.211917251348495,0.211917340755463,0.954034745693207,-0.211917266249657,0.211917325854301,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,1,0,0,1,0,0,1,0,0,1,0,0,-0.954034686088562,-0.211917355656624,-0.211917459964752,-1,0,0,-0.954034626483917,-0.211917325854301,-0.211917445063591,-0.954034686088562,-0.211917355656624,-0.211917474865913,-0.965206980705261,-0.261487066745758,0,-0.965206980705261,-0.261487066745758,0,-0.965206980705261,-0.261487066745758,0,-0.965206980705261,-0.261487066745758,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0.211917281150818,-0.211917400360107,0.954034626483917,0,0,1,0.211917266249657,-0.211917415261269,0.954034626483917,0.211917266249657,-0.211917415261269,0.954034626483917,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261, +0,0,1,0,0,1,0,0,1,0,0,1,0.211917296051979,0.211917415261269,0.954034626483917,0,0,1,0.211917296051979,0.211917415261269,0.954034626483917,0.211917281150818,0.211917415261269,0.954034626483917,0,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0,1,0,0,1,0,0,1,0,0,1,-0.211917281150818,0.211917445063591,0.954034626483917,0,0,1,-0.211917281150818,0.211917445063591,0.954034626483917,-0.211917266249657,0.211917445063591,0.954034626483917,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,0.211917445063591,0.954034626483917,0.211917445063591,0,1,0,0.211917415261269,0.954034566879272,0.211917415261269,0.211917445063591,0.954034626483917,0.211917445063591,0.261487185955048,0.965206921100616,0,0.261487185955048,0.965206921100616,0,0.261487185955048,0.965206921100616,0,0.261487185955048,0.965206921100616,0,0,1,0,0,1,0,0,1,0,0,1,0,0.211917445063591,0.954034626483917,-0.211917489767075,0,1,0,0.21191743016243,0.954034566879272,-0.211917489767075,0.211917445063591,0.954034566879272,-0.211917474865913,0,0.965206921100616,-0.261487156152725,0,0.965206921100616,-0.261487156152725,0,0.965206921100616,-0.261487156152725,0,0.965206921100616,-0.261487156152725,0,1,0,0,1,0,0,1,0,0,1,0,-0.211917459964752,0.954034686088562,-0.211917340755463,0,1,0,-0.211917445063591,0.954034626483917,-0.21191731095314,-0.211917489767075,0.954034686088562,-0.211917355656624,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0,0,1,0,0,1,0,0,1,0,0,1,0,0.211917608976364,0.211917579174042,-0.954034507274628,0,0,-1,0.211917608976364,0.211917564272881,-0.954034566879272,0.211917594075203,0.211917579174042,-0.954034507274628,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261, +0.261487126350403,0,-0.965206980705261,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0.211917579174042,-0.211917534470558,-0.954034507274628,0,0,-1,0.211917594075203,-0.211917549371719,-0.954034507274628,0.211917594075203,-0.211917519569397,-0.954034507274628,0,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.211917594075203,-0.211917549371719,-0.954034507274628,0,0,-1,-0.211917579174042,-0.211917534470558,-0.954034566879272,-0.211917594075203,-0.211917519569397,-0.954034507274628,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0.211917340755463,-0.954034686088562,-0.211917519569397,0,-1,0,0.211917325854301,-0.954034626483917,-0.211917489767075,0.211917325854301,-0.954034686088562,-0.211917489767075,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0.211917281150818,-0.954034626483917,0.211917445063591,0,-1,0,0.211917296051979,-0.954034626483917,0.211917445063591,0.211917266249657,-0.954034626483917,0.211917445063591,0,-0.965206921100616,0.261487156152725,0,-0.965206921100616,0.261487156152725,0,-0.965206921100616,0.261487156152725,0,-0.965206921100616,0.261487156152725,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0.211917296051979,-0.954034626483917,0.211917296051979,0,-1,0,-0.211917296051979,-0.954034626483917,0.211917296051979,-0.211917281150818,-0.954034686088562,0.211917281150818,-0.261487185955048,-0.965206921100616,0,-0.261487185955048,-0.965206921100616,0,-0.261487185955048,-0.965206921100616,0,-0.261487185955048,-0.965206921100616,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0.954034626483917,-0.211917325854301,-0.211917400360107,1,0,0,0.954034686088562,-0.211917340755463,-0.211917400360107,0.954034686088562,-0.211917355656624,-0.21191743016243,0.965206980705261,0,-0.261487185955048, +0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,1,0,0,1,0,0,1,0,0,1,0,0,0.954034686088562,0.211917370557785,-0.211917489767075,1,0,0,0.954034686088562,0.211917355656624,-0.211917445063591,0.954034626483917,0.211917355656624,-0.211917445063591,0.965206980705261,0.261487066745758,0,0.965206980705261,0.261487066745758,0,0.965206980705261,0.261487066745758,0,0.965206980705261,0.261487066745758,0,1,0,0,1,0,0,1,0,0,1,0,0,0.954034626483917,0.211917296051979,0.211917385458946,1,0,0,0.954034626483917,0.211917296051979,0.211917385458946,0.954034626483917,0.211917266249657,0.211917355656624,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,1,0,0,1,0,0,1,0,0,1,0,0,-0.954034626483917,-0.211917251348495,0.211917400360107,-1,0,0,-0.954034626483917,-0.211917266249657,0.211917400360107,-0.954034626483917,-0.211917251348495,0.211917400360107,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-0.954034626483917,0.211917281150818,0.211917445063591,-1,0,0,-0.954034626483917,0.211917281150818,0.211917445063591,-0.954034626483917,0.211917266249657,0.211917445063591,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-0.954034566879272,0.211917355656624,-0.211917519569397,-1,0,0,-0.954034686088562,0.211917370557785,-0.211917534470558,-0.954034626483917,0.211917355656624,-0.211917504668236,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0, +1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0, +-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0 + } + NormalsW: *768 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *2304 { + a: 0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0.965207040309906,0.261487185955048,0,0.965207040309906,0.261487185955048,0,0.965207040309906,0.261487185955048,0,0.965207040309906,0.261487185955048,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,0.965206980705261,-0.261487185955048,0,0.965206980705261,-0.261487185955048,0,0.965206980705261,-0.261487185955048,0,0.965206980705261,-0.261487185955048,0,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0.261487126350403,-0.965206980705261,0,-0.261487126350403,-0.965206980705261,0,-0.261487126350403,-0.965206980705261,0,-0.261487126350403,-0.965206980705261,0,-0.965207040309906,-0.261487185955048,0,-0.965207040309906,-0.261487185955048,0,-0.965207040309906,-0.261487185955048,0,-0.965207040309906,-0.261487185955048,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-0.965206980705261,0.261487185955048,0,-0.965206980705261,0.261487185955048,0,-0.965206980705261,0.261487185955048,0,-0.965206980705261,0.261487185955048,0,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0,0,1,0,0,1,0,0,1,0,0,1,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,0,1,0,0,1,0,0,1,0, +0,1,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,-0.0554696954786777,0.977241098880768,0.204750895500183,0.0677256807684898,0.997704029083252,-0,0.0995207726955414,0.966452240943909,0.236782029271126,0.022095151245594,0.974918127059937,0.221464186906815,0,0.965206980705261,0.261487185955048,0,0.965206980705261,0.261487185955048,0,0.965206980705261,0.261487185955048,0,0.965206980705261,0.261487185955048,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0.0554696545004845,0.204750746488571,-0.977241158485413,0.0677258297801018,0,-0.997703969478607,0.0995210781693459,0.23678195476532,-0.966452240943909,0.0220953319221735,0.221464082598686,-0.974918246269226,0,0.261487126350403,-0.965206980705261,0,0.261487126350403,-0.965206980705261,0,0.261487126350403,-0.965206980705261,0,0.261487126350403,-0.965206980705261,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.055469736456871,-0.977241158485413,-0.204751059412956,0.0677258297801018,-0.997703969478607,0,0.0995209664106369,-0.966452121734619,-0.236782252788544,0.0220952294766903,-0.974918127059937,-0.221464350819588,0,-0.965206980705261,-0.261487185955048,0,-0.965206980705261,-0.261487185955048,0,-0.965206980705261,-0.261487185955048,0,-0.965206980705261,-0.261487185955048,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,-0,-0.0554696694016457,-0.204750820994377,0.977241218090057,0.0677259787917137,0,0.997703969478607,0.0995214134454727,-0.236782014369965,0.966452121734619,0.0220954976975918,-0.221464157104492,0.974918186664581,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,0.204750746488571,0.977241218090057,0.0554696507751942,0,0.997704029083252,-0.0677256807684898,0.236781880259514,0.966452300548553,-0.0995208472013474,0.221463993191719,0.974918186664581,-0.0220952127128839,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0, +-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0.204750791192055,0.977241098880768,-0.0554696619510651,0,0.997704029083252,0.0677257031202316,-0.236781939864159,0.966452240943909,0.099520817399025,-0.221464112401009,0.974918246269226,0.022095188498497,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,0,-0.099520780146122,0.966452240943909,0.236781999468803,-0.0677256733179092,0.997704029083252,0,0.0554696880280972,0.977241098880768,0.204750865697861,-0.022095151245594,0.974918127059937,0.221464157104492,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0.0554696880280972,0.977241098880768,-0.204750865697861,0.0677258223295212,0.997703969478607,-0,0.0995210558176041,0.966452181339264,-0.236782059073448,0.0220952890813351,0.974918246269226,-0.221464201807976,0,0.965207040309906,-0.261487185955048,0,0.965207040309906,-0.261487185955048,0,0.965207040309906,-0.261487185955048,0,0.965207040309906,-0.261487185955048,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0.0995210707187653,0.966452240943909,-0.236782118678093,-0.0677258297801018,0.997703969478607,0,0.0554696954786777,0.977241098880768,-0.204750895500183,-0.0220952928066254,0.974918186664581,-0.221464231610298,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0.0995210558176041,0.236782118678093,-0.966452240943909,-0.0677258223295212,0,-0.997703969478607,0.0554696917533875,0.204750880599022,-0.977241098880768,-0.0220952853560448,0.221464216709137,-0.974918127059937,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.0554697066545486,-0.204750955104828,-0.977241158485413,0.0677259713411331,0,-0.997703969478607,0.0995213314890862,-0.236782237887383,-0.966452181339264,0.0220954213291407,-0.221464306116104,-0.974918186664581,0,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.0995213687419891,-0.236782059073448,-0.966452181339264, +-0.0677259787917137,0,-0.997703969478607,0.0554696545004845,-0.204750776290894,-0.977241158485413,-0.0220954604446888,-0.221464172005653,-0.974918246269226,0,0,-1,0,0,-1,-0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.0995209515094757,-0.966452121734619,-0.236782252788544,-0.0677258223295212,-0.997703969478607,-0,0.0554697290062904,-0.977241098880768,-0.204751014709473,-0.0220952183008194,-0.974918127059937,-0.221464365720749,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,-0,-0.0554697290062904,-0.977241158485413,0.204751014709473,0.0677256733179092,-0.997704029083252,0,0.099520668387413,-0.966452181339264,0.236782178282738,0.022095087915659,-0.974918127059937,0.221464276313782,0,-0.965207040309906,0.261487185955048,0,-0.965207040309906,0.261487185955048,0,-0.965207040309906,0.261487185955048,0,-0.965207040309906,0.261487185955048,0,-1,0,0,-1,0,0,-1,-0,0,-1,0,-0.0995206907391548,-0.966452181339264,0.236782178282738,-0.0677256807684898,-0.997704029083252,-0,0.0554697178304195,-0.977241098880768,0.20475098490715,-0.0220951028168201,-0.974918127059937,0.221464276313782,0,-1,-0,0,-1,-0,-0,-1,0,0,-1,-0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0.0995213836431503,-0.23678220808506,0.966452121734619,-0.0677259713411331,0,0.997703969478607,0.0554697066545486,-0.204750940203667,0.977241098880768,-0.0220954623073339,-0.221464291214943,0.974918186664581,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0.0554696954786777,0.204750895500183,0.977241098880768,0.0677258223295212,0,0.997703969478607,0.0995211154222488,0.236782103776932,0.966452181339264,0.0220953226089478,0.221464246511459,0.974918186664581,0,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0,1,0,0,1,0,0,1,0,0,1,-0.0995211601257324,0.23678195476532,0.966452181339264,-0.0677258297801018,0,0.997703969478607,0.0554696619510651,0.204750776290894,0.977241218090057,-0.022095363587141,0.221464082598686,0.974918246269226,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0.236781939864159,0.966452240943909,0.0995208621025085, +-0,0.997704029083252,0.0677257031202316,0.204750806093216,0.977241158485413,-0.0554696656763554,0.221464112401009,0.974918186664581,0.0220951996743679,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0.204750806093216,0.977241098880768,0.0554696694016457,0,0.997703969478607,-0.0677258521318436,-0.236782044172287,0.966452240943909,-0.0995211452245712,-0.221464172005653,0.974918246269226,-0.0220953542739153,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,0,1,-0,-0,1,0,-0,1,0,-0,1,0,-0.236781984567642,0.966452300548553,0.09952113032341,-0,0.997703969478607,0.0677258297801018,-0.204750761389732,0.977241158485413,-0.0554696582257748,-0.221464067697525,0.974918246269226,0.022095350548625,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,-0,-0,1,0,-0.236781880259514,0.966452360153198,-0.0995208248496056,0,0.997704029083252,-0.0677256807684898,-0.20475073158741,0.977241158485413,0.0554696470499039,-0.221464022994041,0.974918246269226,-0.0220951903611422,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0.204750746488571,0.977241158485413,-0.0554696545004845,0,0.997703969478607,0.0677258297801018,0.23678195476532,0.966452240943909,0.0995210781693459,0.221464082598686,0.974918246269226,0.0220953319221735,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,0,0.236782059073448,0.966452240943909,-0.0995211154222488,0,0.997703969478607,-0.0677258521318436,0.204750806093216,0.977241098880768,0.0554696656763554,0.221464142203331,0.974918186664581,-0.0220953188836575,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,-0,-1,0,-0,-1, +0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1, +-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0 + } + BinormalsW: *768 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *2304 { + a: 0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965207040309906,0.26148721575737,0,0.965207040309906,0.26148721575737,0,0.965207040309906,0.26148721575737,0,0.965207040309906,0.26148721575737,0,0.965206980705261,-0,-0.261487126350403,0.965206980705261,-0,-0.261487126350403,0.965206980705261,-0,-0.261487126350403,0.965206980705261,-0,-0.261487126350403,0.965206980705261,-0.261487156152725,-0,0.965206980705261,-0.261487156152725,-0,0.965206980705261,-0.261487156152725,-0,0.965206980705261,-0.261487156152725,-0,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,0.965206980705261,-0.261487156152725,0,0.965206980705261,-0.261487156152725,0,0.965206980705261,-0.261487156152725,0,0.965206980705261,-0.261487156152725,0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,-0,0,1,0,0,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,-0,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0.26148721575737,-0,0.965207040309906, +0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0.97571212053299,0.00952975451946259,0.218849271535873,0.997704029083252,-0.0677256807684898,0,0.972207129001617,-0.145124465227127,0.183717742562294,0.977037787437439,-0.0680116266012192,0.201919630169868,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0.97571212053299,0.218849420547485,-0.0095297135412693,0.997703969478607,0,0.0677258297801018,0.972207069396973,0.183717846870422,0.145124778151512,0.977037727832794,0.20191977918148,0.0680118054151535,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0.975712060928345,-0.00952968932688236,-0.21884959936142,0.997703969478607,0.0677258297801018,0,0.972207009792328,0.145124763250351,-0.183717966079712,0.977037727832794,0.0680118054151535,-0.201919928193092,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0.97571212053299,-0.218849316239357,0.00952973961830139,0.997703969478607,0,-0.0677259787917137,0.972207069396973,-0.183717638254166,-0.145125105977058,0.977037727832794,-0.201919630169868,-0.068011961877346,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0.218849301338196,0.00952973961830139,-0.97571212053299,0,-0.0677256807684898,-0.997704029083252,0.1837178170681,-0.145124509930611,-0.972207069396973,0.201919689774513,-0.0680116564035416,-0.977037787437439,-0,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.218849420547485,0.0095297172665596,0.97571212053299,0,-0.0677257031202316,0.997704029083252,-0.183717906475067,-0.145124524831772,0.972207069396973,-0.201919823884964,-0.068011686205864,0.977037727832794,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0.972207129001617,0.145124465227127,-0.183717742562294,0.997704029083252,0.0677256733179092,0,0.97571212053299,-0.00952975824475288,-0.218849256634712,0.977037787437439,0.0680116191506386,-0.201919630169868,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403, +1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0.97571212053299,0.00952975172549486,-0.218849286437035,0.997703969478607,-0.0677258223295212,0,0.972207069396973,-0.14512474834919,-0.183717682957649,0.977037847042084,-0.0680117681622505,-0.20191964507103,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,0.972207069396973,0.14512474834919,0.183717668056488,0.997703969478607,0.0677258297801018,0,0.97571212053299,-0.00952975451946259,0.218849271535873,0.977037847042084,0.0680117756128311,0.201919630169868,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,1,-0,-0,1,-0,0,1,-0,0,1,-0,0,0.972207069396973,-0.183717831969261,-0.145124778151512,0.997703969478607,0,-0.0677258223295212,0.97571212053299,-0.218849420547485,0.00952972378581762,0.977037727832794,-0.20191977918148,-0.0680117979645729,0.965207040309906,-0.26148721575737,-0,0.965207040309906,-0.26148721575737,-0,0.965207040309906,-0.26148721575737,-0,0.965207040309906,-0.26148721575737,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0.97571212053299,-0.218849420547485,-0.0095297247171402,0.997703969478607,0,0.0677259713411331,0.972207009792328,-0.183717742562294,0.145125061273575,0.977037727832794,-0.201919749379158,0.0680119395256042,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,-0,-0,1,0,0,0.972207009792328,0.183717772364616,-0.145125061273575,0.997703969478607,0,-0.0677259787917137,0.97571212053299,0.218849420547485,0.00952971447259188,0.977037727832794,0.20191977918148,-0.0680119544267654,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,-0,0.965206980705261,0.261487156152725,0,1,-0,0,1,0,0,1,0,0,1,0,0,0.972207009792328,-0.14512474834919,0.183717995882034,0.997703969478607,-0.0677258223295212,0,0.975712060928345,0.00952969118952751,0.218849584460258,0.977037727832794,-0.0680117979645729,0.201919928193092,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403, +1,-0,0,1,-0,0,1,-0,0,1,-0,0,0.975712060928345,-0.00952969212085009,0.218849584460258,0.997704029083252,0.0677256733179092,0,0.972207069396973,0.145124465227127,0.183718055486679,0.977037727832794,0.0680116564035416,0.201919972896576,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,0.972207069396973,-0.145124480128288,-0.183718040585518,0.997704029083252,-0.0677256807684898,0,0.975712060928345,0.00952969398349524,-0.218849569559097,0.977037727832794,-0.0680116713047028,-0.201919972896576,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,-0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,1,0,0,1,0,0,1,0,0,1,0,0,0.972207069396973,0.183717623353004,0.145125105977058,0.997703969478607,0,0.0677259713411331,0.97571212053299,0.218849316239357,-0.00952974893152714,0.977037847042084,0.201919630169868,0.0680119544267654,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0.97571212053299,0.218849271535873,0.00952975638210773,0.997703969478607,0,-0.0677258223295212,0.972207069396973,0.183717668056488,-0.145124807953835,0.977037847042084,0.201919630169868,-0.0680118054151535,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0.972207069396973,-0.183717682957649,0.145124822854996,0.997703969478607,0,0.0677258297801018,0.97571212053299,-0.218849286437035,-0.00952974427491426,0.977037847042084,-0.201919630169868,0.0680118054151535,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,-0.183717846870422,0.145124554634094,-0.972207069396973,0,0.0677257031202316,-0.997704029083252,-0.218849360942841,-0.0095297284424305,-0.97571212053299,-0.20191977918148,0.068011686205864,-0.977037727832794,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906, +0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.218849450349808,0.00952971167862415,-0.97571212053299,0,-0.0677258521318436,-0.997703969478607,-0.1837178170681,-0.145124852657318,-0.972207069396973,-0.201919764280319,-0.0680118426680565,-0.977037727832794,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0,0,-1,0,0,-1,0.183717772364616,0.145124807953835,-0.972207069396973,0,0.0677258297801018,-0.997703969478607,0.218849375844002,-0.00952972657978535,-0.97571212053299,0.201919689774513,0.0680118054151535,-0.977037727832794,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0.183717876672745,0.145124495029449,0.972207069396973,0,0.0677256807684898,0.997704029083252,0.218849375844002,-0.00952972192317247,0.97571212053299,0.20191977918148,0.0680116564035416,0.977037727832794,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0.218849420547485,0.0095297135412693,0.97571212053299,0,-0.0677258297801018,0.997703969478607,0.183717846870422,-0.145124778151512,0.972207069396973,0.20191977918148,-0.0680118054151535,0.977037727832794,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,-0.183717906475067,0.145124837756157,0.972207009792328,0,0.0677258521318436,0.997703969478607,-0.21884948015213,-0.00952970236539841,0.97571212053299,-0.201919838786125,0.0680118277668953,0.977037727832794,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,0,-0,1,0,-0,1,0,-0,1,0,-0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,0,1,0,0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0,0,1,0,0,1,0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0, +1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1, +0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1 + } + TangentsW: *768 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *542 { + a: 0.375,0,0.625,0,0.375,0.25,0.625,0.25,0.375,0.5,0.625,0.5,0.375,0.75,0.625,0.75,0.375,1,0.625,1,0.875,0,0.875,0.25,0.125,0,0.125,0.25,0.5,0.125,0.5,0,0.5,1,0.625,0.125,0.5,0.25,0.375,0.125,0.5,0.375,0.625,0.375,0.75,0.25,0.5,0.5,0.375,0.375,0.25,0.25,0.5,0.625,0.625,0.625,0.875,0.125,0.5,0.75,0.375,0.625,0.125,0.125,0.5,0.875,0.625,0.875,0.75,0,0.5,1,0.375,0.875,0.25,0,0.75,0.125,0.75,0,0.875,0.125,0.75,0.25,0.25,0.125,0.25,0,0.25,0.25,0.125,0.125,0.4375,0.0625,0.375,0.0625,0.4375,0,0.4375,1,0.5,0.0625,0.4375,0.125,0.4375,0.3125,0.375,0.3125,0.3125,0.25,0.4375,0.25,0.5,0.3125,0.4375,0.375,0.4375,0.5625,0.375,0.5625,0.125,0.1875,0.4375,0.5,0.5,0.5625,0.4375,0.625,0.4375,0.8125,0.375,0.8125,0.1875,0,0.4375,0.75,0.5,0.8125,0.4375,0.875,0.6875,0.0625,0.625,0.0625,0.625,0.9375,0.6875,0,0.75,0.0625,0.6875,0.125,0.1875,0.0625,0.375,0.6875,0.125,0.0625,0.1875,0,0.25,0.0625,0.1875,0.125,0.5625,0.0625,0.5625,0,0.5625,1,0.5625,0.125,0.5625,0.1875,0.625,0.1875,0.5625,0.25,0.5,0.1875,0.4375,0.1875,0.375,0.1875,0.5625,0.3125,0.625,0.3125,0.6875,0.25,0.5625,0.375,0.5625,0.4375,0.625,0.4375,0.8125,0.25,0.5625,0.5,0.5,0.4375,0.4375,0.4375,0.375,0.4375,0.1875,0.25,0.5625,0.5625,0.625,0.5625,0.875,0.1875,0.5625,0.625,0.5625,0.6875,0.625,0.6875,0.875,0.0625,0.5625,0.75,0.5,0.6875,0.4375,0.6875,0.375,0.6875,0.5625,0.8125,0.625,0.8125,0.8125,0,0.5625,0.875,0.5625,0.9375,0.625,0.9375,0.5625,1,0.5,0.9375,0.4375,0.9375,0.4375,1,0.375,0.9375,0.3125,0,0.8125,0.0625,0.8125,0,0.875,0.0625,0.8125,0.125,0.8125,0.1875,0.875,0.1875,0.8125,0.25,0.75,0.1875,0.6875,0.1875,0.6875,0.25,0.3125,0.0625,0.3125,0,0.3125,0.125,0.3125,0.1875,0.3125,0.25,0.25,0.1875,0.1875,0.1875,0.1875,0.25,0.125,0.1875,0.4375,0.125,0.375,0.125,0.375,0.0625,0.4375,0.0625,0.4375,0.375,0.375,0.375,0.375,0.3125,0.4375,0.3125,0.4375,0.625,0.375,0.625,0.375,0.5625,0.4375,0.5625,0.4375,0.875,0.375,0.875,0.375,0.8125,0.4375,0.8125,0.6875,0.125,0.625,0.125,0.625,0.0625,0.6875,0.0625,0.1875,0.125,0.125,0.125,0.125,0.0625,0.1875,0.0625,0.5,0.0625,0.5,0,0.5625,0, +0.5625,0.0625,0.5625,0.125,0.625,0.1875,0.5625,0.1875,0.5,0.1875,0.5,0.25,0.4375,0.25,0.4375,0.1875,0.5,0.3125,0.5625,0.25,0.5625,0.3125,0.5625,0.375,0.625,0.375,0.625,0.4375,0.5625,0.4375,0.5,0.4375,0.5,0.5,0.4375,0.5,0.4375,0.4375,0.5,0.5625,0.5625,0.5,0.5625,0.5625,0.5625,0.625,0.625,0.625,0.625,0.6875,0.5625,0.6875,0.5,0.6875,0.5,0.75,0.4375,0.75,0.4375,0.6875,0.5,0.8125,0.5625,0.75,0.5625,0.8125,0.5625,0.875,0.625,0.875,0.625,0.9375,0.5625,0.9375,0.5,0.9375,0.5,1,0.4375,1,0.4375,0.9375,0.75,0.0625,0.75,0,0.8125,0,0.8125,0.0625,0.8125,0.125,0.875,0.125,0.875,0.1875,0.8125,0.1875,0.75,0.1875,0.75,0.25,0.6875,0.25,0.6875,0.1875,0.25,0.0625,0.25,0,0.3125,0,0.3125,0.0625,0.3125,0.125,0.375,0.1875,0.3125,0.1875,0.25,0.1875,0.25,0.25,0.1875,0.25,0.1875,0.1875,0.375,0,0.4375,0,0.5,0.125,0.375,0.25,0.5,0.375,0.375,0.5,0.5,0.625,0.375,0.75,0.5,0.875,0.625,0,0.6875,0,0.75,0.125,0.125,0,0.1875,0,0.25,0.125,0.625,0.25,0.625,0.3125,0.625,0.5,0.375,0.4375,0.625,0.5625,0.625,0.75,0.375,0.6875,0.625,0.8125,0.625,1,0.5625,1,0.375,1,0.375,0.9375,0.875,0,0.875,0.0625,0.875,0.25,0.8125,0.25,0.3125,0.25,0.125,0.25,0.125,0.1875 + } + UVIndex: *768 { + a: 51,19,47,46,57,24,53,52,63,30,59,58,69,36,65,64,75,17,71,70,81,45,78,76,50,15,83,82,85,17,87,86,89,18,55,90,56,18,88,92,95,21,97,96,100,23,61,101,62,23,99,104,107,27,109,108,112,29,67,113,68,29,111,115,118,33,120,119,122,35,124,123,74,39,128,127,130,40,132,131,134,41,136,135,80,43,138,137,139,19,91,140,142,44,144,143,47,0,48,46,48,15,50,46,50,14,51,46,53,2,55,52,55,18,56,52,56,20,57,52,59,4,61,58,61,23,62,58,62,26,63,58,65,6,67,64,67,29,68,64,68,32,69,64,71,1,73,70,73,39,74,70,74,38,75,70,78,12,79,76,79,43,80,76,80,42,81,76,83,1,71,82,71,17,85,82,85,14,50,82,87,3,88,86,88,18,89,86,89,14,85,86,55,2,91,90,91,19,51,90,51,14,89,90,88,3,93,92,93,21,95,92,95,20,56,92,97,5,99,96,99,23,100,96,100,20,95,96,61,4,102,101,102,24,57,101,57,20,100,101,99,5,105,104,105,27,107,104,107,26,62,104,109,7,111,108,111,29,112,108,112,26,107,108,67,6,114,113,114,30,63,113,63,26,112,113,111,7,116,115,116,33,118,115,118,32,68,115,120,9,121,119,121,35,122,119,122,32,118,119,124,8,125,123,125,36,69,123,69,32,122,123,128,10,129,127,129,40,130,127,130,38,74,127,132,11,133,131,133,41,134,131,134,38,130,131,136,3,87,135,87,17,75,135,75,38,134,135,138,0,47,137,47,19,139,137,139,42,80,137,91,2,141,140,141,44,142,140,142,42,139,140,144,13,145,143,145,45,81,143,81,42,142,143,146,149,148,147,150,153,152,151,154,157,156,155,158,161,160,159,162,165,164,163,166,169,168,167,170,173,172,171,174,176,175,163,177,180,179,178,181,183,182,178,184,187,186,185,188,191,190,189,192,194,193,189,195,198,197,196,199,202,201,200,203,205,204,200,206,209,208,207,210,213,212,211,214,217,216,215,218,221,220,219,222,225,224,223,226,229,228,227,230,232,231,147,233,236,235,234,148,149,238,237,238,149,170,171,170,149,146,239,152,153,179,240,179,153,181,178,181,153,150,241,156,157,190,242,190,157,192,189,192,157,154,243,160,161,201,244,201,161,203,200,203,161,158,245,164,165,247,246,247,165,214,215,214,165,162,248,168,169,250,249,250,169,226,227,226,169,166,251,172,173,164,246,164,173,174,163,174,173,170,239,175,176,182,252,182,176,177,178,177,176,174,239, +179,180,231,240,231,180,146,147,146,180,177,239,182,183,253,252,253,183,184,185,184,183,181,241,186,187,193,254,193,187,188,189,188,187,184,241,190,191,255,242,255,191,150,151,150,191,188,241,193,194,256,254,256,194,195,196,195,194,192,243,197,198,204,257,204,198,199,200,199,198,195,243,201,202,258,244,258,202,154,155,154,202,199,243,204,205,259,257,259,205,206,207,206,205,203,245,208,209,261,260,261,209,210,211,210,209,206,245,212,213,263,262,263,213,158,159,158,213,210,245,216,217,265,264,265,217,218,219,218,217,214,248,220,221,267,266,267,221,222,223,222,221,218,248,224,225,175,252,175,225,162,163,162,225,222,248,228,229,148,237,148,229,230,147,230,229,226,251,231,232,268,240,268,232,233,234,233,232,230,251,235,236,270,269,270,236,166,167,166,236,233,251 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *384 { + a: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Model: 1827098352032, "Model::Cube2", "Mesh" { + Version: 232 + Properties70: { + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",-0.0104023897647858,0.00998288810253143,-0.0104375958442688 + P: "Lcl Scaling", "Lcl Scaling", "", "A",0.1,-0.1,0.1 + P: "currentUVSet", "KString", "", "U", "map1" + } + Shading: T + Culling: "CullingOff" + } + Model: 1827098379872, "Model::Cube1", "Mesh" { + Version: 232 + Properties70: { + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",1.04023897647858,-0.998288810253143,1.04375958442688 + P: "currentUVSet", "KString", "", "U", "map1" + } + Shading: T + Culling: "CullingOff" + } + Model: 1827098382192, "Model::Cube3", "Mesh" { + Version: 232 + Properties70: { + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",-0.0106711769104004,0.00998288810253143,0.0939023494720459 + P: "Lcl Scaling", "Lcl Scaling", "", "A",0.1,0.1,0.1 + P: "currentUVSet", "KString", "", "U", "map1" + } + Shading: T + Culling: "CullingOff" + } + Model: 1827098384512, "Model::Cube1", "Mesh" { + Version: 232 + Properties70: { + P: "RotationPivot", "Vector3D", "Vector", "",-0.578102593944473,0.709856817059169,-0.892474638271642 + P: "ScalingOffset", "Vector3D", "Vector", "",0.168946330316482,-0.207450555573549,0.260819301999204 + P: "ScalingPivot", "Vector3D", "Vector", "",-0.747048924260949,0.917307372632704,-1.15329394027084 + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",1.04023897647858,-0.998288810253143,1.18067407608032 + P: "Lcl Scaling", "Lcl Scaling", "", "A",0.77384837213491,0.77384837213491,0.77384837213491 + P: "currentUVSet", "KString", "", "U", "map1" + } + Shading: T + Culling: "CullingOff" + } + Material: 1827074508720, "Material::Mat_Green", "" { + Version: 102 + ShadingModel: "lambert" + MultiLayer: 0 + Properties70: { + P: "AmbientColor", "Color", "", "A",0,0,0 + P: "DiffuseColor", "Color", "", "A",0,1,0 + P: "DiffuseFactor", "Number", "", "A",0.800000011920929 + P: "TransparencyFactor", "Number", "", "A",1 + P: "Emissive", "Vector3D", "Vector", "",0,0,0 + P: "Ambient", "Vector3D", "Vector", "",0,0,0 + P: "Diffuse", "Vector3D", "Vector", "",0,0.800000011920929,0 + P: "Opacity", "double", "Number", "",1 + } + } + Material: 1827074501920, "Material::Mat_Red", "" { + Version: 102 + ShadingModel: "lambert" + MultiLayer: 0 + Properties70: { + P: "AmbientColor", "Color", "", "A",0,0,0 + P: "DiffuseColor", "Color", "", "A",1,0,0 + P: "DiffuseFactor", "Number", "", "A",0.800000011920929 + P: "TransparencyFactor", "Number", "", "A",1 + P: "Emissive", "Vector3D", "Vector", "",0,0,0 + P: "Ambient", "Vector3D", "Vector", "",0,0,0 + P: "Diffuse", "Vector3D", "Vector", "",0.800000011920929,0,0 + P: "Opacity", "double", "Number", "",1 + } + } + AnimationStack: 1825586153728, "AnimStack::Take 001", "" { + Properties70: { + P: "LocalStart", "KTime", "Time", "",1924423250 + P: "LocalStop", "KTime", "Time", "",230930790000 + P: "ReferenceStart", "KTime", "Time", "",1924423250 + P: "ReferenceStop", "KTime", "Time", "",230930790000 + } + } + AnimationLayer: 1827070038960, "AnimLayer::BaseLayer", "" { + } +} + +; Object connections +;------------------------------------------------------------------ + +Connections: { + + ;Model::Cube2, Model::RootNode + C: "OO",1827098352032,0 + + ;Model::Cube3, Model::RootNode + C: "OO",1827098382192,0 + + ;AnimLayer::BaseLayer, AnimStack::Take 001 + C: "OO",1827070038960,1825586153728 + + ;Geometry::, Model::Cube2 + C: "OO",1827080157856,1827098352032 + + ;Material::Mat_Green, Model::Cube2 + C: "OO",1827074508720,1827098352032 + + ;Model::Cube1, Model::Cube2 + C: "OO",1827098379872,1827098352032 + + ;Geometry::, Model::Cube1 + C: "OO",1827080155296,1827098379872 + + ;Material::Mat_Green, Model::Cube1 + C: "OO",1827074508720,1827098379872 + + ;Geometry::, Model::Cube3 + C: "OO",1827080156320,1827098382192 + + ;Material::Mat_Red, Model::Cube3 + C: "OO",1827074501920,1827098382192 + + ;Model::Cube1, Model::Cube3 + C: "OO",1827098384512,1827098382192 + + ;Geometry::, Model::Cube1 + C: "OO",1827080139424,1827098384512 + + ;Material::Mat_Red, Model::Cube1 + C: "OO",1827074501920,1827098384512 +} +;Takes section +;---------------------------------------------------- + +Takes: { + Current: "Take 001" + Take: "Take 001" { + FileName: "Take_001.tak" + LocalTime: 1924423250,230930790000 + ReferenceTime: 1924423250,230930790000 + } +} diff --git a/test/models/FBX/cubes_with_names.fbx b/test/models/FBX/cubes_with_names.fbx new file mode 100644 index 000000000..203543ec8 --- /dev/null +++ b/test/models/FBX/cubes_with_names.fbx @@ -0,0 +1,852 @@ +; FBX 7.5.0 project file +; ---------------------------------------------------- + +FBXHeaderExtension: { + FBXHeaderVersion: 1003 + FBXVersion: 7500 + CreationTimeStamp: { + Version: 1000 + Year: 2019 + Month: 1 + Day: 7 + Hour: 16 + Minute: 17 + Second: 31 + Millisecond: 730 + } + Creator: "FBX SDK/FBX Plugins version 2018.1.1" + SceneInfo: "SceneInfo::GlobalInfo", "UserData" { + Type: "UserData" + Version: 100 + MetaData: { + Version: 100 + Title: "" + Subject: "" + Author: "" + Keywords: "" + Revision: "" + Comment: "" + } + Properties70: { + P: "DocumentUrl", "KString", "Url", "", "U:\Some\Absolute\Path\cubes_with_names.fbx" + P: "SrcDocumentUrl", "KString", "Url", "", "U:\Some\Absolute\Path\cubes_with_names.fbx" + P: "Original", "Compound", "", "" + P: "Original|ApplicationVendor", "KString", "", "", "Autodesk" + P: "Original|ApplicationName", "KString", "", "", "Maya" + P: "Original|ApplicationVersion", "KString", "", "", "201800" + P: "Original|DateTime_GMT", "DateTime", "", "", "07/01/2019 16:17:31.730" + P: "Original|FileName", "KString", "", "", "U:\Some\Absolute\Path\cubes_with_names.fbx" + P: "LastSaved", "Compound", "", "" + P: "LastSaved|ApplicationVendor", "KString", "", "", "Autodesk" + P: "LastSaved|ApplicationName", "KString", "", "", "Maya" + P: "LastSaved|ApplicationVersion", "KString", "", "", "201800" + P: "LastSaved|DateTime_GMT", "DateTime", "", "", "07/01/2019 16:17:31.730" + P: "Original|ApplicationActiveProject", "KString", "", "", "U:\Some\Absolute\Path" + } + } +} +GlobalSettings: { + Version: 1000 + Properties70: { + P: "UpAxis", "int", "Integer", "",1 + P: "UpAxisSign", "int", "Integer", "",1 + P: "FrontAxis", "int", "Integer", "",2 + P: "FrontAxisSign", "int", "Integer", "",1 + P: "CoordAxis", "int", "Integer", "",0 + P: "CoordAxisSign", "int", "Integer", "",1 + P: "OriginalUpAxis", "int", "Integer", "",1 + P: "OriginalUpAxisSign", "int", "Integer", "",1 + P: "UnitScaleFactor", "double", "Number", "",1 + P: "OriginalUnitScaleFactor", "double", "Number", "",1 + P: "AmbientColor", "ColorRGB", "Color", "",0,0,0 + P: "DefaultCamera", "KString", "", "", "Producer Perspective" + P: "TimeMode", "enum", "", "",11 + P: "TimeProtocol", "enum", "", "",2 + P: "SnapOnFrameMode", "enum", "", "",0 + P: "TimeSpanStart", "KTime", "Time", "",1924423250 + P: "TimeSpanStop", "KTime", "Time", "",384884650000 + P: "CustomFrameRate", "double", "Number", "",-1 + P: "TimeMarker", "Compound", "", "" + P: "CurrentTimeMarker", "int", "Integer", "",-1 + } +} + +; Documents Description +;------------------------------------------------------------------ + +Documents: { + Count: 1 + Document: 2359325563280, "", "Scene" { + Properties70: { + P: "SourceObject", "object", "", "" + P: "ActiveAnimStackName", "KString", "", "", "Take 001" + } + RootNode: 0 + } +} + +; Document References +;------------------------------------------------------------------ + +References: { +} + +; Object definitions +;------------------------------------------------------------------ + +Definitions: { + Version: 100 + Count: 13 + ObjectType: "GlobalSettings" { + Count: 1 + } + ObjectType: "AnimationStack" { + Count: 1 + PropertyTemplate: "FbxAnimStack" { + Properties70: { + P: "Description", "KString", "", "", "" + P: "LocalStart", "KTime", "Time", "",0 + P: "LocalStop", "KTime", "Time", "",0 + P: "ReferenceStart", "KTime", "Time", "",0 + P: "ReferenceStop", "KTime", "Time", "",0 + } + } + } + ObjectType: "AnimationLayer" { + Count: 1 + PropertyTemplate: "FbxAnimLayer" { + Properties70: { + P: "Weight", "Number", "", "A",100 + P: "Mute", "bool", "", "",0 + P: "Solo", "bool", "", "",0 + P: "Lock", "bool", "", "",0 + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "BlendMode", "enum", "", "",0 + P: "RotationAccumulationMode", "enum", "", "",0 + P: "ScaleAccumulationMode", "enum", "", "",0 + P: "BlendModeBypass", "ULongLong", "", "",0 + } + } + } + ObjectType: "Geometry" { + Count: 4 + PropertyTemplate: "FbxMesh" { + Properties70: { + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "BBoxMin", "Vector3D", "Vector", "",0,0,0 + P: "BBoxMax", "Vector3D", "Vector", "",0,0,0 + P: "Primary Visibility", "bool", "", "",1 + P: "Casts Shadows", "bool", "", "",1 + P: "Receive Shadows", "bool", "", "",1 + } + } + } + ObjectType: "Material" { + Count: 2 + PropertyTemplate: "FbxSurfaceLambert" { + Properties70: { + P: "ShadingModel", "KString", "", "", "Lambert" + P: "MultiLayer", "bool", "", "",0 + P: "EmissiveColor", "Color", "", "A",0,0,0 + P: "EmissiveFactor", "Number", "", "A",1 + P: "AmbientColor", "Color", "", "A",0.2,0.2,0.2 + P: "AmbientFactor", "Number", "", "A",1 + P: "DiffuseColor", "Color", "", "A",0.8,0.8,0.8 + P: "DiffuseFactor", "Number", "", "A",1 + P: "Bump", "Vector3D", "Vector", "",0,0,0 + P: "NormalMap", "Vector3D", "Vector", "",0,0,0 + P: "BumpFactor", "double", "Number", "",1 + P: "TransparentColor", "Color", "", "A",0,0,0 + P: "TransparencyFactor", "Number", "", "A",0 + P: "DisplacementColor", "ColorRGB", "Color", "",0,0,0 + P: "DisplacementFactor", "double", "Number", "",1 + P: "VectorDisplacementColor", "ColorRGB", "Color", "",0,0,0 + P: "VectorDisplacementFactor", "double", "Number", "",1 + } + } + } + ObjectType: "Model" { + Count: 4 + PropertyTemplate: "FbxNode" { + Properties70: { + P: "QuaternionInterpolate", "enum", "", "",0 + P: "RotationOffset", "Vector3D", "Vector", "",0,0,0 + P: "RotationPivot", "Vector3D", "Vector", "",0,0,0 + P: "ScalingOffset", "Vector3D", "Vector", "",0,0,0 + P: "ScalingPivot", "Vector3D", "Vector", "",0,0,0 + P: "TranslationActive", "bool", "", "",0 + P: "TranslationMin", "Vector3D", "Vector", "",0,0,0 + P: "TranslationMax", "Vector3D", "Vector", "",0,0,0 + P: "TranslationMinX", "bool", "", "",0 + P: "TranslationMinY", "bool", "", "",0 + P: "TranslationMinZ", "bool", "", "",0 + P: "TranslationMaxX", "bool", "", "",0 + P: "TranslationMaxY", "bool", "", "",0 + P: "TranslationMaxZ", "bool", "", "",0 + P: "RotationOrder", "enum", "", "",0 + P: "RotationSpaceForLimitOnly", "bool", "", "",0 + P: "RotationStiffnessX", "double", "Number", "",0 + P: "RotationStiffnessY", "double", "Number", "",0 + P: "RotationStiffnessZ", "double", "Number", "",0 + P: "AxisLen", "double", "Number", "",10 + P: "PreRotation", "Vector3D", "Vector", "",0,0,0 + P: "PostRotation", "Vector3D", "Vector", "",0,0,0 + P: "RotationActive", "bool", "", "",0 + P: "RotationMin", "Vector3D", "Vector", "",0,0,0 + P: "RotationMax", "Vector3D", "Vector", "",0,0,0 + P: "RotationMinX", "bool", "", "",0 + P: "RotationMinY", "bool", "", "",0 + P: "RotationMinZ", "bool", "", "",0 + P: "RotationMaxX", "bool", "", "",0 + P: "RotationMaxY", "bool", "", "",0 + P: "RotationMaxZ", "bool", "", "",0 + P: "InheritType", "enum", "", "",0 + P: "ScalingActive", "bool", "", "",0 + P: "ScalingMin", "Vector3D", "Vector", "",0,0,0 + P: "ScalingMax", "Vector3D", "Vector", "",1,1,1 + P: "ScalingMinX", "bool", "", "",0 + P: "ScalingMinY", "bool", "", "",0 + P: "ScalingMinZ", "bool", "", "",0 + P: "ScalingMaxX", "bool", "", "",0 + P: "ScalingMaxY", "bool", "", "",0 + P: "ScalingMaxZ", "bool", "", "",0 + P: "GeometricTranslation", "Vector3D", "Vector", "",0,0,0 + P: "GeometricRotation", "Vector3D", "Vector", "",0,0,0 + P: "GeometricScaling", "Vector3D", "Vector", "",1,1,1 + P: "MinDampRangeX", "double", "Number", "",0 + P: "MinDampRangeY", "double", "Number", "",0 + P: "MinDampRangeZ", "double", "Number", "",0 + P: "MaxDampRangeX", "double", "Number", "",0 + P: "MaxDampRangeY", "double", "Number", "",0 + P: "MaxDampRangeZ", "double", "Number", "",0 + P: "MinDampStrengthX", "double", "Number", "",0 + P: "MinDampStrengthY", "double", "Number", "",0 + P: "MinDampStrengthZ", "double", "Number", "",0 + P: "MaxDampStrengthX", "double", "Number", "",0 + P: "MaxDampStrengthY", "double", "Number", "",0 + P: "MaxDampStrengthZ", "double", "Number", "",0 + P: "PreferedAngleX", "double", "Number", "",0 + P: "PreferedAngleY", "double", "Number", "",0 + P: "PreferedAngleZ", "double", "Number", "",0 + P: "LookAtProperty", "object", "", "" + P: "UpVectorProperty", "object", "", "" + P: "Show", "bool", "", "",1 + P: "NegativePercentShapeSupport", "bool", "", "",1 + P: "DefaultAttributeIndex", "int", "Integer", "",-1 + P: "Freeze", "bool", "", "",0 + P: "LODBox", "bool", "", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",0,0,0 + P: "Lcl Rotation", "Lcl Rotation", "", "A",0,0,0 + P: "Lcl Scaling", "Lcl Scaling", "", "A",1,1,1 + P: "Visibility", "Visibility", "", "A",1 + P: "Visibility Inheritance", "Visibility Inheritance", "", "",1 + } + } + } +} + +; Object properties +;------------------------------------------------------------------ + +Objects: { + Geometry: 2358377979296, "Geometry::", "Mesh" { + Vertices: *24 { + a: -0.5,-0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,-0.5,-0.5,-0.5,-0.5,0.5,-0.5,-0.5 + } + PolygonVertexIndex: *24 { + a: 0,1,3,-3,2,3,5,-5,4,5,7,-7,6,7,1,-1,1,7,5,-4,6,0,2,-5 + } + Edges: *12 { + a: 0,1,2,3,5,6,7,9,10,11,13,15 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *72 { + a: 0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 + } + NormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *72 { + a: 0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,-0,1,0,-0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0 + } + BinormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *72 { + a: 1,-0,-0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0,-0,1,0,-0,1,0,-0,1,0,-0,1 + } + TangentsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *28 { + a: 0.375,0,0.625,0,0.375,0.25,0.625,0.25,0.375,0.5,0.625,0.5,0.375,0.75,0.625,0.75,0.375,1,0.625,1,0.875,0,0.875,0.25,0.125,0,0.125,0.25 + } + UVIndex: *24 { + a: 0,1,3,2,2,3,5,4,4,5,7,6,6,7,9,8,1,10,11,3,12,0,2,13 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *12 { + a: 0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Geometry: 2358377961872, "Geometry::", "Mesh" { + Vertices: *24 { + a: -0.5,-0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,-0.5,-0.5,-0.5,-0.5,0.5,-0.5,-0.5 + } + PolygonVertexIndex: *24 { + a: 0,1,3,-3,2,3,5,-5,4,5,7,-7,6,7,1,-1,1,7,5,-4,6,0,2,-5 + } + Edges: *12 { + a: 0,1,2,3,5,6,7,9,10,11,13,15 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *72 { + a: 0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 + } + NormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *72 { + a: 0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,-0,1,0,-0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0 + } + BinormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *72 { + a: 1,-0,-0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0,-0,1,0,-0,1,0,-0,1,0,-0,1 + } + TangentsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *28 { + a: 0.375,0,0.625,0,0.375,0.25,0.625,0.25,0.375,0.5,0.625,0.5,0.375,0.75,0.625,0.75,0.375,1,0.625,1,0.875,0,0.875,0.25,0.125,0,0.125,0.25 + } + UVIndex: *24 { + a: 0,1,3,2,2,3,5,4,4,5,7,6,6,7,9,8,1,10,11,3,12,0,2,13 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *12 { + a: 0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Geometry: 2358377982464, "Geometry::", "Mesh" { + Vertices: *24 { + a: -0.5,-0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,0.5,0.5,0.5,-0.5,0.5,-0.5,0.5,0.5,-0.5,-0.5,-0.5,-0.5,0.5,-0.5,-0.5 + } + PolygonVertexIndex: *24 { + a: 0,1,3,-3,2,3,5,-5,4,5,7,-7,6,7,1,-1,1,7,5,-4,6,0,2,-5 + } + Edges: *12 { + a: 0,1,2,3,5,6,7,9,10,11,13,15 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *72 { + a: 0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 + } + NormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *72 { + a: 0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,-0,1,0,-0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0 + } + BinormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *72 { + a: 1,-0,-0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0,-0,1,0,-0,1,0,-0,1,0,-0,1 + } + TangentsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *28 { + a: 0.375,0,0.625,0,0.375,0.25,0.625,0.25,0.375,0.5,0.625,0.5,0.375,0.75,0.625,0.75,0.375,1,0.625,1,0.875,0,0.875,0.25,0.125,0,0.125,0.25 + } + UVIndex: *24 { + a: 0,1,3,2,2,3,5,4,4,5,7,6,6,7,9,8,1,10,11,3,12,0,2,13 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *12 { + a: 0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Geometry: 2358377979824, "Geometry::", "Mesh" { + Vertices: *588 { + a: -0.499999970197678,-0.5,0.5,0.500000059604645,-0.5,0.5,-0.499999970197678,0.5,0.5,0.500000059604645,0.5,0.5,-0.499999970197678,0.5,-0.49999988079071,0.500000059604645,0.5,-0.49999988079071,-0.499999970197678,-0.5,-0.49999988079071,0.500000059604645,-0.5,-0.49999988079071,0,0,0.5,0,-0.5,0.5,0.500000059604645,0,0.5,0,0.5,0.5,-0.499999970197678,0,0.5,0,0.5,1.19209289550781e-07,0.500000059604645,0.5,1.19209289550781e-07,0,0.5,-0.49999988079071,-0.499999970197678,0.5,1.19209289550781e-07,0,0,-0.49999988079071,0.500000059604645,0,-0.49999988079071,0,-0.5,-0.49999988079071,-0.499999970197678,0,-0.49999988079071,0,-0.5,1.19209289550781e-07,0.500000059604645,-0.5,1.19209289550781e-07,-0.499999970197678,-0.5,1.19209289550781e-07,0.500000059604645,0,1.19209289550781e-07,-0.499999970197678,0,1.19209289550781e-07,-0.25,-0.25,0.5,-0.499999970197678,-0.25,0.5,-0.25,-0.5,0.5,0,-0.25,0.5,-0.25,0,0.5,-0.25,0.5,0.25,-0.499999970197678,0.5,0.25,-0.25,0.5,0.5,0,0.5,0.25,-0.25,0.5,1.19209289550781e-07,-0.25,0.25,-0.49999988079071,-0.499999970197678,0.25,-0.49999988079071,-0.25,0.5,-0.49999988079071,0,0.25,-0.49999988079071,-0.25,0,-0.49999988079071,-0.25,-0.5,-0.24999988079071,-0.499999970197678,-0.5,-0.24999988079071,-0.25,-0.5,-0.49999988079071,0,-0.5,-0.24999988079071,-0.25,-0.5,1.19209289550781e-07,0.500000059604645,-0.25,0.25,0.500000059604645,-0.25,0.5,0.500000059604645,-0.5,0.25,0.500000059604645,-0.25,1.19209289550781e-07,0.500000059604645,0,0.25,-0.499999970197678,-0.25,-0.24999988079071,-0.499999970197678,-0.25,-0.49999988079071,-0.499999970197678,-0.25,1.19209289550781e-07,-0.499999970197678,0,-0.24999988079071,0.250000059604645,-0.25,0.5,0.250000059604645,-0.5,0.5,0.250000059604645,0,0.5,0.250000059604645,0.25,0.5,0.500000059604645,0.25,0.5,0.250000059604645,0.5,0.5,0,0.25,0.5,-0.25,0.25,0.5,-0.499999970197678,0.25,0.5,0.250000059604645,0.5,0.25,0.500000059604645,0.5,0.25,0.250000059604645,0.5,1.19209289550781e-07,0.250000059604645,0.5,-0.24999988079071,0.500000059604645,0.5,-0.24999988079071,0.250000059604645,0.5,-0.49999988079071, +0,0.5,-0.24999988079071,-0.25,0.5,-0.24999988079071,-0.499999970197678,0.5,-0.24999988079071,0.250000059604645,0.25,-0.49999988079071,0.500000059604645,0.25,-0.49999988079071,0.250000059604645,0,-0.49999988079071,0.250000059604645,-0.25,-0.49999988079071,0.500000059604645,-0.25,-0.49999988079071,0.250000059604645,-0.5,-0.49999988079071,0,-0.25,-0.49999988079071,-0.25,-0.25,-0.49999988079071,0.250000059604645,-0.5,-0.24999988079071,0.500000059604645,-0.5,-0.24999988079071,0.250000059604645,-0.5,1.19209289550781e-07,0.250000059604645,-0.5,0.25,0,-0.5,0.25,-0.25,-0.5,0.25,-0.499999970197678,-0.5,0.25,0.500000059604645,-0.25,-0.24999988079071,0.500000059604645,0,-0.24999988079071,0.500000059604645,0.25,-0.24999988079071,0.500000059604645,0.25,1.19209289550781e-07,0.500000059604645,0.25,0.25,-0.499999970197678,-0.25,0.25,-0.499999970197678,0,0.25,-0.499999970197678,0.25,0.25,-0.499999970197678,0.25,1.19209289550781e-07,-0.499999970197678,0.25,-0.24999988079071,-0.594913899898529,0,0.594913899898529,-0.152911216020584,0,0.714658200740814,-0.594913899898529,-0.152911216020584,0.594913899898529,-0.152911216020584,-0.152911216020584,0.714658200740814,-0.594913899898529,0.594913899898529,7.29137497046395e-08,-0.152911216020584,0.714658200740814,7.29137497046395e-08,-0.594913899898529,0.594913899898529,0.152911216020584,-0.152911216020584,0.714658200740814,0.152911216020584,-0.594913899898529,0,-0.594913899898529,-0.152911216020584,0,-0.714658200740814,-0.594913899898529,0.152911216020584,-0.594913899898529,-0.152911216020584,0.152911216020584,-0.714658200740814,-0.594913899898529,-0.594913899898529,7.29137497046395e-08,-0.152911216020584,-0.714658200740814,7.29137497046395e-08,-0.594913899898529,-0.594913899898529,-0.152911216020584,-0.152911216020584,-0.714658200740814,-0.152911216020584,0.594913899898529,0,0.594913899898529,0.714658200740814,0,0.152911216020584,0.594913899898529,-0.152911216020584,0.594913899898529,0.714658200740814,-0.152911216020584,0.152911216020584,-0.714658200740814,0,-0.152911216020584,-0.594913899898529,-0.152911216020584,-0.594913899898529, +-0.714658200740814,-0.152911216020584,-0.152911216020584,8.62321627254444e-17,-0.594913899898529,0.594913899898529,8.62321627254444e-17,-0.152911216020584,0.714658200740814,0.152911230921745,-0.594913899898529,0.594913899898529,0.152911230921745,-0.152911216020584,0.714658200740814,0.152911230921745,0,0.714658200740814,0.594913899898529,0.152911216020584,0.594913899898529,0.152911230921745,0.152911216020584,0.714658200740814,8.62321627254444e-17,0.594913899898529,0.594913899898529,8.62321627254444e-17,0.152911216020584,0.714658200740814,-0.152911216020584,0.594913899898529,0.594913899898529,-0.152911216020584,0.152911216020584,0.714658200740814,8.62321627254444e-17,0.714658200740814,0.152911216020584,0.152911230921745,0.594913899898529,0.594913899898529,0.152911230921745,0.714658200740814,0.152911216020584,0.594913899898529,0.594913899898529,7.29137497046395e-08,0.152911230921745,0.714658200740814,7.29137497046395e-08,0.594913899898529,0.594913899898529,-0.152911216020584,0.152911230921745,0.714658200740814,-0.152911216020584,8.62321627254444e-17,0.594913899898529,-0.594913899898529,8.62321627254444e-17,0.714658200740814,-0.152911216020584,-0.152911216020584,0.594913899898529,-0.594913899898529,-0.152911216020584,0.714658200740814,-0.152911216020584,8.62321627254444e-17,0.152911216020584,-0.714658200740814,0.152911230921745,0.594913899898529,-0.594913899898529,0.152911230921745,0.152911216020584,-0.714658200740814,0.594913899898529,0,-0.594913899898529,0.152911230921745,0,-0.714658200740814,0.594913899898529,-0.152911216020584,-0.594913899898529,0.152911230921745,-0.152911216020584,-0.714658200740814,8.62321627254444e-17,-0.594913899898529,-0.594913899898529,8.62321627254444e-17,-0.152911216020584,-0.714658200740814,-0.152911216020584,-0.594913899898529,-0.594913899898529,-0.152911216020584,-0.152911216020584,-0.714658200740814,8.62321627254444e-17,-0.714658200740814,-0.152911216020584,0.152911230921745,-0.594913899898529,-0.594913899898529,0.152911230921745,-0.714658200740814,-0.152911216020584,0.594913899898529,-0.594913899898529,7.29137497046395e-08, +0.152911230921745,-0.714658200740814,7.29137497046395e-08,0.594913899898529,-0.594913899898529,0.152911216020584,0.152911230921745,-0.714658200740814,0.152911216020584,8.62321627254444e-17,-0.714658200740814,0.152911216020584,-0.152911216020584,-0.594913899898529,0.594913899898529,-0.152911216020584,-0.714658200740814,0.152911216020584,0.714658200740814,-0.152911216020584,7.29137497046395e-08,0.594913899898529,-0.594913899898529,-0.152911216020584,0.714658200740814,-0.152911216020584,-0.152911216020584,0.714658200740814,0,-0.152911216020584,0.594913899898529,0.152911216020584,-0.594913899898529,0.714658200740814,0.152911216020584,-0.152911216020584,0.714658200740814,0.152911216020584,7.29137497046395e-08,0.594913899898529,0.594913899898529,0.152911216020584,0.714658200740814,0.152911216020584,0.152911216020584,-0.714658200740814,-0.152911216020584,7.29137497046395e-08,-0.594913899898529,-0.594913899898529,0.152911216020584,-0.714658200740814,-0.152911216020584,0.152911216020584,-0.714658200740814,0,0.152911216020584,-0.594913899898529,0.152911216020584,0.594913899898529,-0.714658200740814,0.152911216020584,0.152911216020584,-0.714658200740814,0.152911216020584,7.29137497046395e-08,-0.594913899898529,0.594913899898529,-0.152911216020584,-0.714658200740814,0.152911216020584,-0.152911216020584,-0.541863918304443,-0.541864037513733,0.541863918304443,8.62321627254444e-17,0,0.714658200740814,-0.541863918304443,0.541863918304443,0.541863918304443,8.62321627254444e-17,0.714658200740814,7.29137497046395e-08,-0.541863918304443,0.541863918304443,-0.541863799095154,8.62321627254444e-17,0,-0.714658200740814,-0.541863918304443,-0.541864037513733,-0.541863799095154,8.62321627254444e-17,-0.714658200740814,7.29137497046395e-08,0.541863977909088,-0.541864037513733,0.541863918304443,0.714658200740814,0,7.29137497046395e-08,-0.714658200740814,0,7.29137497046395e-08,0.541863977909088,0.541863918304443,0.541863918304443,0.541863977909088,0.541863918304443,-0.541863799095154,0.541863977909088,-0.541864037513733,-0.541863799095154 + } + PolygonVertexIndex: *768 { + a: 99,98,100,-102,103,102,104,-106,107,106,108,-110,111,110,112,-114,115,114,116,-118,118,106,119,-121,122,121,123,-125,125,114,126,-128,129,128,130,-132,132,128,133,-135,136,135,137,-139,140,139,141,-143,143,139,144,-146,147,146,148,-150,151,150,152,-154,154,150,155,-157,158,157,159,-161,161,121,162,-164,164,157,165,-167,167,146,168,-170,170,135,171,-173,173,110,174,-176,176,98,177,-179,179,102,180,-182,100,182,162,-102,162,121,122,-102,122,183,99,-102,104,184,130,-106,130,128,132,-106,132,185,103,-106,108,186,141,-110,141,139,143,-110,143,187,107,-110,112,188,152,-114,152,150,154,-114,154,189,111,-114,116,190,159,-118,159,157,164,-118,164,191,115,-118,119,188,112,-121,112,110,173,-121,173,192,118,-121,123,190,116,-125,116,114,125,-125,125,183,122,-125,126,193,133,-128,133,128,129,-128,129,183,125,-128,130,184,177,-132,177,98,99,-132,99,183,129,-132,133,193,171,-135,171,135,136,-135,136,185,132,-135,137,194,144,-139,144,139,140,-139,140,185,136,-139,141,186,180,-143,180,102,103,-143,103,185,140,-143,144,194,168,-146,168,146,147,-146,147,187,143,-146,148,195,155,-150,155,150,151,-150,151,187,147,-150,152,188,119,-154,119,106,107,-154,107,187,151,-154,155,195,165,-157,165,157,158,-157,158,189,154,-157,159,190,123,-161,123,121,161,-161,161,189,158,-161,162,182,174,-164,174,110,111,-164,111,189,161,-164,165,195,148,-167,148,146,167,-167,167,191,164,-167,168,194,137,-170,137,135,170,-170,170,191,167,-170,171,193,126,-173,126,114,115,-173,115,191,170,-173,174,182,100,-176,100,98,176,-176,176,192,173,-176,177,184,104,-179,104,102,179,-179,179,192,176,-179,180,186,108,-182,108,106,118,-182,118,192,179,-182,30,26,27,-13,35,31,32,-17,40,36,37,-21,45,41,42,-24,50,46,47,-11,54,51,52,-21,29,55,56,-10,57,58,59,-11,61,62,33,-12,34,64,60,-12,66,67,68,-15,70,71,38,-16,39,73,69,-16,75,76,77,-19,79,80,43,-20,44,81,78,-20,83,84,48,-23,85,86,28,-10,49,88,82,-23,89,90,74,-19,91,92,65,-15,53,93,87,-24,94,95,63,-13,96,97,72,-17,27,26,28,-1,28,26,29,-10,29,26,30,-9,32,31,33,-3,33,31,34,-12,34,31,35,-14,37,36,38,-5,38,36,39, +-16,39,36,40,-18,42,41,43,-7,43,41,44,-20,44,41,45,-22,47,46,48,-2,48,46,49,-23,49,46,50,-25,52,51,42,-7,42,51,53,-24,53,51,54,-26,56,55,47,-2,47,55,57,-11,57,55,29,-9,59,58,60,-4,60,58,61,-12,61,58,57,-9,33,62,63,-3,63,62,30,-13,30,62,61,-9,60,64,65,-4,65,64,66,-15,66,64,34,-14,68,67,69,-6,69,67,70,-16,70,67,66,-14,38,71,72,-5,72,71,35,-17,35,71,70,-14,69,73,74,-6,74,73,75,-19,75,73,39,-18,77,76,78,-8,78,76,79,-20,79,76,75,-18,43,80,52,-7,52,80,40,-21,40,80,79,-18,78,81,82,-8,82,81,83,-23,83,81,44,-22,48,84,56,-2,56,84,85,-10,85,84,83,-22,28,86,87,-1,87,86,45,-24,45,86,85,-22,82,88,77,-8,77,88,89,-19,89,88,49,-25,74,90,68,-6,68,90,91,-15,91,90,89,-25,65,92,59,-4,59,92,50,-11,50,92,91,-25,87,93,27,-1,27,93,94,-13,94,93,53,-26,63,95,32,-3,32,95,96,-17,96,95,94,-26,72,97,37,-5,37,97,54,-21,54,97,96,-26 + } + Edges: *384 { + a: 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,102,104,105,108,109,110,114,116,117,120,121,122,126,128,129,132,133,134,138,140,141,144,145,146,150,152,153,156,158,162,164,165,168,170,174,176,180,181,182,186,188,193,194,198,205,206,210,212,216,217,218,222,224,229,230,234,241,242,246,248,252,253,254,258,260,266,270,277,278,282,284,290,294,296,301,302,306,314,318,320,326,330,332,338,342,350,354,356,362,366,368,374,378,384,385,386,387,388,389,390,391,392,393,394,395,396,397,398,399,400,401,402,403,404,405,406,407,408,409,410,411,412,413,414,415,416,417,418,419,420,421,422,423,424,425,426,427,428,429,430,431,432,433,434,435,436,437,438,439,440,441,442,443,444,445,446,447,448,449,450,451,452,453,454,455,456,457,458,459,460,461,462,463,464,465,466,467,468,469,470,471,472,473,474,475,476,477,478,479,481,482,483,485,490,491,493,494,495,497,502,503,505,506,507,509,514,515,517,518,519,521,526,527,529,530,531,533,538,539,541,543,545,550,551,553,555,557,563,565,566,567,569,575,577,578,581,589,590,593,599,601,602,603,605,611,613,614,617,625,626,629,635,637,638,639,641,647,649,653,661,662,665,671,673,677,683,685,686,689,697,701,707,709,713,719,721,725,733,737,743,745,749,755,757,761 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *2304 { + a: -0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.26148721575737,0.965207040309906,0,-0.26148721575737,0.965207040309906,0,-0.26148721575737,0.965207040309906,0,-0.26148721575737,0.965207040309906,0,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,0,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.965207040309906,0.261487185955048,0,0.965207040309906,0.261487185955048,0,0.965207040309906,0.261487185955048,0,0.965207040309906,0.261487185955048,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0.261487126350403,0,-0.965206980705261, +0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.965207040309906,-0.261487185955048,0,-0.965207040309906,-0.261487185955048,0,-0.965207040309906,-0.261487185955048,0,-0.965207040309906,-0.261487185955048,0.26148721575737,-0.965207040309906,0,0.26148721575737,-0.965207040309906,0,0.26148721575737,-0.965207040309906,0,0.26148721575737,-0.965207040309906,0,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0.965206980705261,-0.261487066745758,0,0.965206980705261,-0.261487066745758,0,0.965206980705261,-0.261487066745758,0,0.965206980705261,-0.261487066745758,0,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0.261487066745758,0,-0.965206980705261,0.261487066745758,0,-0.965206980705261,0.261487066745758,0,-0.965206980705261,0.261487066745758,0,-0.211917281150818,-0.211917445063591,0.954034626483917,0,0,1,-0.211917281150818,-0.21191743016243,0.954034626483917,-0.211917266249657,-0.211917445063591,0.954034626483917,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,-0.211917445063591,0.954034626483917,0.211917281150818, +0,1,0,-0.211917445063591,0.954034626483917,0.211917281150818,-0.211917445063591,0.954034626483917,0.211917266249657,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,1,0,0,1,0,0,1,0,0,1,0,-0.211917623877525,0.211917608976364,-0.954034626483917,0,0,-1,-0.211917623877525,0.211917608976364,-0.954034626483917,-0.211917623877525,0.211917594075203,-0.954034626483917,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.211917355656624,-0.954034745693207,-0.211917355656624,0,-1,0,-0.211917325854301,-0.954034686088562,-0.211917325854301,-0.211917355656624,-0.954034686088562,-0.211917355656624,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0.954034745693207,-0.211917281150818,0.211917340755463,1,0,0,0.954034745693207,-0.211917281150818,0.211917370557785,0.954034626483917,-0.211917236447334,0.211917296051979,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,1,0,0,1,0,0,1,0,0,1,0,0,-0.954034686088562,-0.211917355656624,-0.211917459964752,-1,0,0,-0.954034626483917,-0.211917325854301,-0.211917445063591,-0.954034686088562,-0.211917355656624,-0.211917474865913,-0.965206980705261,-0.261487066745758,0,-0.965206980705261,-0.261487066745758,0,-0.965206980705261,-0.261487066745758,0,-0.965206980705261,-0.261487066745758,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0.211917281150818,-0.211917400360107,0.954034626483917,0,0,1,0.211917266249657,-0.211917415261269,0.954034626483917,0.211917266249657,-0.211917415261269,0.954034626483917,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261,0.261487126350403,0,0.965206980705261, +0,0,1,0,0,1,0,0,1,0,0,1,0.211917296051979,0.211917415261269,0.954034626483917,0,0,1,0.211917296051979,0.211917415261269,0.954034626483917,0.211917281150818,0.211917415261269,0.954034626483917,0,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0.261487185955048,0.965207040309906,0,0,1,0,0,1,0,0,1,0,0,1,-0.211917281150818,0.211917445063591,0.954034626483917,0,0,1,-0.211917281150818,0.211917445063591,0.954034626483917,-0.211917266249657,0.211917445063591,0.954034626483917,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,-0.261487126350403,0,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,0.211917445063591,0.954034626483917,0.211917445063591,0,1,0,0.211917445063591,0.954034686088562,0.211917445063591,0.211917445063591,0.954034626483917,0.211917445063591,0.26148721575737,0.965207040309906,0,0.26148721575737,0.965207040309906,0,0.26148721575737,0.965207040309906,0,0.26148721575737,0.965207040309906,0,0,1,0,0,1,0,0,1,0,0,1,0,0.211917445063591,0.954034626483917,-0.211917489767075,0,1,0,0.211917459964752,0.954034686088562,-0.211917519569397,0.211917474865913,0.954034686088562,-0.211917504668236,0,0.965207040309906,-0.261487185955048,0,0.965207040309906,-0.261487185955048,0,0.965207040309906,-0.261487185955048,0,0.965207040309906,-0.261487185955048,0,1,0,0,1,0,0,1,0,0,1,0,-0.211917459964752,0.954034686088562,-0.211917340755463,0,1,0,-0.211917445063591,0.954034626483917,-0.21191731095314,-0.211917489767075,0.954034686088562,-0.211917355656624,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0,-0.261487185955048,0.965207040309906,0,0,1,0,0,1,0,0,1,0,0,1,0,0.211917638778687,0.211917608976364,-0.954034626483917,0,0,-1,0.211917608976364,0.211917564272881,-0.954034566879272,0.211917623877525,0.211917608976364,-0.954034626483917,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261, +0.261487126350403,0,-0.965206980705261,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0.211917608976364,-0.211917564272881,-0.954034626483917,0,0,-1,0.211917623877525,-0.211917579174042,-0.954034626483917,0.211917623877525,-0.211917549371719,-0.954034626483917,0,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,-0.261487185955048,-0.965207040309906,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.211917623877525,-0.211917579174042,-0.954034626483917,0,0,-1,-0.211917579174042,-0.211917534470558,-0.954034566879272,-0.211917623877525,-0.211917549371719,-0.954034626483917,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,-0.261487126350403,0,-0.965206980705261,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0.211917340755463,-0.954034686088562,-0.211917519569397,0,-1,0,0.211917325854301,-0.954034626483917,-0.211917489767075,0.211917325854301,-0.954034686088562,-0.211917489767075,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0,0.261487185955048,-0.965207040309906,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0.211917281150818,-0.954034626483917,0.211917445063591,0,-1,0,0.211917296051979,-0.954034626483917,0.211917445063591,0.211917266249657,-0.954034626483917,0.211917445063591,0,-0.965207040309906,0.261487185955048,0,-0.965207040309906,0.261487185955048,0,-0.965207040309906,0.261487185955048,0,-0.965207040309906,0.261487185955048,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0.211917325854301,-0.954034745693207,0.211917325854301,0,-1,0,-0.211917325854301,-0.954034745693207,0.211917325854301,-0.211917281150818,-0.954034686088562,0.211917281150818,-0.26148721575737,-0.965207040309906,0,-0.26148721575737,-0.965207040309906,0,-0.26148721575737,-0.965207040309906,0,-0.26148721575737,-0.965207040309906,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0.954034626483917,-0.211917325854301,-0.211917400360107,1,0,0,0.954034686088562,-0.211917340755463,-0.211917400360107,0.954034686088562,-0.211917355656624,-0.21191743016243,0.965206980705261,0,-0.261487185955048, +0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,0.965206980705261,0,-0.261487185955048,1,0,0,1,0,0,1,0,0,1,0,0,0.954034686088562,0.211917370557785,-0.211917489767075,1,0,0,0.954034686088562,0.211917355656624,-0.211917445063591,0.954034626483917,0.211917355656624,-0.211917445063591,0.965206980705261,0.261487066745758,0,0.965206980705261,0.261487066745758,0,0.965206980705261,0.261487066745758,0,0.965206980705261,0.261487066745758,0,1,0,0,1,0,0,1,0,0,1,0,0,0.954034626483917,0.211917296051979,0.211917385458946,1,0,0,0.954034626483917,0.211917296051979,0.211917385458946,0.954034745693207,0.211917296051979,0.211917385458946,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,0.965206980705261,0,0.261487185955048,1,0,0,1,0,0,1,0,0,1,0,0,-0.954034626483917,-0.211917251348495,0.211917400360107,-1,0,0,-0.954034626483917,-0.211917266249657,0.211917400360107,-0.954034626483917,-0.211917251348495,0.211917400360107,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-0.965206980705261,0,0.261487185955048,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-0.954034626483917,0.211917281150818,0.211917445063591,-1,0,0,-0.954034626483917,0.211917281150818,0.211917445063591,-0.954034626483917,0.211917266249657,0.211917445063591,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-0.965206980705261,0.261487126350403,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-0.954034686088562,0.211917385458946,-0.211917549371719,-1,0,0,-0.954034686088562,0.211917370557785,-0.211917534470558,-0.954034626483917,0.211917355656624,-0.211917504668236,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-0.965206980705261,0,-0.261487185955048,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0, +1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0, +-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0 + } + NormalsW: *768 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *2304 { + a: 0,1,0,0,1,0,0,1,0,0,1,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,0,0,1,0,0,1,0,0,1,0,0,1,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0.965206921100616,0.261487156152725,0,0.965206921100616,0.261487156152725,0,0.965206921100616,0.261487156152725,0,0.965206921100616,0.261487156152725,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,0.965206980705261,-0.261487185955048,0,0.965206980705261,-0.261487185955048,0,0.965206980705261,-0.261487185955048,0,0.965206980705261,-0.261487185955048,0,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0,0.261487156152725,-0.965206921100616,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0.261487126350403,-0.965206980705261,0,-0.261487126350403,-0.965206980705261,0,-0.261487126350403,-0.965206980705261,0,-0.261487126350403,-0.965206980705261,0,-0.965206921100616,-0.261487156152725,0,-0.965206921100616,-0.261487156152725,0,-0.965206921100616,-0.261487156152725,0,-0.965206921100616,-0.261487156152725,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-0.965206980705261,0.261487185955048,0,-0.965206980705261,0.261487185955048,0,-0.965206980705261,0.261487185955048,0,-0.965206980705261,0.261487185955048,0,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0,-0.261487156152725,0.965206921100616,0,0,1,0,0,1,0,0,1,0,0,1,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,0,1,0,0,1,0,0,1,0, +0,1,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,0.261487066745758,0.965206980705261,0,-0.0554696954786777,0.977241098880768,0.204750895500183,0.0677256807684898,0.997704029083252,-0,0.0995207726955414,0.966452240943909,0.236782029271126,0.022095151245594,0.974918127059937,0.221464186906815,0,0.965206980705261,0.261487185955048,0,0.965206980705261,0.261487185955048,0,0.965206980705261,0.261487185955048,0,0.965206980705261,0.261487185955048,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0.0554696545004845,0.204750746488571,-0.977241158485413,0.0677258297801018,0,-0.997703969478607,0.0995210781693459,0.23678195476532,-0.966452240943909,0.0220953319221735,0.221464082598686,-0.974918246269226,0,0.261487126350403,-0.965206980705261,0,0.261487126350403,-0.965206980705261,0,0.261487126350403,-0.965206980705261,0,0.261487126350403,-0.965206980705261,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.0554697290062904,-0.977241039276123,-0.204751029610634,0.0677258297801018,-0.997703969478607,0,0.0995209515094757,-0.966452121734619,-0.236782252788544,0.0220952276140451,-0.974918127059937,-0.221464350819588,0,-0.965206980705261,-0.261487185955048,0,-0.965206980705261,-0.261487185955048,0,-0.965206980705261,-0.261487185955048,0,-0.965206980705261,-0.261487185955048,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,-0,-0.0554696619510651,-0.204750776290894,0.977241098880768,0.0677259787917137,0,0.997703969478607,0.0995214134454727,-0.236782014369965,0.966452121734619,0.0220954976975918,-0.221464157104492,0.974918186664581,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,0.20475073158741,0.977241218090057,0.0554696507751942,0,0.997704029083252,-0.0677256807684898,0.236781880259514,0.966452300548553,-0.0995208472013474,0.221463993191719,0.974918186664581,-0.0220952145755291,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0, +-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0.204750791192055,0.977241098880768,-0.0554696619510651,0,0.997704029083252,0.0677257031202316,-0.236781939864159,0.966452240943909,0.099520817399025,-0.221464112401009,0.974918246269226,0.022095188498497,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,0,-0.099520780146122,0.966452240943909,0.236781999468803,-0.0677256733179092,0.997704029083252,0,0.0554696880280972,0.977241098880768,0.204750865697861,-0.022095151245594,0.974918127059937,0.221464157104492,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0.0554696880280972,0.977241098880768,-0.204750865697861,0.0677258223295212,0.997703969478607,-0,0.0995210558176041,0.966452181339264,-0.236782059073448,0.0220952890813351,0.974918246269226,-0.221464201807976,0,0.965206921100616,-0.261487156152725,0,0.965206921100616,-0.261487156152725,0,0.965206921100616,-0.261487156152725,0,0.965206921100616,-0.261487156152725,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0.0995210707187653,0.966452240943909,-0.236782118678093,-0.0677258297801018,0.997703969478607,0,0.0554696954786777,0.977241098880768,-0.204750895500183,-0.0220952928066254,0.974918186664581,-0.221464231610298,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0.0995210558176041,0.236782118678093,-0.966452240943909,-0.0677258223295212,0,-0.997703969478607,0.0554696880280972,0.204750880599022,-0.977241098880768,-0.0220952853560448,0.221464216709137,-0.974918127059937,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.0554697066545486,-0.204750955104828,-0.977241158485413,0.0677259713411331,0,-0.997703969478607,0.0995213389396667,-0.236782237887383,-0.966452181339264,0.0220954176038504,-0.221464291214943,-0.974918127059937,0,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,-0.261487156152725,-0.965206921100616,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.0995213687419891,-0.236782059073448,-0.966452181339264, +-0.0677259787917137,0,-0.997703969478607,0.0554696545004845,-0.204750776290894,-0.977241158485413,-0.0220954604446888,-0.221464172005653,-0.974918246269226,0,0,-1,0,0,-1,-0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.0995209366083145,-0.966452121734619,-0.236782252788544,-0.0677258223295212,-0.997703969478607,-0,0.0554697290062904,-0.977241098880768,-0.204751014709473,-0.0220952201634645,-0.974918127059937,-0.221464365720749,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,-0,-0.0554697252810001,-0.977241158485413,0.204751014709473,0.0677256733179092,-0.997704029083252,0,0.099520668387413,-0.966452181339264,0.236782178282738,0.0220950860530138,-0.974918127059937,0.221464276313782,0,-0.965206921100616,0.261487156152725,0,-0.965206921100616,0.261487156152725,0,-0.965206921100616,0.261487156152725,0,-0.965206921100616,0.261487156152725,0,-1,0,0,-1,0,0,-1,-0,0,-1,0,-0.0995206832885742,-0.966452181339264,0.236782178282738,-0.0677256807684898,-0.997704029083252,-0,0.0554697178304195,-0.977241098880768,0.20475098490715,-0.0220950935035944,-0.974918127059937,0.221464276313782,0,-1,-0,0,-1,-0,-0,-1,0,0,-1,-0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0.0995213836431503,-0.23678220808506,0.966452121734619,-0.0677259713411331,0,0.997703969478607,0.0554697066545486,-0.204750940203667,0.977241098880768,-0.0220954623073339,-0.221464291214943,0.974918186664581,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0.0554696954786777,0.204750895500183,0.977241098880768,0.0677258223295212,0,0.997703969478607,0.0995211154222488,0.236782103776932,0.966452181339264,0.0220953226089478,0.221464246511459,0.974918186664581,0,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0.261487156152725,0.965206921100616,0,0,1,0,0,1,0,0,1,0,0,1,-0.0995211452245712,0.23678195476532,0.966452181339264,-0.0677258297801018,0,0.997703969478607,0.0554696656763554,0.204750776290894,0.977241218090057,-0.022095363587141,0.221464082598686,0.974918246269226,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0.236781939864159,0.966452240943909,0.0995208621025085, +-0,0.997704029083252,0.0677257031202316,0.204750806093216,0.977241158485413,-0.0554696656763554,0.221464112401009,0.974918186664581,0.0220951996743679,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0.204750806093216,0.977241098880768,0.0554696694016457,0,0.997703969478607,-0.0677258521318436,-0.236782044172287,0.966452240943909,-0.0995211452245712,-0.221464172005653,0.974918246269226,-0.0220953542739153,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,-0.261487066745758,0.965206980705261,0,0,1,-0,-0,1,0,-0,1,0,-0,1,0,-0.236781984567642,0.966452300548553,0.09952113032341,-0,0.997703969478607,0.0677258297801018,-0.204750761389732,0.977241158485413,-0.0554696582257748,-0.221464067697525,0.974918246269226,0.0220953486859798,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,-0,-0,1,0,-0.236781880259514,0.966452360153198,-0.0995208248496056,0,0.997704029083252,-0.0677256807684898,-0.20475073158741,0.977241158485413,0.0554696470499039,-0.221464022994041,0.974918246269226,-0.0220951903611422,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0.204750746488571,0.977241158485413,-0.0554696545004845,0,0.997703969478607,0.0677258297801018,0.23678195476532,0.966452240943909,0.0995210781693459,0.221464082598686,0.974918246269226,0.0220953319221735,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0,1,0,0,1,0,0,1,0,0,1,0,0.236782073974609,0.966452240943909,-0.0995211005210876,0,0.997703969478607,-0.0677258521318436,0.204750806093216,0.977241098880768,0.0554696656763554,0.221464142203331,0.974918186664581,-0.0220953188836575,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,-0,-1,0,-0,-1, +0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-1,-0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1, +-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0 + } + BinormalsW: *768 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *2304 { + a: 0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965207040309906,0.26148721575737,0,0.965207040309906,0.26148721575737,0,0.965207040309906,0.26148721575737,0,0.965207040309906,0.26148721575737,0,0.965206980705261,-0,-0.261487126350403,0.965206980705261,-0,-0.261487126350403,0.965206980705261,-0,-0.261487126350403,0.965206980705261,-0,-0.261487126350403,0.965206980705261,-0.261487156152725,-0,0.965206980705261,-0.261487156152725,-0,0.965206980705261,-0.261487156152725,-0,0.965206980705261,-0.261487156152725,-0,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,0.965206980705261,-0.261487156152725,0,0.965206980705261,-0.261487156152725,0,0.965206980705261,-0.261487156152725,0,0.965206980705261,-0.261487156152725,0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,-0,0,1,0,0,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,-0,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0.26148721575737,-0,0.965207040309906, +0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0.97571212053299,0.00952975451946259,0.218849271535873,0.997704029083252,-0.0677256807684898,0,0.972207129001617,-0.145124465227127,0.183717742562294,0.977037787437439,-0.0680116266012192,0.201919630169868,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0.97571212053299,0.218849420547485,-0.0095297135412693,0.997703969478607,0,0.0677258297801018,0.972207069396973,0.183717846870422,0.145124778151512,0.977037727832794,0.20191977918148,0.0680118054151535,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0.975712060928345,-0.00952969118952751,-0.218849584460258,0.997703969478607,0.0677258297801018,0,0.972207009792328,0.145124763250351,-0.183717995882034,0.977037727832794,0.0680118054151535,-0.201919928193092,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0.97571212053299,-0.218849301338196,0.00952974148094654,0.997703969478607,0,-0.0677259787917137,0.972207069396973,-0.183717638254166,-0.145125105977058,0.977037727832794,-0.201919630169868,-0.068011961877346,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0.218849286437035,0.00952974148094654,-0.97571212053299,0,-0.0677256807684898,-0.997704029083252,0.183717831969261,-0.145124509930611,-0.972207069396973,0.201919674873352,-0.0680116564035416,-0.977037787437439,-0,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.218849420547485,0.0095297172665596,0.97571212053299,0,-0.0677257031202316,0.997704029083252,-0.183717906475067,-0.145124524831772,0.972207069396973,-0.201919823884964,-0.068011686205864,0.977037727832794,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0.972207129001617,0.145124465227127,-0.183717742562294,0.997704029083252,0.0677256733179092,0,0.97571212053299,-0.00952975824475288,-0.218849256634712,0.977037787437439,0.0680116191506386,-0.201919630169868,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403, +1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0.97571212053299,0.00952975172549486,-0.218849286437035,0.997703969478607,-0.0677258223295212,0,0.972207069396973,-0.14512474834919,-0.183717682957649,0.977037847042084,-0.0680117681622505,-0.20191964507103,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,0.972207069396973,0.14512474834919,0.183717668056488,0.997703969478607,0.0677258297801018,0,0.97571212053299,-0.00952975451946259,0.218849271535873,0.977037847042084,0.0680117756128311,0.201919630169868,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,0.965206980705261,-0,0.261487126350403,1,-0,-0,1,-0,0,1,-0,0,1,-0,0,0.972207069396973,-0.183717831969261,-0.145124778151512,0.997703969478607,0,-0.0677258223295212,0.97571212053299,-0.218849405646324,0.00952972564846277,0.977037727832794,-0.20191977918148,-0.0680117979645729,0.965207040309906,-0.26148721575737,-0,0.965207040309906,-0.26148721575737,-0,0.965207040309906,-0.26148721575737,-0,0.965207040309906,-0.26148721575737,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0.97571212053299,-0.218849420547485,-0.0095297247171402,0.997703969478607,0,0.0677259713411331,0.972207009792328,-0.183717757463455,0.145125061273575,0.977037727832794,-0.201919749379158,0.0680119395256042,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,0,1,0,0,1,-0,-0,1,0,0,0.972207009792328,0.183717772364616,-0.145125061273575,0.997703969478607,0,-0.0677259787917137,0.97571212053299,0.218849420547485,0.00952971447259188,0.977037727832794,0.20191977918148,-0.0680119544267654,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,-0,0.965206980705261,0.261487156152725,0,1,-0,0,1,0,0,1,0,0,1,0,0,0.972207009792328,-0.14512474834919,0.183718010783195,0.997703969478607,-0.0677258223295212,0,0.975712060928345,0.00952969118952751,0.218849584460258,0.977037727832794,-0.0680117979645729,0.201919928193092,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403,0.965206980705261,0,0.261487126350403, +1,-0,0,1,-0,0,1,-0,0,1,-0,0,0.975712060928345,-0.00952969398349524,0.218849569559097,0.997704029083252,0.0677256733179092,0,0.972207069396973,0.145124465227127,0.18371807038784,0.977037727832794,0.0680116564035416,0.201919972896576,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,0.972207069396973,-0.145124480128288,-0.183718055486679,0.997704029083252,-0.0677256807684898,0,0.975712060928345,0.00952969398349524,-0.218849569559097,0.977037727832794,-0.0680116638541222,-0.201919972896576,0.965206980705261,0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,0.965206980705261,-0,-0.261487126350403,0.965206980705261,0,-0.261487126350403,1,0,0,1,0,0,1,0,0,1,0,0,0.972207069396973,0.183717623353004,0.145125105977058,0.997703969478607,0,0.0677259713411331,0.97571212053299,0.218849316239357,-0.00952974893152714,0.977037847042084,0.201919630169868,0.0680119544267654,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,0,0.965206980705261,0.261487156152725,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0.97571212053299,0.218849271535873,0.00952975638210773,0.997703969478607,0,-0.0677258223295212,0.972207069396973,0.183717668056488,-0.145124807953835,0.977037847042084,0.201919630169868,-0.0680118054151535,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,0.972207069396973,-0.18371769785881,0.145124822854996,0.997703969478607,0,0.0677258297801018,0.97571212053299,-0.218849286437035,-0.00952974613755941,0.977037847042084,-0.201919630169868,0.0680118054151535,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,-0.183717846870422,0.145124554634094,-0.972207069396973,0,0.0677257031202316,-0.997704029083252,-0.218849360942841,-0.0095297284424305,-0.97571212053299,-0.20191977918148,0.068011686205864,-0.977037727832794,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906,-0.26148721575737,-0,-0.965207040309906, +0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0.218849450349808,0.00952971167862415,-0.97571212053299,0,-0.0677258521318436,-0.997703969478607,-0.1837178170681,-0.145124852657318,-0.972207069396973,-0.201919764280319,-0.0680118426680565,-0.977037727832794,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0,0,-1,0,0,-1,0.183717772364616,0.145124807953835,-0.972207069396973,0,0.0677258297801018,-0.997703969478607,0.218849375844002,-0.00952972657978535,-0.97571212053299,0.201919689774513,0.0680118054151535,-0.977037727832794,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0.26148721575737,0,-0.965207040309906,0,0,-1,0,0,-1,0,-0,-1,0,0,-1,0.183717876672745,0.145124495029449,0.972207069396973,0,0.0677256807684898,0.997704029083252,0.218849375844002,-0.00952972192317247,0.97571212053299,0.20191977918148,0.0680116564035416,0.977037727832794,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0.26148721575737,-0,0.965207040309906,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0.218849420547485,0.0095297135412693,0.97571212053299,0,-0.0677258297801018,0.997703969478607,0.183717846870422,-0.145124778151512,0.972207069396973,0.20191977918148,-0.0680118054151535,0.977037727832794,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,-0.183717921376228,0.145124837756157,0.972207009792328,0,0.0677258521318436,0.997703969478607,-0.21884948015213,-0.00952970236539841,0.97571212053299,-0.201919838786125,0.0680118277668953,0.977037727832794,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,-0.26148721575737,0,0.965207040309906,0,-0,1,0,-0,1,0,-0,1,0,-0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,0,1,0,0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,-0,0,1,0,0,1,0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0, +1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,-0,1,-0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,0,0,1,0,0,1,0,0,1,0,0,1, +0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1 + } + TangentsW: *768 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "map1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *542 { + a: 0.375,0,0.625,0,0.375,0.25,0.625,0.25,0.375,0.5,0.625,0.5,0.375,0.75,0.625,0.75,0.375,1,0.625,1,0.875,0,0.875,0.25,0.125,0,0.125,0.25,0.5,0.125,0.5,0,0.5,1,0.625,0.125,0.5,0.25,0.375,0.125,0.5,0.375,0.625,0.375,0.75,0.25,0.5,0.5,0.375,0.375,0.25,0.25,0.5,0.625,0.625,0.625,0.875,0.125,0.5,0.75,0.375,0.625,0.125,0.125,0.5,0.875,0.625,0.875,0.75,0,0.5,1,0.375,0.875,0.25,0,0.75,0.125,0.75,0,0.875,0.125,0.75,0.25,0.25,0.125,0.25,0,0.25,0.25,0.125,0.125,0.4375,0.0625,0.375,0.0625,0.4375,0,0.4375,1,0.5,0.0625,0.4375,0.125,0.4375,0.3125,0.375,0.3125,0.3125,0.25,0.4375,0.25,0.5,0.3125,0.4375,0.375,0.4375,0.5625,0.375,0.5625,0.125,0.1875,0.4375,0.5,0.5,0.5625,0.4375,0.625,0.4375,0.8125,0.375,0.8125,0.1875,0,0.4375,0.75,0.5,0.8125,0.4375,0.875,0.6875,0.0625,0.625,0.0625,0.625,0.9375,0.6875,0,0.75,0.0625,0.6875,0.125,0.1875,0.0625,0.375,0.6875,0.125,0.0625,0.1875,0,0.25,0.0625,0.1875,0.125,0.5625,0.0625,0.5625,0,0.5625,1,0.5625,0.125,0.5625,0.1875,0.625,0.1875,0.5625,0.25,0.5,0.1875,0.4375,0.1875,0.375,0.1875,0.5625,0.3125,0.625,0.3125,0.6875,0.25,0.5625,0.375,0.5625,0.4375,0.625,0.4375,0.8125,0.25,0.5625,0.5,0.5,0.4375,0.4375,0.4375,0.375,0.4375,0.1875,0.25,0.5625,0.5625,0.625,0.5625,0.875,0.1875,0.5625,0.625,0.5625,0.6875,0.625,0.6875,0.875,0.0625,0.5625,0.75,0.5,0.6875,0.4375,0.6875,0.375,0.6875,0.5625,0.8125,0.625,0.8125,0.8125,0,0.5625,0.875,0.5625,0.9375,0.625,0.9375,0.5625,1,0.5,0.9375,0.4375,0.9375,0.4375,1,0.375,0.9375,0.3125,0,0.8125,0.0625,0.8125,0,0.875,0.0625,0.8125,0.125,0.8125,0.1875,0.875,0.1875,0.8125,0.25,0.75,0.1875,0.6875,0.1875,0.6875,0.25,0.3125,0.0625,0.3125,0,0.3125,0.125,0.3125,0.1875,0.3125,0.25,0.25,0.1875,0.1875,0.1875,0.1875,0.25,0.125,0.1875,0.4375,0.125,0.375,0.125,0.375,0.0625,0.4375,0.0625,0.4375,0.375,0.375,0.375,0.375,0.3125,0.4375,0.3125,0.4375,0.625,0.375,0.625,0.375,0.5625,0.4375,0.5625,0.4375,0.875,0.375,0.875,0.375,0.8125,0.4375,0.8125,0.6875,0.125,0.625,0.125,0.625,0.0625,0.6875,0.0625,0.1875,0.125,0.125,0.125,0.125,0.0625,0.1875,0.0625,0.5,0.0625,0.5,0,0.5625,0, +0.5625,0.0625,0.5625,0.125,0.625,0.1875,0.5625,0.1875,0.5,0.1875,0.5,0.25,0.4375,0.25,0.4375,0.1875,0.5,0.3125,0.5625,0.25,0.5625,0.3125,0.5625,0.375,0.625,0.375,0.625,0.4375,0.5625,0.4375,0.5,0.4375,0.5,0.5,0.4375,0.5,0.4375,0.4375,0.5,0.5625,0.5625,0.5,0.5625,0.5625,0.5625,0.625,0.625,0.625,0.625,0.6875,0.5625,0.6875,0.5,0.6875,0.5,0.75,0.4375,0.75,0.4375,0.6875,0.5,0.8125,0.5625,0.75,0.5625,0.8125,0.5625,0.875,0.625,0.875,0.625,0.9375,0.5625,0.9375,0.5,0.9375,0.5,1,0.4375,1,0.4375,0.9375,0.75,0.0625,0.75,0,0.8125,0,0.8125,0.0625,0.8125,0.125,0.875,0.125,0.875,0.1875,0.8125,0.1875,0.75,0.1875,0.75,0.25,0.6875,0.25,0.6875,0.1875,0.25,0.0625,0.25,0,0.3125,0,0.3125,0.0625,0.3125,0.125,0.375,0.1875,0.3125,0.1875,0.25,0.1875,0.25,0.25,0.1875,0.25,0.1875,0.1875,0.375,0,0.4375,0,0.5,0.125,0.375,0.25,0.5,0.375,0.375,0.5,0.5,0.625,0.375,0.75,0.5,0.875,0.625,0,0.6875,0,0.75,0.125,0.125,0,0.1875,0,0.25,0.125,0.625,0.25,0.625,0.3125,0.625,0.5,0.375,0.4375,0.625,0.5625,0.625,0.75,0.375,0.6875,0.625,0.8125,0.625,1,0.5625,1,0.375,1,0.375,0.9375,0.875,0,0.875,0.0625,0.875,0.25,0.8125,0.25,0.3125,0.25,0.125,0.25,0.125,0.1875 + } + UVIndex: *768 { + a: 51,19,47,46,57,24,53,52,63,30,59,58,69,36,65,64,75,17,71,70,81,45,78,76,50,15,83,82,85,17,87,86,89,18,55,90,56,18,88,92,95,21,97,96,100,23,61,101,62,23,99,104,107,27,109,108,112,29,67,113,68,29,111,115,118,33,120,119,122,35,124,123,74,39,128,127,130,40,132,131,134,41,136,135,80,43,138,137,139,19,91,140,142,44,144,143,47,0,48,46,48,15,50,46,50,14,51,46,53,2,55,52,55,18,56,52,56,20,57,52,59,4,61,58,61,23,62,58,62,26,63,58,65,6,67,64,67,29,68,64,68,32,69,64,71,1,73,70,73,39,74,70,74,38,75,70,78,12,79,76,79,43,80,76,80,42,81,76,83,1,71,82,71,17,85,82,85,14,50,82,87,3,88,86,88,18,89,86,89,14,85,86,55,2,91,90,91,19,51,90,51,14,89,90,88,3,93,92,93,21,95,92,95,20,56,92,97,5,99,96,99,23,100,96,100,20,95,96,61,4,102,101,102,24,57,101,57,20,100,101,99,5,105,104,105,27,107,104,107,26,62,104,109,7,111,108,111,29,112,108,112,26,107,108,67,6,114,113,114,30,63,113,63,26,112,113,111,7,116,115,116,33,118,115,118,32,68,115,120,9,121,119,121,35,122,119,122,32,118,119,124,8,125,123,125,36,69,123,69,32,122,123,128,10,129,127,129,40,130,127,130,38,74,127,132,11,133,131,133,41,134,131,134,38,130,131,136,3,87,135,87,17,75,135,75,38,134,135,138,0,47,137,47,19,139,137,139,42,80,137,91,2,141,140,141,44,142,140,142,42,139,140,144,13,145,143,145,45,81,143,81,42,142,143,146,149,148,147,150,153,152,151,154,157,156,155,158,161,160,159,162,165,164,163,166,169,168,167,170,173,172,171,174,176,175,163,177,180,179,178,181,183,182,178,184,187,186,185,188,191,190,189,192,194,193,189,195,198,197,196,199,202,201,200,203,205,204,200,206,209,208,207,210,213,212,211,214,217,216,215,218,221,220,219,222,225,224,223,226,229,228,227,230,232,231,147,233,236,235,234,148,149,238,237,238,149,170,171,170,149,146,239,152,153,179,240,179,153,181,178,181,153,150,241,156,157,190,242,190,157,192,189,192,157,154,243,160,161,201,244,201,161,203,200,203,161,158,245,164,165,247,246,247,165,214,215,214,165,162,248,168,169,250,249,250,169,226,227,226,169,166,251,172,173,164,246,164,173,174,163,174,173,170,239,175,176,182,252,182,176,177,178,177,176,174,239, +179,180,231,240,231,180,146,147,146,180,177,239,182,183,253,252,253,183,184,185,184,183,181,241,186,187,193,254,193,187,188,189,188,187,184,241,190,191,255,242,255,191,150,151,150,191,188,241,193,194,256,254,256,194,195,196,195,194,192,243,197,198,204,257,204,198,199,200,199,198,195,243,201,202,258,244,258,202,154,155,154,202,199,243,204,205,259,257,259,205,206,207,206,205,203,245,208,209,261,260,261,209,210,211,210,209,206,245,212,213,263,262,263,213,158,159,158,213,210,245,216,217,265,264,265,217,218,219,218,217,214,248,220,221,267,266,267,221,222,223,222,221,218,248,224,225,175,252,175,225,162,163,162,225,222,248,228,229,148,237,148,229,230,147,230,229,226,251,231,232,268,240,268,232,233,234,233,232,230,251,235,236,270,269,270,236,166,167,166,236,233,251 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *384 { + a: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Model: 2359439406816, "Model::Cube2", "Mesh" { + Version: 232 + Properties70: { + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",-1.04023893373156,0.998288783259251,-1.04375962988677 + P: "Lcl Scaling", "Lcl Scaling", "", "A",10,10,10 + P: "currentUVSet", "KString", "", "U", "map1" + } + Shading: T + Culling: "CullingOff" + } + Model: 2359439411456, "Model::Куб1", "Mesh" { + Version: 232 + Properties70: { + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",1.04023893373156,-0.998288783259251,1.04375962988677 + P: "currentUVSet", "KString", "", "U", "map1" + } + Shading: T + Culling: "CullingOff" + } + Model: 2359439409136, "Model::Cube3", "Mesh" { + Version: 232 + Properties70: { + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",-1.0671176743957,0.998288783259251,9.39023469168045 + P: "Lcl Scaling", "Lcl Scaling", "", "A",10,10,10 + P: "currentUVSet", "KString", "", "U", "map1" + } + Shading: T + Culling: "CullingOff" + } + Model: 2359439416096, "Model::Куб1", "Mesh" { + Version: 232 + Properties70: { + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",1.04023893373156,-0.998288783259251,1.1806740271636 + P: "Lcl Scaling", "Lcl Scaling", "", "A",0.77384837213491,0.77384837213491,0.77384837213491 + P: "currentUVSet", "KString", "", "U", "map1" + } + Shading: T + Culling: "CullingOff" + } + Material: 2359823919504, "Material::Mat_Green", "" { + Version: 102 + ShadingModel: "lambert" + MultiLayer: 0 + Properties70: { + P: "AmbientColor", "Color", "", "A",0,0,0 + P: "DiffuseColor", "Color", "", "A",0,1,0 + P: "DiffuseFactor", "Number", "", "A",0.800000011920929 + P: "TransparencyFactor", "Number", "", "A",1 + P: "Emissive", "Vector3D", "Vector", "",0,0,0 + P: "Ambient", "Vector3D", "Vector", "",0,0,0 + P: "Diffuse", "Vector3D", "Vector", "",0,0.800000011920929,0 + P: "Opacity", "double", "Number", "",1 + } + } + Material: 2359823921584, "Material::Mat_Red", "" { + Version: 102 + ShadingModel: "lambert" + MultiLayer: 0 + Properties70: { + P: "AmbientColor", "Color", "", "A",0,0,0 + P: "DiffuseColor", "Color", "", "A",1,0,0 + P: "DiffuseFactor", "Number", "", "A",0.800000011920929 + P: "TransparencyFactor", "Number", "", "A",1 + P: "Emissive", "Vector3D", "Vector", "",0,0,0 + P: "Ambient", "Vector3D", "Vector", "",0,0,0 + P: "Diffuse", "Vector3D", "Vector", "",0.800000011920929,0,0 + P: "Opacity", "double", "Number", "",1 + } + } + AnimationStack: 2359349464816, "AnimStack::Take 001", "" { + Properties70: { + P: "LocalStart", "KTime", "Time", "",1924423250 + P: "LocalStop", "KTime", "Time", "",230930790000 + P: "ReferenceStart", "KTime", "Time", "",1924423250 + P: "ReferenceStop", "KTime", "Time", "",230930790000 + } + } + AnimationLayer: 2359327403664, "AnimLayer::BaseLayer", "" { + } +} + +; Object connections +;------------------------------------------------------------------ + +Connections: { + + ;Model::Cube2, Model::RootNode + C: "OO",2359439406816,0 + + ;Model::Cube3, Model::RootNode + C: "OO",2359439409136,0 + + ;AnimLayer::BaseLayer, AnimStack::Take 001 + C: "OO",2359327403664,2359349464816 + + ;Geometry::, Model::Cube2 + C: "OO",2358377979296,2359439406816 + + ;Material::Mat_Green, Model::Cube2 + C: "OO",2359823919504,2359439406816 + + ;Model::Куб1, Model::Cube2 + C: "OO",2359439411456,2359439406816 + + ;Geometry::, Model::Куб1 + C: "OO",2358377961872,2359439411456 + + ;Material::Mat_Green, Model::Куб1 + C: "OO",2359823919504,2359439411456 + + ;Geometry::, Model::Cube3 + C: "OO",2358377982464,2359439409136 + + ;Material::Mat_Red, Model::Cube3 + C: "OO",2359823921584,2359439409136 + + ;Model::Куб1, Model::Cube3 + C: "OO",2359439416096,2359439409136 + + ;Geometry::, Model::Куб1 + C: "OO",2358377979824,2359439416096 + + ;Material::Mat_Red, Model::Куб1 + C: "OO",2359823921584,2359439416096 +} +;Takes section +;---------------------------------------------------- + +Takes: { + Current: "Take 001" + Take: "Take 001" { + FileName: "Take_001.tak" + LocalTime: 1924423250,230930790000 + ReferenceTime: 1924423250,230930790000 + } +} diff --git a/test/models/FBX/embedded_ascii/box.FBX b/test/models/FBX/embedded_ascii/box.FBX new file mode 100644 index 000000000..424dd736a --- /dev/null +++ b/test/models/FBX/embedded_ascii/box.FBX @@ -0,0 +1,490 @@ +; FBX 7.4.0 project file +; ---------------------------------------------------- + +FBXHeaderExtension: { + FBXHeaderVersion: 1003 + FBXVersion: 7400 + CreationTimeStamp: { + Version: 1000 + Year: 2019 + Month: 3 + Day: 29 + Hour: 16 + Minute: 20 + Second: 29 + Millisecond: 0 + } + Creator: "FBX SDK/FBX Plugins version 2018.1" + SceneInfo: "SceneInfo::GlobalInfo", "UserData" { + Type: "UserData" + Version: 100 + MetaData: { + Version: 100 + Title: "" + Subject: "" + Author: "" + Keywords: "" + Revision: "" + Comment: "" + } + Properties70: { + P: "DocumentUrl", "KString", "Url", "", "C:\Users\HTC Vive 1\Documents\3dsMax\export\box_with_embeded_texture_for_matias.FBX" + P: "SrcDocumentUrl", "KString", "Url", "", "C:\Users\HTC Vive 1\Documents\3dsMax\export\box_with_embeded_texture_for_matias.FBX" + P: "Original", "Compound", "", "" + P: "Original|ApplicationVendor", "KString", "", "", "Autodesk" + P: "Original|ApplicationName", "KString", "", "", "3ds Max" + P: "Original|ApplicationVersion", "KString", "", "", "2018" + P: "Original|DateTime_GMT", "DateTime", "", "", "29/03/2019 15:20:28.999" + P: "Original|FileName", "KString", "", "", "C:\Users\HTC Vive 1\Documents\3dsMax\export\box_with_embeded_texture_for_matias.FBX" + P: "LastSaved", "Compound", "", "" + P: "LastSaved|ApplicationVendor", "KString", "", "", "Autodesk" + P: "LastSaved|ApplicationName", "KString", "", "", "3ds Max" + P: "LastSaved|ApplicationVersion", "KString", "", "", "2018" + P: "LastSaved|DateTime_GMT", "DateTime", "", "", "29/03/2019 15:20:28.999" + P: "Original|ApplicationActiveProject", "KString", "", "", "C:\Users\HTC Vive 1\Documents\3dsMax" + } + } +} +GlobalSettings: { + Version: 1000 + Properties70: { + P: "UpAxis", "int", "Integer", "",2 + P: "UpAxisSign", "int", "Integer", "",1 + P: "FrontAxis", "int", "Integer", "",1 + P: "FrontAxisSign", "int", "Integer", "",-1 + P: "CoordAxis", "int", "Integer", "",0 + P: "CoordAxisSign", "int", "Integer", "",1 + P: "OriginalUpAxis", "int", "Integer", "",2 + P: "OriginalUpAxisSign", "int", "Integer", "",1 + P: "UnitScaleFactor", "double", "Number", "",100 + P: "OriginalUnitScaleFactor", "double", "Number", "",2.54 + P: "AmbientColor", "ColorRGB", "Color", "",0,0,0 + P: "DefaultCamera", "KString", "", "", "Producer Perspective" + P: "TimeMode", "enum", "", "",6 + P: "TimeProtocol", "enum", "", "",2 + P: "SnapOnFrameMode", "enum", "", "",0 + P: "TimeSpanStart", "KTime", "Time", "",0 + P: "TimeSpanStop", "KTime", "Time", "",153953860000 + P: "CustomFrameRate", "double", "Number", "",-1 + P: "TimeMarker", "Compound", "", "" + P: "CurrentTimeMarker", "int", "Integer", "",-1 + } +} + +; Documents Description +;------------------------------------------------------------------ + +Documents: { + Count: 1 + Document: 2671589736064, "", "Scene" { + Properties70: { + P: "SourceObject", "object", "", "" + P: "ActiveAnimStackName", "KString", "", "", "" + } + RootNode: 0 + } +} + +; Document References +;------------------------------------------------------------------ + +References: { +} + +; Object definitions +;------------------------------------------------------------------ + +Definitions: { + Version: 100 + Count: 7 + ObjectType: "GlobalSettings" { + Count: 1 + } + ObjectType: "AnimationStack" { + Count: 1 + PropertyTemplate: "FbxAnimStack" { + Properties70: { + P: "Description", "KString", "", "", "" + P: "LocalStart", "KTime", "Time", "",0 + P: "LocalStop", "KTime", "Time", "",0 + P: "ReferenceStart", "KTime", "Time", "",0 + P: "ReferenceStop", "KTime", "Time", "",0 + } + } + } + ObjectType: "Model" { + Count: 1 + PropertyTemplate: "FbxNode" { + Properties70: { + P: "QuaternionInterpolate", "enum", "", "",0 + P: "RotationOffset", "Vector3D", "Vector", "",0,0,0 + P: "RotationPivot", "Vector3D", "Vector", "",0,0,0 + P: "ScalingOffset", "Vector3D", "Vector", "",0,0,0 + P: "ScalingPivot", "Vector3D", "Vector", "",0,0,0 + P: "TranslationActive", "bool", "", "",0 + P: "TranslationMin", "Vector3D", "Vector", "",0,0,0 + P: "TranslationMax", "Vector3D", "Vector", "",0,0,0 + P: "TranslationMinX", "bool", "", "",0 + P: "TranslationMinY", "bool", "", "",0 + P: "TranslationMinZ", "bool", "", "",0 + P: "TranslationMaxX", "bool", "", "",0 + P: "TranslationMaxY", "bool", "", "",0 + P: "TranslationMaxZ", "bool", "", "",0 + P: "RotationOrder", "enum", "", "",0 + P: "RotationSpaceForLimitOnly", "bool", "", "",0 + P: "RotationStiffnessX", "double", "Number", "",0 + P: "RotationStiffnessY", "double", "Number", "",0 + P: "RotationStiffnessZ", "double", "Number", "",0 + P: "AxisLen", "double", "Number", "",10 + P: "PreRotation", "Vector3D", "Vector", "",0,0,0 + P: "PostRotation", "Vector3D", "Vector", "",0,0,0 + P: "RotationActive", "bool", "", "",0 + P: "RotationMin", "Vector3D", "Vector", "",0,0,0 + P: "RotationMax", "Vector3D", "Vector", "",0,0,0 + P: "RotationMinX", "bool", "", "",0 + P: "RotationMinY", "bool", "", "",0 + P: "RotationMinZ", "bool", "", "",0 + P: "RotationMaxX", "bool", "", "",0 + P: "RotationMaxY", "bool", "", "",0 + P: "RotationMaxZ", "bool", "", "",0 + P: "InheritType", "enum", "", "",0 + P: "ScalingActive", "bool", "", "",0 + P: "ScalingMin", "Vector3D", "Vector", "",0,0,0 + P: "ScalingMax", "Vector3D", "Vector", "",1,1,1 + P: "ScalingMinX", "bool", "", "",0 + P: "ScalingMinY", "bool", "", "",0 + P: "ScalingMinZ", "bool", "", "",0 + P: "ScalingMaxX", "bool", "", "",0 + P: "ScalingMaxY", "bool", "", "",0 + P: "ScalingMaxZ", "bool", "", "",0 + P: "GeometricTranslation", "Vector3D", "Vector", "",0,0,0 + P: "GeometricRotation", "Vector3D", "Vector", "",0,0,0 + P: "GeometricScaling", "Vector3D", "Vector", "",1,1,1 + P: "MinDampRangeX", "double", "Number", "",0 + P: "MinDampRangeY", "double", "Number", "",0 + P: "MinDampRangeZ", "double", "Number", "",0 + P: "MaxDampRangeX", "double", "Number", "",0 + P: "MaxDampRangeY", "double", "Number", "",0 + P: "MaxDampRangeZ", "double", "Number", "",0 + P: "MinDampStrengthX", "double", "Number", "",0 + P: "MinDampStrengthY", "double", "Number", "",0 + P: "MinDampStrengthZ", "double", "Number", "",0 + P: "MaxDampStrengthX", "double", "Number", "",0 + P: "MaxDampStrengthY", "double", "Number", "",0 + P: "MaxDampStrengthZ", "double", "Number", "",0 + P: "PreferedAngleX", "double", "Number", "",0 + P: "PreferedAngleY", "double", "Number", "",0 + P: "PreferedAngleZ", "double", "Number", "",0 + P: "LookAtProperty", "object", "", "" + P: "UpVectorProperty", "object", "", "" + P: "Show", "bool", "", "",1 + P: "NegativePercentShapeSupport", "bool", "", "",1 + P: "DefaultAttributeIndex", "int", "Integer", "",-1 + P: "Freeze", "bool", "", "",0 + P: "LODBox", "bool", "", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",0,0,0 + P: "Lcl Rotation", "Lcl Rotation", "", "A",0,0,0 + P: "Lcl Scaling", "Lcl Scaling", "", "A",1,1,1 + P: "Visibility", "Visibility", "", "A",1 + P: "Visibility Inheritance", "Visibility Inheritance", "", "",1 + } + } + } + ObjectType: "Geometry" { + Count: 1 + PropertyTemplate: "FbxMesh" { + Properties70: { + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "BBoxMin", "Vector3D", "Vector", "",0,0,0 + P: "BBoxMax", "Vector3D", "Vector", "",0,0,0 + P: "Primary Visibility", "bool", "", "",1 + P: "Casts Shadows", "bool", "", "",1 + P: "Receive Shadows", "bool", "", "",1 + } + } + } + ObjectType: "Material" { + Count: 1 + PropertyTemplate: "FbxSurfacePhong" { + Properties70: { + P: "ShadingModel", "KString", "", "", "Phong" + P: "MultiLayer", "bool", "", "",0 + P: "EmissiveColor", "Color", "", "A",0,0,0 + P: "EmissiveFactor", "Number", "", "A",1 + P: "AmbientColor", "Color", "", "A",0.2,0.2,0.2 + P: "AmbientFactor", "Number", "", "A",1 + P: "DiffuseColor", "Color", "", "A",0.8,0.8,0.8 + P: "DiffuseFactor", "Number", "", "A",1 + P: "Bump", "Vector3D", "Vector", "",0,0,0 + P: "NormalMap", "Vector3D", "Vector", "",0,0,0 + P: "BumpFactor", "double", "Number", "",1 + P: "TransparentColor", "Color", "", "A",0,0,0 + P: "TransparencyFactor", "Number", "", "A",0 + P: "DisplacementColor", "ColorRGB", "Color", "",0,0,0 + P: "DisplacementFactor", "double", "Number", "",1 + P: "VectorDisplacementColor", "ColorRGB", "Color", "",0,0,0 + P: "VectorDisplacementFactor", "double", "Number", "",1 + P: "SpecularColor", "Color", "", "A",0.2,0.2,0.2 + P: "SpecularFactor", "Number", "", "A",1 + P: "ShininessExponent", "Number", "", "A",20 + P: "ReflectionColor", "Color", "", "A",0,0,0 + P: "ReflectionFactor", "Number", "", "A",1 + } + } + } + ObjectType: "Texture" { + Count: 1 + PropertyTemplate: "FbxFileTexture" { + Properties70: { + P: "TextureTypeUse", "enum", "", "",0 + P: "Texture alpha", "Number", "", "A",1 + P: "CurrentMappingType", "enum", "", "",0 + P: "WrapModeU", "enum", "", "",0 + P: "WrapModeV", "enum", "", "",0 + P: "UVSwap", "bool", "", "",0 + P: "PremultiplyAlpha", "bool", "", "",1 + P: "Translation", "Vector", "", "A",0,0,0 + P: "Rotation", "Vector", "", "A",0,0,0 + P: "Scaling", "Vector", "", "A",1,1,1 + P: "TextureRotationPivot", "Vector3D", "Vector", "",0,0,0 + P: "TextureScalingPivot", "Vector3D", "Vector", "",0,0,0 + P: "CurrentTextureBlendMode", "enum", "", "",1 + P: "UVSet", "KString", "", "", "default" + P: "UseMaterial", "bool", "", "",0 + P: "UseMipMap", "bool", "", "",0 + } + } + } + ObjectType: "Video" { + Count: 1 + PropertyTemplate: "FbxVideo" { + Properties70: { + P: "Path", "KString", "XRefUrl", "", "" + P: "RelPath", "KString", "XRefUrl", "", "" + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "ClipIn", "KTime", "Time", "",0 + P: "ClipOut", "KTime", "Time", "",0 + P: "Offset", "KTime", "Time", "",0 + P: "PlaySpeed", "double", "Number", "",0 + P: "FreeRunning", "bool", "", "",0 + P: "Loop", "bool", "", "",0 + P: "Mute", "bool", "", "",0 + P: "AccessMode", "enum", "", "",0 + P: "ImageSequence", "bool", "", "",0 + P: "ImageSequenceOffset", "int", "Integer", "",0 + P: "FrameRate", "double", "Number", "",0 + P: "LastFrame", "int", "Integer", "",0 + P: "Width", "int", "Integer", "",0 + P: "Height", "int", "Integer", "",0 + P: "StartFrame", "int", "Integer", "",0 + P: "StopFrame", "int", "Integer", "",0 + P: "InterlaceMode", "enum", "", "",0 + } + } + } +} + +; Object properties +;------------------------------------------------------------------ + +Objects: { + Geometry: 2671579482576, "Geometry::", "Mesh" { + Properties70: { + P: "Color", "ColorRGB", "Color", "",0.603921568627451,0.603921568627451,0.898039215686275 + } + Vertices: *24 { + a: -23.6220474243164,-23.6220474243164,0,23.6220474243164,-23.6220474243164,0,-23.6220474243164,23.6220474243164,0,23.6220474243164,23.6220474243164,0,-23.6220474243164,-23.6220474243164,47.2440948486328,23.6220474243164,-23.6220474243164,47.2440948486328,-23.6220474243164,23.6220474243164,47.2440948486328,23.6220474243164,23.6220474243164,47.2440948486328 + } + PolygonVertexIndex: *24 { + a: 0,2,3,-2,4,5,7,-7,0,1,5,-5,1,3,7,-6,3,2,6,-8,2,0,4,-7 + } + Edges: *12 { + a: 0,1,2,3,4,5,6,7,9,11,13,17 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *72 { + a: 0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,1,0,0,1,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 + } + NormalsW: *24 { + a: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "UVChannel_1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *72 { + a: 0,1,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,0,1,0,0,1,0,0,1,0,0,1 + } + BinormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "UVChannel_1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *72 { + a: -1,-0,0,-1,-0,0,-1,-0,0,-1,-0,0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,0,-0,1,0,-0,1,0,-0,1,0,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,0,-1,-0,0,-1,-0,0,-1,-0,0,-1,-0 + } + TangentsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "UVChannel_1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *48 { + a: 1,0,0,0,1,1,0,1,0,0,1,0,0,1,1,1,0,0,1,0,0,1,1,1,0,0,1,0,0,1,1,1,0,0,1,0,0,1,1,1,0,0,1,0,0,1,1,1 + } + UVIndex: *24 { + a: 0,2,3,1,4,5,7,6,8,9,11,10,12,13,15,14,16,17,19,18,20,21,23,22 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygon" + ReferenceInformationType: "Direct" + Smoothing: *6 { + a: 2,4,8,16,32,64 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + } + Model: 2672936127584, "Model::Box001", "Mesh" { + Version: 232 + Properties70: { + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",0.000114116096496582,0,0 + P: "Lcl Scaling", "Lcl Scaling", "", "A",0.0254,0.0254,0.0254 + P: "MaxHandle", "int", "Integer", "UH",1 + } + Shading: T + Culling: "CullingOff" + } + Material: 2669981279872, "Material::03 - Default", "" { + Version: 102 + ShadingModel: "phong" + MultiLayer: 0 + Properties70: { + P: "ShadingModel", "KString", "", "", "phong" + P: "EmissiveFactor", "Number", "", "A",0 + P: "AmbientColor", "Color", "", "A",0.588235318660736,0.588235318660736,0.588235318660736 + P: "DiffuseColor", "Color", "", "A",0.588235318660736,0.588235318660736,0.588235318660736 + P: "TransparentColor", "Color", "", "A",1,1,1 + P: "SpecularColor", "Color", "", "A",0.899999976158142,0.899999976158142,0.899999976158142 + P: "SpecularFactor", "Number", "", "A",0 + P: "ShininessExponent", "Number", "", "A",1.99999988079071 + P: "Emissive", "Vector3D", "Vector", "",0,0,0 + P: "Ambient", "Vector3D", "Vector", "",0.588235318660736,0.588235318660736,0.588235318660736 + P: "Diffuse", "Vector3D", "Vector", "",0.588235318660736,0.588235318660736,0.588235318660736 + P: "Specular", "Vector3D", "Vector", "",0,0,0 + P: "Shininess", "double", "Number", "",1.99999988079071 + P: "Opacity", "double", "Number", "",1 + P: "Reflectivity", "double", "Number", "",0 + } + } + Video: 2669981292352, "Video::Map #7", "Clip" { + Type: "Clip" + Properties70: { + P: "Path", "KString", "XRefUrl", "", "C:\Users\HTC Vive 1\Desktop\uv_test.png" + P: "RelPath", "KString", "XRefUrl", "", "..\..\..\Desktop\uv_test.png" + } + UseMipMap: 0 + Filename: "C:\Users\HTC Vive 1\Desktop\uv_test.png" + RelativeFilename: "..\..\..\Desktop\uv_test.png" + Content: , + "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" + } + Texture: 2669981291872, "Texture::Map #7", "" { + Type: "TextureVideoClip" + Version: 202 + TextureName: "Texture::Map #7" + Properties70: { + P: "UVSet", "KString", "", "", "UVChannel_1" + P: "UseMaterial", "bool", "", "",1 + } + Media: "Video::Map #7" + FileName: "C:\Users\HTC Vive 1\Desktop\uv_test.png" + RelativeFilename: "..\..\..\Desktop\uv_test.png" + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + } + AnimationStack: 2669472506272, "AnimStack::Take 001", "" { + Properties70: { + P: "LocalStop", "KTime", "Time", "",153953860000 + P: "ReferenceStop", "KTime", "Time", "",153953860000 + } + } +} + +; Object connections +;------------------------------------------------------------------ + +Connections: { + + ;Model::Box001, Model::RootNode + C: "OO",2672936127584,0 + + ;Geometry::, Model::Box001 + C: "OO",2671579482576,2672936127584 + + ;Material::03 - Default, Model::Box001 + C: "OO",2669981279872,2672936127584 + + ;Texture::Map #7, Material::03 - Default + C: "OP",2669981291872,2669981279872, "DiffuseColor" + + ;Video::Map #7, Texture::Map #7 + C: "OO",2669981292352,2669981291872 +} diff --git a/test/models/FBX/embedded_ascii/box_embedded_texture_fragmented.fbx b/test/models/FBX/embedded_ascii/box_embedded_texture_fragmented.fbx new file mode 100644 index 000000000..6a476d3a1 --- /dev/null +++ b/test/models/FBX/embedded_ascii/box_embedded_texture_fragmented.fbx @@ -0,0 +1,697 @@ +; FBX 7.5.0 project file +; ---------------------------------------------------- + +FBXHeaderExtension: { + FBXHeaderVersion: 1003 + FBXVersion: 7500 + CreationTimeStamp: { + Version: 1000 + Year: 2019 + Month: 5 + Day: 14 + Hour: 12 + Minute: 35 + Second: 1 + Millisecond: 267 + } + Creator: "FBX SDK/FBX Plugins version 2018.1.1" + SceneInfo: "SceneInfo::GlobalInfo", "UserData" { + Type: "UserData" + Version: 100 + MetaData: { + Version: 100 + Title: "" + Subject: "" + Author: "" + Keywords: "" + Revision: "" + Comment: "" + } + Properties70: { + P: "DocumentUrl", "KString", "Url", "", "U:\Some\Absolute\Path\box_embedded_texture_fragmented.fbx" + P: "SrcDocumentUrl", "KString", "Url", "", "U:\Some\Absolute\Path\box_embedded_texture_fragmented.fbx" + P: "Original", "Compound", "", "" + P: "Original|ApplicationVendor", "KString", "", "", "Autodesk" + P: "Original|ApplicationName", "KString", "", "", "Maya" + P: "Original|ApplicationVersion", "KString", "", "", "201800" + P: "Original|DateTime_GMT", "DateTime", "", "", "14/05/2019 11:35:01.267" + P: "Original|FileName", "KString", "", "", "U:\Some\Absolute\Path\box_embedded_texture_fragmented.fbx" + P: "LastSaved", "Compound", "", "" + P: "LastSaved|ApplicationVendor", "KString", "", "", "Autodesk" + P: "LastSaved|ApplicationName", "KString", "", "", "Maya" + P: "LastSaved|ApplicationVersion", "KString", "", "", "201800" + P: "LastSaved|DateTime_GMT", "DateTime", "", "", "14/05/2019 11:35:01.267" + P: "Original|ApplicationActiveProject", "KString", "", "", "U:\Some\Absolute\Path" + } + } +} +GlobalSettings: { + Version: 1000 + Properties70: { + P: "UpAxis", "int", "Integer", "",1 + P: "UpAxisSign", "int", "Integer", "",1 + P: "FrontAxis", "int", "Integer", "",2 + P: "FrontAxisSign", "int", "Integer", "",1 + P: "CoordAxis", "int", "Integer", "",0 + P: "CoordAxisSign", "int", "Integer", "",1 + P: "OriginalUpAxis", "int", "Integer", "",1 + P: "OriginalUpAxisSign", "int", "Integer", "",1 + P: "UnitScaleFactor", "double", "Number", "",100 + P: "OriginalUnitScaleFactor", "double", "Number", "",1 + P: "AmbientColor", "ColorRGB", "Color", "",0,0,0 + P: "DefaultCamera", "KString", "", "", "Producer Perspective" + P: "TimeMode", "enum", "", "",6 + P: "TimeProtocol", "enum", "", "",2 + P: "SnapOnFrameMode", "enum", "", "",0 + P: "TimeSpanStart", "KTime", "Time", "",0 + P: "TimeSpanStop", "KTime", "Time", "",153953860000 + P: "CustomFrameRate", "double", "Number", "",-1 + P: "TimeMarker", "Compound", "", "" + P: "CurrentTimeMarker", "int", "Integer", "",-1 + } +} + +; Documents Description +;------------------------------------------------------------------ + +Documents: { + Count: 1 + Document: 1827090966928, "", "Scene" { + Properties70: { + P: "SourceObject", "object", "", "" + P: "ActiveAnimStackName", "KString", "", "", "Take 001" + } + RootNode: 0 + } +} + +; Document References +;------------------------------------------------------------------ + +References: { +} + +; Object definitions +;------------------------------------------------------------------ + +Definitions: { + Version: 100 + Count: 17 + ObjectType: "GlobalSettings" { + Count: 1 + } + ObjectType: "AnimationStack" { + Count: 1 + PropertyTemplate: "FbxAnimStack" { + Properties70: { + P: "Description", "KString", "", "", "" + P: "LocalStart", "KTime", "Time", "",0 + P: "LocalStop", "KTime", "Time", "",0 + P: "ReferenceStart", "KTime", "Time", "",0 + P: "ReferenceStop", "KTime", "Time", "",0 + } + } + } + ObjectType: "AnimationLayer" { + Count: 1 + PropertyTemplate: "FbxAnimLayer" { + Properties70: { + P: "Weight", "Number", "", "A",100 + P: "Mute", "bool", "", "",0 + P: "Solo", "bool", "", "",0 + P: "Lock", "bool", "", "",0 + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "BlendMode", "enum", "", "",0 + P: "RotationAccumulationMode", "enum", "", "",0 + P: "ScaleAccumulationMode", "enum", "", "",0 + P: "BlendModeBypass", "ULongLong", "", "",0 + } + } + } + ObjectType: "Geometry" { + Count: 1 + PropertyTemplate: "FbxMesh" { + Properties70: { + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "BBoxMin", "Vector3D", "Vector", "",0,0,0 + P: "BBoxMax", "Vector3D", "Vector", "",0,0,0 + P: "Primary Visibility", "bool", "", "",1 + P: "Casts Shadows", "bool", "", "",1 + P: "Receive Shadows", "bool", "", "",1 + } + } + } + ObjectType: "Material" { + Count: 1 + PropertyTemplate: "FbxSurfacePhong" { + Properties70: { + P: "ShadingModel", "KString", "", "", "Phong" + P: "MultiLayer", "bool", "", "",0 + P: "EmissiveColor", "Color", "", "A",0,0,0 + P: "EmissiveFactor", "Number", "", "A",1 + P: "AmbientColor", "Color", "", "A",0.2,0.2,0.2 + P: "AmbientFactor", "Number", "", "A",1 + P: "DiffuseColor", "Color", "", "A",0.8,0.8,0.8 + P: "DiffuseFactor", "Number", "", "A",1 + P: "Bump", "Vector3D", "Vector", "",0,0,0 + P: "NormalMap", "Vector3D", "Vector", "",0,0,0 + P: "BumpFactor", "double", "Number", "",1 + P: "TransparentColor", "Color", "", "A",0,0,0 + P: "TransparencyFactor", "Number", "", "A",0 + P: "DisplacementColor", "ColorRGB", "Color", "",0,0,0 + P: "DisplacementFactor", "double", "Number", "",1 + P: "VectorDisplacementColor", "ColorRGB", "Color", "",0,0,0 + P: "VectorDisplacementFactor", "double", "Number", "",1 + P: "SpecularColor", "Color", "", "A",0.2,0.2,0.2 + P: "SpecularFactor", "Number", "", "A",1 + P: "ShininessExponent", "Number", "", "A",20 + P: "ReflectionColor", "Color", "", "A",0,0,0 + P: "ReflectionFactor", "Number", "", "A",1 + } + } + } + ObjectType: "Texture" { + Count: 1 + PropertyTemplate: "FbxFileTexture" { + Properties70: { + P: "TextureTypeUse", "enum", "", "",0 + P: "Texture alpha", "Number", "", "A",1 + P: "CurrentMappingType", "enum", "", "",0 + P: "WrapModeU", "enum", "", "",0 + P: "WrapModeV", "enum", "", "",0 + P: "UVSwap", "bool", "", "",0 + P: "PremultiplyAlpha", "bool", "", "",1 + P: "Translation", "Vector", "", "A",0,0,0 + P: "Rotation", "Vector", "", "A",0,0,0 + P: "Scaling", "Vector", "", "A",1,1,1 + P: "TextureRotationPivot", "Vector3D", "Vector", "",0,0,0 + P: "TextureScalingPivot", "Vector3D", "Vector", "",0,0,0 + P: "CurrentTextureBlendMode", "enum", "", "",1 + P: "UVSet", "KString", "", "", "default" + P: "UseMaterial", "bool", "", "",0 + P: "UseMipMap", "bool", "", "",0 + } + } + } + ObjectType: "Model" { + Count: 1 + PropertyTemplate: "FbxNode" { + Properties70: { + P: "QuaternionInterpolate", "enum", "", "",0 + P: "RotationOffset", "Vector3D", "Vector", "",0,0,0 + P: "RotationPivot", "Vector3D", "Vector", "",0,0,0 + P: "ScalingOffset", "Vector3D", "Vector", "",0,0,0 + P: "ScalingPivot", "Vector3D", "Vector", "",0,0,0 + P: "TranslationActive", "bool", "", "",0 + P: "TranslationMin", "Vector3D", "Vector", "",0,0,0 + P: "TranslationMax", "Vector3D", "Vector", "",0,0,0 + P: "TranslationMinX", "bool", "", "",0 + P: "TranslationMinY", "bool", "", "",0 + P: "TranslationMinZ", "bool", "", "",0 + P: "TranslationMaxX", "bool", "", "",0 + P: "TranslationMaxY", "bool", "", "",0 + P: "TranslationMaxZ", "bool", "", "",0 + P: "RotationOrder", "enum", "", "",0 + P: "RotationSpaceForLimitOnly", "bool", "", "",0 + P: "RotationStiffnessX", "double", "Number", "",0 + P: "RotationStiffnessY", "double", "Number", "",0 + P: "RotationStiffnessZ", "double", "Number", "",0 + P: "AxisLen", "double", "Number", "",10 + P: "PreRotation", "Vector3D", "Vector", "",0,0,0 + P: "PostRotation", "Vector3D", "Vector", "",0,0,0 + P: "RotationActive", "bool", "", "",0 + P: "RotationMin", "Vector3D", "Vector", "",0,0,0 + P: "RotationMax", "Vector3D", "Vector", "",0,0,0 + P: "RotationMinX", "bool", "", "",0 + P: "RotationMinY", "bool", "", "",0 + P: "RotationMinZ", "bool", "", "",0 + P: "RotationMaxX", "bool", "", "",0 + P: "RotationMaxY", "bool", "", "",0 + P: "RotationMaxZ", "bool", "", "",0 + P: "InheritType", "enum", "", "",0 + P: "ScalingActive", "bool", "", "",0 + P: "ScalingMin", "Vector3D", "Vector", "",0,0,0 + P: "ScalingMax", "Vector3D", "Vector", "",1,1,1 + P: "ScalingMinX", "bool", "", "",0 + P: "ScalingMinY", "bool", "", "",0 + P: "ScalingMinZ", "bool", "", "",0 + P: "ScalingMaxX", "bool", "", "",0 + P: "ScalingMaxY", "bool", "", "",0 + P: "ScalingMaxZ", "bool", "", "",0 + P: "GeometricTranslation", "Vector3D", "Vector", "",0,0,0 + P: "GeometricRotation", "Vector3D", "Vector", "",0,0,0 + P: "GeometricScaling", "Vector3D", "Vector", "",1,1,1 + P: "MinDampRangeX", "double", "Number", "",0 + P: "MinDampRangeY", "double", "Number", "",0 + P: "MinDampRangeZ", "double", "Number", "",0 + P: "MaxDampRangeX", "double", "Number", "",0 + P: "MaxDampRangeY", "double", "Number", "",0 + P: "MaxDampRangeZ", "double", "Number", "",0 + P: "MinDampStrengthX", "double", "Number", "",0 + P: "MinDampStrengthY", "double", "Number", "",0 + P: "MinDampStrengthZ", "double", "Number", "",0 + P: "MaxDampStrengthX", "double", "Number", "",0 + P: "MaxDampStrengthY", "double", "Number", "",0 + P: "MaxDampStrengthZ", "double", "Number", "",0 + P: "PreferedAngleX", "double", "Number", "",0 + P: "PreferedAngleY", "double", "Number", "",0 + P: "PreferedAngleZ", "double", "Number", "",0 + P: "LookAtProperty", "object", "", "" + P: "UpVectorProperty", "object", "", "" + P: "Show", "bool", "", "",1 + P: "NegativePercentShapeSupport", "bool", "", "",1 + P: "DefaultAttributeIndex", "int", "Integer", "",-1 + P: "Freeze", "bool", "", "",0 + P: "LODBox", "bool", "", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",0,0,0 + P: "Lcl Rotation", "Lcl Rotation", "", "A",0,0,0 + P: "Lcl Scaling", "Lcl Scaling", "", "A",1,1,1 + P: "Visibility", "Visibility", "", "A",1 + P: "Visibility Inheritance", "Visibility Inheritance", "", "",1 + } + } + } + ObjectType: "AnimationCurveNode" { + Count: 8 + PropertyTemplate: "FbxAnimCurveNode" { + Properties70: { + P: "d", "Compound", "", "" + } + } + } + ObjectType: "CollectionExclusive" { + Count: 1 + PropertyTemplate: "FbxDisplayLayer" { + Properties70: { + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "Show", "bool", "", "",1 + P: "Freeze", "bool", "", "",0 + P: "LODBox", "bool", "", "",0 + } + } + } + ObjectType: "Video" { + Count: 1 + PropertyTemplate: "FbxVideo" { + Properties70: { + P: "Path", "KString", "XRefUrl", "", "" + P: "RelPath", "KString", "XRefUrl", "", "" + P: "Color", "ColorRGB", "Color", "",0.8,0.8,0.8 + P: "ClipIn", "KTime", "Time", "",0 + P: "ClipOut", "KTime", "Time", "",0 + P: "Offset", "KTime", "Time", "",0 + P: "PlaySpeed", "double", "Number", "",0 + P: "FreeRunning", "bool", "", "",0 + P: "Loop", "bool", "", "",0 + P: "Mute", "bool", "", "",0 + P: "AccessMode", "enum", "", "",0 + P: "ImageSequence", "bool", "", "",0 + P: "ImageSequenceOffset", "int", "Integer", "",0 + P: "FrameRate", "double", "Number", "",0 + P: "LastFrame", "int", "Integer", "",0 + P: "Width", "int", "Integer", "",0 + P: "Height", "int", "Integer", "",0 + P: "StartFrame", "int", "Integer", "",0 + P: "StopFrame", "int", "Integer", "",0 + P: "InterlaceMode", "enum", "", "",0 + } + } + } +} + +; Object properties +;------------------------------------------------------------------ + +Objects: { + Geometry: 1827080161440, "Geometry::", "Mesh" { + Vertices: *24 { + a: -0.5,-0.5,-0.5,0.5,-0.50000011920929,-0.5,-0.5,0.50000011920929,-0.5,0.5,0.50000011920929,-0.5,-0.5,-0.500000059604645,0.5,0.5,-0.500000059604645,0.5,-0.5,0.500000059604645,0.5,0.5,0.500000059604645,0.5 + } + PolygonVertexIndex: *24 { + a: 0,2,3,-2,4,5,7,-7,0,1,5,-5,1,3,7,-6,3,2,6,-8,2,0,4,-7 + } + Edges: *12 { + a: 0,1,2,3,4,5,6,7,9,11,13,17 + } + GeometryVersion: 124 + LayerElementNormal: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Normals: *72 { + a: 0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,1,0,0,1,0,0,1,0,0,1,-5.96046447753906e-08,-1,0,-5.96046447753906e-08,-1,0,-5.96046447753906e-08,-1,0,-5.96046447753906e-08,-1,0,1,0,0,1,0,0,1,0,0,1,0,0,0,1,5.96046447753906e-08,0,1,5.96046447753906e-08,0,1,5.96046447753906e-08,0,1,5.96046447753906e-08,-1,0,0,-1,0,0,-1,0,0,-1,0,0 + } + NormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementBinormal: 0 { + Version: 102 + Name: "UVChannel_1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *72 { + a: 1.19209289550781e-07,1,0,5.96046447753906e-08,1,0,0,1,0,5.96046447753906e-08,1,0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,0,1,0,0,1,0,0,1,0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,0,1,-0,-5.96046447753906e-08,1,-0,-5.96046447753906e-08,1,-0,-5.96046447753906e-08,1,-0,-5.96046447753906e-08,1,0,0,1,0,0,1,0,0,1,0,0,1 + } + BinormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementBinormal: 1 { + Version: 102 + Name: "UVChannel_3" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Binormals: *72 { + a: -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-0,0,-1,-0,0,-1,0,-0,-1,-0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,5.96046447753906e-08,-1,0,5.96046447753906e-08,-1,0,5.96046447753906e-08,-1,0,5.96046447753906e-08,-1,-0,0,-1,-0,0,-1,-0,0,-1,-0,0,-1 + } + BinormalsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + + } + LayerElementTangent: 0 { + Version: 102 + Name: "UVChannel_1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *72 { + a: -1,1.19209289550781e-07,0,-1,5.96046447753906e-08,0,-1,-0,0,-1,5.96046447753906e-08,0,1,-0,-0,1,-0,0,1,-0,0,1,-0,0,1,-5.96046447753906e-08,-0,1,-5.96046447753906e-08,0,1,-5.96046447753906e-08,0,1,-5.96046447753906e-08,0,-0,1,-0,0,1,-0,0,1,-0,0,1,-0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,-0,0,-1,-0,0,-1,0,0,-1,0,0,-1,0 + } + TangentsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementTangent: 1 { + Version: 102 + Name: "UVChannel_3" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "Direct" + Tangents: *72 { + a: -0,-1,0,-0,-1,0,-0,-1,0,-0,-1,0,0,1,0,0,1,0,-0,1,-0,0,1,0,-1,5.96046447753906e-08,0,-1,5.96046447753906e-08,0,-1,5.96046447753906e-08,-0,-1,5.96046447753906e-08,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,1,-0,-0,1,-0,-0,1,-0,-0,1,-0,-0,0,1,-0,0,1,-0,0,1,-0,0,1,-0 + } + TangentsW: *24 { + a: 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 + } + } + LayerElementUV: 0 { + Version: 101 + Name: "UVChannel_1" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *48 { + a: 1,0,0,0,1,1,0,1,0,0,1,0,0,1,1,1,0,0,1,0,0,1,1,1,0,0,1,0,0,1,1,1,0,0,1,0,0,1,1,1,0,0,1,0,0,1,1,1 + } + UVIndex: *24 { + a: 0,2,3,1,4,5,7,6,8,9,11,10,12,13,15,14,16,17,19,18,20,21,23,22 + } + } + LayerElementUV: 1 { + Version: 101 + Name: "UVChannel_3" + MappingInformationType: "ByPolygonVertex" + ReferenceInformationType: "IndexToDirect" + UV: *48 { + a: 0.28125,0.28125,0,0.28125,0,0,0.28125,0,0.34375,1,0.34375,0.71875,0.625,0.71875,0.625,1,0.28125,0.65625,0,0.65625,0,0.375,0.28125,0.375,0.625,0.28125,0.34375,0.28125,0.34375,0,0.625,0,0.28125,1,0,1,0,0.71875,0.28125,0.71875,0.625,0.65625,0.34375,0.65625,0.34375,0.375,0.625,0.375 + } + UVIndex: *24 { + a: 0,1,2,3,4,5,6,7,20,21,22,23,8,9,10,11,16,17,18,19,12,13,14,15 + } + } + LayerElementSmoothing: 0 { + Version: 102 + Name: "" + MappingInformationType: "ByEdge" + ReferenceInformationType: "Direct" + Smoothing: *12 { + a: 0,0,0,0,0,0,0,0,0,0,0,0 + } + } + LayerElementMaterial: 0 { + Version: 101 + Name: "" + MappingInformationType: "AllSame" + ReferenceInformationType: "IndexToDirect" + Materials: *1 { + a: 0 + } + } + Layer: 0 { + Version: 100 + LayerElement: { + Type: "LayerElementNormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementMaterial" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementSmoothing" + TypedIndex: 0 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 0 + } + } + Layer: 1 { + Version: 100 + LayerElement: { + Type: "LayerElementBinormal" + TypedIndex: 1 + } + LayerElement: { + Type: "LayerElementTangent" + TypedIndex: 1 + } + LayerElement: { + Type: "LayerElementUV" + TypedIndex: 1 + } + } + } + Model: 1826985145024, "Model::Box", "Mesh" { + Version: 232 + Properties70: { + P: "RotationActive", "bool", "", "",1 + P: "InheritType", "enum", "", "",1 + P: "ScalingMax", "Vector3D", "Vector", "",0,0,0 + P: "DefaultAttributeIndex", "int", "Integer", "",0 + P: "Lcl Translation", "Lcl Translation", "", "A",0,0.5,2.18556946492754e-06 + P: "Lcl Rotation", "Lcl Rotation", "", "A",-90,0,0 + P: "currentUVSet", "KString", "", "U", "UVChannel_1" + P: "mr displacement use global settings", "Bool", "", "A+U",1 + P: "mr displacement view dependent", "Bool", "", "A+U",1 + P: "mr displacement method", "Integer", "", "A+U",6,6,6 + P: "mr displacement smoothing on", "Bool", "", "A+U",1 + P: "mr displacement edge length", "Number", "", "A+U",2,2,2 + P: "mr displacement max displace", "Number", "", "A+U",20,20,20 + P: "mr displacement parametric subdivision level", "Integer", "", "A+U",5,5,5 + P: "MaxHandle", "Integer", "", "A+UH",1,0,0 + } + Shading: T + Culling: "CullingOff" + } + Material: 1826343864784, "Material::Default", "" { + Version: 102 + ShadingModel: "phong" + MultiLayer: 0 + Properties70: { + P: "AmbientColor", "Color", "", "A",0,0,0 + P: "DiffuseColor", "Color", "", "A",1,1,1 + P: "TransparencyFactor", "Number", "", "A",1 + P: "SpecularColor", "Color", "", "A",0,0,0 + P: "ShininessExponent", "Number", "", "A",2 + P: "Emissive", "Vector3D", "Vector", "",0,0,0 + P: "Ambient", "Vector3D", "Vector", "",0,0,0 + P: "Diffuse", "Vector3D", "Vector", "",1,1,1 + P: "Specular", "Vector3D", "Vector", "",0,0,0 + P: "Shininess", "double", "Number", "",2 + P: "Opacity", "double", "Number", "",1 + P: "Reflectivity", "double", "Number", "",0 + } + } + Video: 1826343863824, "Video::Map #2", "Clip" { + Type: "Clip" + Properties70: { + P: "Path", "KString", "XRefUrl", "", "U:/Some/Absolute/Path/paper.png" + P: "RelPath", "KString", "XRefUrl", "", "paper.png" + } + UseMipMap: 0 + Filename: "U:/Some/Absolute/Path/paper.png" + RelativeFilename: "paper.png" + Content: , + "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" + } + Texture: 1826343863344, "Texture::Map #2", "" { + Type: "TextureVideoClip" + Version: 202 + TextureName: "Texture::Map #2" + Properties70: { + P: "CurrentTextureBlendMode", "enum", "", "",0 + P: "UVSet", "KString", "", "", "UVChannel_1" + P: "UseMaterial", "bool", "", "",1 + } + Media: "Video::Map #2" + FileName: "U:/Some/Absolute/Path/paper.png" + RelativeFilename: "paper.png" + ModelUVTranslation: 0,0 + ModelUVScaling: 1,1 + Texture_Alpha_Source: "None" + Cropping: 0,0,0,0 + } + AnimationStack: 1827077611568, "AnimStack::Take 001", "" { + Properties70: { + P: "LocalStop", "KTime", "Time", "",153953860000 + P: "ReferenceStop", "KTime", "Time", "",153953860000 + } + } + AnimationCurveNode: 1827077610320, "AnimCurveNode::mr displacement use global settings", "" { + Properties70: { + P: "d|mr displacement use global settings", "Bool", "", "A",1 + } + } + AnimationCurveNode: 1827077600128, "AnimCurveNode::mr displacement view dependent", "" { + Properties70: { + P: "d|mr displacement view dependent", "Bool", "", "A",1 + } + } + AnimationCurveNode: 1827077602624, "AnimCurveNode::mr displacement method", "" { + Properties70: { + P: "d|mr displacement method", "Integer", "", "A",6 + } + } + AnimationCurveNode: 1827077604912, "AnimCurveNode::mr displacement smoothing on", "" { + Properties70: { + P: "d|mr displacement smoothing on", "Bool", "", "A",1 + } + } + AnimationCurveNode: 1827077603664, "AnimCurveNode::mr displacement edge length", "" { + Properties70: { + P: "d|mr displacement edge length", "Number", "", "A",2 + } + } + AnimationCurveNode: 1827077606160, "AnimCurveNode::mr displacement max displace", "" { + Properties70: { + P: "d|mr displacement max displace", "Number", "", "A",20 + } + } + AnimationCurveNode: 1827077607824, "AnimCurveNode::mr displacement parametric subdivision level", "" { + Properties70: { + P: "d|mr displacement parametric subdivision level", "Integer", "", "A",5 + } + } + AnimationCurveNode: 1827077611360, "AnimCurveNode::MaxHandle", "" { + Properties70: { + P: "d|MaxHandle", "Integer", "", "A",1 + } + } + AnimationLayer: 1827070138064, "AnimLayer::BaseLayer", "" { + } + CollectionExclusive: 1827093511360, "DisplayLayer::Box", "DisplayLayer" { + Properties70: { + P: "Color", "ColorRGB", "Color", "",0.607999980449677,0,0.157000005245209 + } + } +} + +; Object connections +;------------------------------------------------------------------ + +Connections: { + + ;Model::Box, Model::RootNode + C: "OO",1826985145024,0 + + ;AnimLayer::BaseLayer, AnimStack::Take 001 + C: "OO",1827070138064,1827077611568 + + ;AnimCurveNode::mr displacement use global settings, AnimLayer::BaseLayer + C: "OO",1827077610320,1827070138064 + + ;AnimCurveNode::mr displacement view dependent, AnimLayer::BaseLayer + C: "OO",1827077600128,1827070138064 + + ;AnimCurveNode::mr displacement method, AnimLayer::BaseLayer + C: "OO",1827077602624,1827070138064 + + ;AnimCurveNode::mr displacement smoothing on, AnimLayer::BaseLayer + C: "OO",1827077604912,1827070138064 + + ;AnimCurveNode::mr displacement edge length, AnimLayer::BaseLayer + C: "OO",1827077603664,1827070138064 + + ;AnimCurveNode::mr displacement max displace, AnimLayer::BaseLayer + C: "OO",1827077606160,1827070138064 + + ;AnimCurveNode::mr displacement parametric subdivision level, AnimLayer::BaseLayer + C: "OO",1827077607824,1827070138064 + + ;AnimCurveNode::MaxHandle, AnimLayer::BaseLayer + C: "OO",1827077611360,1827070138064 + + ;Texture::Map #2, Material::Default + C: "OP",1826343863344,1826343864784, "DiffuseColor" + + ;Texture::Map #2, Material::Default + C: "OP",1826343863344,1826343864784, "TransparentColor" + + ;Video::Map #2, Texture::Map #2 + C: "OO",1826343863824,1826343863344 + + ;Geometry::, Model::Box + C: "OO",1827080161440,1826985145024 + + ;Material::Default, Model::Box + C: "OO",1826343864784,1826985145024 + + ;AnimCurveNode::mr displacement use global settings, Model::Box + C: "OP",1827077610320,1826985145024, "mr displacement use global settings" + + ;AnimCurveNode::mr displacement view dependent, Model::Box + C: "OP",1827077600128,1826985145024, "mr displacement view dependent" + + ;AnimCurveNode::mr displacement method, Model::Box + C: "OP",1827077602624,1826985145024, "mr displacement method" + + ;AnimCurveNode::mr displacement smoothing on, Model::Box + C: "OP",1827077604912,1826985145024, "mr displacement smoothing on" + + ;AnimCurveNode::mr displacement edge length, Model::Box + C: "OP",1827077603664,1826985145024, "mr displacement edge length" + + ;AnimCurveNode::mr displacement max displace, Model::Box + C: "OP",1827077606160,1826985145024, "mr displacement max displace" + + ;AnimCurveNode::mr displacement parametric subdivision level, Model::Box + C: "OP",1827077607824,1826985145024, "mr displacement parametric subdivision level" + + ;AnimCurveNode::MaxHandle, Model::Box + C: "OP",1827077611360,1826985145024, "MaxHandle" + + ;Model::Box, DisplayLayer::Box + C: "OO",1826985145024,1827093511360 +} +;Takes section +;---------------------------------------------------- + +Takes: { + Current: "Take 001" + Take: "Take 001" { + FileName: "Take_001.tak" + LocalTime: 0,153953860000 + ReferenceTime: 0,153953860000 + } +} diff --git a/test/models/FBX/transparentTest.fbx b/test/models/FBX/transparentTest.fbx new file mode 100644 index 000000000..2c4f1cd82 --- /dev/null +++ b/test/models/FBX/transparentTest.fbx @@ -0,0 +1,839 @@ +Kaydara FBX Binary  „ ¼ FBXHeaderExtension\   FBXHeaderVersionIë x   +FBXVersionI„ ˜   EncryptionTypeI  CreationTimeStampÏ   VersionIè å   YearIã ü   MonthI    DayI '   HourI ?   MinuteI W   SecondI t   MillisecondID ¼  ' CreatorS" FBX SDK/FBX Plugins version 2017.1¯  ' SceneInfoS GlobalInfo SceneInfoS UserData  TypeS UserData0   VersionId  MetaData^   VersionId u   TitleS Ž   SubjectS ¦   AuthorS À   KeywordsS Ú   RevisionS ó   CommentS ¢ Properties70˜  q PS DocumentUrlS KStringS UrlS SC C:\Users\Destranix\Documents\maya\projects\Test\transparentTest.fbx  t PS SrcDocumentUrlS KStringS UrlS SC C:\Users\Destranix\Documents\maya\projects\Test\transparentTest.fbxL  $ PS OriginalS CompoundS S œ  B PS Original|ApplicationVendorS KStringS S S Autodeskæ  < PS Original|ApplicationNameS KStringS S S Maya3  ? PS Original|ApplicationVersionS KStringS S S 2017Ž  M PS Original|DateTime_GMTS DateTimeS S S 11/09/2019 14:11:05.265  t PS Original|FileNameS KStringS S SC C:\Users\Destranix\Documents\maya\projects\Test\transparentTest.fbxC  % PS LastSavedS CompoundS S ”  C PS LastSaved|ApplicationVendorS KStringS S S Autodeskß  = PS LastSaved|ApplicationNameS KStringS S S Maya-  @ PS LastSaved|ApplicationVersionS KStringS S S 2017‰  N PS LastSaved|DateTime_GMTS DateTimeS S S 11/09/2019 14:11:05.265  p PS! Original|ApplicationActiveProjectS KStringS S S/ C:\Users\Destranix\Documents\maya\projects\Test•  € PS Original|ApplicationNativeFileS KStringS S SB C:\Users\Destranix\Documents\maya\projects\Test\transparentTest.mb ä   FileIdR (¶/æ»/Æȶø+®%óÿ   CreationTimeS 2019-09-11 16:11:05:324c  6 CreatorS1 FBX SDK/FBX Plugins version 2017.1 build=20161007È GlobalSettings—   VersionIè » Properties70ç  ) PS UpAxisS intS IntegerS I " +  - PS + UpAxisSignS intS IntegerS I \ +  , PS FrontAxisS intS IntegerS I š +  0 PS FrontAxisSignS intS IntegerS I Ô +  , PS CoordAxisS intS IntegerS I   0 PS CoordAxisSignS intS IntegerS I Q  1 PS OriginalUpAxisS intS IntegerS I ”  5 PS OriginalUpAxisSignS intS IntegerS I Ú  8 PS UnitScaleFactorS doubleS NumberS D ð?(  @ PS OriginalUnitScaleFactorS doubleS NumberS D ð?~  H PS AmbientColorS ColorRGBS ColorS D D D Í  A PS DefaultCameraS KStringS S S Producer Perspective  % PS TimeModeS enumS S I 7  ) PS TimeProtocolS enumS S I q  , PS SnapOnFrameModeS enumS S I ²  3 PS TimeSpanStartS KTimeS TimeS LR^´r ò  2 PS TimeSpanStopS KTimeS TimeS L°éœY 8  8 PS CustomFrameRateS doubleS NumberS D ð¿l  & PS + TimeMarkerS CompoundS S ®  4 PS CurrentTimeMarkerS intS IntegerS Iÿÿÿÿ ý Documentsõ   CountI ð   DocumentL@q®– S S SceneÅ Properties70o  & PS SourceObjectS objectS S ¸  ; PS ActiveAnimStackNameS KStringS S S Take 001 ã  RootNodeL ! +References (\ DefinitionsR   VersionId i   CountI@ ·   +ObjectTypeS GlobalSettingsª   CountI    +ObjectTypeS AnimationStackø   CountI    PropertyTemplateS FbxAnimStackƒ Properties70x  + PS DescriptionS KStringS S S ¶  0 PS + LocalStartS KTimeS TimeS L ó  / PS LocalStopS KTimeS TimeS L 5  4 PS ReferenceStartS KTimeS TimeS L v  3 PS ReferenceStopS KTimeS TimeS L Z   +ObjectTypeS AnimationLayerÞ   CountI M   PropertyTemplateS FbxAnimLayer@ Properties70]  * PS WeightS NumberS S AD Y@Œ  ! PS MuteS boolS S I »  ! PS SoloS boolS S I ê  ! PS LockS boolS S I 9  A PS ColorS ColorRGBS ColorS Dš™™™™™é?Dš™™™™™é?Dš™™™™™é?m  & PS BlendModeS enumS S I °  5 PS RotationAccumulationModeS enumS S I ð  2 PS ScaleAccumulationModeS enumS S I 3  5 PS BlendModeBypassS ULongLongS S L    +ObjectTypeS Geometry•   CountI “  PropertyTemplateS FbxMesh† Properties70&  A PS ColorS ColorRGBS ColorS Dš™™™™™é?Dš™™™™™é?Dš™™™™™é?x  D PS BBoxMinS Vector3DS VectorS D D D Ê  D PS BBoxMaxS Vector3DS VectorS D D D   / PS Primary VisibilityS boolS S I ?  * PS Casts ShadowsS boolS S I y  , PS Receive ShadowsS boolS S I ¢  +ObjectTypeS MaterialÛ   CountI •   PropertyTemplateS FbxSurfacePhongˆ Properties70d  1 PS ShadingModelS KStringS S S Phong™  ' PS + MultiLayerS boolS S I é  B PS EmissiveColorS ColorS S AD D D )  2 PS EmissiveFactorS NumberS S AD ð?x  A PS AmbientColorS ColorS S ADš™™™™™É?Dš™™™™™É?Dš™™™™™É?·  1 PS AmbientFactorS NumberS S AD ð?  A PS DiffuseColorS ColorS S ADš™™™™™é?Dš™™™™™é?Dš™™™™™é?E  1 PS DiffuseFactorS NumberS S AD ð?”  A PS BumpS Vector3DS VectorS D D D è  F PS NormalMapS Vector3DS VectorS D D D )  3 PS + BumpFactorS doubleS NumberS D ð?|  E PS TransparentColorS ColorS S AD D D À  6 PS TransparencyFactorS NumberS S AD   M PS DisplacementColorS ColorRGBS ColorS D D D d  ; PS DisplacementFactorS doubleS NumberS D ð?Å  S PS VectorDisplacementColorS ColorRGBS ColorS D D D   A PS VectorDisplacementFactorS doubleS NumberS D ð?d  B PS SpecularColorS ColorS S ADš™™™™™É?Dš™™™™™É?Dš™™™™™É?¤  2 PS SpecularFactorS NumberS S AD ð?ç  5 PS ShininessExponentS NumberS S AD 4@9  D PS ReflectionColorS ColorS S AD D D {  4 PS ReflectionFactorS NumberS S AD ð? ^#  +ObjectTypeS TextureÜ   CountI Q#   PropertyTemplateS FbxFileTextureD# Properties70^  + PS TextureTypeUseS enumS S I   1 PS Texture alphaS NumberS S AD ð?Ú  / PS CurrentMappingTypeS enumS S I   & PS WrapModeUS enumS S I B  & PS WrapModeVS enumS S I s  # PS UVSwapS boolS S I ®  - PS PremultiplyAlphaS boolS S I ý  A PS TranslationS VectorS S AD D D I!  > PS RotationS VectorS S AD D D ”!  = PS ScalingS VectorS S AD ð?D ð?D ð?ó!  Q PS TextureRotationPivotS Vector3DS VectorS D D D Q"  P PS TextureScalingPivotS Vector3DS VectorS D D D “"  4 PS CurrentTextureBlendModeS enumS S I Í"  , PS UVSetS KStringS S S default#  ( PS UseMaterialS boolS S I 7#  & PS UseMipMapS boolS S I 7  + +ObjectTypeS Model–#   CountI ô6  PropertyTemplateS FbxNodeç6 Properties70$  2 PS QuaternionInterpolateS enumS S I q$  K PS RotationOffsetS Vector3DS VectorS D D D É$  J PS RotationPivotS Vector3DS VectorS D D D !%  J PS ScalingOffsetS Vector3DS VectorS D D D x%  I PS ScalingPivotS Vector3DS VectorS D D D ´%  . PS TranslationActiveS boolS S I &  K PS TranslationMinS Vector3DS VectorS D D D f&  K PS TranslationMaxS Vector3DS VectorS D D D  &  , PS TranslationMinXS boolS S I Ú&  , PS TranslationMinYS boolS S I '  , PS TranslationMinZS boolS S I N'  , PS TranslationMaxXS boolS S I ˆ'  , PS TranslationMaxYS boolS S I Â'  , PS TranslationMaxZS boolS S I ú'  * PS RotationOrderS enumS S I >(  6 PS RotationSpaceForLimitOnlyS boolS S I ‡(  ; PS RotationStiffnessXS doubleS NumberS D Ð(  ; PS RotationStiffnessYS doubleS NumberS D )  ; PS RotationStiffnessZS doubleS NumberS D W)  0 PS AxisLenS doubleS NumberS D $@­)  H PS PreRotationS Vector3DS VectorS D D D *  I PS PostRotationS Vector3DS VectorS D D D =*  + PS RotationActiveS boolS S I “*  H PS RotationMinS Vector3DS VectorS D D D é*  H PS RotationMaxS Vector3DS VectorS D D D +  ) PS RotationMinXS boolS S I W+  ) PS RotationMinYS boolS S I Ž+  ) PS RotationMinZS boolS S I Å+  ) PS RotationMaxXS boolS S I ü+  ) PS RotationMaxYS boolS S I 3,  ) PS RotationMaxZS boolS S I i,  ( PS InheritTypeS enumS S I ¡,  * PS ScalingActiveS boolS S I ö,  G PS + ScalingMinS Vector3DS VectorS D D D K-  G PS + ScalingMaxS Vector3DS VectorS D ð?D ð?D ð?-  ( PS ScalingMinXS boolS S I ·-  ( PS ScalingMinYS boolS S I í-  ( PS ScalingMinZS boolS S I #.  ( PS ScalingMaxXS boolS S I Y.  ( PS ScalingMaxYS boolS S I .  ( PS ScalingMaxZS boolS S I î.  Q PS GeometricTranslationS Vector3DS VectorS D D D J/  N PS GeometricRotationS Vector3DS VectorS D D D ¥/  M PS GeometricScalingS Vector3DS VectorS D ð?D ð?D ð?é/  6 PS MinDampRangeXS doubleS NumberS D -0  6 PS MinDampRangeYS doubleS NumberS D q0  6 PS MinDampRangeZS doubleS NumberS D µ0  6 PS MaxDampRangeXS doubleS NumberS D ù0  6 PS MaxDampRangeYS doubleS NumberS D =1  6 PS MaxDampRangeZS doubleS NumberS D „1  9 PS MinDampStrengthXS doubleS NumberS D Ë1  9 PS MinDampStrengthYS doubleS NumberS D 2  9 PS MinDampStrengthZS doubleS NumberS D Y2  9 PS MaxDampStrengthXS doubleS NumberS D  2  9 PS MaxDampStrengthYS doubleS NumberS D ç2  9 PS MaxDampStrengthZS doubleS NumberS D ,3  7 PS PreferedAngleXS doubleS NumberS D q3  7 PS PreferedAngleYS doubleS NumberS D ¶3  7 PS PreferedAngleZS doubleS NumberS D ì3  ( PS LookAtPropertyS objectS S $4  * PS UpVectorPropertyS objectS S S4  ! PS ShowS boolS S I ™4  8 PS NegativePercentShapeSupportS boolS S I ß4  8 PS DefaultAttributeIndexS intS IntegerS Iÿÿÿÿ5  # PS FreezeS boolS S I A5  # PS LODBoxS boolS S I 5  N PS Lcl TranslationS Lcl TranslationS S AD D D ó5  H PS Lcl RotationS Lcl RotationS S AD D D G6  F PS Lcl ScalingS Lcl ScalingS S AD ð?D ð?D ð?‡6  2 PS + VisibilityS + VisibilityS S AD ð?Ú6  E PS Visibility InheritanceS Visibility InheritanceS S I R   +ObjectTypeS NodeAttributeA7   CountI R   PropertyTemplateS FbxCamera R Properties70Ô7  A PS ColorS ColorRGBS ColorS Dš™™™™™é?Dš™™™™™é?Dš™™™™™é? 8  > PS PositionS VectorS S AD D D l8  > PS UpVectorS VectorS S AD D ð?D À8  F PS InterestPositionS VectorS S AD D D ô8  & PS RollS RollS S AD <9  : PS OpticalCenterXS OpticalCenterXS S AD „9  : PS OpticalCenterYS OpticalCenterYS S AD Ö9  D PS BackgroundColorS ColorS S AD)\Âõ(ä?D)\Âõ(ä?D)\Âõ(ä?:  - PS TurnTableS NumberS S AD P:  1 PS DisplayTurnTableIconS boolS S I ˆ:  * PS UseMotionBlurS boolS S I È:  2 PS UseRealTimeMotionBlurS boolS S I ;  9 PS Motion Blur IntensityS NumberS S AD ð?I;  , PS AspectRatioModeS enumS S I ‹;  4 PS AspectWidthS doubleS NumberS D t@Î;  5 PS AspectHeightS doubleS NumberS D i@<  9 PS PixelAspectRatioS doubleS NumberS D ð?R<  / PS FilmOffsetXS NumberS S AD <  / PS FilmOffsetYS NumberS S AD Ï<  2 PS FilmWidthS doubleS NumberS Dé&1¬ê?=  3 PS + FilmHeightS doubleS NumberS D/Ý$•ã?V=  8 PS FilmAspectRatioS doubleS NumberS DUUUUUUõ?=  9 PS FilmSqueezeRatioS doubleS NumberS D ð?×=  , PS FilmFormatIndexS enumS S I >  , PS PreScaleS NumberS S AD ð?Q>  2 PS FilmTranslateXS NumberS S AD ‘>  2 PS FilmTranslateYS NumberS S AD Ñ>  2 PS FilmRollPivotXS NumberS S AD ?  2 PS FilmRollPivotYS NumberS S AD P?  1 PS FilmRollValueS NumberS S AD ˆ?  * PS FilmRollOrderS enumS S I ¿?  ) PS ApertureModeS enumS S I ñ?  $ PS GateFitS enumS S I 3@  4 PS FieldOfViewS FieldOfViewS S AD  p9@w@  6 PS FieldOfViewXS FieldOfViewXS S AD D@»@  6 PS FieldOfViewYS FieldOfViewYS S AD D@ø@  / PS FocalLengthS NumberS S AD&‘àVrA@/A  ) PS CameraFormatS enumS S I gA  * PS UseFrameColorS boolS S I »A  F PS + FrameColorS ColorRGBS ColorS D333333Ó?D333333Ó?D333333Ó?îA  % PS ShowNameS boolS S I )B  - PS ShowInfoOnMovingS boolS S I \B  % PS ShowGridS boolS S I ˜B  . PS ShowOpticalCenterS boolS S I ÍB  ' PS + ShowAzimutS boolS S I C  ) PS ShowTimeCodeS boolS S I 8C  & PS ShowAudioS boolS S I C  G PS + AudioColorS Vector3DS VectorS D D ð?D ÍC  2 PS NearPlaneS doubleS NumberS D $@ D  1 PS FarPlaneS doubleS NumberS D @¯@KD  1 PS AutoComputeClipPanesS boolS S I ˆD  / PS ViewCameraToLookAtS boolS S I ÊD  4 PS ViewFrustumNearFarPlaneS boolS S I E  5 PS ViewFrustumBackPlaneModeS enumS S I PE  5 PS BackPlaneDistanceS NumberS S AD @¯@E  2 PS BackPlaneDistanceModeS enumS S I ÔE  6 PS ViewFrustumFrontPlaneModeS enumS S I F  6 PS FrontPlaneDistanceS NumberS S AD $@YF  3 PS FrontPlaneDistanceModeS enumS S I ŒF  % PS LockModeS boolS S I ÍF  3 PS LockInterestNavigationS boolS S I G  . PS BackPlateFitImageS boolS S I AG  * PS BackPlateCropS boolS S I {G  , PS BackPlateCenterS boolS S I ¸G  / PS BackPlateKeepRatioS boolS S I H  @ PS BackgroundAlphaTresholdS doubleS NumberS D à?>H  * PS ShowBackplateS boolS S I €H  4 PS BackPlaneOffsetXS NumberS S AD ÂH  4 PS BackPlaneOffsetYS NumberS S AD I  5 PS BackPlaneRotationS NumberS S AD FI  3 PS BackPlaneScaleXS NumberS S AD ð?‡I  3 PS BackPlaneScaleYS NumberS S AD ð?ÁI  , PS Background TextureS objectS S þI  / PS FrontPlateFitImageS boolS S I 7J  + PS FrontPlateCropS boolS S I rJ  - PS FrontPlateCenterS boolS S I °J  0 PS FrontPlateKeepRatioS boolS S I ùJ  ; PS Foreground OpacityS doubleS NumberS D ð?2K  + PS ShowFrontplateS boolS S I uK  5 PS FrontPlaneOffsetXS NumberS S AD ¸K  5 PS FrontPlaneOffsetYS NumberS S AD üK  6 PS FrontPlaneRotationS NumberS S AD >L  4 PS FrontPlaneScaleXS NumberS S AD ð?€L  4 PS FrontPlaneScaleYS NumberS S AD ð?ºL  , PS Foreground TextureS objectS S ôL  , PS DisplaySafeAreaS boolS S I 6M  4 PS DisplaySafeAreaOnRenderS boolS S I uM  1 PS SafeAreaDisplayStyleS enumS S I ¿M  < PS SafeAreaAspectRatioS doubleS NumberS DFUUUUUõ?üM  / PS Use2DMagnifierZoomS boolS S I ?N  5 PS 2D Magnifier ZoomS NumberS S AD Y@N  2 PS 2D Magnifier XS NumberS S AD I@¿N  2 PS 2D Magnifier YS NumberS S AD I@þN  1 PS CameraProjectionTypeS enumS S I >O  2 PS OrthoZoomS doubleS NumberS D ð?|O  0 PS UseRealTimeDOFAndAAS boolS S I ¶O  , PS UseDepthOfFieldS boolS S I ìO  ( PS FocusSourceS enumS S I -P  3 PS + FocusAngleS doubleS NumberS D @qP  6 PS FocusDistanceS doubleS NumberS D i@«P  , PS UseAntialiasingS boolS S I ÷P  > PS AntialiasingIntensityS doubleS NumberS DÝê9é}ãè?4Q  / PS AntialiasingMethodS enumS S I tQ  2 PS UseAccumulationBufferS boolS S I ·Q  5 PS FrameSamplingCountS intS IntegerS I óQ  . PS FrameSamplingTypeS enumS S I FT   +ObjectTypeS Implementation[R   CountI 9T   PropertyTemplateS FbxImplementation,T Properties70îR  9 PS ShaderLanguageS KStringS S S MentalRaySL1S  5 PS ShaderLanguageVersionS KStringS S S qS  2 PS RenderAPIS KStringS S S MentalRay¯S  0 PS RenderAPIVersionS KStringS S S ìS  / PS RootBindingNameS KStringS S S T  % PS ConstantsS CompoundS S ìV   +ObjectTypeS BindingTable…T   CountI ßV   PropertyTemplateS FbxBindingTableÒV Properties70U  * PS + TargetNameS KStringS S S ?U  * PS + TargetTypeS KStringS S S ƒU  6 PS CodeAbsoluteURLS KStringS XRefUrlS S ÇU  6 PS CodeRelativeURLS KStringS XRefUrlS S V  - PS CodeTAGS KStringS S S shaderFV  6 PS DescAbsoluteURLS KStringS XRefUrlS S ŠV  6 PS DescRelativeURLS KStringS XRefUrlS S ÅV  - PS DescTAGS KStringS S S shader ÎW   +ObjectTypeS AnimationCurveNode1W   CountI ÁW   PropertyTemplateS FbxAnimCurveNode´W Properties70§W   PS dS CompoundS S X   +ObjectTypeS AnimationCurveX   CountI + \  + +ObjectTypeS VideoTX   CountI \  PropertyTemplateS FbxVideo\ Properties70ÏX  * PS ImageSequenceS boolS S I Y  6 PS ImageSequenceOffsetS intS IntegerS I SY  2 PS FrameRateS doubleS NumberS D Y  , PS LastFrameS intS IntegerS I ÃY  ( PS WidthS intS IntegerS I úY  ) PS HeightS intS IntegerS I 3Z  + PS PathS KStringS XRefUrlS S nZ  - PS + StartFrameS intS IntegerS I ¨Z  , PS StopFrameS intS IntegerS I èZ  2 PS PlaySpeedS doubleS NumberS D "[  , PS OffsetS KTimeS TimeS L Z[  * PS InterlaceModeS enumS S I [  ( PS FreeRunningS boolS S I ¿[  ! PS LoopS boolS S I ô[  ' PS + AccessModeS enumS S I ¢â Objects8f  ! GeometryLÐü* S + GeometryS MeshT]  Í Verticesd À ®þ +À €±À €~Þ@ ®þ +@ €±À €~Þ@ ®þ +À €±@ €~Þ@ ®þ +@ €±@ €~Þ@ ®þ +À €±@ €~ÞÀ ®þ +@ €±@ €~ÞÀ ®þ +À €±À €~ÞÀ ®þ +@ €±À €~ÞÀà]  m PolygonVertexIndexi `   ýÿÿÿ   ûÿÿÿ   ùÿÿÿ   ÿÿÿÿ   üÿÿÿ  ûÿÿÿ/^  = Edgesi 0   +      P^   GeometryVersionI| xa   LayerElementNormalI ^   VersionIe £^   NameS Ú^   MappingInformationTypeS ByPolygonVertex +_  ReferenceInformationTypeS Directka  M NormalsdH @ ð? ð? ð? ð? ð? ð? ð? ð? ð¿ ð¿ ð¿ ð¿ ð¿ ð¿ ð¿ ð¿ ð? ð? ð? ð? ð¿ ð¿ ð¿ ð¿ Ãc   LayerElementUVI ±a   VersionIe Ëa  NameS map1b   MappingInformationTypeS ByPolygonVertex9b   ReferenceInformationTypeS IndexToDirect5c  í UVd à Ø? ä? Ø? Ð? ä? Ð? Ø? à? ä? à? Ø? è? ä? è? Ø? ð? ä? ð? ì? ì? Ð? À? À? Ð?¶c  m UVIndexi `                +   ²d   LayerElementMaterialI d   VersionIe d   NameS Gd  MappingInformationTypeS AllSame~d   ReferenceInformationTypeS IndexToDirect¥d   Materialsi  +f   LayerI âd   VersionId Le LayerElement#e   TypeS LayerElementNormal?e   +TypedIndexI ¸e LayerElemente   TypeS LayerElementMaterial«e   +TypedIndexI f LayerElementõe   TypeS LayerElementUVf   +TypedIndexI ùÕ  ! GeometryLÐÒ* S + GeometryS Meshß1  \Ë VerticesdTW  OË xl½yàžÃÕÿ?‰¥©¥”Ðj…¡Ä[(ú¨~†>B(¥ZQ[†Ò>žÇÚÖöÕ&SK’Øj©õ¢‚Rû[rO" ’„DpYB"ö=¿÷œ™sÿ朸ÿù$¯Ï|Îuæœ3ï{î랙˾|G1¦=¸ÿŠ?ÝU}Oïàg³ÛÉ‚‡uÞ9?ñvý‰·‹ö§¼,qsùe· >wè5‰û6¿EðiGSû=ö¸©æq“ÛoL¼ùÖç××Ü<ûè͉‡5öûgÍãA¿»5qÛïÞ«jî>ÚçöÄÍj{\\s3´ÿ‰ÇÕûœSóæì{3ŸÐï·5·Û|™ù¤~¿MÇñaîÖèsNÍC±Óàº5‡æë6ð³æí‡ÙÏÔ¯š›Ò¯€8ÔÜÏËqˆƒ÷¸©æ¦ÄÍ Î5SsœÃe—Ý&ø39/y¬¹ùSΣCÞkîûå¼;ÔIÍùNÚ½ûÜYs3|¯~„xYÕÞ¢®zWö-ê*q¯üiàOâFùßÂj?Dö·AÉþWÄ'ñ¸¦Œ§C<‰÷•ñþîÖÄÍÚ2_ ò•¸û¦Ì¯G~oV“õ`PduÕÁï¹~ÂÀ/‰{ÔUúýR¼¯¬ÏöoÙN‹ëÖím¹n€Ÿ5wÅψ~Õ¼ýeîWƒ8ÔÜÏ-qØ]ŽG»ñí7R»ýåøå8»ÈñnJ^âzJBÎc$õÄ¢®’ýðšÔŸu•¸E]Õ~Ñ z5¾æЫ :ø ôJpèéô*Šö§¤ñ½ê>w(Õ7ôj¬àÓÞ“ì›=öx æЫû‡^Ý[sèÕƒ‰c\ßUsèոġWT_œwèULz%ò½Ÿ8ôêòÚô*ó ý(Nlº”ù¤~¤ßšC¯.Oö˜C¯¨=ôJè ô*søY·‡^‘Ÿ©_5‡^Q¿ W÷ÖzEq€^=PsèÅ z5¶æÐ+Š3ôª#ø39/Ð+º>û½¢7û±š‡7ס¸‡Åo7_Hõì·íÿhÝ>®÷:7ÿÁ]Sjn&¯BãÊ÷~iRÍýÀiT͘1 ¾î™T÷qæNÂÄÓ;ðÓ5ÿy¨nßž9grâíE}ÆÔÜŸpê#‰7#Ljy`uÿ£Ôþƒ®«ÛÛç?–¸½n€˜wÅi_7ó¨¦p³ê ëÈ^‰;=Û1£Æˆy‹+×u÷#ÚŸýLýª¹/ýj‡šÇ_å8xÄMðurÜ â\s·uŽsûþ]SjÞNÌy‰ÛôÏñ(þG›óؾ>úÍãË(yŸ?[ðøz®wÒJSkûnÝO‘ôÊ©öuÕ•}‡ºJ¼Qþ8Ôqå¿Ÿ´ +½Ï5½dú›Ú·÷.ŸÄíWÄ3qwµŒ¿Eü©=ꪓì•øä+ñv„Ìo3ò~uU··¨‡ÔÞüSÖO;õ âuEö8þ…ûUd}¶Od;AÕ³+×õªþMñ3õ«¶ÎÈý2j|YÔUj× nu{‹ºJÿwˆsÍÝV9Îy©¹A]¥ÿÇRêŠÚ-’z7Ëy÷ÏJý1‹s¸Wš*ìÃvza~5³æ˜_]ÛÇüJp̯òçõ'ÎíOIº„ùÕtÁç¥ñ†ùÕã‚OHã +ó+¡‡˜_eùÖçT/\'˜_ÑxÀ¡é:s̯2ŸÔ/Ï#J]1ÇüêædÛc~Eí1¿ïã˜_e?ëö˜_‘Ÿ©_5ÇüŠú…ùUÖãr]̯(˜_ ÝÀüŠâ†ùÕãµ̯(Θ_Mü™œ̯èúì?æW”G̯È_æ˜_Ý‘þó+Á1¿¢:ÁüêÉÚ>æW‡”ù•hùÕµ=°ƒù•ä¨«Ä1¿þ`~Eõù•ðó+z?óCd1¿¢qe¿">É>æW"ž˜_ÑxÀ‰‡ƒe<=♸Qñˆ?µŸ)óe/âÉü¶Gã¤YQÖC°«0PÖE]%;Ív²ÞLáQ×g±ãU=7åº~&{\ŸÍÀìgêWÍmé—CjÞn”ã·šÛóIßâ\óðÇçxµïu•Ú9ä±noQWéÿy¯¹G]¥ÿû¥þDÔUâÍagSœ¸_@ùõÜìyÂΛëÐû„_ ½uGSêëºN}&ÙÁü™âÄýõ£îŸ›xüÆ »ëöfÆùó7×  Ï+ÜŸûˆ77 ÏÇÌCáí*ƒîNǯQ¿™›%ïóg Þ¼žëÄž´Ò³µ}»î§G’^©öuÕƒx5ʾE]%”?ø‰x6ˆgâöjƒøS{ÔU¿ç8xä+q|ù #ï§ñ€Ïƒ¢ êÚ_+ë'Ný‚¸A]ÑïËûoS¸C]Õ<>‘íxU϶\שúoË~¦~Õvü¥_j|™‡€¸ÕíñytÊ"΂o•ãܾ§ÆûÃ9/Í@©u•þ>.’zÒl–óîž•úÓ¢®R{{âJÏÖ×¢—}zïjÞö½î¶~ãÆž÷|ÍÝ÷è$ÞþpÈs5ogîHymv»AØ·ý†æKî–¿H}ûíÒ¥hz }ó\Fã­ù}?¡ÏÍÕûþÄ;Ψ¯ëÞ¹ŽÆOøå T¿\WñÖ‘ó“Ÿqz 81·ý—y>q÷ÍÆÔvšß~I¼é{÷Õ5÷ÿöBjo¾s÷Õé'Ûq…‡ÕnSs_ì¸AÌ£â†ùº~Öíû‰~Õ¼y»ô q¨¹)qˆ[ÍÛï帵ÿþ‹ÐSâl‘Ñþ’ä±æqFÎcxè<Š÷×o“óîæìMñ`¿™ë¤ýÛ(ÁÍôEz¥Ú7¨«ÄÑ+ûqÛ#:‰åG]%Iÿýƒ¿¡÷}¯úkÑßÔ¾ýÒ,â¿“ñl¯Ú‡ôǪø{Ä?µÈ|Å[FÎOÜ ®:é:Eg ò›¸[UÖC8áKâ~uU?—£ñæÖ’õf ª>]±Ó¨zn6È×mágº>ûc‹Ÿ©_5oÞÊýŠˆCÍm‰Cƒ¸ Žº¢ÿß,ǯ?!ÇÙ /uûöþœ³£Ô‹ºJíüƒROÚ%ï³¥þ˜Õr4Eqâ~Á½pÿêÅúº¸ug¿Áý+Áqÿj|âíú[Ñþô‘4qÿJØws‡Òûî_ }sÓ’.áþÕûƒûW¤Kø~Þߘãþճ麸Ï#ô÷¯h\áþÕ/·Çý«6µÇý«ÉµŸ¸õbâ¸õ`Íqÿ*ó ýès3ÛÁ}ªÌ'õ»6ýæ¸õ`ÍqÿŠÚãþ•¸O‚ûW™ÃϺ=î_‘Ÿ©_5Çý+êî_åù#þ—ã€ûW¤Óìî_QÜpÿJèî_QœqÿJèIx&ç÷¯èú];ÊyÄý+ò—9î_Oþáþ•à¸Eu‚ûW/ ÿ‡ïuL¹%ÚãþÕ=°ƒûW’£®Çý+áî_Ñ8Äý+á?î_ͤöCdqÿŠÆî_-ŸÔ÷¯D„œGÜ¿Êý(õŒïÇ'ÿpÿJpÜ¿Êu‚ºªýGSzÅ#í+‚BóÚf«ë_®¹_‹‰ü…»a¾°¾@÷yÝÇ“Åuý¬s¨⟎þÇ çÒûŸ»ðB¡cí“I—šæ‹ù˜_óÇT¯ö”±Yïyþü²¥º÷Ç¢8q^ÌÑøq?_]|ÙnºçËäÿšG«ûe~“¸9í°ëjÖêy%µÃ».ýdûÌÛo5®æíAÙN‹ëÖ¼)×mà§à}³Ÿ©_5wÜ/Ä¡æÍ9q«¹-q ˆsÍÛ rœÛ& }hž*y¹~¾Ô™­s-ò^Û1땼£NߪÔɃ÷—œv<é•jßn=„>çe¿…ýÄ·Qþ´ð‡¸ò¿…ÿ‰[Õ_‹º"~ÁÒñ!;÷ËxÄ3q²Œ¿AüÇÉ|yä‹Úï'ók‘ßÄͲê!q÷ÿdý´ßî¡ñfPWé÷\W±ðVÕ§-v¬®çMÊuUý·«?ѯÚ~óRîW@júæ8´çËñh7ŸL:Ö9~-ê*ý½E^j;¦äÅ 5w[å<ú-¥žD›óîúcQWô÷CSœ8>¸$½p¿ýÕÚ>î·ßÛÁop¿}AÍq¿}2ñÍ>vp¿=ži¢Ð7Üo§qˆûíÒÿáÃéý÷Û[aÛùy^qÈC4ïf?q¿=·ye½çùÆZ}²þ<¹µxÁýv?¸ß>µ¶ûí ’ÿ¸ßkŽûí¯ßfôõ5Ç}uâ¸ß~}ú}×æ+/ˆ5ÇýöÜþ’ùSkŽûít]Üoïã¸ßžÇ9úU·Çývêî·ÓçZ¾.î·Sp¿½­Ûã~;Å ÷Û…þà~;Å÷Û…þà~;å÷ÛóõYÿÏyÄývò—¯‹ûí“Óõp¿úÇ÷Ûs~¶à¸ßþ[Ò+Õ÷ÛïíIqü¶´û퓉o*ýÁývú<ƒûíÂÜo§qˆûí¢¿¸ß>/ÙiŽY:>‰ã~»ˆ'î·ÓxÃ}iÜo§:3e¾p¿ê>\$ó‹ûí4Np¿]Ôî·¿J×(ë÷Û‰ã~ûõÔïÜo'Žûí²>‹ÜoõŒûít]ÜoõûíägêWm÷Û³~"5ÇývŠî··5Çývšá~ûK5ÇývŠ3î·‹ñŽûí”Üo§ësà~;å÷ÛÉ_æ¸ß>9ÙÅývê7sÜo§:ÁývÁÑ”^íÐ,¬ýi~9ÿ¾~z/+x»ÉMù{¬ÛV~­nïü$µßãáOóØË4ŠVþÇg6ÌóƒÕVqhÖ^Ò&;Þ\!æ™aòw¨^ÃNPœ¸_æ§oÓx3Ûöï#ágÇÑø‰ÏŒóäfÂß_Kö›‘M¨ýo¾8p!ñÅ o¬¹{uñöí…7¦ßóu™‡QM¨y(vÂÜÑâs„+×uð³no‹Ÿ©_5oöÎýrˆCÍm‰Cƒ¸ ^âçšÇ§sœ-ò"ø£9/y¬y³{ÎcÛkÙÜo~_Ø8çÝ¡NêövH®ôTÁÝnþžôJµ÷¨«Ä1jû¨«ÄòÇ¢®oKÿ-ê*q«úÛ¢¿dç+âCüËËE< â™xø¡Œ¿Gü©ý62_qßãhü4OËüÆñ§ñGÈzˆŸHã'¾.ëÇ/GÜ£®Òu¸®˜ÔUÍ›b'¨zöåº~Öí]ñ3õ«æq¯Ü/‹8ÔÜOÊq0z<~w éW³™¿sJœ‘—ÚŽA]¥ÿû[¥>XÔµ3RO ê*qw¨Ô‡º";ÿ7•âÄñAÓüznöëdëóÍuìà7ø~Pp|?H÷©Ü¶ýÕíñý Íðý Ð1|?˜çQ½_ýÂ÷ƒT7ø~Pè3¾¤qˆïÅHïÙO|?Hãߣ‰÷|?Hº„õ¢§nûN¥ñƒïÅýF|?¸(õ ßN¬ýÇ÷ƒ¯'Žïé{ ¶ƒï‰ãûAú¾”9¾$Žï'¦¿cŽï3ÇukŽïéºø~ô»ÛþøìgêWÝßR¿RjŽï)ø~ô»kg7|?(t ßRœñý Ð¥81çß’_lßRñý`î¿ï(yŸ?[p|?Hu‚ï×~âûÁI¯T{|?ø`â…ï…|?øXâø~PøƒïiÞ€ï…ÿø~Æaè%û‹ïiâûÁ¥â“ìãûAO|?Hº„ïÑDüñý é’A]ÕýÂ÷ƒyüŒùÅ÷ƒ4ðý ¨|?˜Çϵ²~ðý q|?(ë­p|?(êßR{|?(êßÒuñý ¨|?H~¦~¥~s~ñý`î—_ø~â€ïÅxÄ÷ƒ/¥¿Ç÷ƒbüÚ­rœñý ïç¼àûA¡ø~òˆïsÖ3LOë„?XÏ@ó¬gþc=ÝWÁzÑ_¬gÈãðK³T|’ýöw2žXÏ@º„ïýEü±žáõÔëD¾°žôëD~±žÆ Ö3ˆzÀzâXÏp[']Ÿß7/öv²õ ·‘_…c=q¬gõ‰õ dëD=c=q¬gõõ Y'ÕxÁzêÖ3ˆñ…õ ‡qþ ®èÿ7Ëñ‹õ g¬gX\·ÇzÊ Ö3}ÀzÊ#Ö3dK±žazú{3[êÖ3P`=Ń㖚¦—½iÒ;õuýÏßÄŸ*x³öLúœãÇ'ìØ›^¡yƒ·~6ÏÎupú¢_áê^NöÃèÑ'öÇn´!Õ™4Rè¼ßiå×ÉŸWú‰÷ÓwÿàcbÞÛ<~IÇ/˜U÷Ë.Yýd§¹`È£57ë_N<¼úÙí‚»2_ôÙíéïØ϶'óöÂ! +¾^±s‚Y‚’¯ágÍmñÓ¢_5÷æ~Ä¡æñ‡%ˆ[ÍCÿ·€8×<^•ãܾÓ0%/1't¦½1ç1>9”úÍý ßÍyÿš$xó³\'í£¯ nn8å´¤WjïPW=àÚ¾C]%”?Í¿^¡y³Wþ;øŸÚÕßý%;×-ŸÄý®2ž âIí_–ñ·ˆâfÚ%4Þ,ꪃßwãƒü’óe=xÔCâíY?õ“¸A]ÑïYÇ +·¨+Á‹¨êÙ•ëFøY·o§f?úUs¿AéâPó¸cŽƒCÜjÞl¸!éWø“¿¶Ä¹y[Ž÷0/çÅw¤>8ÔU²kQWµ}‡ºJÿ7¨“šGÔUú¿C]Õ<5M/¬¿z·æX5¡ŽõW‚cýÕÌıþJØq§¤÷!¬¿:†õW/¦öX%t ë¯hbýÕ çë¯hbýÕ«µ?XEã딨»íúéÖ_‘®3Çú+?X5GØÚÿÝäÖ_M­9Ö_e>¡ß5Çú«Ì'õ»3ýÛgŽõWSkŽõWÔë¯æÔë¯2‡Ÿ5Çú+ò3õ«æXEýÂú«WkŽýƒ¬¿"ýf°þŠâ†õWB—°þŠâŒõWB—°þŠò‚õWRgþ”óˆõWä/ÛÇú«™É¬¿믨N°þê½ÚOìü#ͯT{¬¿šÐ;X%ìXÔUâX%üÁú+š7`ý•ðë¯^¤öCd±þŠÆ!Ö_-ŸÔë¯D<±þj1ñ¾2þXEº„õW"_XEuõW"¿XEãë¯D=`ýq¬¿õƒuVıþJÔ[—÷•õ‰õWÔë¯D=cýq¬¿’õ_üÄú+1^°þŠú…õWb|aýUŽÃîr¸JzÒ®“ónP'µºJÿ7¨«š'”^X/úà‡Lì€c½¨hõ¢³ÇzQ¡caà ´>ëE¥ŽÍ:‡æ X/*ú…õ¢¯‘ /ó.¬¥qˆõ¢‹j°^”Æ!ÖU’®wóþ²¥ñ†õ¢¤ë̱^”ÆÖ‹ŠuqX/JãÊ­yÔµ}¬%Žõ¢w×ëB?H~b½èÝé'ÛgŽõ¢OÔëEó¸ÅukŽõ¢Ä±^”æ5l§é›ýLýªÛc½hîâPs¬¥8`½¨˜Ga½(Å ëE….a½(ÅëE….a½hÎËõó….™­s±^4÷£Ô9Ö‹æ¼£NjÌV¥N,8Ö‹š_©öX/:±qÄzQaëEg%Žõ¢Â¬¥õ òëE_Ní±^TôëE_#~ÁÒñ!û÷Ëxb½(C¬ñÇzQªc¬ùÂzQª{¿ŸÌ/Ö‹Ò8ÁzQQX/JëEEý`½èɬ½;ýäzÀzQâX/*êëEÉÖ‹ÊzÞ¤\WÕ?Ö‹f?ѯÚ>Ö‹R¿°^TŒ/¬Ízt¾X/šõ+Èñ‹õ¢9ÎÈKmëE)/X/*ôëE)X/*ôëEg¥¿ÇzÑÜïRoX/JuÒ,x +Yzùë~ôa}Ýö´S&uÀíè±¢½Û`¯Ù‰ûE Åu›þJßo™i ?Í“×м!¼ñ3ѯð³yn¿CŽSñ3l½/C3â'Bçͼáï¤ë†½'æ±aX߬KëÉõl~OãÁx²¸Ï;„ÆUœºÒŒº¿ÍÄ>R‡œqOÍãJC‰·žqOú=×USx3m¥5ÅŽùèdú|ÌíC¹n€Ÿu{SüLý¼ô«=ç'¤Cl§™›ãÐ nuûf«7‡8 ¾oŽsœú°Ð;3çÅ u{ûõœÇpÝX¡?íú9ïñŸ?Êñà÷ëSs4Ï%¸_æ×¢ù•nºêIyTöã÷öšx\(ýiáµWþøŸx»Xö7¢¿dg»¥ã“¸Qñ ˆgâÍ2þíûR7Væ«ùž§º÷Èüä7Ù±¨«~r¾Ú‡ûиòûËú1¨ŸÔÞ£®ÒÏnû3·¨«šÇbÇéz>7_·…Ÿu{WüLýª¹/ýjÏVã«ÄÁ#nuûfË}i>çšÇ}rœ òRó0#çÅ"5w}rã?¥žÔµ»Véê*ñ8ÿ(ŠÇˆ^XßþQmëÛ'wð¬oí±¾}ñÍ>¤ü°¬ooo›(üÄúvzßÂúvÑ/œ'CŸû°¾ê…íà<™|ßæ‡Þþl|è»dÞFbë×êCã çÉ®³¬o§ñ†õíÏÖv°¾ÆÖ·‹zÀúö’}¿Íè{ëöXßNëÛï¥ë—qÚå+/õ‰õí¹ý%óŸ­Ûc};]ëÛi^Ã~b};ùÙ¢_u{¬oÏz‹8ÔëÛ)XßþNͱ¾â†õíB—°¾âŒõíB—°¾ò‚õíùú¥_Íñ9Xß.ôëÛç¤ëa};õýÇúö\'‡Ÿ-8Ö·ŸNó+ÕëÛ'÷¤:ù¶´õísˆo*ýÁúö6q¬oþc};Í°¾]ôëÛ_Oí±¾}©ø$Žõí"žXßNãëÀEü±¾êëÛE¾°¾ý²s‘Ì/Ö·Ó8ÁúöÔ?~ÿ°ÁGÔ~ ¬¬o'Žõí÷¦ßs{¬o'Žõí²>‹¬oõŒõít]¬oõõíägêWmëÛ©_q¨9Ö·S°¾ýšc}û[éÿXßþ^ͱ¾âŒõíb¼c};åëÛéúÜ/¬o§æö¾\×ÃOÑ~—ìgê—àwå~Å-±Wâà·º}{YŽ[¿¡×7ç8{ä¥nï¦å¼8ä±æÍüœÇ0ò ÁCÿ’w{Å£ëÏʹNük7IþìAó+Õ> ®zG¯íotÎÓ‰[åA]%n”ÿþ“Õ_‡þ&Þv–ŽñÍe<-♸[QÆ? þdÿt™/|%¶“ùm:ƃû‰¬‹zHí›oÈúqï]EÜ ®Òï9ž¶p¯ë³Ø ªžC¹n?k;íÎÙÏÔ¯š›Ò¯q¨ysRŽCDÜjîQWéÿq®¹½)Ç9ü^Ž÷0µäåh©u•þ>ŒzbQWdw]©?uEí_½‰âÄñI®¤öã|Rûƒý8tÀ±GpìÇ¡u ím+ ;Øóµßã¡ŸØóZâØ#ôûqès_»ÚêT/ìöã^a?Ž˜—b?Îûd§ H×¹=öãÐ8Ä~ÒuæØCã ûqÄ÷&ØCã +ûqžìIýæyÅ~’ì7‹ÞWsì»!Žý8÷¥ßs{æØódͱ‡Úc?Žø^ ûqèºØCó¶ƒý8ä'öãÐ<ˆ9öãP¿°G|îÃ~Šöã¼W_×–¸a?ŽÐ%ìÇ¡8c?é7Ûæ¼`?ùÅûq(Ø“û]âã7ÎyÇ~Á±‡êûqÇ~œ3i~¥Úc?Î#)¾Ø#Ú{ÔUâØ#üÁ~œü9g°ôûq^Kí±Gôûqèó‹ûŠøý//ñÄ~œ÷ǾìÇ¡zuÛÈ|a?éöãˆüb?ìÇõ€ý84~°ç¾®ÃqƾâØ#ê9öãÈú,v°GÔ3öãÐu±GÔ?ö㟩_©|]ìÇ¡~a?Ž_ØCqÀ~œ÷êöÍw—¼“þý8rüÎ)qF^êöØCyÁ~ò‹¯‹ý89Fê öãä¼*õûq¨NüÿM¥8±¸B¯pÕ˜%õuÃ??´“~sòwo7{”î#›÷ÖvÂ=k¼œÚûuÇPœØ¾{d ͳÃ%Ÿˆþ†åN¥yƒ;rˆ¹jÍÌ¢³(Nlǯ±„Æi{ì”üþYÆQ»è¥<_YÞo¹}{ØïsÝÿp9š‡2ß@ãÄ>qÌSuÝoNZ’üo§¬ð@ÍÃÜ牻i+<@¿çñË|ú1OÕÜ;~§åòçãÒޕ뺫Ñ|³ëû‰~Õv<÷káYïÔ¼í›ã`·šû+sÜâ\ó°lŽ³A^j¼¼»–Ðæî’Ç“¾›ãÁþošó¯#xÛä:qï.ÜݵÊY4¿RíêªqvÚ>ê*q¯ü±¨«Ä›u¤ÿ üO<^,ûÛ ¿‰‡#–ŽÙWñŒˆgâí12þñOÜ¢®:é÷%ù";¨«š7Ý@ãÁ?.ëÁÿú$?q²¬ŸðÌóÄ›©ªÞ˜ëú,vZUÏŽ¯«ê?øìgêWò—ýoæ~9Ä¡æ¶ÄÁ!n5o¯Gó-8×<,“ãl—šûÉ9/á©u•Úù¥žÄMrÞãRÌ5¥NÞY,ô&òë¹ÙŸŠë¾¹ÎÔ~ƒýƒ‚cÿ ÝGÆþAaûI¯°Pè*öÒû–ëãÄqÃþAzŸÃþÁ\/<.Ö=“Æ!ö͉y)öÒ8Ä>;ñ¹ûó8¼¨éz×þ §Ò8ÄþA¡WØ?Hã +ûgÕýÅþÁOS±ðÁšcÿ qì|0ýžícÿ qìœUsìÌ×­9öÒu±æ›lç‹fýD¿êöØ?HýJq¨9öR°0ëw‰[\'Ç ûÅ< +û)ÎØ?˜õ›ÛOÌyÁþA¡3Ø?HyÄþÁܧJÞçÏû©N°ð³ÚOì$½²ª=öNíA±PØÁþÁy‰cÿ ðû©Î±Pøýƒ4oÀþAÑ_ì¤yö.ŸdûE<±Æ!öÙ‰øcÿ CìùÂþÁü>=Bæûi<`ÿ ¨ìÌãçZY?Ø?Hûe½Žýƒ¢>±Úcÿ ¨gì¤ëbÿ ¨ì$?S¿R¿¹Þ°0÷K/ì¤8`ÿ Ø?Hú…ýƒ¤ßlû)ÎØ?(ÇûÃ9/Ø?(ôû)Ø?˜ãQê +ûç%ÿ°Ppì¤:ÁþÁÏjÿS +Ó+|÷ÁÝönZ¼º‡àÍ–_›Ÿ¸?I]wä8º/c½=ç³øãÞpqjoŽ™*t8Üvî;‰Ç¯ŸMqâ8„f0Õ™àC¡Wö®{¨.qÿ“Þ?¹}³îcTÇqÐ"_MFuož?Š>7s{ÿÁT'þ§ëÌîÁõ™7;ÜBã͆½ªyÛYç?äÿY{?”~rûXxØgÙ5÷ÅNÀuknÊuÍn_ˆú·ÅÏÔ¯º½-ýrˆCÍÃ9 âVsSâÖ=5ëw‰{kŽsóÈíbå&ä¼´'J݈#rò^Ûo7Ïyßù@p¿m®ûÙ ŠÇÇžóÊŸi~¥ÚÔUâh•}ƒºJ¼Qþ8ÔUâNùá?qÕ_ƒºJÜ|E|÷ËxzÄ3q?CÆ¿]ç±<w•ùŠÃ‡Ñ8ôÏÉüú÷§Òx {Ëzh¶¿…Æ.맷ÎèºgÊz‹…·ª>=ÛQõlÊu­ªË~¢_é:œWúÕ 5wä8´}äxôW&ýŠÿ'ǯG]¥¿o¦¨ñ>>ç%þ^êƒE]¥ööP©'uEvÖ’úÓ ®7Ÿ 8±ÿ ¥ö;ž~ÏûïàÿØï,Úc¿ós‰c¿³Ð1ìwÎ÷e®¼Eè*ö;Óûö;KÞõ4±ß™ê…¯‹ýÎ4±ß™t½Ë{ý=Ã޿ɺ^Æ#ö;Bþ|üþÂÚìw&]Â~çü¹¹´Ç~goØï<»nýÎ4Þ°ßylͱßùódûǦŸ]îÌû…^a¿3ÙÁ~ç|¨\ûóu?yamûó<ýª9ö;S¿°ß™æ›|]ìwÎq8è`ÒoæØïLqÃ~g9)qÆ~g1oÁ~gÊ ö; ýÁ~gÊ#ö; ýÁ~gÊ;ö;S<øºØïLu‚ýÎ’üÄ_èþ•jýÎ÷ ŽØï,ìc¿ós‰c¿³ðûé¾ ö; ÿ±ß™æ Øï,ú‹ýÎ4±ßy©øÐu¯•ñÄ~gzž`ìwþ„üùHæ ûó<`s™_ìw¦ñ€ý΢°ß™Æö;‹úÁ~çÏ“}ìw›~r<±ß™8ö;‹úÄ~g²ƒý΢ž±ß9롪ìw&?S¿jû¦ô ûÅøÂ~gŠö;‹ñØØ|ß +ûÅøÅ~çç+äxÇ~gÊ ö; }À~gÊ#ö;S?¸¿Øïü\òû©ß̱ߙꤶ—àhJ¯æÒ­¾ýšzúü¦ÝýTÑÞo³ëó‰ÇO÷×Gþ†>çÇßÞ”óÉz2.¯ +»\EùgÜü—ÞMvü­[ˆy—ýç,wí9G’®sû¸Ïo©.íwö&]gîqÇ’d'ܸhQOò·\×_ýWª{;ü ‘_ß¡qÒÌxbNÝÞ¬ð +·°Ããjî®?ô‹d?îtÁ¸ô“íÛÂÛ™OÌ©yüz¶Óàº5o;ùº-üüªâ'úUóøóܯˆ8ÔÜr·š‡ksÜ,â\óæÙg‡¼ÔÜÍy±ÈcÍã9y¯yغäý’­(‡vJ®³Ü±‚›_ÝÿWš_©öñ±ÓŸèA²ßÜõùÄÛ%Òº"~‚ô¿…ÿ‰Çe#ú›xsËÒñIܪxÄ3ñ°–Œ@üÉÎ 2_ù¢öÃd~-òKí§Ëzhû¼BãÇm¯êgô¡4Þ ê*ýÇÓnQW5oŠ£ê9ŽË×5ªþÛ+‹ŸèWm'î—ûeÔøò?Íqðˆ[ݾ½f}þqˆsÍM‰³E^jîÊy1ÈcÍ-êŠþ?Hê‰A]%Þ\,õÇ>’ë$.s,Å©´M/œÏðemç3Lï€ã|Ñç3¼8Îg:†óèsÎgºúÐoò}õ[þBùçëâ|†÷’œÏ tç3Ðû"ÎgŸq>CœÏ âó>Mvp>ÝÏ`ûxÞCœÏ@Ÿ›™ã|WxÞÄÓ=©Eßšß~Iç3tjŽó¾Löq>C'ýäö8Ÿ8Îgxºæ¾ØÁó&è>·Çù dç3Ðý<æ8Ÿ!û‰~Õvp>CîâPsœÏ@qÀù b^ó(nxÞé7Û7%Î8ŸAÌ[p>CÎ òXÛÇù ”GœÏ@þ²œÏðBj‡ó¨ßÌq>Õ Îgç3üæWª=Îg˜Þ;8ŸAØÇù /$Žó„?8Ÿ>çã|á?Îg Ï98ŸAôç3äy×f©ø$û8ŸAÄç3Ð8Äù "þ8ŸáÓÔç3ˆ|á|‡8ŸAäç3Ð8Áù ¢p>qœÏÐé¤ë—zs—û2ÙÇù ò«pœÏ@ç3ˆúÄù dç3ˆzÆù Äq>ƒ¨œÏ@~¦~Õöq>õ ç3ˆñ…ó( âV··¨+úÿÍrüâ|Š3Îgø¬nó(/8ŸAèÎg <â|†ìoé/Îgx!ý=Îg ~s|p>Õ Îg<µÅ«={;ãÒÏbÇßvøŒþ·¾Q´o.ß™î#Ûá¿’×ÝiUúœã×¾ŽâÄvšûÿHólóí(NÌÍ×·{?Ù7û=%âG¥yƒ?d¶ˆ§k ªK¿çôþÉvì9—~–ìøf/NýîòqPÝ;» }nîòkäqµïðgêöÍ1+C;aç“ÿ5wƒ~JÜ}ö¿1]‡í0·û ¦æ¡Ø‰¸nÍã9ùº~Ö¼›ýLýªy8;÷Ë!5oæ8ÄŸ=%Æ£-qk¾u§u{ß'ǹýîu¤‹ì¿¿/ç% û•Ôæ<佶Ó\–óîQ')Nl'Þ’ëÄÿeˆàfÇQg'½Òíêª'ýýVÒ¾C]%n•?u•xPþ·ðŸÚ«þô—øWÄ'ñæ`ÏñL<î!ãoÿÄý×e¾,ò•xXWæ·={z…ódòø¼pÈ\ê¿_¬W윰@èUûI¾.Γ¡ûF|]œ'C~¦~Õvpž õ çÉäyS±ódr·º=Γ¡¸á<Òo¶ód(Î8OFÌ[pž åçÉ]Ây2”Gœ÷’ûW®‹ód(ï8OFpœ'Cu‚ódÇy2çÐçAÕçÉä:Töqž Õ-Γþà<ªsœ'#üÇy2ï¤üá<Ñ_œ'Cz®[:>©=ΓñÄy2ô>ŠsWDüqž ½ïâ<‘/œ'CïÓ8OFä7 ¿öÃù²pžL? dýà<â8OFÔ›+çɈútÅΓõŒódÈΓõódÈÏÔ¯Ôo®œ'“û…8ÔçÉPpžÌ'5Çy24ŸÀy2büâ<Š3ΓãçÉP^pžŒÐœ'CyÄy29¥®pž åçÉŽód¨NpžŒàè +½Â£?ïåð¯n¿–œ1³ƒÿ‡‘‹EûæJŸ¿÷êõ#ÁÝšù¼_7ùJŠÛ ófåqñæ)NÌÛïÿíƒd¿ýøä%u|¯Ӹ3[îJºÎí݈Å4NÛ?Ü'âoƧ:öGGºŸÁíísWP݇ñ—Ð}¾.p%+÷Ô–óêëú9÷Šð§™5b|Í›—ùÓ#Æ“¿<~™ÏÚr^Í]±c'\’¿(íÛÍòu#ü¬Û7󳟩_5÷1÷«ÝbWšo²ÿÍ99 âV·ooÈqóˆsÍ]‰sœt%é"Ûiçæ¼ä1õ›¹Y£œÛŒ¼×<\‘ónP'5o>ÎuâW:Ep»ú¯F$½Òíêª'qeß¡®÷ÊŸˆ+ÿ-ê*ñø†ì¯Go?Z:>‰[Ï€x&îTü âOüÿd¾ ò•xŒ2¿ùuÉþ“²âìi\ÔU¿ïÆõ“Ú;ÔU²Ç¼Ý!óVÕgSìxUÏ®\·Ÿµÿlö3õ«æ®“ûe‡š7gç84ˆ[Í ê*ýß!Î5Ûæ8‡‰r¼;ÔUjÔß·äq„Ô‡ºJíý#R"êŠì¬xŠÐ%4¥W»ðeÁýU}Ÿìà7q·“oÖyçÅÄÍ÷& +½ò§¤ÏùîòË„®ú¹CésNsÀæB‡ý´ô>çö؃꥛¯Mnÿ„®û­ÏE<ݳÒûh³Æ~¤ëÜÞü;‡¾ß½ô¹™9οʺ´Úù>_Ñ ;´?+ӷϳ)Ü>ž}ooúM¨¹ÛæËÌ'õ›üâöÌý}ž­9ÎÑ¢ö×­y{h¾n„Ÿ57ÅÏÔ¯š»ƒr¿p˜Ð«0/Çç†eýæ~•¸9Ŷƒó (ÎÍe—ÉyË3%/ëOºdÿ”óè‘÷Xõ7ôËy÷¨“šãœ"ªóÓ>½kn‡ï52éÎËíq®Ú“=‰+ûu•8Îãþ´ð‡Ú+ÿ ê*ñfˆìoD©ýà¥ã“¸QñÄybyÞÐWÆçÑû®[[æ+~¸Õ½ÿ¦Ìo@~Ì·«Éz°¨‡Ä-ꪓ~_òÕ ü’x@]%¿–âª>qŽµÇyn¢ž]¹n?k;¾øÙ¢_5·æ~á01¾Â܃¸ÕíýÆ·Ó|Ë"Î5oËqöÿãÝ¢®¨ÝzJBÎc3Hê‰C]¥öÍkR"ê*q·wŸÞ?9>ø'½lŸßõvøsÿãÑT‡¶÷2‚7W©ƒvö¿÷ øqûðÖat_ÆÞ·§Ð1÷Ìë¤Wáá5)ÿÜ>>?£+ÖÎõRòèn>‘æ ¹‡tÛÛMo¤yƒ¿õMóñ¯iú'n¦ûÜÞ {*×ýáÿùµÜ–õäçí³W¾nÏÓx3wÜ*ê§p.q{÷­¢Þº|ÿVè•)vü¯þ#õêü|Ý~¦ø±ŸñÙÏÔ¯š»r¿âPó°I‰â&øM9nq®¹-qŽcö:žÎy‰?ÞCêÉ›9M¯e„þ„«rÞ›¯ýNòs„ó/Ü-Þ~}TíêªýʾC]%Þ( ꊸò?²3Aöס¿Ôþò¥ã“xüR®pˆ'µ¿EÆ¿ýð×_&î—ù +È—7¨«~pò›xØOÖCøÑ÷NÜÝ.ëÇ¡®Ç9i¢Þ˜»_ÈúôÅN£êÙ•ë6ð3ùËþØâgƒ~ÕÜ”~5ˆCÍýÆ9q«yó¯ó|k¼¿þ°g‹¼¤~ðuÛ99/y¬yx#ç±5ROꊮ·¼ÔŸu•x<ïÒÞµ z…z/ãð/¾®_øý§:ø¿hTïšc=}/⎜!ü‰nGŸó›õþÛ§O|ìla(ÿlß-9ë£ÄÍÛoÉø Ø‘æ ~ÑÑâs´=õÏ4o°»ý5Ï÷‹Î˜Á›Ó8Ä9x4eûq¹ýi†»n¥ï%˜ÛI;иòÝ7?ŃyóþLâöꞇï¿î2íüµ='¹}(¼½ø¾ù‚;æî[é{6noÊu[ø)Ú?S¿jÞìžû凚ûSrâ[o ½j7Ëqùˆ¤ß|ÝðIŽ³C^R?˜ã¼;ÊK{Ä ¡Wþ—9탣„þ„usÞ ê¤¶^Íubfm,¸²þ¹I¯Úþ²½C]õ$®ì;ÔUâQùcQW‰ã¼Aáÿwª¿ úKí¿">‰‡…2žñLÜ’ñÇy‰TÇ8Oä ç+RÝ7wÊü†‰;ôv°ãþ.ë¡}o&q•¬ŸvÃui¼ÔUº>ç¥ËQW5lGÕ3Î ÌöUý·Ëf?S¿j;¦ôË#5w'ç8Ä7åx4¨«Ô® Çoü8ǹYOŽ÷8;çÅ"®êWs@ΣEÞknQWɾCÔ¼A]jcÁÑ”^í ó÷#'“^5'}Gðæš«H¯üŸ÷ïíð—Ý8O^» ?ÛÙ†æ ö‹„^Ås·¤yCØy<½¿±s«¡qèžÜ@~Ž~äˆ0_è•]³Äq«Û7[ä¸áW1ñæ8ãÜW¡W¦äÅ"Ô¿·fë’Ç­®úã×ËyoŽ´9¥½ßªÔÉ/ /9ô*¨öuÕƒ8zeß¡®7Ê?ðÒ+£üwð?µÇyª¢¿ýM<^°t|·*žñ¤ö'Ëø{Äߥö¨«~rÞqlïÄã~2¿aÓ=³.­!ë¡9èMâÍÿ“õãPWÉÖq‹z³…‡oÉú lG×s¹.ÎוõÏ~¢_©ìûRîW{¿_v¸Õí›Í'“^áW1~Ã9Îá#9ÞýS9/þz©q«œÇ¸¥Ô‹º¢ø!õ' ®w ºD¯pÖm‚û§_#½r‹·ç’^ÅG:f¯¾‹î#›Ãwíí`‘ãÓ<µæü?lÿ¼èoóÐéô9ǽz¤¼¯uû9yÞðÏ¿Ó<”혻V5vÜ7 ù>sÇe4Ýàñ"_æÊçhúÑ“¤^:‹Æa²ó u^⪧Ñx G½'ê'¬>¸=æ=¡W]þË_HýcšbÇ\?Iê_~ÖíãÙÏÔ¯š›Ò¯ˆ8Ô<Ü™ãÐ.82Ï7ùsq‰›CœSœØŸø`ŽssØ®B—â“9/yí¯ÌyŒ¯oMýf;þÚœ÷öÌÛ$Ÿë¤¹|®àññwH¯t{‡ºê²ïPW‰[åO¸ê.ºì•ÿu•Ú·ÛÉþÔÙùŠøPûk—Ž§ƒ°ªŒ{ûe¤WÍî2_ùJíýu2¿áY4Üþ² ê!µÿ#ë§]m:ñæhYo±p{€¬Ïv•lÇéz.×ð“úÇõPüLýª¹/ýŠˆCÍ êŠü|EŽGsÛ94ß +ˆsú=׃A]Ñß{9Þ-ê*ñ0EêC{EΣAÞk;u•Ú[ÔUÍê*ñxÙ\Áè¯ûÑrÿbüN™ÝÁÿÃè±¢}Ü`¯‰·‹ +½ò+þ•î#‡i÷vé÷%náÉkH¯Ú7~&æ]f¿4ohvØÞ߸½¸/Íš?!]gîç 7vÍMï‰ø·ÃúæyÔzòüø§qˆs‰Åº_wþ!4®pÞl›âÁöí¤>Ë%ûÍ3&ÕÜ­<”¸?èŒIÔïÒ/[¸y|¥¶æ†íຂ—ëšõÕy˜ì'úU·Ç9ÏÔ¯€8ÔÜ”88Ä­æ~ë7Ä9õƒûå~–ãl‘—š73s^p®µÐ+œ?Ly4È{ÝÞ/çÝ¡Njîþ_®ûüQ‚Çe~}~úÛÁuS?ØW®ëtý/û™úU·Ìý +ˆCÍ}‰ƒEÜßj_šo5~ý¾9ÎyIñ` ê*ý}³PêƒA]%zbPW‰û*ýA]QûçŽÊqbFÛô²<¬÷õ9ðvè`Áãèù¤WfÅ㤎í¸Å;©½Ù~¡cnæ€w×Néåð“ûÍ&½ +».'t»¹+ßN\V|Žn{½MzwIó}¶ã’ï »Oï¥û¯Ìÿ_¢qØ Ú”¾_bî&¾Jã0¼qŠÐ«pêÅy¼íÚwrŠ·o—›x3¸ïdŠG‰[,Ü¿yŠÐ+_ìøÝ6]\·7|]øYs[üLýª¹á~!5%q‹•ŸñÎ7ƒ8×¼Y˜ãÜl·‹Ð¥0#ç%¬pœÐ%Sòè‘÷ÚŽ¿.ç=<ü¸ànÝ\'ýTðøƒgI¯–jºêßNÙw¨«Ä½òÇÃâÊÿÿ×ÈþFô7ñö¿—ŽOâá÷2žñt©ýÎ2þqÏ|_8,‘ùjo~‰ê»ÙUæ7<ü*‡¸XÖC<åb?uÕI×á÷;ÔOº®E]‘¿< ª>›b'èzæëÂÏÚŽ/~¦~ÕÜ•~9Ä¡æ­Éqˆˆ[ò‹ýlîÈß zĹæñµçïËñ§—¼|]êCø¯œÇp¨ÔƒºJ~4¤þxÔUâqÝO…þ Ñ+¼|ðòÿb?Ãä^ÙïÌícÿ£_í ð¡Ð«ö„KI¯ü5Qè•1†ô*ùaïÚ¾ ÃésN<öXóýùô9Çúˆ§ßäÐ^× Ïn”ç¡%¿íZ}hÆ'·¦ûì¿ÛöH‡î’ùR¯>>.«•½2[l°|²o¶-ê'˜áÄÛíG‹zcW^ ô*n^ì\:_êU¹®yjkºŸÇ~¶Ûd?S¿R\™ã\zê—EjÞn\‸Ū=ν§¸ĹæfxŽ³A^jî¦ç¼4›}Hqâëâ¼tÊc³Öl¡?~Ãœwœó¿|mÇN,uò«³oÛç‚4¿Šª½C]õ€ã¹ ¾C]Wþø“xl¤ÿ üOܪþ:ô—øWÄ'qwÈÒñtàÍ<‡ø'nPWüàø4ÈWâîb™_œÏŸõuU·Çyþ4®ì6²~â—È㹠¢ÞšÂ-ê*ùË×5lG×s¹.ž_ êß?S¿j;8—>÷ q¨¹C]¥~µÇ¨ñ¸Í|º_÷—ã×ËqvÈ ý]ቜ—¸©Ô< çñÛRO ê*ùaP'µºJÜ~¶à©izÅÞoþoÓ§;à~–<Þðé•Ûë4¡cí ½ßMíÛó}Änœ§ïòQâvå;z»ôûÒ/¿æ&ùsÎ%O ½ò÷^CŸsìn¿÷ýÚ}'½r¿Ÿ âï_ûCwó¿E¾ÌC¯åqøÚ(±OÁoº„ƉÝ|_Z§Öõç¥;–ðÏ®¿Ý”'æöÓo|xÿí¦PÿŠÿ]¾Å¾/ +^ì4 G‰}¶\7ÀϺ}ó`ö3õ«æí«¹_í ß‹ûê¾Ä!"nÉ/öÓß“ãÖ®tG5rœòRsûDÎKüÉiB7,çñ)¿|ÝÞ]ŸónQ'5·Gå:iF‡âÄþ´£'‘^éöuÕcPoÚ>ê*ñFùàOâNùàâAõ·A©ýWÄ'q£âéOì'ãÿÄÃM2_ùJ¼}Uæ7l²„ÆC ë!¼x·ž¬¿ä_#ûÊzsÌu};QÕ³+×ð3õ¯ÿ²Ÿ©_5·¥_í®r|ÅŸæ8X=ニ>ZÄ9ùËö›¾9Îq9Þýã9/ížRšës ò^Û1¨+ÊW/©?u•x¼î;'¾.½ìú§ V}ô*Ž’vâÆç¼ÖÁ_øc{Éë>4é•?I~>mœôª™°¡ÐáößO’^Ùñ.ë:Ï—.ß&Ã-ˆûðî”?™‡{ö|¦“~1øÑ>þë;´®(œûáéûtž_µ;R>ÙN3í€ÉÎ)—Qþ™»ÿ>çø×ÿ%⾘ô*~ûÏxõͽ#܉£?ñw§ŸHãÐ|­Ð«0õ Ò+÷·÷¥^·b?ÇlòRŠûc÷|œ¸ÿbÈ#5onÑ']7ô>à‘Ônï oÝ䥚·{d;æì÷E=ÛrÝ ?ëö¶ø™úUóöO¹_q¨¹+q°ˆ[ò‹ý±·“/[¦æ~—瀼Ôõ@v>"ê§yc ou•üåö¡p‡ºª¹-vŒªgW®ágÝÞ?S¿jnK¿<âPó檛{“Ÿˆ[úÙõç ‹I¯ â\s¿s‰ó r¼ÔU²k‘Ǻ}\-ç1ì&õ¤½¡ä½GêC]%;q“….Ñ+úœOzå—YVð¸éM¤Wñö•…ŽÙ=v~¯KnÏ(ŸÝþN}™ô*l¾ŠÐá8wÃÏSû°úê½~r{×o éUè•÷kvù”¼~Ñÿèº?Á<þômÒ«¸m?ºŸÁÜíwÜò1Ù;š¾gîþ;C7ê"Qá˳.½±PÔ}mñøÎBQo¦pwîE¢>}±ÓÌMë;øº¶\×|¿ß‡©ßÌÛŸe?S¿jîJ¿<âPó8¹Äq£þ=‰kç¸YÄYðgrœÛ=zËyqÈcÝÞ ÎyŒ½—úã6Éy·¨“º½9 ׉;fªä»oø÷4¿2ª½C]õ 7Ú>ê*q£ü‰ð‡Ú+ÿ ê*qZç·m÷þz²c^8õÑn onëõ²àÅŽÛì ZÀím¹n€Ÿuûf^öÓ¢_5kç~¥8¤ë³Wâ·š‡·q®¹;.ÇÙ#/5÷æ¼xäQðá9y¯¹»)çÝߘâÁþ´ÿÉuo;Hp3ì2Ò+ÝÞ¡®z úó²ºJÜ*ZøC\ùáâNõ×£¿‰›¯ˆn>ñ´ˆgâvŽŒƒø'V’ùrÈWân™ßða?'ñYõÚǹ²~Úö¦ñžWõV¸A]¥~pœqN%Ùqªž_~Šös³Ÿ©_57Ü/Ä!ùÅöÛ9íŽj<Î?ˆæ[ñE5~ÍqwËñÞ<’óâgH}h‡å<ä½¾nû¯œ÷0Lêý<×I¼õ ¡Kp™^áê1‚‡ë>'½jOþ®àqÀ£¤WæýµÄuݽk¼ß%gǽr.!½r—~"ôªYþÔü9çȽþŽãÖ\5ŽôªYt–ˆ§]s éU{ÜÿøúK4oˆ V£ÏÍl'þ{‡a§åè{ æa“ò8|âQîNÊãí‘«óæ=OÜ=¾Âc©lÇnf#ôÊ;æGËÑ÷lÜÞ–ëÚWW£ûyÌ}ñ3õ«¶ïJ¿â«ë6kä8DÄ­æ¶ÄÍ Î5o–+q^wÌò5ÇsÖ(/á½µ„.ù{J‘wÑ~³œ÷xÕÁÛkr¸÷ nî^å¢4¿jT{‡ºJñuÚ>ꊸò§…?‰åÿo.‘ýmÑ_²óñqhçĉxÄ3q<'NÄß þ‰ÔU'ý¾Ì òEuUs<'ŽÆž'êÁÿæ$?qŠ¬<'Žx3MÕ[á~º¬O<'ŽÚëzÆsⲎ©ú‡e?S¿R<Øÿ°(÷«](Ç—)qÀsâz§þuÛ_9Žô +ω“ãwÙg<'NŒw?%ç%¼+õ¡½;çÏq“z²iÎ;ž'¸¹¶ÔÉ»‹%‡oéÇ ZÁág×ÏÁ£æ¥|¸7ˆöí-¼ž¸íÛ½òo '½ŠgŸòÉvì#g.Iíã^ÇPþ»üÊõ¿$;çîë¥ÔƒºCóü‹B¯šþ‡ÆaÓçðÿôT~ºû^>âÿnÜH¡WáõH¯Ú#•zuðVYÞž+ôªY{Ù’3ær¡WvÖ±Ä× ½2…ûwæŠú ÅŽûõ¡¢žm¹n?S¿»q(~¦~Õ<ŽÉýjŸ{QŒ/[âÐŽÚ;ë7<4ÇÍ#Ωlß\‘ãì‘Á§ä¼4«7R¯ç<6[ß ôÇþ;çÝ Nj;qP®“¸í7¯ŸIz¥Û;ÔUÊ_Pöê*q¯ü1¨«Äò?À⪿ý%;_—ì«xÄ3ñæk2þñO<Œ•ùj}DõíPWüžãÚŠÆIxKÖCüî²y\Ý#ëÇ=ulæ¨z+<ªú ÅNTõìÊu#üLýflñ3õ«æí½¹_qHýãöþ‡9q«¹E]¥ÿ7?‘ã×\^âü79ÞÝ䜗f5©íë9a+©'ñæœw3VêÙ-×IÜæB—à +½ìó³o­ólÊGxc àí I¯Ü÷û  ë¿žçWÞ%ôª¼ +Ý°Ë]/ã+l3ôÊß7FÄ óI¯ü“;‘®s<í‘O“^ùkþ#âÏš³|„Ÿñâ>t?ƒÛ»ßžJãÐŽ#õêÜûi6« z¥Î£y>7;zÀÔšÇÇ¿ ÿ5`jŠÛo˜¯:è•š·3²×­¹+×µ—ô¡ûyl§=!û™ú%Ú—~9Ä!õÛ7Gä8XÄ­æaÝ·¶wžorû00Ç9~p—Ð+<’ò·í/t)¬—óØ.(ôϤ¼ûçf ç:q'¯´bíµŸ’^9ÕÞ¡®zП¨ì;ÔUâAùcPWÄ•ÿu•¸Wýèoâ͘¥ããÀãLÏ€x&îƒø'Þ^$ó呯Äñ\K‘ß0ê~x®¥¨‹zHíñ\KQ?í´/ˆ[ÔUò—󙣮jÞNÏvt=»r]§ê¿=>û™úUÛñgæ~á¹–b|µ¿Êqðˆ[ò—ýi×9³wú?žk)æxÎ#Ź}_Žwƒº¢øo#õÁ ®È×¥žÄ9ï~¾ÔóF®wÒJ+¦ë³?É•ô +Ÿ!x¸ð6Ò«xý8©W·Lë ýþÿ–zuÀÏé{¯fè@1.£qÑÜ·Î?Ï«üÍ‹–ê…ý‰í«¤Wqò?D<›ƒhÞ`ÿëº?ÁíÝ~ûÐ8tÇ!ôÊ|úéU¸wUú~‰Û‡ »Ðx3[Ý)ê!œµ.7wáXQ?aÊ(âæÒ±¢Þ|ávë;E}ºb§Åu;ˆ+_וë6ð³æÍ’ìgê—à?ËýJqˆ•Sâà·šÛ7‡8×<¼’ãì—š7s^Ú_ü[êÕœG‹¼×íí­9ïñ?G]jÎËuÒÞ…àvÿã.¦Ïƒª½C]¥º5ʾC]%Þ(,ê*ñöPé¿E]#ûÛ ¿íc»t|·*ží9ƒhšÈøÄ?µ÷ÇÊ|Yä+ñö™ß0~—¬?[Êzg®KãÊ^ ë'LEÜ_"ëÍ3Wõ銯êÙ•ëFøIñ(ã«ù$û™úUó¸oî—QãË•8ÄúÇóŠ^íþïçš·/ç8;äEð‡s^âÏ¥>ÔUòÃŽ–zÒÜRòþ™ÔŸu•ÚÇû®ºD/ÛÇóR)x^ªÐ+íð¼TO¦õŠ¹Ö«.WzÅ\ës­W]®ôŠ¹Ö+æZ¯º\és­W̵^1×zÅ\ës­W̵^1×zÕåJ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½êr¥W̵^1×zÅ\ëU—+½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õªË•^u¹Ò+æZ¯˜k½b®õŠyV«ÿ_¯š}_ÉŸCÔçAæZ¯º\és­W̵^u¹Ò+æZ¯˜k½êr¥W̵^1×zÅ\ës­W̵^1×zÅ\ëU—+½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õªË•^1×zÅ\ës­W]®ôŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö«.WzÕåJ¯˜k½b®õŠ¹Ö+æZ¯Ú½žX>êùs­W]®ôŠ¹Ö+æZ¯º\és­W̵^u¹Ò+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õªË•^1×zÅ\ës­W̵^1×zÅ\ës­W̵^1×zÕåJ¯˜k½b®õŠ¹Ö«.WzÅ\ës­W̵^1×zÅ\ës­W̵^1×zÅ\ës­W̵^1×zÅ\ëU—+½êr¥W̵^1×zÅ\ës­Wvûè~®Ö+æZ¯º\és­W̵^u¹Ò+æZ¯˜k½êr¥W̵^1×zÅ\ës­W̵^1×zÅ\ëU—+½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õªË•^1×zÅ\ës­W]®ôŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö«.WzÕåJ¯˜k½b®õŠ¹Ö+æZ¯ü ké{­W̵^u¹Ò+æZ¯˜k½êr¥W̵^1×zÕåJ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö«.WzÅ\ës­W̵^1×zÅ\ës­W̵^1×zÅ\ëU—+½b®õŠ¹Ö+æZ¯º\és­W̵^1×zÅ\ës­W̵^1×zÅ\ës­W̵^1×zÅ\ës­W]®ôªË•^1×zÅ\ës­W̵^5»Œ ïŵ^1×zÕåJ¯˜k½b®õªË•^1×zÅ\ëU—+½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯º\és­W̵^1×zÅ\ës­W̵^1×zÅ\ës­W]®ôŠ¹Ö+æZ¯˜k½êr¥W̵^1×zÅ\ës­W̵^1×zÅ\ës­W̵^1×zÅ\ës­W̵^u¹Ò«.WzÅ\ës­W̵^1×zÕþè$Z¯©õŠ¹Ö«.WzÅ\ës­W]®ôŠ¹Ö+æZ¯º\és­W̵^1×zÅ\ës­W̵^1×zÕåJ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½êr¥W̵^1×zÅ\ëU—+½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õªË•^u¹Ò+æZ¯˜k½b®õŠ¹Ö+»£§õtZ¯˜k½êr¥W̵^1×zÕåJ¯˜k½b®õªË•^1×zÅ\ës­W̵^1×zÅ\ës­W]®ôŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö«.WzÅ\ës­W̵^u¹Ò+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯º\éU—+½b®õŠ¹Ö+æZ¯˜k½òÛïA롵^1×zÕåJ¯˜k½b®õªË•^1×zÅ\ëU—+½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯º\és­W̵^1×zÅ\ës­W̵^1×zÅ\ës­W]®ôŠ¹Ö+æZ¯˜k½êr¥W̵^1×zÅ\ës­W̵^1×zÅ\ës­W̵^1×zÅ\ës­W̵^u¹Ò«.WzÅ\ës­W̵^1×zå~ó?´/Aës­W]®ôŠ¹Ö+æZ¯º\és­W̵^u¹Ò+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õªË•^1×zÅ\ës­W̵^1×zÅ\ës­W̵^1×zÕåJ¯˜k½b®õŠ¹Ö«.WzÅ\ës­W̵^1×zÅ\ës­W̵^1×zÅ\ës­W̵^1×zÅ\ëU—+½êr¥W̵^1×zÅ\ës­Wqèéœ ­W̵^u¹Ò+æZ¯˜k½êr¥W̵^1×zÕåJ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö«.WzÅ\ës­W̵^1×zÅ\ës­W̵^1×zÅ\ëU—+½b®õŠ¹Ö+æZ¯º\és­W̵^1×zÅ\ës­W̵^1×zÅ\ës­W̵^1×zÅ\ës­W]®ôªË•^1×zÅ\ës­W̵^¹V¥ó´^1×zÕåJ¯˜k½b®õªË•^1×zÅ\ëU—+½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯º\és­W̵^1×zÅ\ës­W̵^1×zÅ\ës­W]®ôŠ¹Ö+æZ¯˜k½êr¥W̵^1×zÅ\ës­W̵^1×zÅ\ës­W̵^1×zÅ\ës­W̵^u¹Ò«.WzÅ\ës­W̵^1×z÷y…ÎÐzÅ\ëU—+½b®õŠ¹Ö«.WzÅ\ës­W]®ôŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½êr¥W̵^1×zÅ\ës­W̵^1×zÅ\ës­W̵^u¹Ò+æZ¯˜k½b®õªË•^1×zÅ\ës­W̵^1×zÅ\ës­W̵^1×zÅ\ës­W̵^1×zÕåJ¯º\és­W̵^1×zÅ\ë•|/®õŠ¹Ö«.WzÅ\ës­W]®ôŠ¹Ö+æZ¯º\és­W̵^1×zÅ\ës­W̵^1×zÕåJ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½êr¥W̵^1×zÅ\ëU—+½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õŠ¹Ö+æZ¯˜k½b®õªË•^u¹Ò+æÿ[ç¯IQ¥ÿfDvD\XÒŠŠ4,Ù! Šº¨·ÐQ\@@htÙ%ˆJðç +-¨«$1DÀI‚Ép‹4„!Ãhr‚D¿§NõÓŸ:ÏûÌ÷Ö­®:çÔ÷í÷Þª~ÕWäê+rõ¹ú*®wðË“€ê+rõÕÈÅWäê+rõÕÈÅWäê+rõÕÈÅWäê+rõ¹úŠ\}E®¾"W_‘«¯F.¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_\|E®¾"W_‘«¯F.¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõÕÈÅW#_‘«¯ÈÕWäê+rõUø÷ÆžC¦¾"W_\|E®¾"W_\|E®¾"W_\|E®¾"W_‘«¯ÈÕWäê+rõ¹újäâ+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõÕÈÅWäê+rõ¹újäâ+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_\|5rñ¹úŠ\}E®¾"W_u;ý×óóº¿"W_\|E®¾"W_\|E®¾"W_\|E®¾"W_‘«¯ÈÕWäê+rõ¹újäâ+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõÕÈÅWäê+rõ¹újäâ+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_\|5rñ¹úŠ\}E®¾"W_Å-ÉŸ'!Ï¿"W_\|E®¾"W_\|E®¾"W_\|E®¾"W_‘«¯ÈÕWäê+rõ¹újäâ+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõÕÈÅWäê+rõ¹újäâ+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_\|5rñ¹úŠ\}E®¾"W_õ^`ÏŸÖ÷ƒäê«‘‹¯ÈÕWäê«‘‹¯ÈÕWäê«‘‹¯ÈÕWäê+rõ¹úŠ\}E®¾"W_\|E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾¹øŠ\}E®¾"W_\|E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê«‘‹¯F.¾"W_‘«¯ÈÕWäê«ê£ÍCóz?H®¾¹øŠ\}E®¾¹øŠ\}E®¾¹øŠ\}E®¾"W_‘«¯ÈÕWäê+rõÕÈÅWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê«‘‹¯ÈÕWäê+rõÕÈÅWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾¹øjäâ+rõ¹úŠ\}E®¾ +_\äÞyùŠ\}5rñ¹úŠ\}5rñ¹úŠ\}5rñ¹úŠ\}E®¾"W_‘«¯ÈÕWäê«‘‹¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕW#_‘«¯ÈÕWäê«‘‹¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}5rñÕÈÅWäê+rõ¹úŠ\}Õ®ÓÜ:/_‘«¯F.¾"W_‘«¯F.¾"W_‘«¯F.¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}5rñ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõy%Ÿç5rñ¹úŠ\}E®¾¹øŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕW#_\|E®¾"W_‘«¯È§øj­æòyújàS|E®¾ø_ |Š¯ÈÕWŸâ«Oñ¹újàS|Åöòy^íÀ§øjàS|ÅþåóÙÏ_ í§øŠ\}5ð)¾ø_ |Š¯>ÅWŸâ+ö#Ÿ?ÈyMñÕÐ~Š¯^©¯ÈÕWŸâ«Oñû‘Ïä8S|ŠŸçE>ÅWC?S|Åëòsý†Ïû‘Ï$Ÿâ+ö/Ÿ?ÈöS|5´Ÿâ«OñÕÀ§øjàS|5ð)¾ø_‘«¯ÈÕWŸâ+¶—Ïd¦øjh¯¾Â¿ÏMŸËäïƒäê«‘‹¯ÈÕWäê«‘‹¯ÈÕWäê«‘‹¯ÈÕWäzE®¾"W_‘ëý¹úŠ\}5rñ¹úŠ\}E®¾"W_‘«¯ÈõþŠ\}E®¾"W_\|E®¾"W_‘ëýÕÈÅWäê+rõ¹Þ_‘ëý¹úŠ\ï¯ÈÕWäê+rõ¹úŠ\}E®¾"W_\|5rñ¹úŠ\ï¯ÈÕWäø¯}ñóÛõ›Ë'@ÔWäê«‘‹¯ÈÕWäê«‘‹¯ÈÕWäê«‘‹¯ÈÕWäê+rõ¹úŠ\}E®¾"W_\|E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾¹øŠ\}E®¾"W_\|E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê«‘‹¯F.¾"W_‘«¯ÈÕW䃮ÆÏKmCsë<}5ð)¾"W_ |Š¯>ÅWäê«OñÕÀ§øŠ\}5ð)¾b{}?8ð)¾ø_±}?8ð)¾ø_‘«¯>ÅWìˆ?žyœâ«¡ý_ |Š¯>ÅWŸâ«OñÕÀ§øŠ\}5ð)¾ø_±}?H®¾ø_ |Š¯>ÅWìGß|Š¯Ø¿¾dÿòyôÌã_ í§øjàS|5ð)¾âuåóèÇëÊçÑ\}5ôÓ¨¯8ù<ú±}?8´Ÿâ««¯Âv‹Ü;/_‘«¯F.¾"W_‘«¯F.¾"W_‘«¯F.¾"W_‘ëý¹úŠ\}E®÷Wäê+rõÕÈÅWäê+r½¿"W_‘«¯ÈÕWäê+rõ¹úŠ\}5rñ¹úŠ\}E®÷W#_‘«¯ÈÕWäê+r½¿"W_‘ëý¹Þ_‘«¯ÈÕWäê+rõ¹Þ_‘ëýÕÈÅW#_‘ëý¹Þ_‘«¯ÈÕWÕ'š‡æå+rõÕÈÅWäê+rõÕÈÅWäê+rõÕÈÅWäê+rõ¹úŠ\}E®¾"W_‘«¯F.¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_\|E®¾"W_‘«¯F.¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõÕÈÅW#_‘«¯ÈÕWäê+rõUÿ™ ›—¯ÈÕW#_‘«¯ÈÕW#_‘«¯ÈÕW#_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾¹øŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}5rñ¹úŠ\}E®¾¹øŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕW#_\|E®¾"W_‘«¯ÈÕWq›Ežž—¯ÈÕW#_‘«¯ÈÕW#_‘«¯ÈÕW#_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾¹øŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}5rñ¹úŠ\}E®¾¹øŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕW#_\|E®¾"W_‘«¯ÈÕWÝÿ×óóò¹újäâ+rõ¹újäâ+rõ¹újäâ+rõ¹úŠ\}E®¾"W_‘«¯ÈÕW#_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯F.¾"W_‘«¯ÈÕW#_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹újäâ«‘‹¯ÈÕWäê+rõ¹ú*~¬ùó¼|E®¾¹øŠ\}E®¾¹øŠ\}E®¾¹øŠ\}E®¾"W_‘«¯ÈÕWäê+rõÕÈÅWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê«‘‹¯ÈÕWäê+rõÕÈÅWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾¹øjäâ+rõ¹úŠ\}E®¾ +ÿqðËóò¹újäâ+rõ¹újäâ+rõ¹újäâ+rõ¹úŠ\}E®¾"W_‘«¯ÈÕW#_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯F.¾"W_‘«¯ÈÕW#_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹újäâ«‘‹¯ÈÕWäê+rõ¹ú*nrÁ+óò¹újäâ+rõ¹újäâ+rõ¹újäâ+rõ¹úŠ\}E®¾"W_‘«¯ÈÕW#_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯F.¾"W_‘«¯ÈÕW#_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹újäâ«‘‹¯ÈÕWäê+rõ¹ú*lþèkóò¹újäâ+rõ¹újäâ+rõ¹újäâ+rõ¹úŠ\}E®¾"W_‘«¯ÈÕW#_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯F.¾"W_‘«¯ÈÕW#_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹újäâ«‘‹¯ÈÕWäê+rõ¹ú*n½È›óò¹újäâ+rõ¹újäâ+rõ¹újäâ+rõ¹úŠ\}E®¾"W_‘«¯ÈÕW#_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯F.¾"W_‘«¯ÈÕW#_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹újäâ«‘‹¯ÈÕWäê+rõ¹ú*|åc›—¯ÈÕW#_‘«¯ÈÕW#_‘«¯ÈÕW#_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾¹øŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}5rñ¹úŠ\}E®¾¹øŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕW#_\|E®¾"W_‘«¯ÈÕWqçÿúǼ|E®¾¹øŠ\}E®¾¹øŠ\}E®¾¹øŠ\}E®¾"W_‘«¯ÈÕWäê+rõÕÈÅWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê«‘‹¯ÈÕWäê+rõÕÈÅWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾¹øjäâ+rõ¹úŠ\}E®¾ê>²q ƒ/_‘«¯F.¾"W_‘«¯F.¾"W_‘«¯F.¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}5rñ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹újäâ+rõ¹úŠ\}5rñ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯F.¾¹øŠ\}E®¾"W_‘«¯š­Yp^¾"W_\|E®¾"W_\|E®¾"W_\|E®¾"W_‘«¯ÈÕWäê+rõ¹újäâ+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõÕÈÅWäê+rõ¹újäâ+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}E®¾"W_\|5rñ¹úŠ\}E®¾"W_õÛ®øÎyùŠ\}5rñ¹úŠ\}5rñ¹úŠ\}5rñ¹úŠ\}E®¾"W_‘«¯ÈÕWäê«‘‹¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕW#_‘«¯ÈÕWäê«‘‹¯ÈÕWäê+rõ¹úŠ\}E®¾"W_‘«¯ÈÕWäê+rõ¹úŠ\}5rñÕÈÅWäê+rõ¹úŠ|ôÕßw4O‘·¿8ë¾I|3ž|™Ýo‘÷gíýLâÍ¿Gòy»Õÿ’x·ýL{?I¯>úMãla¿Ç'¯û÷*¢}ûPmû'Ècÿø´Äã¬_Ù>{òîà ÞžxýïGþ}ÿ%›oöO‰‡Ý°çàWoþuzâíy‹ØóRÉÛ+>¹`âÕš|´ì§ýá2ïL<üâÒÙŽ_s¨ñê¨Kg§y°ŸfàõZ|´äaè§Çu®Ûaœ%ïÞÈãLórü y^)i\¼n5Ä! n%¯‡¸Ĺäí£9Îy)ywUÎKÿŸ¿GÉÛ-skä½äõ™9ïño;Z<8žî°\'ý…Ç8^o±ûésÂ;iPWà•ôPW‰w2žu•x¿º2~¾Ÿo‡ù´ýÔø$^K<ûƒ6°¿‡WõñoÿÔ¾ÙÍç«F¾ïÿäóÛ^þI['õ¾Ú,cëªþ¹¯ŸvÖ¡Æ›#}½5äRŸa觑zÃu#Æiñî7º×ó8Ó¼J?ŸçUÉú +CZÄÍæ7ôÓ>øø´ôïq.yÿHŽs@^¿2ç%~Ñû¡B]¥qÔ'yŸtg yÿ«÷OºJíãÇ8/ÙWýÀç¥öù÷›¯Úgg:Þ¯þäÓ“ø‰ð¡½¯–{úe㯜cyf=÷³6_Õo{Øꂼ]û†·Rûæ‚óm*yUÿÀ|ÕÜöqç«z§»l}6ÇÿÍžÁöñ‡w.ÑO¿í¡Úzˆÿìë¡F=¤öÕ‰¾~úþ‘ý†ºJãe^"9êªäý͹­ç0\7Hý÷ßÈãLó*ûi~çÕ!i\¼nÿÕ‡qsüý?˜–þ]!Îé¿l߬•ãÜ¿ì×{…º²ø¯íýP¡®lO{ŸÄ9ïÍ\ïŸêÙ\'a¯…æé«xÙÎKíF‡Þ;‰ñ…™§8/õgle¾ªïœW›g÷3_Å?ä|U_ûƒ7R?ñ³»ºùÖÇ.g¾ªº©‹O³ý²æ«ê‡ìu’ñé>þ_æ«núW\üÃÛ.Ó8/;äU‹_ž~5¯Ï¶ó¾ÚvM[Ÿá…{)Ûwï›ßÖauþ¯¯/y}ÇnÆÛ‹}}šÇS ¼yñžGJÞý„¯mç|U×í0β}=Œ3Í«äñü<¯þþ‡ª4?^·âк©óUÜ.Ç­AœËöÕ19Î òâø59/Ýb»ïjžÉyìÖ:Åy¬þ}Î{…:)û‰ä:‰ü_Ç«§`¾Òöu5ù´Ò@]%ÞÈx*ÔUâ•Œ¿ÅøË|ækýÌ#>!õ/ñ¬ÏÄ»òñoÿÄÛK}¾º§^µú¨«I|Ÿyi·YÓÖIû¼¯‡øÞùóºú“¯Ÿpûn™_$õ6ð(õÙýD©ç0\7bœiÞO=Œ3Í«äýyy^qHócûæc95âVòu•þÝ}Ưßê×Cœâ×{˜•óÒ-êýÐ?óØ®é}OÏy¯.õþ©6Ìu×þ_ç% žÚßœï¼Ôžø÷{,{¿×ñ8㺧¯^^Êù*œ·D¾¿ªÏϯKü=Øuo¼žÚ‡£^·º`|º¾óë§Ç¦|äÇ]f÷ÝS?tñ¬—|#¯ÏݯùëDÑ>>ï'âc‹º|ů|ÛÖgûñ·{_­rJ^Ÿ7íê|þk¯¼>¯]Ðùª½÷ì·t¾j^ݲ«óU=ôS}âí®žëáºõã‹:_5Ã8{ÌËâÁ¸ ój‡XÌ·["Ç!"n%¯‡¸UˆsÉ»·q^æüJ®Íyi_ZÊûêOC‘w×þ9ïñ¸óïÏu^zÆñêÜ…ÍW´¨«”¿ ý£®ŒËxzŒ'ñVÆßaü‰wGúùö˜¯õ3ø´¯$ž-â™x¿›…ø'^¡®&Ó÷‡¼TÈ—qÔUÉÛ•O±õP£®JÞ|}/[?ñ_?í=ïnzxs³¯ÏzèGë9 × Rÿíyœi^)ûÔpŸô¤__Õ‡JÖc{ìevç4oöÓÍŸã\!/%o®ÉyiÿìýП›óöŸ¬šóõþ©NêäÏÏ8ÿ`öU·+;Þ¾µ‹ùª»ô§ÎKñôš¯ú[ayãøC{úK)OñOñã¿~7óUÿðn¾á7ÛïkâÇþwZÀϱŸþþmÌWõ+«8_Åçb¾ªïšáâ–ÞÙî'»Ž²çγŸê¾?/Ño»êV/”ùj^]ÚÖgwæ|ÎWý9Of~ïw®+Û÷ý¦¶«¿s]šûïΚÏÕgú Øê…²}=\·Å8KÞݛǙæUòø¾<¯‡4^7 qh·’·CÜ:Ĺäa÷çy)ys]ÎKƒ<:¾_Îc…¼—<œ–óÞì·²óRÿ·\'ñ¬m¯ö=ú—éý ¶¨« ðþéu•x-ãé1ã2þˆñ'd¾ æ›x5øàî/>ž5â™x}§‡ø'Þ.äó¯ÄÃ*>¿í+KÛ:‰gøz¨P©}¼Ç×OÿশÞÚ¤Þ^¡®Ò<˜÷øÇÜOz¼.ÆéÚß“Ç™æUòŠóBÒ¸Øû\ŽC¿®¬Ç¹Û˜¯âC²~wËqnÏõë½»6祹Åû¡ß7ç±BÞËëö¿Ëyo÷õþ©ÿžë$ž¹ó†l_±ù•ë§ÝzîÝ“øNó¶ù«žödâñìw9_Õ¯g¾ +›\dyã0û‘×Rûvµ…¯â=+˜¯ÚÅ›ð}¶K¿aë³ï»¯ù5ï1_5Ÿø¹½?&Ÿ{ÁÖgüàÒ._aó݈©ß{Nz¾ÌWså/m}†C¸äí[[ÛúlŸ}òÚ’×O\f<¾øäµi¼n5ððÓÃ.y3ôÓÝ{Òó%¯‡ëVZÚùªÿBgšWÙ> ój‡’ÇYC7›ßðºß—ãV#ÎŽßãÜo|‘{ŸØ^ŸóDz}Ø(ç1N›ßûj•œ÷uR¶¯¶Êuvíù§W0_UÒ> ®&*xCûG]%^Éx"Æcíeüê*ñ8ÃÏ·B]%Þ/:5>¼©|<;Ä3ñöã>þ5âŸx…ºšÄ˜÷ùJ¼»Û緽◶ÚC|=tÿØÚÖO÷Œ¯ŸðøeÆêÊÆËûêwZŸìGê9 × RÿÕ0Î4¯²ÿvÓ<¯€8”¼âÐ!ni~œoºJÿnç’Ç»rœ+äÅñër^ÂYÞñÓ9q>ï“~åœ÷z{ïŸu•Æv™íüd_íz :ÞþióUµÑ>ÎKñwï1_µ?ý?ËçU-~Wþ{X¿®wÃVæ«jŸ£­.Ø>|êÿ6‰+7OÿÎüMÞn{„ù*¾ûQ»¯'¿9ÝÖg<éµ7Ê8‡ý÷´õ¶=á/%og?kë3üäåçJÞöμ>w]ÅùªÞäFãÍ?¶tõÓ>·º­ÃvÚVÎWÍÀûÝVq¾ê7ÎýT¾ü\šÇ_×m1NLJq¦y•¼ÿ~žW‹8”< q¨·Xöϸí}´y×m>™ãÜ"/eû8;ç¥FKËyl?½OŽ×Ñ©9ï1,è½tN®“¸êºŽ÷ÿrö/Òý•¶¨« ðFûG]%ÞêÇÓa<‰×2þueýÈ|[Ì7ñî©©ñ ‰ÿëÔx&OôñïÿÄÛm|¾âõÏZ}W?öùmúN['5êj?ÇøÔƒõó÷-]ýtÏ®në­B]¥ñ²};ð€º*y=ôSI=‡áºã,Û‡aœi^%¯‡y5ˆCÉ»ãNŸfãDÜÒÇñls„ùªBœKÞ¬7ÄùA¿Þ+ÔUê·FËöqÑœÇvCï“þ”!ïÞ?u•ú‰«¬ë¼d_õrßu^j¹ø®I|'ú¬¿îÊ=‘x³Û|ŽWìb¾jöºÔy¸¿ñF{ÿß]±‚›oÿûÛìýO}ypñ齶ùª_c†‹gØçcæ«ê]_vñïÏý«­ÏxÀJ._ñSÿmë³ýÈzÞW_Þˆñ·Ÿ½ô¡æ%1aë3,rÍ5%ï_>Îx³ø5פyíÞnzéC%oÙÏG×ó¾®[ý`%ç«fgšWÙOÃy!%ï÷Îqècp¾j†¸5ˆsšÇÙŸžã\!/ŽßóR!%¯ïÏy¬‘÷’‡•rÞÛe¿kñ`ÿÕ?ç:©Ÿ<Íñþ¾7_5Ò> ®&ªTÏÒ?ê*ñ¸«O‡ñßÓ? ®¯d¾5ê*ñvñ àquψx&^-äã_#þÆQW“øö8_ä+ñöÃ>¿í¶ûÛzˆŸñõÐ>aëªYØ×O…úIýÄŤÞ^ʼ×úd?RÏa¸núï>™Ç™æ•âÁñwçäyuˆCÉë!qKãbûþèµÍWÝå~ýV¨«ôó5òR¶¯QW‰WÈcÉ»¹9áï“~Åœ÷¶öþ ¨«ÔOxâ4‹Ç“ºN_qšï§ýŸUÍWÍ»n<å¯O¢}øìw-oì§?eZ¾¿zç„uó'ÍWõ»þ0-àçؾYr•üûš#ï²xŒü¼ãíýO½á·ó}ýðúÞov£­Ïðí+^OóÛ?ñ}[Ÿáôß¿\òê’'òú|âÐgKÞ¬ú†y¬^íóÎWÍÃX ¢ßz¹uœ¯ê7ÿÙÖa½â:ÎW#_ýóÎWõÐO÷ä¡Ï¦8qœõpÝã,ywqgšWÉûÇó¼ú ¾ý÷’7C"â–ÆËþ›?å¸õ ýÁ¼NÞ.‘ãÜ"/eûú¦œ—ø™ïZ<ؾfoo(Û‡“sÞkÔIÉëst'½Çû꤫žî¯´}@]M€Gíu•x'ãi1žÄƒŒ¿Åøoe¾ækíçŸÄ+‰g@<pó-ÿˆø'Þžæó¯ÄûÇ}~ÛUÞÈ›áë¡}è¶~²¾~š7þÙÖa»‚¯·@®õ9ô¥žÃp݈q¦ù1ýEyœi^%¯‡yõëûõ?—ãPëz<÷x{ßX#Î6ïa=v‹ç8ÇýzonÌyé7ñ~èNÎy¬÷²Ÿ +ueùšÏû' ®'¾gž¾jÉçä|ÛY¿ºsíë÷Ìq^Š+îb¾ªg¼â¼Ôïq”ý½¤9>ZžÙO}Ëùöþ?n™_ÇÈ«v¿7Sÿq·Ýœ¯ª͵û‰°Ý%v_ÏöÍ*Û™¯ÚûVrñï—šn¾Š·­åò>¸“­Ïpä\Û‡È~Âk»çõ¹Ðc}Šyµúò Dü»úàI³JÞVûï?|Ò¬4^¶'ïz¬/y\mè稹¶¯–í«áºÕík9_õkçq¦y•ý4üjÄ¡äýÊC·XŒ§þ`Ž[‹8—¼Ú/ǹB^JnÎyé>ðŠóX5ä±[jŽóX³BÎ{ÿ𶠔ýÔW uòÕïwßÌ|¥}@]MTð€ôPWÆe<-Æ“xìüø;Œ?ñZæ0_ãóˆOâáËSãÀ»{}üâŸx…ºšÄ˜ÇùJ<áóÛ¾º»­“uU¶¯Q©}½¶¯ŸøÖ¾Æê*kìà5êªäûÑz®¤þëaœi^e?ñÝü‡’ÔUg¿«¬ÇµçÚ}Xܯßzß瀼ØÏ koÊy‰«z?tßòønï“ +u•ÆQ¡NÊ~ÔUâá+:žš¦¯úª—Úeßa¾ê·ßÈñxÒÜÇ&Ó¼sw竸îêæ«êßtã·Î0_…®Éñ༞šcïÚõßî|Õ³¤ùªÝs~Ï~¾l}ÆOòZçæ3‡N‹Nxó¼—JÞþþa[ŸÝ«z_]õ¸­ÏöÙ}\=´ß9"¯ÏõwõÓ/ð‚ñn£Å¯âÀ›çöqõÙ ý4®ê}Åëbœ)~¬ÏzgšWÉ+Î q(y;Ä¡AÜÒ¼ÙOücŽ[…8—¼{2ǹ[ç“ÎWí-9/í‚»{_ yl÷²ŸæÄœ÷öÊËä:éê7½ïgéþjJ{ÔUÊSþê*ñFÆÓ`<ÆeüãO<ïç1ßÄûÿ˜ŸÄÛoûx6ˆgHí×óñ›:-ñö Ÿ¯þô‡­¾»õ}~Û+·õŸñõ÷9ÂÖO…ºšL×ê¿Fý¤þkÔ•wàÕÀ£Ôg7ôÓj=óºgÙO3Œ3Í«äa˜W@JÞW9qKãâ8»?,i¾jç’Ç'†8ȯ÷xó—wx?´ÿžóØnç}R¡®Ò8º+¼ÔUâq™7€ì+žø Ç›ÿÝgÎ$¾ÓžäߟÆå?k¾êŸzÒy©yçíï÷í WN ø9η½íøüþÿÙ/¸ùV›Ï0_uùˆÿ;ÅÌÏÛûŸîàÏØ}=ûiîÝÏÖguÚK¯º8ﻸù*.û1—¯¸|cë³zuoÛ‡È~ÂϾlë³¾a!ç«úêé¶Þº-¸ºì?¼k{ãÍ6\âÁ~êW7.ä|U±\·l_ ×­–û˜óUËqb^eûv˜W‹8”¼â·’7k qCœc1Îð…çy)ywkÎKƒ<–¼GÎc…¼—¼ù·œ÷€:)yø¹Nêòþ Æ'¾íkæ«ZÛ£®&*|Iÿu•xñt þ8ïG™íÇ_¡®¬½Ì·Á|o?<5>‰wùxö÷ìgë3üÎÇ? þí+ÔÕ$þÃyÕÈ—ñW|~Ûþl¾jgûzh®šž×Õ¾~Ú…¶Ï|k_oÍÀ[©ÏÀ~pÝ4Ž' × Zÿÿ–Ç™æU¶ßËój‡’7CjÄÍñ5?o¿—©dý6ŸÏqn—Ž§B]¥Ÿïžô~¨PW‰‡½O*ÔUâÍoÅ?¨+kÿÎÎKhj_íϲxóºÍ]OÜ1‰ï„gÖr<þöÒG×~ÅùªþÍ9ö÷ûê+ëO ø>ûén_Ò|Õ~øïíKö·÷?áñÜïýâÙåû‰ßþÒîëÙOuÎ"æ«ð/[¹ø78ÚÖgØèrû=ÇØþØûm}6']mûzÈÃvwØúl·\ïÁò¸Èwm}¶;¿tUÉÛÅn6^ïúÒUiÞl?ò/­÷`É»¡Ÿêä«ó>5¾nòºgÙ>“Ç™æUòj˜WDJÞþ1Ç¡l'»åxª!nqŽÅ8ãÅ9ÎÝë;_ÅÛr^òèÚ›óŸ^ËæÍþ›rÞûœåùœ\'ݯïq<ÞøâaéþJÛÔÕx'ýÔUⵌ§=îÛÒÈøkÔUj߯ãç[¡®¬ŸyÄÇÚŸ05žý´‹øø÷g=_âݧ}¾ä+ñæDŸßöËwØz[øz¨P©}ü/_?ý¢7ïvñõ^oåë³_8÷´ž‡ëFŒÓæÇzÆ™æUòf˜WDJ^¡®lœúõXu݇µˆsú>ë¡B]ÙÏ7~½×¨«ÄÛk¼úcr+ä½ì§F]¥ö5êªä-ê*ñxô=ŽÙWýµÚñfæ–æ«j­“—âr«›¯ÚSæN øÉqük?hk_›ey&wdïÿ«ýwvó­W¼'¿ÿùÅ/ÜïÕ›5fÙýDuñÜ|_Ïøÿë§ÞšÄõÚ}.µ÷쿤6_Åolàò–Ø&ßw}q1ï«lbë3.¹ó)ì§Ùö9ãÍwwp¾ê—~O½ïÎWäÍ»w~ ‹ýöóŸ‹y_ ×­öØÀùªÆ™æUöÓóê/šk÷¡ì¿^rˆâV¶ïVÏq‹ßß¹ŠÅxšrœòRòjÈK<–¼[kÈãš';5Ëæ¼w;ÕÎKÍšC|i#Çã‘ß5_µÒ> ®RÜé? ®¯d<ÍÌíﻕŒ?`ü©}+óm1ßÄãϧÆ'ñZâY!žÖ~oÿñ©=êjÿeü»Å·™–xÜÜç·]u['í¾ºmž3Þý?_?u•úiPWéúì¿xû¯¾>[ö£õ<\·Ñúç81¯²ÿþá<¯þB¿¾ê%rÄ­lß­6ËîÃjÄ9—ãl—Ïqn_õë½¹=ç¥9Ùû!®™ó×ð>©QWézqGïŸu•xØj#ç% ûê7ø™óRsȬÛ'ñn¯¼ŸŽãìŽ?Îös7?ÚbZÀ÷ÉûY š¯ªC>í|ÕÏ©ÌWõ¯žr÷™ñ§k˜¯Úõ.w3+óU¸myï«kwÌ÷.çâß.yŠ­ÏpÔìË8·‡Üm볞‡¼¯gð^xýr[Ÿõ‡Ý_¶¯NÝÞÖg8ä–+K곌w‡ÝreŠç[“ßuØý%ïOÉýD\·äÕpÝã,yÆÙc^%¯†yÕˆCÉÃ595âæø9nñ¨§ÌëghŽs<øÓÎWõ— +yŒÅ¼Ú«sòîx—óP'%oÊuÒ.y¡ãÝ ˜¯´}@]MàzµôPW‰÷?ôã ¨«Ä[‹ñ[?2ßu•x¦Æ'ñp«gx&^Iüû%N±õÙéóÕ|wöØÛ|~Û×.ŸÐM‡¯‡€zH¼=Ø×O»ÌYÆkÔUº>óE¥>ë¡ŸJë™×Å8]?Ã8Ó¼JÞ óª‡’‡YC·’7¿¯ÌWí‘~ýÖ¨«Ô®B^B9þ;r^òXòxUÎc³§÷IºJý´ë{ÿt¨«Äã:/ÙW»Ò4Ç›'?d¾j.É¿wd<»zaóUØé7θõ:ö÷ûn¹ë‡ë»ö´÷ÿÍê•óUxã‡öþ§záy‹ÇØÿŒuíýOóÔ.ù~sðLýÙýD½áÿRƳÚh5óUœÜÌå+¾} [Ÿí9g>Q¶¯¯þˆ­Ïæð æ–¼{ùÖì±ßL¸úéV\ÆÖas„óU;ðþˆ æN"‚;ôS{æ%¯†ëögÉÛaœi^%ï>燒7ûä8ÄçŸ7¯óºýrÜúÕ*ç«öõ瀼ÄbœÍ9/ýŽ·85_Êyì/ÎÇ`ÿí29ïê¤ì§}<×IuÇÊŽ‡-—û©½\Ñ·¨«‰4é? ®2žu•x%ãï0þă̷Ã|­ý<â“xû¤g@<o6ðñoÿ ^K¾ò•x÷GŸßöªLK<üÒ×CÿÒ­Æ›ã|ýô+,cë­B]¥ë3Î#G]•<²©ç0\·‘úïçÏãLó*û©†y5ˆCÉÃÞ9ñ9¿+ÔUj×Íðë7¾–ãÜ-ë×{œ“óR#¡˜W·UÎc¼—¼F]¥þê¤äêÊøí+;Ž¦öUOÿÖ´€ÿcÜšOtÛ$þ]O{›ãÝoö{ØølìÆÓ>¿ƒý=¬¾`ç«p÷Óv?Ý^™ÿÎÀþãWæÚýDwÌûœ¯Âé{ÚýDWýÉüÍöõª§ÚýDsæsöºJ^½ö5[ŸÍM§çßËòýã¾·çõù•¿ÙßKÙ¾þùY¶>ãûûR<ÈÃĘ¯ª?œyEÉû?Í;÷Ì+Ò¼Ù~ä[ô÷•¼úi¾ú·ÇKÞÿ,_·Ç8K¿—Ç™æUòðjžW‹8”¼]eˆâæøi9nâ\òzˆs<ç«ö®œ—ø©¯Âs9Ý|o³ys¾íq9ïÝ?}Ëóõr´?;Êñð̇M¾Òöu5ÞJÿu•x'ã©PWÆeüã·~®ðó ˜¯µÿõÔø$ß:×Å3 žÖþ ÿþ•¯Ùëk¸Ñç«E¾ú©PW“øÏä7ñvs_í'þcZâál_?u•x<Ç×yøO_ŸÍÐO'õ†ëvgšÇSãì0¯’Wü:Ä¡äÍÊ9 âVòîw{æû°ËýúmvÈq®‘—4^·¿3ç¥BKÞ>›óØWÞ'ue×[Àû§C]%;jZÙ}õO>âúoŽ[Ü|7ÜÛñîý/>4™~âß®rãlö?Äþ~}´å™ãoîÙÞ|Õmµš½Žü†™æ«°ñÆæoò~•³í~"þëßíu’<Üw­Ïn‰Í}ü·ý–­Ïféóì÷²cûW7³õÝØûjûm}V‹Ow¾Šž—×íK_Qæ+¬ýVæW/í|EÞ,1ý¾^·ú‰¸nÉûíòu#ÆYòjgšWÉÃ6y^âPòöÞ‡ +q+y=Ä- Î%ïfç8wGm^Çy÷—å®r«¿ŸóØ ï±˜W»tÎ{ƒ:)ywL®“êsÓ¯êý>{HòUöu5‘¸ôPW‰·2žã±ö2þ +u•x·¥ŸoÄ|­ýFSã“x%ñlÏÄûÅ}ü+ÄßúyŸÏW|e3«ûæ_|~[ä7¤~õõP£¯QW“éûÃëi7ó-ã-êÊ®¯\ê³ú©¤žÃpÝã,ûi†q¦y•¼Þ:Ï+.é×W{OŽC…¸•í›•Ï¶û°q.y}Žsó+¿ÞkÔ•µ[VüÐæº=õi{ý«ÖXßûêàgòúüß ^²xð>êòýl}6»Dû=û¯ïÏçZÛË´¿—Ž|ƱÙc·¯qoÙOsçʶ»;¾¼äÝGwÏü®ƒ/Oñ`?-ùkÜ[ò0ôS_qäc%ï?¯1Î’ws‡ó·˜WÉ›˜çÕ¯¾¾óUwPŽC‡¸•íûSrÜĹäaˆs¼úXó:Çßß“óÒ"±˜WµDÎc¼—¼=&ç½B”¼{-×I³Ð>Ž×‹}õàä+mPW‰Kÿu•x#ãÁï/ìï%Œ¿F]¥öñY?ßóM¼uj|¯%ž-â™xøWˆ¿ñÿñùª¯Äcôùm‘ßú¿Í×Cœ³²­« +u5‰ï3þê'µ¨«Ôyÿ‘Ì{©Ïn觑zÃu;Œ³ì§¹/3Í«äa2Ï«BJÞ˜ãÐ!n%¯PWéßq.yûÁçö*¿Þê*µ‹•÷C³øǃ½Oê*µo®õþ‰¨+ëçû8/¡©}Õ§]íüÓ|ñå[&ñúöíïÞwkŸxsùîî>ª>íQûýróçÎy¸»o#óU¿ÿÖî>³ý̓v?Ñžt’{]¯´‚ùªÞà{d›¿Ë|U?º´‹µâÁù}âÅ×»s7ÝGæõùÇìïì§~c1[‡ÝÏ·¼'Ń¼Zî×ÆÛÇÿfþÔ_cš7Û÷™÷¿ØòÇ—úÙã1û;êØþõ|݈q–íëaœi^%oVÈóª‡’Ç q@ÜJÞ®˜ãÖ"Î%Çå8÷/væuŽ§òãî?5ç1Þ¶½Í›íÛ÷æ¼Çß]íx÷…\'ýuO8^²ÏAö~PÚÔÕâ¨ýÔUâ­Œ§ûÝ£ö÷’FÆ0þÔ¾’ùö˜¯õsâÔø$Þ¬ïãÙ!žÖþÿñO<\äóÕÝp¤½ר«I|Œòðïög¾ÔCâýc¾~ÔOâê*]‡ý„ר+LJ~¢Ôs®1β}?;³Å¼JÞ,?Ì q(y\7Ç! n%ïVXÁ|Õ~߯ßzˆs÷‚_ïí½9/ͤ÷C@]¥~kÔU(狺J¼B”<¢®¨«’ÙWà:Ž7g}Å|×:Õy©ûõzæ«z¿¯ZÞçþã‹d_½ïDçáîÂïÙïkªwïauÁöÕ;Ö1_U›ßnñ 'mo÷Í—çä×Éá>ªy~u»Ÿh69àÏe<냎²õÙ,8Ç~ÏÁ~êË~në3Ôk{_¼D^ŸŸßïn×wÙzk^ÿo_?|Îxøë;_…×›ïw÷$"Èë¶C?×-y<(_7bœ%ï.ÍãLó*y{`žW@JŸËqˆ_¸Ý¼ÎëÖCܺÝüNÞLÏqîß{âßÊ~š r^Ú}¿š½>Ä9~,ç±BÞËöÝÑ9ï ê$ógä:iþoKÇ«u=0ùJÛÔÕDúù5}ÿu•x-ãiPW‰·2þã·ö2ßó5>ø$ÞmëãÙ!ž‰Ç}ükÄ?ñæ>_5ò•x»ŒÏoàylæë¡B=„Ôÿk¾~âúŸËëíM_oÝÀ›/øúìwÉýÔRÏíp݈q¦q1ïí%yœi^%o~’çÕ"%ïŸÍqè?ï×csâövÖ-é×oü§çø¿Þ›ó‡¼|Ïû¡F]¥ëÅ5¼OÔ•ñŸxÿô¨+ã?ÚÒy ]ØW}צÎKýâ'Þ<‰ï„Ks^ +ÚñÁÄûméî£ú[×µ¿‡užbyfÜêK¾n¿¯ güŸÕy÷̓í~"Vó9_5ËýJê¿ûöÒ.žÝo6³û <·ìÅ4ö^<ÑÖgû¥í÷äñÌCl}Æ›[ûûy½âÛl}†9宲Ÿî›oï?w²äͯöµu[½çÜÉ4.öÞ.zÊ]%o†~Â-­ý•íã +ùºã,ÛŽó*y÷Â0/Ä¡äÕ‡q+yÿo9nýïÿϼÎëVCœkäŵ¿hÈ òXòxKÎc{ÉaÎcÍÚ9ïáÎM-ì?þK®“þ'‡:^ÝüÛŸ$_ÕÒ¾C]M€7ÒüàŽ&^ÉxÔUâq?þæâ¯Ûïk™où¦öý[Õ”øÿ–gÜfv?QKüÄ?µo·òùŠgb¯Çêj2]‡¿—@~Sû°ˆ¯‡v·Œ7‹Iýµ¯­·°”¯·zàQê3 ýtRÏÝòùº=ÆióÆSãLó*y÷|žWDJ^qè7ÇQWöïÓýúmöÈq®—²}aÎKµ®÷CºJíš‹½Oú™CÞçxÿT‹æ:é~|¨ÅiŒ3úH_ÝQk:/U³÷¿i¼ÿôwœ—šµ× ñøæÆî>*îôuûýrüæi–göß^öyû}MûÉã¬.ÈÃ܇í~¢9su÷>ºþíy}´“½N²}Üì›Võ{6uñoþó¶>ÛSŸ²ßs°}ó›Ûú¬÷»éá2ž!¾hën¹éÎ’W >jë¶ýÈÏ/+y8y;[·ñã?¿,Í›ý×ïo½éÎ’Çwä~:\·äýd¾nq:~Ü0NÌ«äñ‹y^q(yÍ8 n%oOÈq«ç’w÷å8ä¥äÍ¥9/5òXò¸cÎc¼—¼]kÈû‘kZ<‡þš\'ÕÛws¼úê…?¶÷ƒÒ>^¿ÿMˆc%ý÷3× ñþ ?žue|?þãO<®çç1ßÄ»3¦Æ'ñZâY!ž‰·Kùø·ˆ¿õsŠÏWƒ|Yû}}~kä×Úßìë¡Ÿþ¨­Ÿða©Ÿ“¶³õV¡®ÒÏ1žÕÀkÔUÉ»¡ŸJê9^–¯[Iý÷ÇãļÊ~âæy^•¬¯æs9 âV¶ï¿Ã¼ç’WCœkä¥äÍ%9/òXòueÿÞÀû¤B]%ÞáýS_›ë$¾m7‹Ó´M_õÖ‹:/ÕßßáÆIðæŽÜuÛµV¼?ñî‚O8¯Æ7~ž¿|ì–ç±ÿË×}6µwù¿ŸöëÔ|Uo»mö÷ðºÐ/»°ùªþíùu’|¾_æõ9íëîï¶íE—Úúì^{Ùî7ÇëvÀ›6ÎÕßç}µõæ±ê°WçL`\lŽ¿ÖÖmØö—–¼:ç¶n›¾qiêíû?f^ÿìÕ9%¯†~ê5Þç|Uñº¯¿lï›ÙOûÓ<Îó*ûé/Ì󪇒7ŒÃ6ÛÚ}(û CÜĹl†87ÈKÉûÉœ— +y,y|=ç±»}ç±nœ÷ð¥E-¼n½o®/ÕÖg{ëZîï¶ø¼T[ŸqƒØý&Ûwí¾oØuØÙþþ@ŽÏK55Ÿ{¿ó>/5ßµ›^2‘æMON¾ßÖmõÃM/Iý‘ãóR·›½NÉñy©ÖO‹ë–Ÿ—j×­6ü‡½of?ø¼TgšWپ懒ãóR-âVr|^ªÅ­Ûe¶»ïÂç¥Zœ»kó>^7\‘óÒï9ÓÆEŽÏKµ<ä½ìŸ—jyïù‹ãø¼T«“ú¯3,쟗ú#»¿’öø¼Ô&ÇZú¯PW‰w2|^ªýþ1Èø#ÆŸÚãy¹n¾ø¼T»Ÿ¨æŸÔ>^èã‰ÏKµõÙÜâãÏKµû®~}Ÿ/|^ê©Ÿæ~Ÿ_|^ª­‡vS_ø¼T[?Õ~¾~ðy©æ±æ¾Þðy©Æ{©O|^jîGꟗj×­¥þñy©yœ˜W/ó‚ÏKµyuˆCÉñy©ÙSÓýzÄç¥Úûœø?~ý6¨«ôóÝ5²Þ/Ïy‰ßö~Àç¥Zëí¼Oðy©9ïKyÿàóR­Nª7gäxз¸¦}Ý?Çù§yîý³'ñæݸړ÷&>¸¢Åƒqè–}ÚÞχ¿œ“óÌõ~õÂO[ûiçx <̼Áî'ÚóÏ·x°Ÿ°Ìì~Ÿæâv¼+ßwu³×U¶?¸3×ëáÓ¯Âßy=]Ÿg¿ÏcûæÐ Íøœ¸;&ð}òê–ŸeŸœ8ãâ’w7üÃxwꌋSlß¼_xƒ;JoÎýô¸nÉëáºõÓ¯â7ò8kÌ«l†y¥8”<~5Ç! nŽ¿?Ç Ÿg>ã8ëµrœãËç¸û®xUÎK\{E‹ÛwuÎc|Ú{¬š1ä}îç·îé\'õ^ 9Õ˼ùC»¿’ö5êjqì¤ÿu•x+ã ¨+ã2þ€º2>ŸŸ/>Ïî'âySã“ÚWÏñL¼þ…ø[{ÔÕ$¾Ïø4ÈWâýÁ>¿í!Úz¨PWeû +õ`íOðõgÿÃx…º²ïë¢x@]•<Þ”ûi¤žëáºAê¿ß=3Í«ì§9`˜—¬¯jˆC‹¸•íkÔUúw8;¾fŽsÿ’¬÷+s^º™Þ5ê*ý||Êû¤û@Î{¸Ïû§G]Ùu÷\È<Íø£ ûj;ßù§ýí߯›LßÙû½Ž÷¸îã/-•ó6ĹýÓæ«f™óÝ}>7êÉÔ¾=òu« ^·}ûwì~"ìô˜Åƒ¼:î2[ŸøÜ%ó7y³Äy}îv½®’÷O õúè¢ùý1=¹Ã·óúüØÛ¯ð¹Kæ1|îÒí)ì'|}¯¼n¯Yð¢’ãs—Œ‡¼(̓íò›w½½äøÜ%kß|üíÎWøÜ%».>wÉ~ÏÇ~ð¹Kyœ˜WÙOÃy=ùÃKÞ/žã€Ï]2¯³ŸæØ7|î’y¼?ÇŸ»äîCÂ5C^þ¼”‹í»s‡<îõÞ¾¾¬šóŽÏ]r¼ïr„??ãx8gaóU'íêjqÄç:ùö¨«ÄOºJ¼{¿‡ñ'ðóÅçLÙýD»ãÔøXÿψx&ÞïêãÿÄkÔÕdúþ‡ +ù²~PW%ïV:ÅÖCs£¯‡æk{Ùú‰³|ý´w?`¼›-õF®õ9ôÓK=^Wê¿mò8Ó¼Òx9þîÉ<¯€8”¼â·’÷Ç\f÷ â\òöm9ÎòRòfVÎKû¢÷CºJíš=½Oâ*9ïñïŸêø¡N^|Æù]ØW¿ý¯œº/ͽvßi§Íïx¿Êiw'ÞŸõ.ËãÐn´žý¾¦Ýø"çáîúGìõ Ÿcâæï^Á~Ï1qñéÞ÷†­O|Ž‰½NŽýÏzù +Ÿ÷a¯«äÕç^°õ‰Ï1±÷Çäø[Ÿñî“(ãÙ]ñKóCwÈá·9þ­mÝâsL.(9>Ç$¯çž¼ÀæÍõ;ðöÐÃo+y;ôÓÞsÒ%Çç˜Øuñ9&ù÷|C?õ0Î4¯²}·iž>Çä…’ãsL,øç+|Ž‰Å­EœËöø‹s¼8~]ÎKƒ<–¼ûtÎc?ßüyÞÃ8›•sÞê¤l_o™ë¤Ùe¶ãaÃ~`÷WÒ¾A]M ~ð9)®}ƒºJŸ«âÆS£®ï7òã¯QW‰×2ßóµ~æãoýÚųB<o?æãß þÖ~mŸ¯øùÝm}vwùüÆËië!ìë!þ}k[?ñi_?Íc—oPWé:¬[ò +uUòn觕zn†ë¶gÙ> ãLó*yülžW8”¼¹:Ç¡ÒõøÞ7ÌkÝdýÞ9Äy)û©PWéßÍ™Þ5êÊÚUÞ'ê*ñ°÷O@]Y?ÿ3ÛâÄø ©}ásœâÂ_3™¾sè³ÎŸÕÊÝ•8>Àñæþ]ì÷5qÏK—êo´×'|.€ÕÅxÝßßf÷] î}>7ÁÖ]µÆ ÷¾Ÿ `ë³^èËO¥y°Ÿpî_mýÖ¬dïÉëOý·­ÏîÃëÝ_¶ï¶ÝßÜóÇ’ãs,í!Ï:Þ®8ä½þnž7½ý®\'ͧy~ß¿`¿¿’ö-êjql´ÿ•º+ñZÆS¡®¯dü-ÆoýÈ|æ›x?95>ÆWóñÄç,¼”xx§‹ø[ÿûû|5ÈWâí:>¿ý6ûÛzŸñõP£RûîŸ}ý„—Ž3^¡®Ò÷™¯zàÖçÐ>çÂÕs;\·Ã8Ë~úõò8Ó¼J^ óꇒw{å8DÄ­ä ê*ý»BœK^Ÿ–ãÜ~Û¯÷vö—]¼jÔUúùö`ï“ueý.ãýÓ¢®¬ýã§YœŸ4”ô…çr;ÿôWÿjÖ$8ž³íüY¯¸ËÆ?ðŠóR³ÇQùþ¸‹n^íÍçÛýDØÒ?ÿÏÙ¶û‰°ÛnŽÏ!·õÙ~ù÷¾Ï-ÏëóÞ•ì} Ûã9ç/§ñàùÕv¿I×ÞÉÖg{ÄÜûÒ¼Gþêîæ±f¡Çn)y³Úò¶>›µO:¯äý[ûÇs¶ÏK×a?#×c·”ÏëÎíœ{_Éñ|o»n‹q–¼ÆÙc^%ïßçÕ %o‡8Ôˆ[ÉÃÚ9nâ\òfßçy)ywSÎK<:þœÇ +y/y\>ç= NJÞ^9ÔÉWt¼Ù}³ýíþJÚw¨«‰Çwûþ»v¹Óøª~›Wö¾wßgûxØ—m}ÆÙ 9_uWM·õYoyÀŸ\û…¶7Þo}ÀŸÒuØO7ðn)y;ôƒç0ßëøpÝã,y5Œ3ÍËña^ýAŸ±û£ñº÷ä8tˆ[Ù¾[3Ç- ÎŽ>Ç9ξÒâÄ~ê[s^*ä±l_¿#ç±=ÑßõËå¼Çß~"ÇcˆsüN®“îþoÞöµïÛý•¶G]M ŽÚü·ÏÎI<>éǃç3?híeü-ÆŸxÿŒŸoÄ|­Ÿu¦Æ'ñJâÙ"ž‰w§úø÷ß[Ü긫}¾ºk¬î›¿øüVÈoê§F]Mâ¿Œsåt[W;~*ÔOjß ®ÒÇöïÌÏëvõ‡~‚ÖóOóu{Œ³ì' ãLó*y3Ì«?PÖׇq+ÛwkäýT-â\ò¸YŽs…¼”¼½%ç¥FK¦ç<âùÄ'ηE]Y»Ä?¨«ÄãÜ-Nld_q§ÚõSÍÜòªI|§[ódwÝf¹ÕïH<œ2×sæƒöþϱtójî8È^ŸðÜK« ^7®pý^+üâöûò~õY¶>»‹æºûØfÉOÙú¬÷¹ÔüÍöÝ#õŸÓxð|E»ß$Çs;³Ç¾¸Ø=iÞäýª›äû±%w¾©äÕ¶ùy"Õww8·äíRIý·ûîpnú/û!ïÿuç›JÞo3<—×-y7\·Ã8_<3Í«äóBJÞ-‘ãP!n%¯‡¸áy›/–¼_>ǹu–ʼnãïnòrò\ç±j­œÇy/û©–òŽ:q|Í¡N¶ÚÈñæÈï¶v%íûµ¶¼jq¬¤ÿý'ÞÉxzŒÇ¸Œ¿ÇøÇs/Ý|kÔ•ñŸOõs¡g‹x&Þìíã_!þ‰ÇÝ}¾äËÚoîó[#¿‰WKøz¨‡ÄÃÿóõÓ¿{â/Öu•þ˼Ä÷RŸõÐO­õ¼Êp]©ÿ~±aœ˜WÙ÷pžW‹8”¼]<Ç¡ÿ™_õj³ò}Cë×oºJ?_#/e?Õ— +y,yX3ç±YÃû$Ö9ïÍŽÞ?5êÊ~~Ë,NŒ.i_a¥iÎKõ“ºrß©/9Ô]·©¾=ñj§[Ü8›­×™›x³Üõ/Úu†×ßþÎ=óýÄj•óvõÆí~¢{þywf¬kïë§vq÷±qŸåõ¹Áóë*_ß?½šÕk;¹™Ýor^ÝÛ·°õYŸsæ]n»äíÐO‡ë–Ÿ¯ùJíÿøü6ÈoâÝ¢¾ðÜ*ãêjßg<Û™ooPWéç¦ðÅ}}ö?Éýô¸nÙ¾®Ûbœ%Ã8#æUòþKy^âPòæž!Ÿöë±^ùììµ-üú×ç8‡_ùõ^ y‰ËŠÚœÇvï“u•ÆÑ>áýƒçªå:A]•ãDSûÂódœð<™8‰ïày2Žãy2·$ŽçÉ8/áy2wÿs缄çÉäû‰ý·vÞÆódl}ây2ÎóxžÌvÝ q÷±xžL¾ïzté‡'p}æÏ“yÖ®{ñõùu˜¯_7ië½ÿÆcw”íñ<[ŸxžÌu%ÇódŒãy2g;Ìü©¿ž®Ãëö™ãy2×9¾ìÐÏÝáøëùºxžŒÝ‡²ñ|‹9žÏ`õ„ç3<êÚÿf3[Ÿx>ƒÅƒíñ|[¿x>ƒÿ½ú™‡ØzÇón/ûÁóÌx>Ã5%ï¾ù–q<Ÿá¬’ãù ¶~ð|†³&‹ñãù Æñ|†kJÞ ýàù ·—Ïg°þñ|÷{x<Ÿ!ó*Ûãù y^ˆCÉñ|‹žÏ`~bð|†¼ÿO¹öCœñ|¿®/ò‚<–íñ|Ë#žÏ`ãeÿx>ÃÍ©žÏ`ó&Çó¬Nð|Çñ|†ïØý•´Çó&'ОÏàúÇónNÏgpãÁóîJÏgpãÇóì~ÏgpóÅóòú|«šŸÔOÿ-O<ŸÁÖ'žcàâç3<Úãù ._x>ƒ­w<ŸÁå·B~S{<ŸÁÕžÏ`Ïg8k2]x= Gíû‚µ_ÊמÏ`Ïgpõ‰ç3X?x>ƒ«g<ŸÁ8žÏàêÏg°q¦y¥ëðºx>ƒÍ Ïgpë Ïg°8tˆ[Ù¾F]Ù¿O÷ëÏg°8ãù Ï”íñ|Ë žÏàü€ç3Xñ|†<Þ!x>CÎûï<ŸÁêÏg°xpü˜Š}á¼³ïÿû;\:‰ï༳͛íqÞùÆÄqÞÙçç$Þ{†óRuùºöú„óÎ.8ïüPjóÎÎó8ïlëçÝëB?ß/·þ§}Ýþ^4Žç¢Kmýâ¼³ù›¼:쀧mœ«¿ï¶‰4.ÖÉÖ<“8Î;_íøñך7pÞùŒ’ã¼³­œw>#ýûÁygã8ï|uÉqÞÙúÁyçÛçu_Ùî_ØÎ;Û8qÞÙþ¾JŽóÎ6/œwö÷]ŒÃ6Ûºûœw¶¸á¼³[§8ïlqÆyg·®qÞÙò‚óÎ^ç-8ïló ÇyçÓ|pÞÙæMŽóÎV'8ïìùk7ím¾’ö8ï|éúÁyg×?Î;ߘ8Î;»ñà¼óœÄqÞÙçí~çÝ|qÞù¡Ôç§ÄÇ®{‚'Î;?n×ÏÇçŸ4þªÏÎ;ÛzÇyg—_œw¶õ€óήpÞ9{c_?8ïü\êçÏHÿeUÆçíõçݼú«¶×§0íaœ´õ‰óƒ”ýàü ­Oœ›³xpü8?˜=ÖýÍÝ÷âü`öØáÓÍßcû=¾cëçí~“çŸJãÇùÁ«Êëâü y£:qÆé%ÇùÁì½Sgœž~Žýàü`öÌÂ\UrœÌ×-9ÎÚuq~Ðî_ØÎÚ8q~ÐüAŽóƒ6¯‡²œ´8àüà#Ž¿?Ç çÝ:ÅùA‹3κuóƒ–œ´qñº8?hyÄùÁ<¡p~ðút½0wŽã8?hu‚óƒÎ38?¸§ùJÚãüàÅèç]?8?x}â8?èƃóƒv?ÑÊøq~Ðî'Úùü|q~ÐÖ'ÎN‰Oêç]qÇÍçqlÿC˜G|¬ÿ·~íâ‰ó8$Žs+.þ8cõÖöùÂyóÎã¸üâ<Ž­œÇqõ€ó8¶~pçÔI\‡yÁ¹ã8ãêçq|}ýà<Ž«gœÇ±ëâ<Ž«œÇ±q¦y¥ùñº8cóÂy·¾pÇâ€ó8—í»÷¾Ñ§ã<ŽýÜØÏCœ‘—²=ÎãX^pÇÆÅö8“óXyŸàËø^qãÇþöüzÓE›7ûÁþv[ŸØßîâ€ýíù¾k·Ý,lýíXÿ_¾Ä½.`ûC‰cøÝé¿\GKM·õ‹ýíæorìo·:ÆþöÙeûøêî¶n±¿=–ûÛOýcûÉ%Ç>vãØß~rú>ûù»‹%ÇþöÜþȹ³KŽýív]ìo·ûöƒýí6Î4¯²=ö·Û¼°¿Ý½îc»ÅûÛû²=ö·[Ü°¿ýá’c»ÅûÛ­?^ûÛ-/Øßž¯Ïשoä»]§Æ'õýí.žØßþPâØîâýíÙc·ú|a»Õ}{¸Ï/ö·Û:ÁþvWØßþ¸]w¦¯ìo7Þ­ãë ûÛc»¯Ï¡ìowõŒýív]ìowõýí6Î4/‹+_‡ya»__+å8`{ïÚÏœû@ú7ö·?\rìo·8c»[ïØßnyÁþv»>ëûÛ-Øßnã%ÇþöY©_ìo·y“c»Õ ö·;žR•¾°_Ôõý¢çN‚c¿¨ö‹^•8ö‹úñÏ|ðFã¯Í²üóºØ/jëûE]°_Ôî»°_Ô^ÙûEï³ë^4÷ž \‡ûEíuû*Ýëö‹ÚúÅ~Ñ[ËöØ/ú°ç‹‹]WrìÍ~[rçËJŽý¢Æ±_ôÄ’c_裩ì=1ý—ã!Ç~ÑËJŽý¢y]áº%Ç~QãØ/z«ã‹çq¦y•ûE󼇒c¿¨ÅûEóý)ëpˆö‹öe{ìµ8c¿¨õÇñc¿hÎËÉs-NäØ/jyÄ~Ñ<¡ìÍyG”ýWku²ÕFŽc¿è7ÌWÒûEÏ@±_Ôõý¢W%Žý¢n<Ø/z£q?ö‹ÚúÄ~Q7_ìµ×÷úçSãcý\èã‰ý¢vŸý¢.þØ/juŒý¢._Ø/jußlîó‹ý¢¶N°_ÔÕö‹Ç~QW?Ø/ú¨Åu•þËøc¿¨qìuõ‰ý¢Öö‹úz^e¸®Ô?ö‹æqb^eÿØ/jóÂ~Q·¾°_4ßoý̯Gì½Ï~¾õëûEsœ‘—²ìµ¼`¿¨óö‹Z±_ÔùûE¯J?ý¢yÞ¬gÔ•õ»åFŽ£©}aÿ•».ö_ýqßÁþ+DZÿêòıÿª·þ†þ±ÿêúıÿÊÝgbÿ•åû¯œ—°ÿÊêû¯ÌÓc¾V9Û^ç°ÿêβì¿2aŸ’Åcl¿Í·H×Åþ+wŸŒýW½gÑg¹~¶_ÑÖ-ö_]\rì¿ÊüŠ¥O(9öYe~õÒ'¤þx]r쿺¸äØeí±ÿjVɱÿ*sŒ³äØeãLó*9ö_Ù¼°ÿêÎ’cÿ•Åû¯ì¾‰ãÁþ+‹ö_9aÿ•Åû¯ÌslýW–쿲ë“cÿ•åû¯l¼äØuyö_9ŽýWV'Øå<ƒýW»š¯¤=ö_ýq"åKúÇþ«ËÇþ+7쿺>qì¿rãÇþ«[­ý–~¾Øe볞G|R{ì¿rñÄþ+[اäâýWv_ýW._ØeuýW.¿Øeëû¯\=`ÿ•qì¿rõƒýWƱÿÊÕÛÈ÷õ‰ýWÖû¯\=cÿ•qì¿òõ?Œ3Í+Í›yÄþ+›ö_¹õ…ýW9Ÿöëû¯òýÙ~ýbÿ•Åû¯,ûÇþ+Ë ö_y?üÿ¶Î'4ÎëŠâÓ®´Hë.´èFÎdã@ãB;tfVÁºi²¥CH…’˜²)ƒ›USˆÚ&PÉŽcLDj»N4‰Üô›Ê‘]°ˆe¥Žì¡Ph²êŸE)i÷Üï ïHÕÆöÑ÷½{ß}gîœ{-ò™¿J? +/‘Wñzæ¯ gþ*ó„¼²õ±/æì¹Ì3œmÀ™gÅ_~ßD8ó Æ?Ì3\ œyù]ìù}:oæŒÏ™gØ{æÄÓÅžyÝ/æþÜç´~ñû&t™g0½‘yÝ[æ”×Åžß7¡ºŸy†Kõ:Ì3ˆ˜g×8ó ™gXªqæ>nØó KñgYŸyáÌ3Œkœy†\kt©Æ™gÎ<ƒø`¶NÙ'~ÕöÌ3¤_Ä¡Æ™gP˜g¸YãÌ3(nü¾ «Ç:mœ™g¸mökí¹pŽ5Î<ƒÎ‘yí·ì“y†&ì˜gßgžAyÂ<ƒáÌ3üP|µËžy†³}ÖažÁÖgž¡ œyÛó WgžÁöÏ<ƒî'ó æ/ó Ûa?ýogO|„ñx2Ï ûHßßâÏ<ÃNØ3Ï`çÅ<ÃÀ™g°óežA÷„yËæ„3Ï°ÔľÊûû¯~úq¬Ãï›XŠ? Î<ƒpæ,?™gÐ:Ì3X>3Ï œyËæ´Ïð«^ŸyùÅ<ƒÝ/æ‡eâVÛ3Ï ^š®øýežAqfžávmÏ<ƒÎ…yãætŽÌ3ä~Û80ÏÐÄë;7œ˜gPž0Ï x”ø„©¾>º!? +Np¥áô §?¸8ýAçŸûîêüèš¿ôuÞôÓïr^½Ík±ýÁb¿å¹ôÅcôÅÄÓ3ü‰›º·ôÑ6k{úƒù~ùÒœâ1³úÙ¼×ÇÆ“Úžþ ò›þà›5Np§aô_©qúƒÂùù¢¯Ä÷Ëúô…óóE߬qúƒ‰óܧ?¨çÒ”uèjŸáWmOP~Ejœþ â@ðÃ÷gÜè&oµq¦?¨8Ó´ûKPçBÐî;ýA#ýÁô£]‡þàZ<þ áô•'ôo×û¡?øñÕ.{úƒ+}Ö¡?hëÐ\ œþ í‡þ î'ýAÛ?ýAÝOúƒæ/ýÁk±ýÁ=ñ œþ Å“þ î-}4‹?ýAÕôí¼èf½ñ ?_úƒºô-èæý9éùCP8ýAÏ·§?hùIPöô-Ÿéê¹ô-ÿé&ãWø]òŸ/š~íº_ô‡q«í銗èÚý¥?¨8Óôû~)Ï…þ ñýA#ýÁŒG›Wô×âyô §?¨<¡?h|G_èíò£ø…Þ~ºGo÷}øѪðþ)ÿŠ=z{ÞÏå‰ù‹Þ¾öèíò»Ø£·'=ùäVì·àèíªÇøy2gôö̳ûÕO(öü<å%z»âQpôvÝkôö‹õúèíÊoôös5ŽÞ.~@o_¬qtuáèí‹MµÏþ¥¿ž«qôö´ÿå‹5ŽÞ®ç¢·‹Ê>ÑÛµOôö?Õöèíò ½Ýîz»â€Þ¾UÛ£·+nèíÛ5ŽÞ®8£·ÛýEo×¹ ·çóKþ<•çˆÞn<ÀÏ“YuÑÛå_Ù?z{æÉã?7½ýqñÕ.{ôöÓýˆãW}}ôöUá_óý ·ë~¢·ÛþÑÛ7½ÝüEo¡·ï‰OØ£·[<ÑÛ¯Ž.mñGoWóódì¼ÐÛ•÷èív¾èíº'èí–èíê¹=Ïôváèí‹ñýOôváè힟í:èí–Ïèíz.z»å?z»ö~Õëw[¿ÐÛý~ÝŸq@oß2ûÞ÷ãßèíÛ5ŽÞ®8£·Û}Go×¹ ·ëùÅ/ôv#z»ö[pôöÕX½]~½]y‚Þn8¦úB¿Ò¹{ô«“ ßA¿2ýê|àèWæú•Þѯ’wÛüG¿’î~%½m¶þfO÷ýJ~œÿ?¨¼A¿º\Çýêj<ÇÎeòØÝSô«?ÔöèW[aÏÿT<Êúï¸8ú•ø»àèW‰¯/¼X¯ƒN•øÆ‹ñºb_pô«•G¿’=úÕj£_%Î>kýJû ¿jýJ~¡_]®qô+ÅýJö~e8ú•òýj»Þ'úÕ÷ZýÊìѯNöYýÊqò*pô+Ûú•ÞѯlÿèW”ý£î/ú•î úÕžø„=ú•Åýêªðy?ú•î)ú•ú•òýÊÎýJ÷ýÊòýJ8ú•å:•pô+Ë·>ïù‰~%{ô+Ëgô+áèWžÿí>ѯ쾠_É/ô+»_èW‡C~ѯ’ïñû‹~•¼ôk¿ïèW:ô+ç‡Qž#úUúÑòÿð|ÄýÊpô«Ìò*¾_ò¿ê«ûÑ ãÑgûõùgôiÏðé×ÿözÃ+†ß:`}ŠÉ}w/ÿÇ«K;—÷)ÿ‡_ü‹ü+Ïö6›°_-žÃ{Ÿ[|rýAù=³âæ{–ÿóû>|ú܇™/Ík|øô³É{ÇÆçj|ôÂ;Ù·ûòC§j¼»u\ùÝ=uðùŸl~.|ræàóMõ\>' +ï|å¡S5>½–ët^Ÿ«ñAûÜÁâܸƧOå>ï¶~ñyP|_üåó â0$nµýdÆσâ§b?øfÆyú÷ Wjûé{y.|Ìx´ù3éæ9Nïöä_Y§{°=÷;7 ŸÜÍ<üäñh±Üûïï_ñùÑìäUœÏ›Ž“W/ïÚŸ/ßµÿáÆ>ñØòÜßþ†ýtuo|ïþŸx>Xòøw‰¿ìÉ«&Ökã3â¼g^ÔÎwùØ;º|´|è’aßyÕógzõsá]òJë•ø·øpŸççôý\‡ùgËçAûÜá®üï´û ¿êõG?K¿ø\l÷«K^…Ý2q«íù<¸ÿç|#ãÜá\j¼C^Å¿'=ç‡y%»OœO&ä¹o;ÿt>Í<üøñh‰?Kë‹úÊöO}¥÷ê+é¯N4¼‚újRï“úêõÀ©¯2_ÚøS_é}™úê]³ßì½%ûÇå_ÙõÕÛS_Ùûõ•êoêô»œïcGôþG}õ[[ÿ_ßÑçSê«Ó5N}¥ûO}¥{SžK}•øúÂÑÚž:*ñ…£±¯b_pê+ñzÁ©¯dO}uº¶§¾Jœ}Ö8õ•ö~Õ8õ•ü¢¾ò÷ñŒõ•ÞÊs©¯7ê«wëu¨¯gê+½?ûÑ­<ê+=¿àÔW:Gê+í·àÔW'b]ê+鯲nxxNï3ÅžúêÛm}eöÔWª'¨¯'¯ú¬O}eû¡¾Q_Ùþ©¯ô¾<|Ôý¥¾z+Ö¡¾ÚŸÀ©¯,žÔW…Ï{ü©¯T¯P_ÙyQ_)﩯ì|©¯tO¨¯,¨¯„S_YþPG §¾²|›áóžŸÔW²§¾²|¦¾N}åùßî“úÊî õ•ü¢¾²ûE}•q8ä÷‘úêíˆÏô¿¿ÔWŠ3ýA»ïÔW:ê+ç‡Qž#õUúÑÞ_꫱>õ•áÔW™'ä•žßÚcª/øJÏ)ù_)¾ð•áðÕñ†WÀWÎóG½8|u¶^¾RžÃWo¾Ù{Mö‡+Ësá«3ÃWv.ð•êlîõ«õ:|T>ÁW¿©q>êý¾Z¬qøJü _Ùû|•øúÂ3µ=¼”øÆÂ3Mø]âÜâð•Õ]ð•ìá«ÅÚ¾Jœ}Ö8|¥}†_5_É/øÊïÅNƾ¯”ýÀWŠ|õF½|¥8ÃWg ¿•ç_Y _éá+í·¬_×ÃW†ÃWyžû]½>|õ`ËWf_é~ÂWŽ“W}Ö‡¯l?ðÕËÃW¶øJy_™¿ðÕka_í‰Oàð•Å¾Z>ïñ‡¯tÿá+;/øJy_ÙùÂWº'ð•å|%¾²ü—„ÃW–o3|Þó¾’=|eù _ ‡¯<ÿÛ}ÂWv_à+ù_Ùý‚¯2‡ü>ÂWg">ð•Ý_øJq†¯ì¾ÃW:øÊùa”ç_¥å‘W±>|e8|•yB^éù»øŠ—è+òsÒþ½þ£ä­°ÿ<˾š.ß  0­ PolygonVertexIndexiÌt  #­ xC°fÝÆþ¶mÛ¶mÛæmÛ¶mÛ¶mÛ¶m÷MúT=õ&µ¿iktþûï¿ÿ°Lìôß¿å€,3;…ËXv—³¬ì.aÙØq\ʲ³c¸Œå`Gq98ËÉŽàr–‹Æå,7;„Ë¡Xv—C³¼ì .‡aùØ~\Ëò³}¸Ž`{q9<+ÈöàrVˆíÆ刬0Û…Ë‘X¶—#³¢l.GaÅØv\ŽÊŠ³m¸•`[q9:+ɶàr VŠmÆ嘬4ۄ˱X¶—c³²l.ÇaåØz\ŽËʳu¸U`kq9>«ÈÖàrV‰­Æ儬2[…ˉX¶—³ªl.'aÕØr\Nʪ³e¸œŒÕ`Kq99«É–àr +V‹-Æ唬6[„Ë©X¶—S³ºl.§aõØ|\NËê³y¸œŽ5`sq9=kÈæàrÖˆÍÆeÿ2²Y¸×6š°™¸lMÙ \¶ÿ±é¸lÍØ4\¶æl*.ÛF 6—m£%›ŒË¶ÑŠMÂeÛhÍ&â²m´apÙ6Ú²ñ¸œ—µcãpÙ6Ú³±¸œŸu`cp¹ ëÈFãrAÖ‰ÂåB¬3‰Ë¶Ñ…ÀeÛèʆã²mtcÃpÙ6º³¡¸l=Ø\¶žl0.ÛF/6—m£7ˆË¶Ñ‡ ÀeÛèËúã²môs¸lýY_\¶¬.ÛÆ@Ö—mcë…˶1˜õÄeÛÂzà²m eÝqÙ6†±n¸lÃYW\¶¬ .ÛÆHÖ—mcë„˶1šuÄeÛÃ:àr6–µÇeÛÇÚá²mŒgmq¹>›ÀÚà²mLd­q¹!›ÄZár#6™µÄ匬1k{mc*kŽË¶15ÃåmxqÙ6f°¦¸l3Y\¶Y¬1.ÛÆlÖ—mckˆË¶1—5ÀeÛ˜Çêã²mÌgõpÙ6°º¸l Y\îÀ±Ú¸l‹Y-\¶%¬&.ÛÆRV—mc«ŽË¶±œUÃeÛXÁªâ²m¬dUpÙ6V±Ê¸l«Y%\îÅÖ°Š¸lkY\¶u¬<.ÛÆzV—û± ¬,.ÛÆFV—mc+ËÙfV +—±-¬$.f[Y \¶m¬8.ÛÆvV —mc+ŠË¶±“ÁeÛØÅ +ã²mìf…pÙ6ö°‚¸l{Y\¶},?.ÛÆ~–—mã ˋ˶qåÁå ìË˶q˜åÂeÛ8Ârâ²me9p¹1›Â²ã^Û8βá²mœ`Yqy:;ɲà²mœb™qy&;Í2á²mœaqÙ6β ¸lçXz\¶ó,.ÏcXZ\¶‹, .ÛÆ%–—mã2K…Ë‹Ø–—³«,./a×Xr\¶ë,.ÛÆ –—mã&K‚˶q‹%ÆeÛ¸Íá²mÜa qÙ6l÷X|\¶û,.ÛÆ—mã!‹ƒË¶ñˆÅÆeÛxÌbá²m²0¸lŸXh\¶Ï,.b_XH\>̾²¸|„}cÁqù(û΂áòvŒŽ¶ñ“ÁeÛøÅã²müfpÙ6þ°€¸lY \¶\¶ øÍŸ¿eÛˆÿÁeÛ„ÿÆeÛŒÿÂeÛ‚ÿÄeÛŠÿÀeÛ†Çå+,8þ —m#þ—m#$þ—¯³Pøg\¶Ðø'\¶0øG\¶°ø\¶pø{\¶ðø;\¶ø[\¾Ç"âopù>‹„¿ÆeÛˆŒ¿ÂeÛˆ‚¿ÄeÛˆŠ¿ÀeÛˆ†?ÇeÛˆŽ?ÃåmàOqÙ6bâOpÙ6báqÙ6bãpÙ6âàqÙ6ââpÙ6âá÷qÙ6âã÷pÙ6àwqÙ6âwpÙ6á·qÙ6ã·pÙ6’à7qÙ6’â7pÙ6’á×qÙ6’ã×pÙ6RàWqÙ6RâWpÙ6Rá—qÙ&~°K¸×6Òðý".ÛFZü.ÛF:ü<.ÛFzü.ÛFü,.ÛFFv—m#;˶‘™ÂeÛÈÂNâ²mde'pÙ6²±ã¸lÙÙ1\¶ì(.ÛFNv—m#;ŒË¶‘›ÂeÛÈÃâ²mäepÙ6ò±ý¸lùÙ>\¶l/.ÛFA¶—m£Û˶Q˜íÂeÛ(Âvâ²me;pÙ6Š±í¸lÅÙ6\¶l+.ÛFI¶—c°Rl3.ÛFi¶ —m£ ۈ˶Q–mÀeÛ(ÇÖã²m”gëpÙ6*°µ¸ŸUdkpÙ6*±Õ¸l•Ù*\¶*l%.ÛFU¶—m£[ŽË¶Q-ÃeÛ¨Á–â²mÔdKpÙ6j±Å¸lµÙ"\¶:l!.ÛDjîÜkõØ|\¶úl.ÛF6—m£!›ƒË¶ÑˆÍÆeÛhÌfá²m4a3qÙ6š²¸lÿcÓqÙ6š±i¸lÍÙT\¶l +.ÛFK6—m£›„˶њMÄeÛhÃ&à²m´eãqÙ6Ú±q¸líÙX\ÎÏ:°1¸lÙh\¶Nl.ÛFg6—m£ ˶ѕ ÇeÛèƆá²mtgCqÙ6z°!¸l=Ù`\¶^l.ÛFo6—m£€Ë¶Ñ—õÇeÛèçpÙ6ú³¾¸lX\¶¬7.ÛÆ Ö —mc0ë‰Ë¶1„õÀeÛʺã²m cÝpÙ6†³®¸l#X\¶‘¬3.ÛÆ(Ö —mc4ëˆË¶1†uÀeÛËÚãrjV—µÃ½¶1žµÅeÛ˜ÀÚà²mLd­qÙ6&±V¸l“YK\¶)¬.ÛÆTÖ—mck†ËÿÚðâ²mÌ`MqÙ6f²&¸l³Xc\¶Ù¬.·bsXC\¶¹¬.ÛÆ«‡Ë¶±€ÕÅeÛXÈêà²m,bµqÙ6³Z¸lKXM\¶¥¬.ÛÆ2V—mc9«†Ë¶±‚UÅeÛXɪà²m¬b•qÙ6V³J¸lkXE\¶µ¬.ÛÆ:V—mc=+‡Ë¶±•ÅeÛØÈÊà²mlb¥qÙ66³R¸lI\¶­¬.ÛÆ6V—mc;+†Ë¶±ƒÅeÛØÉŠà²mìb…qÙ6v³B¸<ŠíaqÙ6ö²¸lûX~\¶ý,.×eãX^ÜkY\¶C,7.ÛÆa– —mãˉ˶q”åÀeÛ8Ʋã²mgÙpÙ6N°¬¸.ÛÆ}—m㋋˶ñÅÁeÛxÄbã²m°°¸lY\ǰи×6>³P¸l_XH\¶¯,.ÛÆ7—mã; †Ë¶ñƒÅeÛøÉ‚à²mübqÙ6~³@¸lX@\¶¿, .ÛÆ.ÛF üïoÞÿð9ÿƒË¶ÿ˶ÿ…˶ÿ‰Ë¶ÿ˶ ÿŽË¶ÿ†Ë¶ÿŠË¶ÿ‚˶ +ÿŒË¶ÿ„˶ÿˆË¶ÿ€Ë¶˶‡Ë¶‹Ë¶ƒË¶ ˶…˶‰Ë¶˶ ŽË¶†ËÿÚÀŸâ²mÄÄŸà²mÄÂã²mÄÆá²mÄÁâ²mÄÅà²mÄÃïã²mÄÇïá²m$Àïâ²m$Äïà²m$Âoã²m$Æoá²m$Áoâ²M|b7p¯m$ãûu\¶äø5\¶øU\¶”ø\¶Tøe\¶Ôø%\¶4øE\¶´ø\¶tøy\¶ôø9\¶ øY\¶Œì .ÛF&v—m#3;…˶‘…ÄeÛÈÊNà²mdcÇqÙ6²³c¸l9ØQ\¶œì.ÛF.v—m#7;„˶‘‡ÄeÛÈËà²mäcûqÙ6ò³}¸lØ^\¶‚l.ÛF!¶—m£0ۅ˶Q„íÄeÛ(Êvà²mcÛqÙ6Š³m¸l%ØV\¶’l .Ç`¥Øf\¶Òl.ÛF¶—m£,ۀ˶QŽ­ÇeÛ(ÏÖá²mT`kq9>«ÈÖà²mTb«qÙ6*³U¸lUØJ\¶ªl.ÛF5¶—m")wîµl).ÛFM¶—m£[ŒË¶Q›-ÂeÛ¨Ãâ²mÔe pÙ6ê±ù¸lõÙ<\¶l..ÛFC6—m£›Ë¶Ñ˜ÍÂeÛhÂfâ²m4e3pÙ6þǦã²m4cÓpÙ6š³©¸l-Ø\¶–l2.ÛF+6 —m£5›ˆË¶Ñ†MÀeÛhËÆã²m´cãpÙ6Ú³±¸œŸu`cpÙ6:²Ñ¸lØ(\¶Îl$.ÛF6—m£+ŽË¶Ñ ÃeÛèΆâ²mô`CpÙ6z²Á¸l½Ø \¶Þl .ÛF6 —m£/ë˶ÑÏá²môg}qÙ6°>¸lYo\¶A¬.ÛÆ`Ö—mcë˶1”uÇeÛƺá²m g]q9)«Îºà^ÛÉ:ã²mŒbpÙ6F³Ž¸lcX\¶±¬=.ÛÆ8Ö—mc–—mc?ˇ˶q€åÅeÛ8Èòà²mb¹qÙ6³\¸lGXN\¶£,.ÛÆ1–—mã8ˆËÓØ –—§³“, .ÛÆ)–—mã4˄˶q†eÄeÛ8Ë2à²mœcéqÙ6γt¸<]`iqÙ6.²4¸l—Xj\¶Ë,.ÛÆ–—mã*K˶q%Çe۸Βá²mÜ`IqÙ6n²$¸l·Xb\¶Û,.ÛÆ–—mã.K€Ë¶qÅÇeÛ¸Ïâá²m<`qqÙ6²8¸lXl\¶Ç,.ÛÆ—mã)‹Ë¶ñŒEÇeÛx΢áò6ö‚EÅeÛxÉ¢à²m¼b‘qÙ6^³H¸<‚íbq¯m¼epÙ6Þ±ð¸lïY8\ÞÇ>°°¸lY\¶O,4.ÛÆg +—m㠉˶ñ•…ÀeÛøÆ‚ã²m|gÁpÙ6~° ¸l?Y\>Á~±À¸l¿Y \¶?, .ÛÆ_ —mã¿@ —m# þ÷ïØ6âpÙ6á¿qÙ6ã¿pÙ6‚à?qÙ6‚â?pÙ6‚áßqÙ6‚ãßpÙ6Bà_qÙ6Bâ_pÙ6BáŸqÙ6BãŸpÙ6ÂàqÙ6ÂâpÙ6ÂáïqÙ6ÂãïpÙ6"àoqÙ6"âopÙ6"á¯qÙ6"ã¯pÙ6¢à/qÙ6¢â/pÙ6¢áÏqÙ6¢ãÏpù_øS\¶˜ø\¶Xøc\¶Øø#\¶8øC\¶¸ø\¶xø}\¶‰7ìîµ|¿‹Ë¶‘¿ƒË¶‘¿Ë¶‘¿…˶‘¿‰Ë¶‘¿Ë¶‘ ¿ŽË¶‘¿†Ë¶‘¿ŠË¶‘¿‚˶‘ +¿ŒË¶‘¿„˶‘¿ˆË¶‘¿€Ë¶‘?˶‘?‡Ë¶‘?‹Ë¶‘‘ÁeÛÈÄNã²mdf§pÙ6²°“¸lYÙ \¶lì8.ÛFvv —m#;ŠË¶‘“ÁeÛÈÅã²mäf‡pÙ6ò°ƒ¸lyÙ\¶|l?.ÛF~¶—m£ ۋ˶QíÁeÛ(Ävã²mf»pÙ6Š°¸lEÙ\¶bl;.ÛFq¶ —m£ۊ˶Q’mÁå¬ی˶QšmÂeÛ(Ã6â²m”epÙ6ʱõ¸låÙ:\¶ +l-.ÛD|îÜk•Øj\¶Êl.ÛF¶—m£*[˶Q-ÇeۨΖá²mÔ`KqÙ6j²%¸lµØb\¶Úl.ÛF¶—m£.[€Ë¶QÍÇeÛ¨Ïæá²m4`sqÙ6²9¸lØl\¶Æl.ÛF6—m£)›Ë¶ñ?6—m£›†Ë¶ÑœMÅeÛhÁ¦à²m´d“qÙ6Z±I¸l­ÙD\¶6l.ÛF[6—m£‡Ë¶ÑžÅåü¬ƒË¶Ñ‘ÆeÛèÄFá²mtf#qÙ6º°¸l]Ùp\¶nl.ÛFw6—m£‚˶ѓ ÆeÛèÅá²môfqÙ6ú°¸l}Y\¶~—m£?ë‹Ë¶1€õÁeÛÈzãr|V‘õ½¶1˜õÄeÛÂzà²m eÝqÙ6†±n¸lÃYW\¶¬ .ÛÆHÖ—mcë„˶1šuÄeÛÃ:à²mŒeíqÙ6Ʊv¸lãY[\®Ï&°6¸lYk\¶I¬.ÛÆdÖ—mc +k˶1•5Çeۘƚáò¿6¼¸l3XS\¶™¬ .ÛÆ,Ö—mc6k„˶1‡5ÄeÛ˜Ëà²mÌcõqÙ6æ³z¸l X]\¶…¬.ÛÆ"V—mc1«…˶±„ÕÄeÛXÊjà²m,cÕqÙ6–³j¸l+XU\¶•¬ +.ÛÆ*V—mc5«„˶±†UÄeÛXË*à²m¬cåqÙ6Ö³r¸Üm`eqÙ66²2¸l›Xi\¶Í¬.WdƒXIÜk \¶m¬8.ÛÆvV —mc+ŠË¶±“ÁeÛØÅ +ã²mìf…pÙ6ö°‚¸l{Y\¶},?.ÛÆ~–—mã ˋ˶qåÁå ìË˶q˜åÂeÛ8Ârâ²me9pÙ6Ž±ì¸lÇY6\¶,+.Og'Y\¶S,3.ÛÆi– —mã ˈ˶q–eÀeÛ8ÇÒã²mœgépy»ÀÒâ²m\dipÙ6.±Ô¸l—Y*\¶+,%.ÛÆU–—mãKŽË¶q%ÃeÛ¸Á’â²mÜdIpÙ6n±Ä¸l·Y"\¶;,!.ÛÆ]– —mã‹Ë¶qŸÅÃeÛxÀââ²m¶—m#?ۇ˶Q€íÅeÛ(Èöà²mb»qÙ6 +³]¸lEØN\¶¢l.ÛF1¶—m£8ۆ˶Q‚mÅeÛ(ɶàr VŠmÆe›ˆÉÝ„{m£ ۈ˶Q–mÀeÛ(ÇÖã²m”gëpÙ6*°µ¸lÙ\¶Jl5.ÛFe¶ +—m£ +[‰Ë¶Q•­ÀeۨƖã²mTgËpÙ6j°¥¸l5Ù\¶Zl1.ÛFm¶—m£[ˆË¶Q—-ÀeÛ¨Çæã²mÔgópÙ6°¹¸l Ù\¶Fl6.ÛFc6 —m£ ›‰Ë¶Ñ”ÍÀeÛø›ŽË¶ÑŒMÃeÛhΦâ²m´`SpÙ6Z²É¸l­Ø$\¶Öl".ÛF6—m£-˶юÃeÛhÏÆâ²mt`cpÙ6:²Ñ¸lØ(\¶Îl$.ÛF6—m£+ŽË¶Ñ ÃeÛèΆâ²mô`CpÙ6z²Á¸l½Ø \¶Þl .Çd¥Ù Ük}Y\¶~—m£?ë‹Ë¶1€õÁeÛÈzã²m b½pÙ6³ž¸lCX\¶¡¬;.ÛÆ0Ö —mc8ëŠË¶1‚uÁeÛÉ:ãrM6ŠuÂeÛÍ:â²mŒapÙ6Ʋö¸lãX;\¶ñ¬-.×gX\¶‰¬5.ÛÆ$Ö +—mc2k‰Ë¶1…µÀeۘʚã²mLcÍpù_^\¶¬).ÛÆLÖ—mckŒË¶1›5ÂeÛ˜Ãâ²mÌe pÙ6æ±ú¸lóY=\¶¬..ÛÆBV—mc«Ë¶±˜ÕÂeÛXÂjâ²m,e5pÙ6–±ê¸lËY5\¶¬*.ÛÆJV—{°U¬2.ÛÆjV —mc «ˆË¶±–UÀåÒ¬+{mc=+‡ËýØV—mc#+ƒË¶±‰•ÆeÛØÌJá²mla%qÙ6¶²¸lÛXq\¶í¬.ÛÆV—mc'+‚˶±‹ÆeÛØÍ +áò(¶‡ÄeÛØË +à²mìcùqÙ6ö³|¸lX^\¶ƒ,.ÛÆ!–—mã0˅˶q„åÄeÛ8Êrà²mcÙqÙ6Ž³l¸l'XV\žÎN²,¸l§Xf\¶Ó,.ÛÆ–—mã,ˀ˶qŽ¥ÇeÛ8ÏÒáò±Ð¸lŸY(\¶/,$.ÛÆW—m㠎˶ñÃeÛøÁ‚â²müdApÙ6~±À¸l¿Y \¶?, .ÛÆ_ —mã¿ —m# þ÷ïØ6âpÙ6á¿qÙ6ã¿pÙ6‚à?qÙ6‚â?pÙ6‚áßqÙ6‚ãßpÙ6Bà_qÙ6Bâ_pÙ6BáŸqÙ6BãŸpÙ6ÂàqÙ6ÂâpÙ6Âáïqù ¿ÃeÛˆ€¿ÅeÛˆˆ¿ÁeÛˆ„¿Æe›xÀ^á^ÛˆÂ÷—¸lQñ¸lÑðç¸lÑñg¸ü¯ ü).ÛFLü .ÛF,ü1.ÛFlü.ÛFü!.ÛF\ü.ÛF<ü>.ÛF|ü.ÛFü..ÛFBü.ÛF"ü6.ÛFbü.ÛFü&.ÛFRü.ÛF2ü:.ÛFrü.ÛF +ü*.ÛFJü +.ÛF*ü2.ÛFjü.ÛFü".ÛFZü.ÛF:ü<.ÛFzü.ÛFü,.ÛFFv—m#;˶‘™ÂeÛÈÂNâ²mde'pÙ6²±ã¸lÙÙ1\¶ì(.ÛFNv—m#;ŒË¶‘›ÂeÛÈÃâ²mäepÙ6ò±ý¸lùÙ>\¶l/.ÛFA¶—m£Û˶Q˜íÂeÛ(Âvâ²MDæîÀ½¶QŒmÇeÛ(ζá²m”`[qÙ6J²-¸ƒ•b›qÙ6J³M¸leØF\¶²l.ÛF9¶—m£<[‡Ë¶Q­ÅeÛ¨ÈÖà²mTb«qÙ6*³U¸lUØJ\¶ªl.ÛF5¶—m£:[†Ë¶Qƒ-Åeۨɖà²mÔb‹qÙ6j³E¸luØB\¶ºl.ÛF=6—m£>›‡Ë¶Ñ€ÍÅeÛhÈæà²m4b³qÙ6³Y¸lMØL\¶¦l.ÛÆÿØt\¶fl.ÛFs6—m£›‚˶ђMÆeÛhÅ&á²m´fqÙ6Ú° ¸lmÙx\¶vl.ÛF{6—ó³l .ÛFG6—m£…˶љÄeÛèÂFà²mteÃq92+ʆá^ÛèΆâ²mô`CpÙ6z²Á¸l½Ø \¶Þl .ÛF6 —m£/ë˶ÑÏá²môg}qÙ6°>¸lYo\¶A¬.ÛÆ`Ö—+³!¬.ÛÆPÖ—mcë†Ë¶1œuÅeÛÁºà²mŒdqÙ6F±N¸l£YG\¶1¬.ÛÆXÖ—mck‡Ë¶1žµÅåúlkƒË¶1‘µÆeÛ˜ÄZá²mLf-qÙ6¦°¸lSYs\¶i¬.ÿkË˶1ƒ5Åeۘɚà²mÌbqÙ6f³F¸lsXC\¶¹¬.ÛÆ«‡Ë¶±€ÕÅeÛXÈêà²m,bµqÙ6³Z¸Ü‰-a5qÙ6–²¸lËXu\¶å¬.eÝXUÜk+Y\¶U¬2.ÛÆjV —mc «ˆË¶±–UÀeÛXÇÊã²m¬gåp¹ÛÀÊâ²mldepÙ66±Ò¸l›Y)\¶-¬$.ÛÆVV—‡°m¬8.ÛÆvV —mc+ŠË¶±“ÁeÛØÅ +ã²mìf…pÙ6ö°‚¸l{Y\¶},?.ÛÆ~–—mã ˋ˶qåÁeÛ8Ärã²mf¹pÙ6Ž°œ¸lGY\¶c,;.ÛÆq– —mãËŠËÓÙI–—mãˌ˶qšeÂeÛ8Ã2â²mœepÙ6αô¸lçY:\žÇ.°´¸lY\¶K,5.ÛÆe– +—mã +K‰Ë¶q•¥Àå%ìKŽË¶q%ÃeÛ¸Á’â²mÜdIp¹[Áã^Û¸Íá²mÜa qÙ6l÷X|\¶û,.ÛÆ—mã!‹ƒË¶ñˆÅÆeÛxÌbá²m²0¸lŸXh\¶Ï,.ÛÆ—mã+ ˶ñÇeÛø΂á²mü`AqÙ6~² ¸l¿X`\¶ß,.ÛÆ—mã/ €Ë¶ñ_P†Ë¶ ÿû÷?lñ?¸lð߸lñ_¸lAðŸ¸lAñ¸lÁðï¸lÁño¸l!ð¯¸|…Ä¿à²m„Â?ã²m„Æ?á²m„Á?â²MÜbp¯m„ãû{\¶ðø;\¶ø[\¶ˆø\¶Høk\¶Èø+\¶(øK\¶¨ø \¶høs\¶èø3\þ×þ—m#&þ—m#þ—m#6þ—m#þ—m#.þ —m#~—m#>~—m#~—m#!~—m#~—m#1~ —m# ~—m#)~—m#~—m#9~ —m#~—m#%~—m#~—m#5~ —m# ~—m#-~—m#~—m#=~—m#~—m##;ƒË¶‘‰ÆeÛÈÌNá²mda'qÙ6²²¸lÙØq\¶ìì.ÛFv—m#';‚˶‘‹ÆeÛÈÍá²mäaqÙ6ò²¸lùØ~\¶‰°Ü}¸×6 +°½¸lÙ\¶Bl7.ÛFa¶ —m£ۉ˶Q”íÀeÛ(ƶã²mgÛpÙ6J°­¸l%Ù\ŽÁJ±Í¸l¥Ù&\¶2l#.ÛFY¶—m£[˶Qž­ÃeÛ¨ÀÖâ²mTdkpÙ6*±Õ¸l•Ù*\¶*l%.ÛFU¶—m£[ŽË¶Q-ÃeÛ¨Á–â²mÔdKpÙ6j±Å¸lµÙ"\¶:l!.ÛF]¶ —m£›Ë¶QŸÍÃeÛhÀæâ²m4dspÙ6±Ù¸lÙ,\¶&l&.ÛFS6—mãl:.ÛF36 —m£9›ŠË¶Ñ‚MÁeÛhÉ&ã²m´b“pÙ6Z³‰¸lmØ\¶¶l<.ÛF;6—m£=‹ËaY~6÷ÚFG6—m£…˶љÄeÛèÂFà²mteÃqÙ6º±a¸lÝÙP\¶l.ÛFO6—m£„˶ћ ÄeÛèÃà²môeýq¹,ëçpÙ6ú³¾¸lX\¶¬7.ÛÆ Ö —mc0ë‰Ë¶1„õÀeÛʺã²m cÝpÙ6†³®¸l#X\¶‘¬3.ÛÆ(Ö —mc4ëˆË¶1†uÀeÛËÚã²mŒcípÙ6Ƴ¶¸lX\¶‰¬5.ÛÆ$Ö +—mc2k‰Ë¶1…µÀeۘʚã²mLcÍpù_^\¶¬).ÛÆLÖ—mckŒË¶1›5ÂeÛ˜Ãâ²mÌe p¹ ›Çêã²mÌgõpÙ6°º¸l Y\ÎÏ:°Ú¸×6³Z¸lKXM\¶¥¬.ÛÆ2V—mc9«†Ë¶±‚UÅeÛXɪà²m¬b•qÙ6V³J¸lkXE\¶µ¬.ÛÆ:V—mc=+‡ËýØV—mc#+ƒË¶±‰•ÆeÛØÌJá²mla%qÙ6¶²¸lÛXq\¶í¬.ÛÆV—mc'+‚˶±‹ÆeÛØÍ +á²mìaqÙ6ö²¸lûX~\¶ý,.ÛÆ–—mã ˃˶qˆåÆeÛ8Ìrá²ma9qÙ6Ž²¸lÇXv\¶ã,.ÛÆ –—§³“, .ÛÆ)–—mã4˄˶q†eÄeÛ8Ë2à²mœcéqÙ6γt¸<]`iqÙ6.²4¸l—Xj\¶Ë,.w`‹XJÜkWY +\¶k,9.ÛÆu– —mãKŠË¶q“%ÁeÛ¸Åã²mÜf‰pÙ6î°„¸lwY\¶{,>.ÛÆ}—m㋋˶ñÅÁå ì‹Ë¶ñ˜ÅÂeÛxÂbâ²m°°¸lY\¶O,4.ÛÆg +—m㠉˶ñ•…ÀeÛøÆ‚ã²m|gÁpÙ6~° ¸l?Y\¶_,0.ÛÆo—m㠈˶ñ—ÀeÛø/ÃeÛ€ÿýÆû¶€ø\¶@øo\¾Àã¿pÙ6‚à?qÙ6‚â?pÙ6‚áßqÙ&®°o¸×6Bðý+.ÛFHü .ÛF(ü3.ÛFhü.ÛFü#.ÛFXü.ÛF8ü=.ÛFxü.ÛFü-.ÛFDü .ÛF$ü5.ÛFdü.ÛFü%.ÛFTü.ÛF4ü9.ÛFtü.ÿkŠË¶‚˶ ŒË¶„˶ˆË¶€Ë¶¿Ë¶¿‡Ë¶‘ ¿‹Ë¶‘¿ƒË¶‘¿Ë¶‘¿…˶‘¿‰Ë¶‘¿Ë¶‘ ¿ŽË¶‘¿†Ë¶‘¿ŠË¶‘¿‚˶‘ +¿ŒË¶‘¿„˶‘¿ˆË¶‘¿€Ë¶‘?˶‘?‡Ë¶‘?‹Ë¶‘‘ÁeÛÈÄNã²mdf§pÙ6²°“¸lYÙ \¶lì8.ÛFvv —m#;ŠË6œ{÷ÚF.v—m#7;„˶‘‡ÄeÛÈËà²mäcûqÙ6ò³}¸lØ^\¶‚l.ÛF!¶—m£0ۅ˶Q„íÄeÛ(Êvà²mcÛqÙ6Š³m¸l%ØV\¶’l .Ç`¥Øf\¶Òl.ÛF¶—m£,ۀ˶QŽ­ÇeÛ(ÏÖá²mT`kq9>«ÈÖà²mTb«qÙ6*³U¸lUØJ\¶ªl.ÛF5¶—m£:[†Ë¶Qƒ-Åeۨɖà²mÔb‹qÙ6j³E¸luØB\¶ºl.ÛF=6—m£>›‡Ë¶Ñ€ÍÅeÛhÈæà²m4b³qÙ6³Y¸lMØL\¶¦l.ÛÆÿØt\¶fl.ÛFs6—m£›‚˶ђMÆåà,'›„{m£5›ˆË¶Ñ†MÀeÛhËÆã²m´cãpÙ6Ú³±¸lØ\¶Žl4.ÛF'6 +—m£3‰Ë¶Ñ…ÀeÛèʆã²mtcÃpÙ6º³¡¸\œõ`CpÙ6z²Á¸l½Ø \¶Þl .ÛF6 —m£/ë˶ÑÏá²môg}qÙ6°>¸lYo\¶A¬.ÛÆ`Ö—mcë˶1”uÇeÛƺá²m g]qÙ6F°.¸l#Yg\¶Q¬.ÛÆhÖ—mc ë€Ë¶1–µÇeÛÇÚá²mŒgmqÙ6&°6¸lYk\¶I¬.ÛÆdÖ—mc +k˶1•5Çeۘƚáò¿6¼¸ÜŒÍ`MqÙ6f²&¸l³Xc\¶Ù¬.çd­XCÜksY\¶y¬>.ÛÆ|V—mc«‹Ë¶±ÕÁeÛXÄjã²m,fµpÙ6–°š¸lKY \¶e¬:.ÛÆrV —mc«ŠË¶±’UÁål«ŒË¶±šUÂeÛXÃ*â²m¬epÙ6Ö±ò¸lëY9\¶ ¬,.ÛÆFV—mc+˶±™•ÂeÛØÂJâ²mle%pÙ6¶±â¸lÛY1\¶¬(.ÛÆNV—mc+ŒË¶±›ÂeÛØà +â²mìepÙ6ö±ü¸lûY>\¶,/.ÛÆA–—mãË˶q˜åÂeÛ8Ârâ²me9pÙ6Ž±ì¸lÇY6\¶,+.Og'Y\žÁN±Ì¸l§Y&\¶3,#.ÛÆY–—[±9,=îµó,.ÛÆ–—mã"KƒË¶q‰¥ÆeÛ¸ÌRá²m\a)qÙ6®²¸l×Xr\¶ë,.ÛÆ –—mã&K‚˶q‹%ÆeÛ¸Íáò*v‡%ÄeÛ¸Ëà²mÜcñqÙ6î³x¸lX\\¶‡,.ÛÆ#—mã1‹…˶ñ„ÅÄeÛxÊbà²m²0¸lŸXh\¶Ï,.ÛÆ—mã+ ˶ñÇeÛø΂á²mü`AqÙ6~² ¸l¿X`\¶ß,.ŸbX@\¶¿, .ÛÆ¿2ŽË¶ 8¿ùÊûžÃα?¸×6ñý7.ÛF`ü.ÛFü'.ÛFPü.ÛF0ü;.ÛFpü.ÛFü+.ÛFHü .ÛF(ü3.ÛFhü.ÛFü#.ÛFXü.ÛF8ü=.ßaáñw¸lð·¸lñ7¸l‘ð׸l‘ñW¸lQð—¸lQñ¸lÑðç¸lÑñg¸ü¯ ü).ÛFLü .ÛF,ü1.ÛFlü.ÛFü!.ÛF\ü.ÛF<ü>.ÛF|ü.ÛFü..ÛFBü.ÛF"ü6.ÛFbü.ÛFü&.ÛFRü.ÛF2ü:.ÛFrü.ÛF +ü*.ÛFJü +.ÛF*ü2.ÛFjü.ÛFü".ÛFZü.ÛF:ü<.ÛFzü.ÛFü,.ÛFFv—m#;Ë6{ +÷ÚFv—m#+;˶‘ÇeÛÈÎŽá²mä`GqÙ6r²#¸l¹Øa\¶Üì.ÛFv—m#/;€Ë¶‘íÇeÛÈÏöá²m`{qÙ6 +²=¸l…Øn\¶Âl.ÛF¶—m£(Û˶QŒmÇeÛ(ζá²m”`[qÙ6J²-¸ƒ•b›qÙ6J³M¸leØF\¶²l.ÛF9¶—m£<[‡Ë¶Q­ÅeÛ¨ÈÖà²mTb«qÙ6*³U¸lUØJ\¶ªl.ÛF5¶—m£:[†Ë¶Qƒ-Åeۨɖà²mÔb‹qÙ6j³E¸luØB\¶ºl.ÛF=6—m£>›‡Ë¶Ñ€ÍÅeÛhÈæà²m4b³qÙ6³Y¸lMØL\È2³¸×6þǦã²m4cÓpÙ6š³©¸l-Ø\¶–l2.ÛF+6 —m£5›ˆË¶Ñ†MÀeÛhËÆã²m´cãpÙ6Ú³±¸lØ\¶Žl4.dØ(\¶Îl$.ÛF6—m£+ŽË¶Ñ ÃeÛèΆâ²mô`CpÙ6z²Á¸l½Ø \¶Þl .ÛF6 —m£/ë˶ÑÏá²môg}qÙ6°>¸lYo\¶A¬.ÛÆ`Ö—mcë˶1”uÇeÛƺá²m g]qÙ6F°.¸l#Yg\¶Q¬.ÛÆhÖ—mc ë€Ë¶1–µÇeÛÇÚá²mŒgmqÙ6&°6¸lYk\nÈ&±V¸l“YK\¶)¬.ÛÆTÖ—3³¦¬îý׆—mckŠË¶1“5ÁeÛ˜Åã²mÌfpÙ6æ°†¸lsY\¶y¬>.ÛÆ|V—mc«‹Ë¶±ÕÁeÛXÄjã²m,fµp¹[Âjâ²m,e5pÙ6–±ê¸lËY5\¶¬*.ÛÆJV—mc«ŒË¶±šUÂeÛXÃ*â²m¬epÙ6Ö±ò¸lëY9\¶ ¬,.ÛÆFV—mc+˶±™•ÂeÛØÂJâ²mle%pÙ6¶±â¸lÛY1\¶¬(.ÛÆNV—mc+ŒË¶±›ÂeÛØà +â²mìepÙ6ö±ü¸lûY>\¶,/.ÛÆA–—mãË˶q˜åÂåIìˉ˶q”åÀeÛ8Ʋã²mgÙp¹)›Æ²âÞéì$˂˶qŠeÆeÛ8Í2á²mœaqÙ6β ¸lçXz\¶ó,.ÛÆ–—mã"KƒË¶q‰¥ÆeÛ¸ÌRá²m\a)qÙ6®²¸¼„]cÉqÙ6®³d¸l7XR\¶›, .ÛÆ-–—mã6K„˶q‡%ÄeÛ¸Ëà²mÜcñqÙ6î³x¸lX\\¶‡,.ÛÆ#—mã1‹…˶ñ„ÅÄeÛxÊbà²m–—mc?ˇ˶q€åÅeÛ8Èòàr}6åƽ¶q˜åÂeÛ8Ârâ²me9pÙ6Ž±ì¸lÇY6\¶,+.Og'Y\¶S,3.ÛÆi– —mã ˈ˶q–eÀeÛ8ÇÒã²mœgépy»ÀÒâ²m\dipÙ6.±Ô¸l—Y*\¶+,%.ÛÆU–—mãKŽË¶q%ÃeÛ¸Á’â²mÜdIpÙ6n±Ä¸l·Y"\¶;,!.ÛÆ]– —mã‹Ë¶qŸÅÃeÛxÀââ²m.ÛF|ü.ÛFü..ÛFBü.ÛF"ü6.ÛFbü.ÛFü&.ÛFRü.ÛF2ü:.ÛÄv ÷ÚF +¾_ÅeÛH‰_ÁeÛH…_ÆeÛH_ÂeÛHƒ_ÄeÛH‹_ÀeÛH‡ŸÇeÛHŸÃeÛÈ€ŸÅeÛÈÈÎà²mdb§qÙ62³S¸lYØI\¶¬ì.ÛF6v—m#;;†Ë¶‘ƒÅeÛÈÉŽà²mäb‡qÙ6r³C¸lyØA\¶¼ì .ÛF>¶—m#?ۇ˶Q€íÅeÛ(Èöà²mb»qÙ6 +³]¸lEØN\¶¢l.ÛF1¶—m£8ۆ˶Q‚mÅeÛ(ɶàr VŠmÆeÛ(Í6á²m”aqÙ6ʲ ¸låØz\¶òl.ÛF¶—m£"[ƒË¶Q‰­ÆeÛ¨ÌVá²mTa+qÙ6ª²¸lÕØr\¶êl.ÛF ¶—m"9w îµZl1.ÛFm¶—m£[ˆË¶Q—-ÀeÛ¨Çæã²mÔgópÙ6°¹¸l Ù\¶Fl6.ÛFc6 —m£ ›‰Ë¶Ñ”ÍÀeÛø›ŽË¶ÑŒMÃeÛhΦâ²m´`SpÙ6Z²É¸l­Ø$\¶Öl".ÛF6—m£-˶юÃeÛhÏÆâ²mt`cpÙ6:²Ñ¸lØ(\¶Îl$.ÛF6—m£+ŽË¶Ñ ÃeÛèΆâ²mô`CpÙ6z²Á¸l½Ø \¶Þl .ÛF6 —m£/ë˶ÑÏá²môg}qÙ6°>¸lYo\¶A¬.ÛÆ`Ö—mcë˶1”uÇeÛƺá²m g]qÙ6F°.¸l#Yg\NÎj²N¸×6F³Ž¸lcX\¶±¬=.ÛÆ8Ö—mc.ÛÆ|V—mc«‹Ë¶±ÕÁeÛXÄjã²m,fµpÙ6–°š¸lKY \¶e¬:.ÛÆrV —mc«ŠË¶±’UÁeÛXÅ*ã²m¬f•pÙ6Ö°Š¸lkY\¶u¬<.ÛÆzV—mc+‹Ë¶±‘•ÁeÛØÄJã²mlf¥pÙ6¶°’¸l \¶m¬8.ÛÆvV —‡±¬(.ÛÆNV—mc+ŒË¶±›Âåšl+ˆ{mc/+ðŽË! +%‹b¿mÛ¶mÛ¶9mÛ¶mÛ¶m۶힤÷¼äÔ:‹ÂeÛØÇòã²mìgùpÙ6°¼¸lY\¶C,7.ÛÆa– —mãˉ˶q”åÀeÛ8Ʋã²mgÙpÙ6N°¬¸.ÛÆ}—m㋋˶ñÅÁeÛxÄbã²m²0¸lŸXh\¶Ï,.ÛÆ—mã+ ˶ñÇeÛø΂á²mü`AqÙ6~² ¸l¿X`\¶ß,.ŸbX@\¶¿, .ÛÆ¡.ÛF üï'þÿ°mÄÿà²mÂã²mÆá²mÁâ²mÅà²mÿã²mÇ¿á²m„À¿â²m„Ä¿à²m„Â?ã²m„Æ?á²m„Á?â²m„Å?à²m„Ãßã²m„Çßá²mDÀßâ²mDÄßà²mDÂ_ã²mDÆ_á²mDÁ_â²mDÅ_à²mDßã²mDÇŸáò¿6ð§¸l1ñ'¸l±ðǸl±ñG¸lqð‡¸lqñ¸lñðû¸lññ{¸l ð»¸lïØÜk‰x¿Ë¶‘¿…˶‘¿‰Ë¶‘¿Ë¶‘ ¿ŽË¶‘¿†Ë¶‘¿ŠË¶‘¿‚˶‘ +¿ŒË¶‘¿„˶‘¿ˆË¶‘¿€Ë¶‘?˶‘?‡Ë¶‘?‹Ë¶‘‘ÁeÛÈÄNã²mdf§pÙ6²°“¸lYÙ \¶lì8.ÛFvv —m#;ŠË¶‘“ÁeÛÈÅã²mäf‡pÙ6ò°ƒ¸lyÙ\¶|l?.ÛF~¶—m£ ۋ˶QíÁeÛ(Ävã²mf»pÙ6Š°¸lEÙ\¶bl;.ÛFq¶ —m£ۊ˶Q’mÁå¬ی˶QšmÂeÛ(Ã6â²m”epÙ6ʱõ¸låÙ:\¶ +l-.ÛFE¶—m£[Ë6‘» +÷ÚF¶—m£*[˶Q-ÇeۨΖá²mÔ`KqÙ6j²%¸lµØb\¶Úl.ÛF¶—m£.[€Ë¶QÍÇeÛ¨Ïæá²m4`sqÙ6²9¸lØl\¶Æl.ÛF6—m£)›Ë¶ñ?6—m£›†Ë¶ÑœMÅeÛhÁ¦à²m´d“qÙ6Z±I¸l­ÙD\¶6l.ÛF[6—m£‡Ë¶ÑžÅeÛèÀÆà²mtd£qÙ6:±Q¸lÙH\¶.l.ÛFW6—m£†Ë¶Ñ ÅeÛèÁ†à²môdƒqÙ6z±A¸l½Ù@\¶>l .ÛF_Ö—m£ŸÃeÛèÏúâ²m `}pÙ6²Þ¸lƒX/\¶Á¬'.'d•YÜkCYw\¶a¬.ÛÆpÖ—mcë‚˶1’uÆeÛÅ:á²mŒfqÙ6Æ°¸lcY{\¶q¬.ÛÆxÖ—mckƒË¶1‘µÆå†lk…˶1™µÄeÛ˜ÂZà²mLeÍqÙ6¦±f¸ü¯ /.ÛÆ Ö—mc&k‚˶1‹5ÆeÛ˜Íá²mÌa qÙ6沸lóX}\¶ù¬.ÛÆV—mc!«ƒË¶±ˆÕÆeÛXÌjá²m,a5qÙ6–²¸lËXu\¶å¬.ÛÆ +V—mc%«‚˶±ŠUÆeÛXÍ*á²m¬aqÙ6Ö² +¸lëXy\¶õ¬.ÛÆV—mc#+ƒËØ&V—mc3+…˶±…•ÄeÛØÊJàre6„ǽ¶±ÃeÛØÁŠâ²mìdEpÙ6v±Â¸l»Y!\¶=¬ .ÛÆ^V —mcË˶±ŸåÃeÛ8Àòâ²mdypÙ6±Ü¸l‡Y.\žÄŽ°œ¸lGY\¶c,;.ÛÆq– —mãËŠËÓÙI–—mãˌ˶qšeÂeÛ8Ã2â²mœepÙ6αô¸lçY:\¶ ,-.ÛÆE–—mãK˶q™¥ÂeÛ¸ÂRâ²m\e)pÙ6®±ä¸l×Y2\¶,).ÛÆM–—mãKŒË¶q›%ÂeÛ¸Ãâ²mÜe pÙ6î±ø¸l÷Y<\¶,..ÛÆC—mã‹Ë¶ñ˜ÅÂåMì ‹‰Ë¶ñ”ÅÀeÛxÆ¢ã²m³P¸l_XH\¶¯,.aßXp\¶ï,.ÛÆ—mã' ‚˶ñ‹ÆeÛøÍá²müaqÙ6þ² ¸lÿ…f¸lð¿ùÿöÿƒË¶ÿ˶ÿ…˶ÿ‰Ë¶ÿ˶ ÿŽË¶ÿ†Ë¶ÿŠË¶ÿ‚˶ +ÿŒË¶ÿ„˶ÿˆË¶ÿ€Ë¶˶‡Ë¶‹Ë¶ƒË¶ ˶…˶‰Ë¶˶ ŽË¶†ËÿÚÀŸâ²mÄÄŸà²mÄÂã²M¼`p¯mÄáý!.ÛF\ü.ÛF<ü>.ÛF|ü.ÛFü..ÛFBü.ÛF"ü6.ÛFbü.ÛFü&.ÛFRü.ÛF2ü:.ÛFrü.ÛF +ü*.ÛFJü +.ÛF*ü2.ÛFjü.ÛFü".ÛFZü.ÛF:ü<.ÛFzü.ÛFü,.ÛFFv—m#;˶‘™ÂeÛÈÂNâ²mde'pÙ6²±ã¸lÙÙ1\¶ì(.ÛFNv—m#;ŒË¶‘›ÂeÛÈÃâ²mäepÙ6ò±ý¸lùÙ>\¶l/.ÛFA¶—m£Û˶Q˜íÂeÛ(Âvâ²me;pÙ6Š±í¸lÅÙ6\¶l+.ÛFI¶—c°Rl3.ÛFi¶ —m£ ÛˆË6›»÷ÚF9¶—m£<[‡Ë¶Q­ÅeÛ¨ÈÖà²mTb«qÙ6*³U¸lUØJ\¶ªl.ÛF5¶—m£:[†Ë¶Qƒ-Åeۨɖà²mÔb‹qÙ6j³E¸luØB\¶ºl.ÛF=6—m£>›‡Ë¶Ñ€ÍÅeÛhÈæà²m4b³qÙ6³Y¸lMØL\¶¦l.ÛÆÿØt\¶fl.ÛFs6—m£›‚˶ђMÆeÛhÅ&á²m´fqÙ6Ú° ¸lmÙx\¶vl.ÛF{6—m£ƒË¶Ñ‘ÆeÛèÄFá²mtf#qÙ6º°¸l]Ùp\¶nl.ÛFw6—m£‚˶ѓ ÆeÛèÅá²môfqÙ6ú°¸l}Y\ŽÍʲ~¸×6ú³¾¸lX\¶¬7.ÛÆ Ö —mc0ë‰Ë¶1„õÀeÛʺã²m cÝpÙ6†³®¸l#X\¶‘¬3.ÛÆ(Ö —mc4ëˆËµÙÖ—mc,k˶1ŽµÃeÛÏÚâ²mL`mpÙ6&²Ö¸l“X+\¶É¬%.ÛÆÖ—mc*kŽË¶15ÃåmxqÙ6f°¦¸l3Y\¶Y¬1.ÛÆlÖ—mckˆË¶1—5ÀeÛ˜Çêã²mÌgõpÙ6°º¸l Y\¶E¬6.ÛÆbV —mc «‰Ë¶±”ÕÀeÛXƪã²m,gÕpÙ6V°ª¸l+Y\¶U¬2.ÛÆjV —{±5¬".ÛÆZV—mc+˶±ž•Ã岬Ÿ÷ÚÆFV—mc+˶±™•ÂeÛØÂJâ²mle%pÙ6¶±â¸lÛY1\¶¬(.ÛÆNV—mc+ŒË¶±›ÂeÛØà +â²mìepy ÛÇòã²mìgùpÙ6°¼¸lY\¶C,7.ÛÆa– —mãˉ˶q”åÀeÛ8Ʋã²mgÙpÙ6N°¬¸.ÛÆ}—m㋋˶ñÅÁå~l‹{mã1‹…˶ñ„ÅÄeÛxÊbà²m²0¸lŸXh\¶Ï,.ÛÆ—mã+ ˶ñÇeÛø΂á²mü`AqÙ6~² ¸l¿X`\¶ß,.ÛÆ—mã/ €Ë¶ñ_†Ë¶ ÿûÿ?lñ?¸lð߸lñ_¸lAðŸ¸lAñ¸lÁðï¸lÁño¸l!ð¯¸l!ñ/¸l¡ðϸl¡ñO¸lað¸lañ¸láð÷¸láñw¸lð·¸lñ7¸l‘ð׸l‘ñW¸lQð—¸lØ ÜkÑxŽË¶†ËÿÚÀŸâ²mÄÄŸà²mÄÂã²mÄÆá²mÄÁâ²mÄÅà²mÄÃïã²mÄÇïá²m$Àïâ²m$Äïà²m$Âoã²m$Æoá²m$Áoâ²m$Åoà²m$ïã²m$ǯá²m¤À¯â²m¤Ä¯à²m¤Â/ã²m¤Æ/á²m¤Á/â²m¤Å/à²m¤ÃÏã²m¤ÇÏá²mdÀÏâ²mddgpÙ62±Ó¸l™Ù)\¶,ì$.ÛFVv—m#;ŽË¶‘ÃeÛÈÁŽâ²mädGpÙ6r±Ã¸l¹Ù!\¶<ì .ÛF^v —m#Û˶‘ŸíÃeÛ(Àöâ²md{pÙ6 +±Ý¸l…Ù.\¶"l'.ÛFQ¶—m£ÛŽË6•» ÷ÚF ¶—m£$Û‚Ë1X)¶—m£4ۄ˶Q†mÄeÛ(Ë6à²m”cëqÙ6ʳu¸lØZ\¶Šl .ÛF%¶—m£2[…˶Q…­ÄeÛ¨ÊVà²mTcËqÙ6ª³e¸l5ØR\¶šl .ÛF-¶—m£6[„˶Q‡-ÄeÛ¨Ëà²mÔcóqÙ6ê³y¸l Ø\\¶†l.ÛF#6—m£1›…˶фÍÄeÛhÊfà²müMÇeÛhƦá²m4gSqÙ6Z°)¸l-Ùd\¶Vl.ÛFk6—m£ ›€Ë¶Ñ–ÇeÛhÇÆá²m´gcqÙ6:°1¸lÙh\¶Nl.ÛFg6—m£ ˶ѕ ÇeÛèƆá²mtgCq9*+Άà^ÛèÉã²môbƒpÙ6z³¸l}Ø \¶¾¬?.ÛF?‡Ë¶ÑŸõÅeÛÀúà²m d½qÙ6±^¸lƒYO\¶!¬.ÛÆPÖ—«²a¬.ÛÆpÖ—mcë‚˶1’uÆeÛÅ:á²mŒfqÙ6Æ°¸lcY{\¶q¬.ÛÆxÖ—mckƒË¶1‘µÆeÛ˜ÄZá²mLf-qÙ6¦°¸lSYs\¶i¬.ÿkË˶1ƒ5Åeۘɚà²mÌbqÙ6f³F¸lsXC\¶¹¬.ÛÆ«‡Ë¶±€ÕÅeÛXÈêà²m,bµqÙ6³Z¸lKXM\¶¥¬.waËXu\¶å¬.ÛÆ +V—mc%«‚ËÅYV÷ÚÆjV —mc «ˆË¶±–UÀeÛXÇÊã²m¬gåpÙ66°²¸lY\¶M¬4.ÛÆfV +—mc +‰Ë¶±••ÀeÛØÆŠã²mlgÅpyÛÁŠâ²mìdEpÙ6v±Â¸l»Y!\¶=¬ .ÛÆ^V —mcË˶±ŸåÃeÛ8Àòâ²mdypÙ6±Ü¸l‡Y.\¶#,'.ÛÆQ–—mãˎ˶qœeÃeÛ8Á²âòtv’eÁeÛ8Å2ã²mœf™pÙ6ΰŒ¸lgY\¶s,=.ÛÆy–—mãK‹Ë¶q‘¥ÁeÛ¸ÄRã²m\f©pÙ6®°”¸lWY +\¶k,9.ÛÆu– ——±,).ÛÆM–—mãKŒË¶q›%ÂålKˆ{mã.K€Ë¶qÅÇeÛ¸Ïâá²m<`qqÙ6²8¸lXl\¶Ç,.ÛÆ—mã)‹Ë¶ñŒEÇeÛx΢á²m¼`QqÙ6^²(¸¼ƒ½b‘qÙ6^³H¸loXD\¶·,.ÛÆ;—mã= ‡Ë¶ñ…ÅeÛøÈÂà²m|b¡qÙ6>³P¸l_XH\¶¯,.ÛÆ7—mã; †Ë¶ñƒÅeÛøÉ‚à²mübqÙ6~³@¸lX@\¶¿, .ÛÆa.ÛF üï{þÿ°mÄÿà²mÂã²mÆá²mÁâ²mÅà²mÿã²mÇ¿á²m„À¿â²m„Ä¿à²m„Â?ãò ÿ„˶ÿˆË¶ÿ€Ë¶Ë6q‡½Ã½¶÷·¸lñ7¸l‘ð׸l‘ñW¸lQð—¸lQñ¸lÑðç¸lÑñg¸ü¯ ü).ÛFLü .ÛF,ü1.ÛFlü.ÛFü!.ÛF\ü.ÛF<ü>.ÛF|ü.ÛFü..ÛFBü.ÛF"ü6.ÛFbü.ÛFü&.ÛFRü.ÛF2ü:.ÛFrü.ÛF +ü*.ÛFJü +.ÛF*ü2.ÛFjü.ÛFü".ÛFZü.ÛF:ü<.ÛFzü.ÛFü,.ÛFFv—m#;˶‘™ÂeÛÈÂNâ²mde'pÙ6²±ã¸lÙÙ1\¶ì(.ÛFNv—m#;ŒË¶‘›ÂeÛÈÃâ²mäepÙ6ò±ý¸lùÙ>\¶l/.ÛDxîÜk…Øn\¶Âl.ÛF¶—m£(Û˶QŒmÇeÛ(ζá²m”`[qÙ6J²-¸ƒ•b›qÙ6J³M¸leØF\¶²l.ÛF9¶—m£<[‡Ë¶Q­ÅeÛ¨ÈÖà²mTb«qÙ6*³U¸lUØJ\¶ªl.ÛF5¶—m£:[†Ë¶Qƒ-Åeۨɖà²mÔb‹qÙ6j³E¸luØB\¶ºl.ÛF=6—m£>›‡Ë¶Ñ€ÍÅeÛhÈæà²m4b³qÙ6³Y¸lMØL\¶¦l.ÛÆÿØt\¶fl.ÛFs6—m£›‚˶ђMÆeÛhÅ&á²m´fqÙ6Ú° ¸lmÙx\¶vl.ÛF{6—m£ƒË¶Ñ‘Æå𬠅{m£3‰Ë¶Ñ…ÀeÛèʆã²mtcÃpÙ6º³¡¸l=Ø\¶žl0.ÛF/6—m£7ˆË¶Ñ‡ ÀeÛèËúã²môs¸lýY_\.Ï°>¸lYo\¶A¬.ÛÆ`Ö—mcë˶1”uÇeÛƺá²m g]qÙ6F°.¸l#Yg\¶Q¬.ÛÆhÖ—mc ë€Ë¶1–µÇeÛÇÚá²mŒgmqÙ6&°6¸lYk\¶I¬.ÛÆdÖ—mc +k˶1•5Çeۘƚáò¿6¼¸l3XS\¶™¬ .ÛÆ,Ö—mc6k„˶1‡5ÄeÛ˜Ëà²mÌcõqÙ6æ³z¸ÜŽ-`uqÙ6²:¸l‹Xm\¶Å¬.dXMÜkKY \¶e¬:.ÛÆrV —mc«ŠË¶±’UÁeÛXÅ*ã²m¬f•pÙ6Ö°Š¸lkY\¶u¬<.ÛÆzV—mc+‹Ë¶±‘•Áål+˶±™•ÂeÛØÂJâ²mle%pÙ6¶±â¸lÛY1\¶¬(.ÛÆNV—mc+ŒË¶±›ÂeÛØà +â²mìepÙ6ö±ü¸lûY>\¶,/.ÛÆA–—mãË˶q˜åÂeÛ8Ârâ²me9pÙ6Ž±ì¸lÇY6\¶,+.Og'Y\¶S,3.ÛÆi– —mã ˈ˶q–eÀeÛ8ÇÒã²mœgépÙ6.°´¸lY\^À.±Ô¸l—Y*\¶+,%.ÛÆU–—;±%,9îµë,.ÛÆ –—mã&K‚˶q‹%ÆeÛ¸Íá²mÜa qÙ6l÷X|\¶û,.ÛÆ—mã!‹ƒË¶ñˆÅÆeÛxÌbáò&ö„ÅÄeÛxÊbà²m‹‡Ë¶ñ€ÅÅeÛxÈâà²m³P¸l_XH\¶¯,.ÛÆ7—mã; †Ë¶ñƒÅeÛøÉ‚à²mübqÙ6~³@¸lX@\¶¿, .Ÿaÿ…g¸lð¿oùÿöÿƒË¶ÿË6qý½¶„÷Ÿ¸lAñ¸lÁðï¸lÁño¸l!ð¯¸l!ñ/¸l¡ðϸl¡ñO¸lað¸lañ¸láð÷¸láñw¸lð·¸lñ7¸l‘ð׸l‘ñW¸lQð—¸lQñ¸lÑðç¸lÑñg¸ü¯ ü).ÛFLü .ÛF,ü1.ÛFlü.ÛFü!.ÛF\ü.ÛF<ü>.ÛF|ü.ÛFü..ÛFBü.ÛF"ü6.ÛFbü.ÛFü&.ÛFRü.ÛF2ü:.ÛFrü.ÛF +ü*.ÛFJü +.ÛF*ü2.ÛFjü.ÛFü".ÛFZü.ÛF:ü<.ÛFzü.ÛFü,.ÛFFv—m#;˶‘™ÂeÛÈÂNâ²MæžÀ½¶‘ÇeÛÈÎŽá²mä`GqÙ6r²#¸l¹Øa\¶Üì.ÛFv—m#/;€Ë¶‘íÇeÛÈÏöá²m`{qÙ6 +²=¸l…Øn\¶Âl.ÛF¶—m£(Û˶QŒmÇeÛ(ζá²m”`[qÙ6J²-¸ƒ•b›qÙ6J³M¸leØF\¶²l.ÛF9¶—m£<[‡Ë¶Q­ÅeÛ¨ÈÖà²mTb«qÙ6*³U¸lUØJ\¶ªl.ÛF5¶—m£:[†Ë¶Qƒ-Åeۨɖà²mÔb‹qÙ6j³E¸luØB\¶ºl.ÛF=6—m£>›‡Ë¶Ñ€ÍÅeÛhÈæà²m4b³qÙ6³Y¸lMØL\¶¦l.ÛÆÿØt\̲²i¸×6š³©¸l-Ø\¶–l2.ÛF+6 —m£5›ˆË¶Ñ†MÀeÛhËÆã²m´cãpÙ6Ú³±¸lØ\¶Žl4.ÛF'6 +—m£3‰Ë…Y6—m£+ŽË¶Ñ ÃeÛèΆâ²mô`CpÙ6z²Á¸l½Ø \¶Þl .ÛF6 —m£/ë˶ÑÏá²môg}qÙ6°>¸lYo\¶A¬.ÛÆ`Ö—mcë˶1”uÇeÛƺá²m g]qÙ6F°.¸l#Yg\¶Q¬.ÛÆhÖ—mc ë€Ë¶1–µÇeÛÇÚá²mŒgmqÙ6&°6¸lYk\¶I¬.ÛÆdÖ—³)¬.ÛÆTÖ—mck†ËÿÚðârVßXSÜk3Y\¶Y¬1.ÛÆlÖ—mckˆË¶1—5ÀeÛ˜Çêã²mÌgõpÙ6°º¸l Y\¶E¬6.ÛÆbV —mc «‰Ë¶±”ÕÀå.l«ŽË¶±œUÃeÛXÁªâ²m¬dUpÙ6V±Ê¸l«Y%\¶5¬".ÛÆZV—mc+˶±ž•ÃeÛØÀÊâ²mldepÙ66±Ò¸l›Y)\¶-¬$.ÛÆVV—mc+ŽË¶±ÃeÛØÁŠâ²mìdEpÙ6v±Â¸l»Y!\¶=¬ .ÛÆ^V —mcË˶±ŸåÃeÛ8Àòâ²mdypÙ6±Ü¸l‡Y.\¶#,'.ÛÆQ–—§°c,;.ÛÆq– —mãËŠËÓÙI–—›±,3îµÓ,.ÛÆ–—mã,ˀ˶qŽ¥ÇeÛ8ÏÒá²m\`iqÙ6.²4¸l—Xj\¶Ë,.ÛÆ–—mã*K˶q%Çe۸Βáò2vƒ%Åe۸ɒà²mÜb‰qÙ6n³D¸lwXB\¶»,.ÛÆ=—mã>‹‡Ë¶ñ€ÅÅeÛxÈâà²m³P¸l_XH\¶¯,.ÛÆ7—mã; †ËÇØ—mã' ‚˶ñ‹ÆeÛøÍáò vŠĽ¶ñ—ÀeÛø/ÃeÛ€ÿ}Ãÿ¶€ø\¶@øo\¶Àø/\¶ øO\¶ ø\¶`øw\¶àø7\¶øW\¶ø\¶Pøg\¾ÁBãŸpÙ6ÂàqÙ6ÂâpÙ6ÂáïqÙ6ÂãïpÙ6"àoqÙ6"âopÙ6"á¯qÙ6"ã¯pÙ6¢à/qÙ6¢â/pÙ6¢áÏqÙ6¢ãÏpù_øS\¶˜ø\¶Xøc\¶Øø#\¶8øC\¶¸ø\¶xø}\¶øø=\¶ø]\¶„ø\¶Døm\¶Äø-\¶$øM\¶¤ø \¶døu\¶äø5\¶øU\¶”ø\¶Tøe\¶Ôø%\¶4øE\¶´ø\¶tøy\¶‰?ìîµ ¼ŸÅeÛÈÈÎà²mdb§qÙ62³S¸lYØI\¶¬ì.ÛF6v—m#;;†Ë¶‘ƒÅeÛÈÉŽà²mäb‡qÙ6r³C¸lyØA\¶¼ì .ÛF>¶—m#?ۇ˶Q€íÅeÛ(Èöà²mb»qÙ6 +³]¸lEØN\¶¢l.ÛF1¶—m£8ۆ˶Q‚mÅeÛ(ɶàr VŠmÆeÛ(Í6á²m”aqÙ6ʲ ¸låØz\¶òl.ÛF¶—m£"[ƒË¶Q‰­ÆeÛ¨ÌVá²mTa+qÙ6ª²¸lÕØr\¶êl.ÛF ¶—m£&[‚˶Q‹-ÆeÛ¨Íá²mÔa qÙ6겸lõØ|\¶úl.ÛF6—m"=wîµFl6.ÛFc6 —m£ ›‰Ë¶Ñ”ÍÀeÛø›ŽË¶ÑŒMÃeÛhΦâ²m´`SpÙ6Z²É¸l­Ø$\¶Öl".ÛF6—m£-˶юÃeÛhÏÆâ²mt`cpÙ6:²Ñ¸lØ(\¶Îl$.ÛF6—m£+ŽË¶Ñ ÃeÛèΆâ²mô`CpÙ6z²Á¸l½Ø \¶Þl .ÛF6 —m£/ë˶ÑÏá²môg}qÙ6°>¸lYo\¶A¬.ÛÆ`Ö—mcë˶1”uÇeÛƺá²m g]qÙ6F°.¸l#Yg\¶Q¬.ÛÆhÖ—mc ë€Ë¶1–µÇeÛÇÚá²mŒgmqÙ6&°6¸lYk\NϲV¸×6&³–¸lSX \¶©¬9.ÛÆ4Ö —ÿµáÅeÛ˜Ášâ²mÌdMpÙ6f±Æ¸l³Y#\¶9¬!.ÛÆ\Ö —mc«Ë¶1ŸÕÃåvl«‹Ë¶±ÕÁeÛXÄjã²m,fµpÙ6–°š¸lKY \¶e¬:.ÛÆrV —mc«ŠË¶±’UÁeÛXÅ*ã²m¬f•pÙ6Ö°Š¸lkY\¶u¬<.ÛÆzV—mc+‹Ë¶±‘•ÁeÛØÄJã²mlf¥pÙ6¶°’¸l \¶m¬8.ÛÆvV —mc+ŠË¶±“ÁeÛØÅ +ã²mìf…pÙ6ö°‚¸l{Y\¶},?.ÛÆ~–—DZ,/.ÛÆA–—mãË˶q˜åÂå†lˉ{mã(Ë˶qŒeÇeÛ8βá²mœ`Yqy:;ɲà²mœb™qÙ6N³L¸lgXF\¶³,.ÛÆ9–—mãÃþ‹ÄpÙ6à_ñÿ‡m# þ—m#þ—m#0þ —m#þ—m#(þ—m#þ—m#8þ —m#þ—m#$þ—m#þ—m#4þ —m# þ—m#,þ—m#þ—m#<þ—m#þ—m#"þ—m#þ—m#2þ +—m# +þ—m#*þ—m#þ—m#:þ —ÿµ?ÅeÛˆ‰?ÁeÛˆ…?ÆeÛˆ?ÂeÛˆƒ?ÄeÛˆ‹?ÀeÛˆ‡ßÇeÛˆßÃeÛH€ßÅeÛHˆßÁeÛH„ßÆe›øÀná^ÛHÂûM\¶¤ø \¶døu\¶äø5\¶øU\¶”ø\¶Tøe\¶Ôø%\¶4øE\¶´ø\¶tøy\¶ôø9\¶ øY\¶Œì .ÛF&v—m#3;…˶‘…ÄeÛÈÊNà²mdcÇqÙ6²³c¸l9ØQ\¶œì.ÛF.v—m#7;„˶‘‡ÄeÛÈËà²mäcûqÙ6ò³}¸lØ^\¶‚l.ÛF!¶—m£0ۅ˶Q„íÄeÛ(Êvà²mcÛqÙ6Š³m¸l%ØV\¶’l .Ç`¥Øf\¶Òl.ÛF¶—m£,ۀ˶QŽ­ÇeÛ(ÏÖá²mT`kqÙ6*²5¸l•Øj\¶Êl.ÛF¶—m"1wîµjl9.ÛFu¶ —m£[ŠË¶Q“-ÁeÛ¨Åã²mÔf‹pÙ6ê°…¸luÙ\¶zl>.ÛF}6—m£›‹Ë¶ÑÍÁeÛhÄfã²m4f³pÙ6š°™¸lMÙ \¶ÿ±é¸lÍØ4\¶æl*.ÛF 6—m£%›ŒË¶ÑŠMÂeÛhÍ&â²m´apÙ6Ú²ñ¸líØ8\¶öl,.ÛF6—m£#˶щÂeÛèÌFâ²mta#pÙ6º²á¸lÝØ0\¶îl(.ÛF6—m£'ŒË¶Ñ‹ ÂeÛèÍâ²môapÙ6ú²þ¸lý.ÛFÖ—mc ëƒË¶1õÆeÛÄzá²m f=qÙ6†°¸lCYw\N̪²n¸×6†³®¸l#X\¶‘¬3.ÛÆ(Ö —mc4ëˆË¶1†uÀeÛËÚã²mŒcípÙ6Ƴ¶¸lX\¶‰¬5.ÛÆ$Ö +—mc2k‰ËÙÖ—mc*kŽË¶15ÃåmxqÙ6f°¦¸l3Y\¶Y¬1.ÛÆlÖ—mckˆË¶1—5ÀeÛ˜Çêã²mÌgõpÙ6°º¸l Y\¶E¬6.ÛÆbV —mc «‰Ë¶±”ÕÀeÛXƪã²m,gÕpÙ6V°ª¸l+Y\¶U¬2.ÛÆjV —mc «ˆË¶±–UÀeÛXÇÊã²m¬gåpÙ66°²¸lY\¶M¬4.ÛÆfV +—±-¬$.ÛÆVV—mc+ŽË¶±Ãåªl+Š{mc'+‚˶±‹ÆeÛØÍ +á²mìaqÙ6ö²¸lûX~\¶ý,.ÛÆ–—mã ˃˶qˆåÆeÛ8Ìrá²ma9qÙ6Ž²¸<…cÙqÙ6Ž³l¸l'XV\žÎN²,¸l§Xf\¶Ó,.ÛÆ–—mã,ˀ˶qŽ¥ÇeÛ8ÏÒá²m\`iqÙ6.²4¸l—Xj\¶Ë,.ÛÆ–—mã*K˶q%Çe۸Βá²mÜ`IqÙ6n²$¸l·Xb\¶Û,.ÛÆ–—mã.K€Ë¶qÅÇeÛ¸Ïâá²m<`qqÙ6²8¸lXl\¶Ç,.ÛÆ—mã)‹Ë[Ø3—mã9‹†Ë¶ñ‚EÅeÛxÉ¢àò0¶ƒEƽ¶ñšEÂeÛxÃ"â²m¼epÙ6Þ±ð¸lïY8\¶,,.ÛÆG—mã ˶ñ™…ÂeÛøÂBâ²m|e!pÙ6¾±à¸lßY0\>Æ~° ¸l?Y\¶_,0.ÛÆo—m㠈˶ñ—ÀeÛø/2ÃeÛ€ÿ}Éÿ¶€ø\¶@øo\¶Àø/\¶ øO\¶ ø\¶`øw\¶àø7\¶øW\¶ø\¶Pøg\¶Ðø'\¶0øG\¶°ø\¶pø{\¶ðø;\¶ø[\¶ˆø\¶Høk\¶Èø+\¶(øK\¶¨ø \¶høs\¶èø3\þ×þ—m#&þ—m#þ—m#6þ—m#þ—mâ{€{m#ï÷qÙ6âã÷pÙ6àwqÙ6âwpÙ6á·qÙ6ã·pÙ6’à7qÙ6’â7pÙ6’á×qÙ6’ã×pÙ6RàWqÙ6RâWpÙ6Rá—qÙ6Rã—pÙ6ÒàqÙ6ÒâpÙ6ÒáçqÙ6ÒãçpÙ62àgqÙ62²3¸l™Øi\¶Ìì.ÛFv—m#+;˶‘ÇeÛÈÎŽá²mä`GqÙ6r²#¸l¹Øa\¶Üì.ÛFv—m#/;€Ë¶‘íÇeÛÈÏöá²m`{qÙ6 +²=¸l…Øn\¶Âl.ÛF¶—m£(Û˶QŒmÇeÛ(ζá²m”`[qÙ6J²-¸ƒ•b›qÙ6J³M¸leØF\¶²l.ÛF9¶—m".wîµ +l-.ÛFE¶—m£[˶Q™­ÂeÛ¨ÂVâ²mTe+pÙ6ª±å¸lÕÙ2\¶l).ÛFM¶—m£[ŒË¶Q›-ÂeÛ¨Ãâ²mÔe pÙ6ê±ù¸lõÙ<\¶l..ÛFC6—m£›Ë¶Ñ˜ÍÂeÛhÂfâ²m4e3pÙ6þǦã²m4cÓpÙ6š³©¸l-Ø\¶–l2.ÛF+6 —m£5›ˆË¶Ñ†MÀeÛhËÆã²m´cãpÙ6Ú³±¸lØ\¶Žl4.ÛF'6 +—m£3‰Ë¶Ñ…ÀeÛèʆã²mtcÃpÙ6º³¡¸l=Ø\¶žl0.ÛF/6—m£7ˆË¶Ñ‡ ÀeÛèËúã²môs¸lýY_\ŽËʳ>¸×6²Þ¸lƒX/\¶Á¬'.ÛÆÖ—mc(ëŽË¶1ŒuÃeÛκâ²mŒ`]pÙ6F²Î¸l£X'\¶Ñ¬#.ÛÆÖ—mc,kËuÙ8Ö—mc‹‡ËëØ—mã!‹ƒË¶ñˆÅÆeÛxÌbáò ¶‰ÅĽ¶ñ”ÅÀeÛxÆ¢ã²m°°¸lY\>À>±Ð¸lŸY(\¶/,$.ÛÆW—m㠎˶ñÃeÛøÁ‚â²müdApÙ6~±À¸l¿Y \¶?, .ÛÆ_ —mã¿( —m# þ÷ÿØ6âpÙ6á¿qÙ6ã¿pÙ6‚à?qÙ6‚â?pÙ6‚áßqÙ6‚ãßpÙ6Bà_qÙ6Bâ_pÙ6BáŸqÙ6BãŸpÙ6ÂàqÙ6ÂâpÙ6ÂáïqÙ6ÂãïpÙ6"àoqÙ6"âopÙ6"á¯qÙ6"ã¯pÙ6¢à/qÙ6¢â/pÙ6¢áÏqÙ&ž°g¸÷_¼?ÅeÛˆ‰?ÁeÛˆ…?ÆeÛˆ?ÂeÛˆƒ?ÄeÛˆ‹?ÀeÛˆ‡ßÇeÛˆßÃeÛH€ßÅeÛHˆßÁeÛH„ßÆeÛHŒßÂeÛH‚ßÄeÛHŠßÀeÛH†_ÇeÛHŽ_ÃeÛH_ÅeÛH‰_ÁeÛH…_ÆeÛH_ÂeÛHƒ_ÄeÛH‹_ÀeÛH‡ŸÇeÛHŸÃeÛÈ€ŸÅeÛÈÈÎà²mdb§qÙ62³S¸lYØI\¶¬ì.ÛF6v—m#;;†Ë¶‘ƒÅeÛÈÉŽà²mäb‡qÙ6r³C¸lyØA\¶¼ì .ÛF>¶—m#?ۇ˶Q€íÅeÛ(Èöà²mb»qÙ6 +³]¸lEØN\¶¢l.ÛF1¶—m£8ۆ˶Q‚mÅe›ˆÎÝ‚{c°Rl3.ÛFi¶ —m£ ۈ˶Q–mÀeÛ(ÇÖã²m”gëpÙ6*°µ¸lÙ\¶Jl5.ÛFe¶ +—m£ +[‰Ë¶Q•­ÀeۨƖã²mTgËpÙ6j°¥¸l5Ù\¶Zl1.ÛFm¶èÿ-ÝcÌ-fÛnáÚ¶mÛ¶mû«m¾µmÛ¶mÛ¶mïq4»É™kŒ>ýµ:ÇÌ´]ͱ6ÖmæXëµ r¬õÛù9ÖÆí¼kcÃvnŽµ±Q;'ÇÚظcmlÒÎʱ66mgæX›µ3r¬ÿk§çX›·Ór¬-Ú©9ÖÆ–í”kc«vrŽµ±u;)ÇÚئ˜cmlÛNȱ6¶kÇçXÛ·ãr¬Ú±9ÖÆŽí˜kc§vtŽµ±s;*ÇÚØ¥™cmìڎȱ6vk‡çX»·Ãr¬=Ú¡9ÖÆžíkc¯vpŽÇhKµƒrWû´s¬}Û9ÖÆ~mÿkã–cmìßö˱6hûæX¶}r¬ƒÚÞ9ÖÆÁm¯kã¶gŽµqhÛ#ÇÚ8¬ížcmÞvËñ툶kŽµqdÛ%ÇÚ8ªíœcmÝvʱ6Ži;æXǶr¬ãÚö9ÖÆñm»kㄶmŽµqbÛ&ÇÚ8©mcmœÜ¶Ê±6Ni[æX§¶-r¬ÓÚæ9þ¯ 7ÇÚ8£m–cmœÙ6ͱ6Îj›äXg·s¬sÚF9ÖƹmÃk㼶AŽµq~[?ÇÚ¸ ­—cm\ØÖͱ6.jëäX·µs¬KÚZ9ÖÆ¥mÍk㲶FŽµqy[=Ç»·+Új9ÖÆ•mÕk㪶JŽµqu[9ÇKµ½ÛJ¹«kÛŠ9ÖÆum…kãú¶|ŽµqC[.ÇÚ¸±-›cmÜԖɱ6nnKçX·´¥r¬[Û’9ÖÆmm‰kãö¶xŽµqG[,ÇÚ¸³-šã#Ú]m‘kãî¶pŽµqO[(ÇÚ¸·-˜cmÜ×ȱ6îoóçX´ùr¬Û¼9ÖÆCmžkãá6wŽµñH›+ÇÚx´Í™cm<Öæȱ6o³çXO´Ùr|z{²Íšcm<Õfɱ6žn3çXÏ´™r¬gÛŒ9ÖÆsm†kãù6}ŽµñB›.ÇÚx±M›cm¼Ô¦É±6^nSçX¯´©r¬WÛ”9ÖÆkmŠkãõ6yŽµñF›,ÇÚx³Mšã+Ú[m’kãí6qŽµñN›(ÇÚx·M˜ã½Û5m‚ÜÕÆûmükãƒ6^Žµña7ÇÚø¨“cm|ÜÆα6>icåXŸ¶1s¬ÏÚ9ÖÆçmôkã‹6ZŽµñe5ÇÚøª’cm|ÝFÎñ]í›6RŽµñm1ÇÚø®cm|߆ϱ6~hÃåX?¶as¬ŸÚ09ÖÆÏmèkã—6TŽµñk2ÇÚø­ ‘cmüÞϱ6þhƒåX¶As¬¿Ú 9ÖÆßmàkãŸ6PŽµño0ÇÚ`´–cm ˜ÿûyßÿcm ”ÿ“cm œÿcm ’ÿ•cm šÿ™cm –ÿ‘cm žÿžcm ‘ÿ–cm ™ÿšcm •ÿ’cm ÿœcm “ÿ”cm ›ÿ˜ã·Úpù9ÖÆðù÷9ÖÆùw9Öƈù·9ÖÄ{í›ÜÕÆÈýüëkc”ü«kcÔüËkc´ü‹kcôüókcŒü³ÿ×FþiŽµ1VþIŽµ1vþqŽµ1NþQŽµ1nþaŽµ1^þAŽµ1~þ~Žµ1Aþ^Žµ1aþnŽµ1QþNŽµ1qþvŽµ1IþVŽµ1iþfŽµ1YþFŽµ1yþzŽµ1EþZŽµ1eþjŽµ1UþJŽµ1uþrŽµ1MþRŽµ1mþbŽµ1]þBŽµ1}þ|Žµ1Cþ\Žµ1cþlŽµ1S{&ÇÚ˜¹=cmÌҞʱ6fmOæX³µ'r¬ÙÛã9ÖÆí±kcÎöhŽµ1W{$ÇÚ˜»=œcmÌÓʱ6æmæXóµr¬ùÛý9ÖÆí¾kcÁvoŽµ±P»'ÇÚX¸ÝcMŒÔ½+wµ±h»3ÇÚX¬Ý‘cm,Þnϱ6–h·åXK¶[s¬¥Ú-9³-Ýnα6–i7åX˶s¬åÚ 9ÖÆòíúkc…v]Žµ±b»6ÇÚX©]“cm¬Ü®Î±6ViWåX«¶+s¬ÕÚ9ÖÆêíòkcvYŽµ±f»4ÇÚX«]’cm¬Ý.α6ÖiåXë¶ s¬õÚ9ÖÆúíükcƒv^Žµ±a;7ÇÚب“cmlÜÎα66igåX›¶3s¬ÍÚ9ÖÆÿµÓs¬ÍÛi9ÖÆíÔkcËvJŽµ±U;9ÇÚغ”cmlÓṈ6¶m'äXÛµãs¬íÛq9ÖÆíØkcÇvLŽµ±S;:ÇÚع•cmìÒŽÌñHm‘vDîjc·vxŽµ±{;,ÇÚØ£šcmìÙɱ6öjçX{·ƒr¬}Ú9Öƾí€kc¿¶Žµñ?˱6öoûåX´}s¬Û>9^©Ôöα6n{åX‡´=s¬CÛ9ÖÆam÷kãð¶[ŽµqDÛ5ÇÚ8²í’cmÕvα6Žn;åXÇ´s¬cÛ9ÖÆqmûkãø¶]ŽµqBÛ6ÇÚ8±m“cmœÔ¶Î±6Nn[åX§´-s¬SÛ9ÖÆimóÿ׆›cmœÑ6˱6Îl›æXgµMr¬³ÛÆ9ÖÆ9m£kãܶaŽµq^Û ÇÚ8¿­Ÿcm\ÐÖ˱6.lëæxÇvQ['ÇÚ¸¸­cm\ÒÖʱ6.mkæx‘¶k[#wµqy[=ÇÚ¸¢­–cm\ÙVͱ6®j«äXW·•s¬kÚJ9ÖƵmÅk㺶BŽµq}[>ÇÚ¸¡-—cmÜؖͱ6njËäX7·¥s|P»¥-•cmÜږ̱6nkKäX··Ås¬;Úb9ÖÆmÑk㮶HŽµqw[8ÇÚ¸§-”cmÜÛ̱6îk äX÷·ùs¬Ú|9ÖƃmÞkã¡6OŽµñp›;ÇÚx¤Í•cm<Úæ̱6ksäX·Ùs¬'Úl9>½=Ùfͱ6žj³äXO·™s¬gÚL9ÖƳmÆkã¹6CŽµñ|›>ÇÚx¡M—cm¼Ø¦Í±6^jÓäX/·©s|Q{¥M•cm¼Ú¦Ì±6^kSäX¯·És¼k»¬M–»Úx³Mšcm¼Õ&ɱ6ÞnçXï´‰r¬wÛ„9ÖÆ{m‚kãý6~ŽµñA/ÇÚø°›cm|ÔÆɱ6>ncçXŸ´±r¬OÛ˜9¾¥}ÖÆȱ6>o£çX_´Ñr¬/Û¨9ÖÆWm”kãë6rŽµñM)ÇÚø¶˜cm|×Fȱ6¾oÃçX?´ár¬Û°9ÖÆOm˜kãç6tŽµñK*ÇÚøµ ™cmüֆȱ6~oƒçX´Ár¬?Û 9ÖÆ_mkãï6pŽµñO(ÇÚø· ˜cm 0z˱6Ìÿý¬ïÿ±6Êÿɱ6Îÿα6Éÿʱ6Íÿ̱6Ëÿȱ6ÏÏñ+mˆü·kcÈü×kc¨ü—kcèüçkâöSîjcØ~þcŽµ1\þCŽµ1|þ}Žµ1Bþ]Žµ1bþmŽµ1RþMŽµ1rþuŽµ1JþUŽµ1jþeŽµ1ZþEŽµ1zþyŽµ1FþYŽÿk#ÿ4ÇÚ+ÿ$ÇÚ;ÿ8ÇÚ'ÿ(ÇÚ7ÿ0ÇÚ/ÿ ÇÚ??ÇÚ˜ /ÇÚ˜07ÇÚ˜('ÇÚ˜8;ÇÚ˜$+ÇÚ˜43ÇÚ˜,#ÇÚ˜<=ÇÚ˜"-ÇÚ˜25ÇÚ˜*%ÇÚ˜:9ÇÚ˜&)ÇÚ˜61ÇÚ˜.!ÇÚ˜>>ÇÚ˜!.ÇÚ˜16ÇÚ˜©=“cmÌܞα6fiOåX³¶'s¬ÙÚ9ÖÆìíñkcŽöXŽµ1g{4ÇÚ˜«=’cmÌÝα6æiåXó¶s¬‰aºä®6æo÷çX ´ûr¬Û½9ÖÆBížkcávwŽµ±H»+ÇÚX´Ý™cm,Öîȱ6o·çXK´Ûr¬%Û­9ÖÆRí–Ù–n7çXË´›r¬eÛ9ÖÆrí†kcùv}Žµ±B».ÇÚX±]›cm¬Ô®É±6VnWçX«´«r¬UÛ•9ÖÆjíŠkcõvyŽµ±F»,ÇÚX³]šcm¬Õ.ɱ6ÖnçXë´‹r¬uÛ…9ÖÆzí‚kcýv~Žµ±A;/ÇÚØ°›cmlÔÎɱ66ngçX›´³r¬MÛ™9ÖÆfíŒkãÿÚé9ÖÆæí´kc‹vjŽµ±e;%ÇÚتœcmlÝNʱ6¶i'æXÛ¶r¬íÚñ9¦Í׎Ë]mìЎͱ6vlÇäX;µ£s¬ÛQ9ÖÆ.íÈkc×vDŽµ±[;<ÇÚؽ–cmìÑͱ6öl‡äX{µƒs¬½ÛA9ÖÆ>íÀ/ÓömäXûµýs¬ÿYŽµ±Û/ÇÚ8 í›cmØöɱ6j{çX·½r¬CÚž9ÖÆ¡mkã°¶{ŽµqxÛ-ÇÚ8¢íšcmÙvɱ6Žj;çXG·r¬cÚŽ9ÖƱm‡k㸶}Žµq|Û.ÇÚ8¡m›cmœØ¶É±6Nj[çX'·­r¬SÚ–9ÖÆ©m‹kã´¶yŽÿkÃͱ6Îh›åXg¶Ms¬³Ú&9ÖÆÙmãoÝÎiåXç¶ s¬óÚ9ÖÆùmýÏ׶oëå®6.lëæXµur¬‹ÛÚ9ÖÆ%m­kãÒ¶fŽµqY[#ÇÚ¸¼­žcm\ÑV˱6®l«æXWµUr¬«ÛÊ9ÖÆ5m¥kãÚ¶bŽ÷m×µr¬ëÛò9ÖÆ m¹kãƶlŽµqS[&ÇÚ¸¹-cmÜҖʱ6nmKæX·µ%r¬ÛÛâ9ÖÆm±kãζhŽµqW[$ÇÚ¸»-œcmÜÓʱ6îm æX÷µr¬ûÛü9ÖÆm¾kãÁ6oŽµñP›'ÇÚx¸Ícm<Òæʱ6msæXµ9r¬ÇÛì9ÖÆm¶ŸÞžl³æXOµYr¬§ÛÌ9ÖÆ3m¦kãÙ6cŽÏiϵr¬çÛô9ÖÆ mºkãÅ6mŽ·o´irW/·©s¬WÚT9ÖÆ«mÊkãµ6EŽµñz›<ÇÚx£M–cm¼Ù&ͱ6Þj“äXo·‰s¬wÚD9ÖÆ»mÂkã½6AŽµñ~?Ç×µÚx9ÖƇmÜkã£6NŽµñq;ÇÚø¤•cm|ÚÆ̱6>kcäXŸ·Ñs¬/Úh9ÖÆ—mÔkã«6JŽµñu9ÇÚø¦”cm|ÛF̱6¾k#äXß·ás¬Úp9ÖÆmØkã§6LŽµñs:ÇÚø¥ •cmüچ̱6~kCäX¿·Ás¬?Ú`9ÖÆŸmÐkã¯6HŽµñw8ÇÚø§ ”cmüÛ̱6£åXæÿ~Ú÷ÿø¹6PþOŽµ1pþwŽµ1HþWŽµ1hþgŽ5ñRû#wµ1x?ÿ=ÇÚ"ÿ-ÇÚ2ÿ5ÇÚ*ÿ%ÇÚ:ÿ9ÇÚ&ÿ)ÇÚ6ÿ1ÇÚ.ÿ!ÇÚ>ÿ>ÇÚ!ÿ.ÇÚ1ÿ6ÇÚ)ÿ&ÇÚ9ÿ:ÇÚ%ÿ*ÇÚ5ÿ2ÇÚ-ÿ"ÇÚ=ÿ<ÇÚ#ÿ,Çÿµ‘šcmŒ•’cmŒœcmŒ“”cmŒ›˜cmŒ—cmŒŸ¿ŸcmL¿—cmL˜¿›cmL”¿“cmLœ¿cmL’¿•cmLš¿™cmL–¿‘cmLž¿žcmL‘¿–cmL™¿šcmL•¿’cmL¿œcmL“¿”cmL›¿˜cmL—¿cmLŸ?ŸcmÌ?—cm̘?›cmÌԞɱ6fnOçX³´§r¬YÛ“9ÖÆlí‰kcööxŽ51X÷±ÜÕÆœíÑkc®öHŽµ1w{8ÇÚ˜§=”cmÌÛ̱6ækäXó·ûs¬Ú}9ÖÆ‚íÞkc¡vOŽµ±p»;ÇÚX¤Ý•cm,Úî̱6kwäX‹·Ûs¬%Úm9ÖÆ’íÖkc©vKŽÇlK·›s¬eÚM9ÖƲíÆkc¹vCŽµ±|»>ÇÚX¡]—cm¬Ø®Í±6Vj×äX+·«s¬UÚU9ÖƪíÊkcµvEŽµ±z»<ÇÚX£]–cm¬Ù.ͱ6Öj—äXk·‹s¬uÚE9ÖƺíÂkc½vAŽµ±~;?ÇÚØ —cmlØÎͱ66jçäX·³s¬MÚY9ÖƦíÌkc³vFŽµñíôkcóvZŽµ±E;5ǃµ9Ú)¹«­ÚÉ9ÖÆÖí¤kc›vbŽµ±m;!ÇÚØ®Ÿcmlߎ˱6vhÇæX;¶cr¬ÚÑ9ÖÆÎí¨kc—vdŽµ±k;"ÇÚØ­žãÅÚîí°kcvhŽµ±g;$ÇÚØ«œcmìÝʱ6öiæXû¶r¬ýÚþ9ÖÆÿ,ÇÚØ¿í—cmÐöͱ6lûäXµ½s¬ƒÛ^9ÖÆ!mÏkãжGŽµqXÛ=ÇÚ8¼í–cmÑvͱ6Žl»äXGµs¬£ÛN9ÖÆ1mÇkãضCŽµq\Û>ÇÚ8¾m—cmœÐ¶Í±6NlÛäX'µ­s¬“ÛV9ÖÆ)mËkãÔ¶EŽ7k§µÍsü_nŽµqFÛ,ÇÚ8³mšã9Ú–m“ÜÕÆÙmãk㜶QŽµqnÛ0ÇÚ8¯mcmœßÖϱ6.hëåX¶us¬‹Ú:9ÖÆÅmíkã’¶VŽµqi[3ÇÚ¸¬­‘cm\ÞVÏñî튶ZŽµqe[5ÇÚ¸ª­’cm\ÝVα6®i+åX׶s¬ëÚ +9ÖÆõmùkㆶ\Žµqc[6ÇÚ¸©-“cmÜܖα6niKåX·¶%s¬ÛÚ9ÖÆímñk㎶XŽµqg[4ÇÚ¸«-’cmÜÝα6îi åX÷¶s¬ûÚ9ÖÆýmþkã6_Žµñ`›7ÇÚx¨Í“cm<Üæα6isåX¶9s¬ÇÚ9ÖÆãmöŸÖžh³åøôöd›5ÇÚxªÍ’cm<ÝfÎñ–í¬6SîjãÙ6cŽµñ\›!ÇÚx¾MŸcm¼Ð¦Ë±6^lÓæX/µir¬—ÛÔ9ÖÆ+mªkãÕ6eŽµñZ›"ÇÚx½Mžcm¼Ñ&˱6Þl“æøŠöV›$ÇÚx»Mœcm¼Ó&ʱ6ÞmæXïµ r¬÷Ûø9ÖÆm¼kãÃ6nŽµñQ'ÇÚø¸cm|ÒÆʱ6>mcæXŸµ1r¬ÏÛè9ÖÆm´kãË6jŽµñU%ÇÚøºœcm|ÓFʱ6¾m#æXßµr¬ïÛð9ÖÆm¸kãÇ6lŽµñS&ÇÚø¹ cmü҆ʱ6~mCæX¿µ!r¬ßÛà9ÖÆm°kãÏ6hŽŸhµAr¬¿ÛÀ9ÖÆ?m kãß6`ŽÏjÏ´rWŽÙ_óIßÿcm ”ÿ“cm œÿcm ’ÿ•cm šÿ™cm –ÿ‘cm žÿžcm ‘ÿ–cm ™ÿšcm •ÿ’cm ÿœcm “ÿ”cm ›ÿ˜ã·Úpù9ÖÆðù÷9ÖÆùw9Öƈù·9ÖÆHù79ÖÆÈù×9ÖÆ(ùW9Öƨù—9ÖÆhù9ÖÆèùç9ÖÆùg9þ¯üÓkc¬ü“kcìüãkcœü£kcÜüÃkc¼üƒkcüüýkc‚ü½kcÂüÝkc¢ükcâüíkc’ü­kcÒüÍkc²ükcòüõkcŠüµkcÊüÕkcªü•kcêüåkcšü¥kcÚüÅkcºü…kcúüùkc†ü¹kcÆüÙÿ×FþL>@W3·§s¬YÚS9ÖƬíÉkc¶öDŽµ1{{<ÇÚ˜£=–cmÌÙͱ6æjäXs·‡s¬yÚC9ÖƼíÁkc¾ö@Žµ1»?ÇÚX Ý—cm,Øîͱ6j÷äX ·»s¬EÚ]9ÖÆ¢íÎkc±vGŽµ±x»=ÇÚX¢Ý–cm,Ùnͱ6–j·äx̶t»9ÇÚX¦Ý”cm,Ûṉ6–k7äXË·ës¬Úu9ÖÆŠíÚkc¥vMŽµ±r»:ÇÚX¥]•cm¬Ú®Ì±6VkWäX«·Ës¬5Úe9ÖÆšíÒkc­vIŽµ±v»8ÇÚX§]”cm¬Û.̱6ÖkäXë·ós¬ Úy9ÖƆíÜkc£vNŽµ±q;;Ç´™ÚY¹«MÛ™9ÖÆfíŒkãÿÚé9ÖÆæí´kc‹vjŽµ±e;%ÇÚتœcmlÝNʱ6¶i'æXÛ¶r¬íÚñ9ÖÆöí¸kc‡vlŽh;¶cr¬ÚÑ9ÖÆÎí¨kc—vdŽµ±k;"ÇÚØ­žcmìÞ˱6öh‡æX{¶Cr¬½ÚÁ9ÖÆÞí kcŸv`Žµ±o; ÇÚدíŸcmüÏr¬ýÛ~9ÖÆmßkãÀ¶OŽµqPÛ;ÇÚ8¸í•cmÒö̱6m{äX‡µÝs¬ÃÛn9ÖÆm×kãȶKŽµqTÛ9ÇÚ8ºí”cmÓv̱6Žm;äXǵís¬ãÛv9ޠжͱ6NlÛäX'µ­s¬“ÛV9ž©mÒ¶Ì]mœÚ¶È±6Nk›çø¿6Ük㌶YŽµqfÛ4ÇÚ8«m’cmœÝ6α6ÎiåXç¶ s¬óÚ9ÖÆùmýkザ^Žµqa[7Ç;¶‹Ú:9ÖÆÅmíkã’¶VŽµqi[3ÇÚ¸¬­‘cm\ÞVϱ6®h«åXW¶Us¬«Ú*9ÖÆÕmåk㚶RŽµqm[1ÇÚ¸®­cm\ߖϱ6nhËåX7¶es¬›Ú29ÖÆÍmékã–¶TŽµqk[2ÇÚ¸­-‘cmÜÞϱ6îh‹åXw¶Es¬»Ú"9ÖÆÝmák㞶PŽµqo[0ÇÚ¸¯-cmÜßæϱ6hóåX¶ys|B{¨Í“cm<Üæα6isåX¶9s¼I;¥Í‘»Úx¼Ížcm<ÑfËñéíÉ6kŽµñT›%ÇÚxºÍœcm<Ófʱ6žm3æXϵr¬çÛô9ÖÆ mºkãÅ6mŽµñR›&ÇÚx¹Mã‹Ú+mªkãÕ6eŽµñZ›"ÇÚx½Mžcm¼Ñ&˱6Þl“æXoµIr¬·ÛÄ9ÖÆ;m¢kãÝ6aŽµñ^› ÇÚx¿Ÿcm|ÐÆ˱6>lãæXµqr¬ÛØ9ÖÆ'm¬kãÓ6fŽµñY#ÇÚø¼žcm|ÑF˱6¾l£æX_µQr¬¯ÛÈ9ÖÆ7m¤kãÛ6bŽµñ]!ÇÚø¾ ŸcmüІ˱6~lÃæX?µar¬ŸÛÐ9~¨ý҆ʱ6~mCæX¿µ!r¬ßÛà9>¥=ÖË]müÙͱ6þjƒäX·s¬Ú@9ÖÆ¿mÀkc€±ZŽµ1`þïÇ}ÿµ1PþOŽµ1pþwŽµ1HþWŽµ1hþgŽµ1XþGŽµ1xþ{Ž_iCä¿åXCæ¿æøµ6TþKŽµ1tþsŽµ1LþSŽµ1lþcŽµ1\þCŽµ1|þ}Žµ1Bþ]Žµ1bþmŽµ1RþMŽµ1rþuŽµ1JþUŽµ1jþeŽµ1ZþEŽµ1zþyŽµ1FþYŽÿk#ÿ4ÇÚ+ÿ$ÇÚ;ÿ8ÇÚ'ÿ(ÇÚ7ÿ0ÇÚ/ÿ ÇÚ??ÇÚ˜ /ÇÚ˜07ÇÚ˜('ÇÚ˜8;ÇÚ˜$+ÇÚ˜43ÇÚ˜,#ÇÚ˜<=ÇÚ˜"-ÇÚ˜25ÇÚ˜*%ÇÚ˜:9Çšø£½”»Ú˜¶Ÿ¿˜cmL—¿cmLŸ?ŸcmÌ?—cm̘?›cmÌԞɱ6fnOçX³´§r¬YÛ“9ÖÆlí‰kcööxŽµ1G{,ÇÚ˜³=šcmÌÕɱ6ænçXó´‡r¬yÛƒ9ÖÆ|íkcþvŽµ±@»/ÇÚX°Ý›cm,Ôîɱ6nwçX‹´»r¬EÛ9ÖÆbíŽkcñv{Žµ±D»-ÇÚX²Ýšcm,ÕnÉñ˜mévsŽµ±L»)ÇÚX¶Ý˜cm,×nȱ6–o×çX+´ër¬Ûµ9ÖÆJíškcåvuŽµ±J»*ÇÚXµ]™cm¬Ö®È±6Vo—çXk´Ër¬5Û¥9ÖÆZí’kcívqŽµ±N»(ÇÚX·]˜cMLÓ½ wµ±~;?ÇÚØ —cmlØÎͱ66jçäX·³s¬MÚY9ÖƦíÌkc³vFŽµñíôkcóvZŽµ±E;5ÇÚز’cmlÕNα6¶n'åXÛ´s¬mÛ 9ÖÆvíøkcûv\Žµ±C;6ÇÚر“cmìԎα6vnGåX»´#s¬]Û9ÖÆníðkc÷vXŽµ±G;4ÇÚس’cmìÕα6önåXû´s¬}Û9ÖÆ~mÿkã–cmìßö˱6hûæX¶}r¬ƒÚÞ9ÖÆÁm¯kã¶gŽµqhÛ#ÇÚ8¬ížcmÞv˱6Žh»æXG¶]r¬£ÚÎ9ÖÆÑm§k㘶cŽµqlÛ!ÇÓ´õÚö¹«ãÛv9ÖÆ mÛkãĶMŽµqRÛ:ÇÚ8¹m•cmœÒ¶Ì±6Nm[äX§µÍsü_nŽµqFÛ,ÇÚ8³mšcmœÕ6ɱ6ÎnçxëvNÛ(ÇÚ8·m˜cmœ×6ȱ6ÎoëçX´õr¬ Ûº9ÖÆEmkãâ¶vŽµqI[+ÇÚ¸´­™cm\ÖÖȱ6.o«çXW´Õr¬+Ûª9ÖÆUm•kãê¶rŽµqM[)ÇÚ¸¶­˜cm\×Vȱ6®oËçX7´år¬Û²9ÖÆMm™kãæ¶tŽµqK[*ÇÚ¸µ-™cmÜ֖ȱ6no‹çXw´År¬;Û¢9ÖÆ]m‘kãî¶pŽj÷´…r¬{Û‚9ÖÆ}mkãþ6Ž×kǵùrW¶ys¬‡Ú<9ÖÆÃmîkã‘6WŽµñh›3ÇÚx¬Í‘cm<Þfϱ6žh³åøôöd›5ÇÚxªÍ’cm<Ýfα6ži3åX϶s|N{®Ícm<ߦϱ6^hÓåX/¶is¬—Ú49ÖÆËmêkã•6UŽµñj›2ÇÚx­M‘cm¼Þ&ϱ6Þh“åXo¶Is¬·Ú$9ÖÆÛmâkã6QŽµñn›0ÇÚx¯Mcm¼ßÆϱ6>hãåX¶qs¬Ú89ÖÆÇmìkã“6VŽµñi3ÇÚø¬‘cm|ÞFÏñmí‹6ZŽµñe5ÇÚøª’cm|ÝFα6¾i#åX߶s|Oû®cm|߆ϱ6~hÃåX?¶as|\{  “»Úø¹ cmü҆ʱ6~mCæX¿µ!r¬ßÛà9ÖÆm°kãÏ6hŽµñW$ÇÚø» œcmüÓʱ6þmæXŒÝr¬ó?êûü\(ÿ'ÇÚ8ÿ;ÇÚ$ÿ+ÇÚ4ÿ3ÇÚ,ÿ#ÇÚ<ÿ=ÇÚ"ÿ-ÇÚ2ÿ5ÇÚ*ÿ%ÇÚ:ÿ9ÇÚ&ÿ)ÇÚ6ÿ1ÇÚ.ÿ!ÇÚ>ÿ>ÇÚ!ÿ.ÇÚ1ÿ6ÇÚ)ÿ&ÇÚ9ÿ:ÇÚ%ÿ*ÇÚ5ÿ2ÇÚ-ÿ"ÇÚ=ÿ<ÇÚ#ÿ,Çÿµ‘šcmŒ•’cmŒœcmŒ“”cmŒ›˜cmŒ—cmŒŸ¿ŸcmL¿—cmL˜¿›cmL”¿“cmLœ¿cmL’¿•cmLš¿™cMüÔÞÈ]mLÞÏ_ϱ6¦È_˱6¦Ì_ͱ6¦Ê_ɱ6¦Î_α6¦É_ʱ6¦Í_̱6¦Ë_ȱ6¦ÏŸÏ±6fȟ˱6f̟ͱ6fjÏäX3·§s¬YÚS9ÖƬíÉkc¶öDŽµ1{{<ÇÚ˜£=–cmÌÙͱ6æjäXs·‡s¬yÚC9ÖƼíÁkc¾ö@Žµ1»?ÇÚX Ý—cm,Øîͱ6j÷äX ·»s¬EÚ]9ÖÆ¢íÎkc±vGŽµ±x»=ÇÚX¢Ý–cm,Ùnͱ6–j·äx̶t»9ÇÚX¦Ý”cm,Ûṉ6–k7äXË·ës¬Úu9ÖÆŠíÚkc¥vMŽµ±r»:ÇÚX¥]•cm¬Ú®Ì±6VkWäX«·Ës¬‰Éº—å®6Öl—æXkµKr¬µÛÅ9ÖÆ:í¢kcÝvaŽµ±^» ÇÚX¿ŸcmlÐÎ˱66lçæXµsr¬ÛÙ9ÖÆ&í¬kcÓvfŽµ±Y;#ÇÚø¿vzŽµ±y;-ÇÚØ¢šcmlÙNɱ6¶j'çX[·“r¬mÚ‰9Öƶí„kc»v|Žµ±};.ÇÚØ¡›cmì؎ɱ6vjGçX;·£r¬]Ú‘9ÖÆ®íˆkc·vxŽµ±{;,ÇÚØ£šcmìÙɱ6öjçX{·ƒr¬}Ú9Öƾí€kc¿¶Žµñ?˱6öoûåX´}s¬Û>9ÖÆAmïkãà¶WŽµqHÛ3ÇÚ8´í‘cmÖvϱ6o»åx²¶FÛ5wµqdÛ%ÇÚ8ªíœcmÝvʱ6Ži;æXǶr¬ãÚö9ÖÆñm»kㄶmŽµqbÛ&ÇÚ8©mcmœÜ¶Ê±6Ni[æX§¶-r¼Y;­mžãÿÚps¬3Úf9ÖÆ™mÓk㬶IŽµqvÛ8ÇÚ8§m”cmœÛ6̱6ÎkäXç·õs¬ Úz9ÖÆ…mÝk㢶NŽµqq[;ÇÚ¸¤­•cm\ÚÖ̱6.kkäX—·Õs¬+Új9ÖÆ•mÕk㪶JŽµqu[9ÇÚ¸¦­”cm\ÛV̱6®k+äX×·ås¬Úr9ÖÆmÙk㦶LŽµqs[:ÇÚ¸¥-•cmÜÚ–Ìñ!í¶¶DŽµq{[<ÇÚ¸£-–cmÜÙÍñ툶Hîjãî¶pŽµqO[(ÇÚ¸·-˜cmÜ×ȱ6îoóçX´ùr¬Û¼9ÖÆCmžkãá6wŽµñH›+ÇÚx´Í™cm<Öæȱ6o³çø´öD›-ǧ·'Û¬9ÖÆSm–kãé6sŽµñL›)ÇÚx¶Í˜cm<×fȱ6žoÓçX/´ér¬Û´9ÖÆKmškãå6uŽµñJ›*ÇÚxµM™cm¼Ö¦È±6^o“çXo´Ér¬7Û¤9ÖÆ[m’kãí6qŽµñN›(ÇÚx·M˜cm¼×&ȱ6ÞoãçX´ñr¬Û¸9ÖÆGmœkãã6vŽµñI+ÇÚø´™cm|ÖÆȱ6>o£çø¶öE-ÇÚø²šcm|ÕFɱ6¾n#çøˆvW)wµñm1ÇÚø®cm|߆ϱ6~hÃåX?¶as¬ŸÚ09ÖÆÏmèkã—6TŽµñk2ÇÚø­ ‘cmüÞϱ6þhƒåX¶AsüDû« ’cmüÝα6þiåXÿ¶s¬Æi9ÖÆ€ù¿öý?ÖÆ@ù?9ÖÆÀùß9ÖÆ ù_9ÖÆ ùŸ9ÖÆ`ù9ÖÆàùï9ÖÆùo9ÖÆù¯9ÖÆPù/9ÖÆÐùÏ9ÖÆ0ùO9ÖÆ°ù9ÖÆpù9ÖÆðù÷9ÖÆùw9Öƈù·9ÖÆHù79ÖÆÈù×9ÖÆ(ùW9Öƨù—9ÖÆhù9ÖÆèùç9ÖÆùg9þ¯üÓkc¬ü“kcìüãkcœü£kcÜüÃkc¼üƒkcüüýkâ›ö^îjcÂ~þnŽµ1QþNŽµ1qþvŽµ1IþVŽµ1iþfŽµ1YþFŽµ1yþzŽµ1EþZŽµ1eþjŽµ1UþJŽµ1uþrŽµ1MþRŽµ1mþbŽµ1]þBŽµ1}þ|Žµ1Cþ\Žµ1cþlŽµ1S{&ÇÚ˜¹=cmÌҞʱ6fmOæX³µ'r¬ÙÛã9ÖÆí±kcÎöhŽµ1W{$ÇÚ˜»=œcmÌÓʱ6æmæXóµr¬ùÛý9ÖÆí¾kcÁvoŽµ±P»'ÇÚX¸Ýcm,Òîʱ6mwæX‹µ;r¬ÅÛí9ÖÆí¶kcÉvkŽµ±T»%Çc¶¥ÛÍ9ÖÆ2í¦kcÙvcŽµ±\»!ÇÚX¾]Ÿcm¬Ð®Ë±6Vl×æXt¯É]m¬Ü®Î±6ViWåX«¶+s¬ÕÚ9ÖÆêíòkcvYŽµ±f»4ÇÚX«]’cm¬Ý.α6ÖiåXë¶ s¬õÚ9ÖÆúíükcƒv^Žµ±a;7ÇÚب“cmlÜÎα66igåX›¶3s¬ÍÚ9ÖÆÿµÓs¬ÍÛi9ÖÆíÔkcËvJŽµ±U;9ÇÚغ”cmlÓṈ6¶m'äXÛµãs¬íÛq9ÖÆíØkcÇvLŽµ±S;:ÇÚع•cmìҎ̱6vmGäX»µÃs¬ÝÛa9ÖÆíÐkcÏvHŽµ±W;8ÇÚØ»”cmìÓ̱6ömäXûµýs¬ÿYŽµ±Û/ÇÚ8 í›cmØöÉñm¥¶wîjãà¶WŽµqHÛ3ÇÚ8´í‘cmÖvϱ6o»åXG´]s¬#Û.9ÖÆQmçkãè¶SŽµqLÛ1ÇÚ8¶ícm׶ϱ6ŽoÛåxƒvBÛ6ÇÚ8±m“cmœÔ¶Î±6Nn[åX§´-s¬SÛ9ÖÆimóÿ׆›cmœÑ6˱6Îl›æXgµMr¬³ÛÆ9ÖÆ9m£kãܶaŽµq^Û ÇÚ8¿­Ÿcm\ÐÖ˱6.lëæXµur¬‹ÛÚ9ÖÆ%m­kãÒ¶fŽµqY[#ÇÚ¸¼­žãÝÛmµkãʶjŽµqU[%ÇÚ¸º­œcm\ÓVʱ6®m+æX×µr¬ëÛò9þ_»¡-—cmÜؖͱ6njËäX7·¥s¼R;¨-•»Ú¸µ-™cmÜ֖ȱ6no‹çXw´År¬;Û¢9ÖÆ]m‘kãî¶pŽµqO[(ÇÚ¸·-˜cmÜ×ȱ6îoóçX´ùr¬Û¼9>¡=Ôæɱ6nsçX´¹r¬GÛœ9ÖÆcmŽkãñ6{ŽµñD›-ǧ·'Û¬9ÖÆSm–kãé6sŽµñL›)ÇÚx¶Í˜cm<×fȱ6žoÓçX/´ér¬Û´9ÖÆKmškãå6uŽµñJ›*ÇÚxµM™cm¼Ö¦È±6^o“çXo´Ér¬7Û¤9ÖÆ[m’kãí6qŽµñN›(ÇÚx·M˜cm¼×&ȱ6ÞoãçX´ñr¬Û¸9¾¡}ÔÆɱ6>ncçXŸ´±r¬OÛ˜9>¨ÝÒÆÈ]m|ÞFϱ6¾h£åX_¶Qs¬¯Ú(9ÖÆ×mäkã›6RŽµñm1ÇÚø®cm|߆ϱ6~hÃåX?¶as¬ŸÚ09ÖÆÏmè?Ô~iCåX¿¶!s¬ßÚ9ÖÆïmðkã6XŽµñg4ÇÚø« ’cmüÝα6þiåXÿ¶s¬Æm9ÖÆ€ù¿ôý?ÖÆ@ù?9ÖÆÀùß9ÖÆ ù_9ÖÆ ùŸ9ÖÆ`ù9ÖÆàùï9ÖÆùo9ÖÆù¯9ÖÆPù/9ÖÆÐùÏ9ÖÆ0ùO9ÖÆ°ù9ÖÆpù9ÖÆðù÷9ÖÆùw9Öƈù·9ÖÆHù79ÖÆÈù×9ÖÆ(ùW9Öƨù—9ÖÆhù9ÖÆèùç9ÖÆùg9þ¯üÓkâ³öI>`›üñqÇþÑ=ǾÆsÜ/å ÷Ë< Çãu9¿Ëñ]Ž'ìr†Œ3aÊŒ9w,X²bÍ=¶<°ã‘'ö8râÌ…+ϼðÊÀ×Oa"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:téÑgÀc&L™1çŽKV¬¹gÖv<òÄžGNœ¹på™^¹øú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡.=ú 2bÌ„)3æܱ`ÉŠ5÷lØòÀŽGžØsàȉ3®<óÂ+7oÖOa"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:téÑgÀc&L™1çŽKV¬¹gÖv<òÄžGNœ¹på™^¹é'Hˆ0¢Äˆ“ IŠ4²äÈS H‰2ªÔ¨Ó I‹6ºôè3`Ȉ1¦Ì˜sÇ‚%+ÖܳaË;ybÏ#'Î\¸òÌ ¯Üü3ú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡.=ú 2bÌ„)3æܱ`ÉŠ5÷lØòÀŽGžØsàȉ3®<óÂ+7R?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐ¥GŸCFŒ™0eÆœ;,Y±æž [ØñÈ{9qæ•g^xåFà-ú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡.=ú 2bÌ„)3æܱ`ÉŠ5÷lØòÀŽGžØsàȉ3®<óÂ+7aý &B”q$I‘&C–y +)Q¦B•u4iѦC—} 1f”sîX°dÅš{6ly`Ç#Oì9päÄ™ Wžyá•V?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐ¥GŸCFŒ™0eÆœ;,Y±æž [ØñÈ{9qæ•g^xåFàOé'Hˆ0¢Äˆ“ IŠ4²äÈS H‰2ªÔ¨Ó I‹6ºôè3`Ȉ1¦Ì˜sÇ‚%+ÖܳaË;ybÏ#'Î\¸òÌ ¯Ü¼U?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐ¥GŸCFŒ™0eÆœ;,Y±æž [ØñÈ{9qæ•g^xåF ¢Ÿ !ÂDˆ#N‚$)ÒdÈ’#O"%ÊT¨R£Nƒ&-Útèңπ!#ÆL˜2cÎ –¬Xsφ-ìxä‰=Žœ8sáÊ3/¼r#ðÏé'Hˆ0¢Äˆ“ IŠ4²äÈS H‰2ªÔ¨Ó I‹6ºôè3`Ȉ1¦Ì˜sÇ‚%+ÖܳaË;ybÏ#'Î\¸òÌ ¯Üüiý &B”q$I‘&C–y +)Q¦B•u4iѦC—} 1f”sîX°dÅš{6ly`Ç#Oì9päÄ™ Wžyá•·é'Hˆ0¢Äˆ“ IŠ4²äÈS H‰2ªÔ¨Ó I‹6ºôè3`Ȉ1¦Ì˜sÇ‚%+ÖܳaË;ybÏ#'Î\¸òÌ ¯ÜDõ$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›]zô0dĘ Sf̹cÁ’kîÙ°å<±çÀ‘g.\yæ…Wnþyý &B”q$I‘&C–y +)Q¦B•u4iѦC—} 1f”sîX°dÅš{6ly`Ç#Oì9päÄ™ Wžyá•?£Ÿ !ÂDˆ#N‚$)ÒdÈ’#O"%ÊT¨R£Nƒ&-Útèңπ!#ÆL˜2cÎ –¬Xsφ-ìxä‰=Žœ8sáÊ3/¼r#ðvý &B”q$I‘&C–y +)Q¦B•u4iѦC—} 1f”sîX°dÅš{6ly`Ç#Oì9päÄ™ Wžyᕘ~‚„!JŒ8 ’¤H“!KŽ<Š”(S¡J: š´hÓ¡K>†Œ3aÊŒ9w,X²bÍ=¶<°ã‘'ö8râÌ…+ϼðÊÀ¿ Ÿ !ÂDˆ#N‚$)ÒdÈ’#O"%ÊT¨R£Nƒ&-Útèңπ!#ÆL˜2cÎ –¬Xsφ-ìxä‰=Žœ8sáÊ3/¼r#ðgõ$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›]zô0dĘ Sf̹cÁ’kîÙ°å<±çÀ‘g.\yæ…WnÞ¡Ÿ !ÂDˆ#N‚$)ÒdÈ’#O"%ÊT¨R£Nƒ&-Útèңπ!#ÆL˜2cÎ –¬Xsφ-ìxä‰=Žœ8sáÊ3/¼r#×Oa"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:téÑgÀc&L™1çŽKV¬¹gÖv<òÄžGNœ¹på™^¹øsú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡.=ú 2bÌ„)3æܱ`ÉŠ5÷lØòÀŽGžØsàȉ3®<óÂ+7^?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐ¥GŸCFŒ™0eÆœ;,Y±æž [ØñÈ{9qæ•g^xåFàú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡.=ú 2bÌ„)3æܱ`ÉŠ5÷lØòÀŽGžØsàȉ3®<óÂ+7 ý &B”q$I‘&C–y +)Q¦B•u4iѦC—} 1f”sîX°dÅš{6ly`Ç#Oì9päÄ™ Wžyá•Q?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐ¥GŸCFŒ™0eÆœ;,Y±æž [ØñÈ{9qæ•g^xåFà/è'Hˆ0¢Äˆ“ IŠ4²äÈS H‰2ªÔ¨Ó I‹6ºôè3`Ȉ1¦Ì˜sÇ‚%+ÖܳaË;ybÏ#'Î\¸òÌ ¯Ü¼K?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐ¥GŸCFŒ™0eÆœ;,Y±æž [ØñÈ{9qæ•g^xåF ©Ÿ !ÂDˆ#N‚$)ÒdÈ’#O"%ÊT¨R£Nƒ&-Útèңπ!#ÆL˜2cÎ –¬Xsφ-ìxä‰=Žœ8sáÊ3/¼r#ðõ$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›]zô0dĘ Sf̹cÁ’kîÙ°å<±çÀ‘g.\yæ…Wnþ’~‚„!JŒ8 ’¤H“!KŽ<Š”(S¡J: š´hÓ¡K>†Œ3aÊŒ9w,X²bÍ=¶<°ã‘'ö8râÌ…+ϼðÊÀ»õ$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›]zô0dĘ Sf̹cÁ’kîÙ°å<±çÀ‘g.\yæ…WnRú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡.=ú 2bÌ„)3æܱ`ÉŠ5÷lØòÀŽGžØsàȉ3®<óÂ+7ÿ’~‚„!JŒ8 ’¤H“!KŽ<Š”(S¡J: š´hÓ¡K>†Œ3aÊŒ9w,X²bÍ=¶<°ã‘'ö8râÌ…+ϼðÊÀ_ÖOa"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:téÑgÀc&L™1çŽKV¬¹gÖv<òÄžGNœ¹på™^¹x~‚„!JŒ8 ’¤H“!KŽ<Š”(S¡J: š´hÓ¡K>†Œ3aÊŒ9w,X²bÍ=¶<°ã‘'ö8râÌ…+ϼðÊ@Z?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐ¥GŸCFŒ™0eÆœ;,Y±æž [ØñÈ{9qæ•g^xåFà_ÖOa"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:téÑgÀc&L™1çŽKV¬¹gÖv<òÄžGNœ¹på™^¹ø+ú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡.=ú 2bÌ„)3æܱ`ÉŠ5÷lØòÀŽGžØsàȉ3®<óÂ+7ïÕOa"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:téÑgÀc&L™1çŽKV¬¹gÖv<òÄžGNœ¹på™^¹Èè'Hˆ0¢Äˆ“ IŠ4²äÈS H‰2ªÔ¨Ó I‹6ºôè3`Ȉ1¦Ì˜sÇ‚%+ÖܳaË;ybÏ#'Î\¸òÌ ¯Üü+ú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡.=ú 2bÌ„)3æܱ`ÉŠ5÷lØòÀŽGžØsàȉ3®<óÂ+7U?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐ¥GŸCFŒ™0eÆœ;,Y±æž [ØñÈ{9qæ•g^xåFà}ú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡.=ú 2bÌ„)3æܱ`ÉŠ5÷lØòÀŽGžØsàȉ3®<óÂ+7Yý &B”q$I‘&C–y +)Q¦B•u4iѦC—} 1f”sîX°dÅš{6ly`Ç#Oì9päÄ™ Wžyá•U?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐ¥GŸCFŒ™0eÆœ;,Y±æž [ØñÈ{9qæ•g^xåFà_ÓOa"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:téÑgÀc&L™1çŽKV¬¹gÖv<òÄžGNœ¹på™^¹x¿~‚„!JŒ8 ’¤H“!KŽ<Š”(S¡J: š´hÓ¡K>†Œ3aÊŒ9w,X²bÍ=¶<°ã‘'ö8râÌ…+ϼðÊ@N?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐ¥GŸCFŒ™0eÆœ;,Y±æž [ØñÈ{9qæ•g^xåFà_×Oa"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:téÑgÀc&L™1çŽKV¬¹gÖv<òÄžGNœ¹på™^¹økú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡.=ú 2bÌ„)3æܱ`ÉŠ5÷lØòÀŽGžØsàȉ3®<óÂ+7ÐOa"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:téÑgÀc&L™1çŽKV¬¹gÖv<òÄžGNœ¹på™^¹Èë'Hˆ0¢Äˆ“ IŠ4²äÈS H‰2ªÔ¨Ó I‹6ºôè3`Ȉ1¦Ì˜sÇ‚%+ÖܳaË;ybÏ#'Î\¸òÌ ¯Üüuý &B”q$I‘&C–y +)Q¦B•u4iѦC—} 1f”sîX°dÅš{6ly`Ç#Oì9päÄ™ Wžyá•¿¡Ÿ !ÂDˆ#N‚$)ÒdÈ’#O"%ÊT¨R£Nƒ&-Útèңπ!#ÆL˜2cÎ –¬Xsφ-ìxä‰=Žœ8sáÊ3/¼r#ðAý &B”q$I‘&C–y +)Q¦B•u4iѦC—} 1f”sîX°dÅš{6ly`Ç#Oì9päÄ™ Wžyá•‚~‚„!JŒ8 ’¤H“!KŽ<Š”(S¡J: š´hÓ¡K>†Œ3aÊŒ9w,X²bÍ=¶<°ã‘'ö8râÌ…+ϼðÊÀ¿¡Ÿ !ÂDˆ#N‚$)ÒdÈ’#O"%ÊT¨R£Nƒ&-Útèңπ!#ÆL˜2cÎ –¬Xsφ-ìxä‰=Žœ8sáÊ3/¼r#ð7õ$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›]zô0dĘ Sf̹cÁ’kîÙ°å<±çÀ‘g.\yæ…Wn>¤Ÿ !ÂDˆ#N‚$)ÒdÈ’#O"%ÊT¨R£Nƒ&-Útèңπ!#ÆL˜2cÎ –¬Xsφ-ìxä‰=Žœ8sáÊ3/¼r#PÔOa"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:téÑgÀc&L™1çŽKV¬¹gÖv<òÄžGNœ¹på™^¹ø7õ$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›]zô0dĘ Sf̹cÁ’kîÙ°å<±çÀ‘g.\yæ…Wnþ–~‚„!JŒ8 ’¤H“!KŽ<Š”(S¡J: š´hÓ¡K>†Œ3aÊŒ9w,X²bÍ=¶<°ã‘'ö8râÌ…+ϼðÊÀ‡õ$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›]zô0dĘ Sf̹cÁ’kîÙ°å<±çÀ‘g.\yæ…WnJú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡.=ú 2bÌ„)3æܱ`ÉŠ5÷lØòÀŽGžØsàȉ3®<óÂ+7ÿ–~‚„!JŒ8 ’¤H“!KŽ<Š”(S¡J: š´hÓ¡K>†Œ3aÊŒ9w,X²bÍ=¶<°ã‘'ö8râÌ…+ϼðÊÀßÖOa"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:téÑgÀc&L™1çŽKV¬¹gÖv<òÄžGNœ¹på™^¹øˆ~‚„!JŒ8 ’¤H“!KŽ<Š”(S¡J: š´hÓ¡K>†Œ3aÊŒ9w,X²bÍ=¶<°ã‘'ö8râÌ…+ϼðÊ@Y?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐ¥GŸCFŒ™0eÆœ;,Y±æž [ØñÈ{9qæ•g^xåFàßÖOa"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:téÑgÀc&L™1çŽKV¬¹gÖv<òÄžGNœ¹på™^¹ø;ú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡.=ú 2bÌ„)3æܱ`ÉŠ5÷lØòÀŽGžØsàȉ3®<óÂ+7ÕOa"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:téÑgÀc&L™1çŽKV¬¹gÖv<òÄžGNœ¹på™^¹¨è'Hˆ0¢Äˆ“ IŠ4²äÈS H‰2ªÔ¨Ó I‹6ºôè3`Ȉ1¦Ì˜sÇ‚%+ÖܳaË;ybÏ#'Î\¸òÌ ¯Üü;ú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡.=ú 2bÌ„)3æܱ`ÉŠ5÷lØòÀŽGžØsàȉ3®<óÂ+7W?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐ¥GŸCFŒ™0eÆœ;,Y±æž [ØñÈ{9qæ•g^xåFàcú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡.=ú 2bÌ„)3æܱ`ÉŠ5÷lØòÀŽGžØsàȉ3®<óÂ+7Uý &B”q$I‘&C–y +)Q¦B•u4iѦC—} 1f”sîX°dÅš{6ly`Ç#Oì9päÄ™ Wžyá•¿§Ÿ !ÂDˆ#N‚$)ÒdÈ’#O"%ÊT¨R£Nƒ&-Útèңπ!#ÆL˜2cÎ –¬Xsφ-ìxä‰=Žœ8sáÊ3/¼r#ð÷õ$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›]zô0dĘ Sf̹cÁ’kîÙ°å<±çÀ‘g.\yæ…Wn>®Ÿ !ÂDˆ#N‚$)ÒdÈ’#O"%ÊT¨R£Nƒ&-Útèңπ!#ÆL˜2cÎ –¬Xsφ-ìxä‰=Žœ8sáÊ3/¼r#PÓOa"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:téÑgÀc&L™1çŽKV¬¹gÖv<òÄžGNœ¹på™^¹øwõ$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›]zô0dĘ Sf̹cÁ’kîÙ°å<±çÀ‘g.\yæ…Wnþ~‚„!JŒ8 ’¤H“!KŽ<Š”(S¡J: š´hÓ¡K>†Œ3aÊŒ9w,X²bÍ=¶<°ã‘'ö8râÌ…+ϼðÊÀ'ô$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›]zô0dĘ Sf̹cÁ’kîÙ°å<±çÀ‘g.\yæ…Wnêú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡.=ú 2bÌ„)3æܱ`ÉŠ5÷lØòÀŽGžØsàȉ3®<óÂ+7ÿP?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐ¥GŸCFŒ™0eÆœ;,Y±æž [ØñÈ{9qæ•g^xåFàé'Hˆ0¢Äˆ“ IŠ4²äÈS H‰2ªÔ¨Ó I‹6ºôè3`Ȉ1¦Ì˜sÇ‚%+ÖܳaË;ybÏ#'Î\¸òÌ ¯Ü|R?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐ¥GŸCFŒ™0eÆœ;,Y±æž [ØñÈ{9qæ•g^xåF ¡Ÿ !ÂDˆ#N‚$)ÒdÈ’#O"%ÊT¨R£Nƒ&-Útèңπ!#ÆL˜2cÎ –¬Xsφ-ìxä‰=Žœ8sáÊ3/¼r#ðïé'Hˆ0¢Äˆ“ IŠ4²äÈS H‰2ªÔ¨Ó I‹6ºôè3`Ȉ1¦Ì˜sÇ‚%+ÖܳaË;ybÏ#'Î\¸òÌ ¯Üücý &B”q$I‘&C–y +)Q¦B•u4iѦC—} 1f”sîX°dÅš{6ly`Ç#Oì9päÄ™ Wžyá•Oé'Hˆ0¢Äˆ“ IŠ4²äÈS H‰2ªÔ¨Ó I‹6ºôè3`Ȉ1¦Ì˜sÇ‚%+ÖܳaË;ybÏ#'Î\¸òÌ ¯Ü4õ$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›]zô0dĘ Sf̹cÁ’kîÙ°å<±çÀ‘g.\yæ…Wnþ}ý &B”q$I‘&C–y +)Q¦B•u4iѦC—} 1f”sîX°dÅš{6ly`Ç#Oì9päÄ™ Wžyá•¢Ÿ !ÂDˆ#N‚$)ÒdÈ’#O"%ÊT¨R£Nƒ&-Útèңπ!#ÆL˜2cÎ –¬Xsφ-ìxä‰=Žœ8sáÊ3/¼r#ðiý &B”q$I‘&C–y +)Q¦B•u4iѦC—} 1f”sîX°dÅš{6ly`Ç#Oì9päÄ™ Wžyá•–~‚„!JŒ8 ’¤H“!KŽ<Š”(S¡J: š´hÓ¡K>†Œ3aÊŒ9w,X²bÍ=¶<°ã‘'ö8râÌ…+ϼðÊÀ Ÿ !ÂDˆ#N‚$)ÒdÈ’#O"%ÊT¨R£Nƒ&-Útèңπ!#ÆL˜2cÎ –¬Xsφ-ìxä‰=Žœ8sáÊ3/¼r#ðOõ$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›]zô0dĘ Sf̹cÁ’kîÙ°å<±çÀ‘g.\yæ…Wn>£Ÿ !ÂDˆ#N‚$)ÒdÈ’#O"%ÊT¨R£Nƒ&-Útèңπ!#ÆL˜2cÎ –¬Xsφ-ìxä‰=Žœ8sáÊ3/¼r#ÐÖOa"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:téÑgÀc&L™1çŽKV¬¹gÖv<òÄžGNœ¹på™^¹øõ$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›]zô0dĘ Sfü¡7¼á oäxoæ-¼•·ñvÞÁ;yïæ=¼—÷ñ~>Àùæ#|”ñq|½ÁS𠮃op$¼ÁX¼á³|ŽÏó¾È—ø2_á«|¯ó ¾É·ø6ßá»|ïóþo~Äù ?ågüœ_ðK~ůù ¿åwüž7¾Q?oâͼ…·ò6ÞÎ;x'ïâݼ‡÷ò>ÞÏø âÃ|„ò1>Î'ø$ŸâÓ|†Ïò9>Ïø"_â¿æ+|•¯ñu¾Á7ùßæ;|—ïñ}~Àù?æ'ü”Ÿñs~Á/ù¿æ7ü–ßñ{ÞÐÏ›x3oá­¼·óÞÉ»x7ïá½¼÷ó>ȇø0áïñ1>Î'ø$ŸâÓ|†Ïò9>Ïø"_âË|…¯ò5¾Î7ø&ßâÛ|‡ïò=¾Ïø!?âÇü„Ÿò3~Î/ø%¿â×ü†ßò;~Ïm‚?àM¼™·ðVÞƟ㼓wñnÞÃ{yïç|ña>ÂGùç|’Oñi>ÃgùŸç |‘/ñe¾ÂWù_ç|“oñm¾Ãwùßçüñc~ÂOù?çü¿üŠ_ó~Ëïø=oüÃúyoæ-¼•·ñvÞÁ;yïæ=¼—÷ñ~>Àùæ#|”ñq>Á'ùŸæ3|–Ïñy¾Àù_æ+|•¯ñu¾Á7ùÿ+ßá»|ïó~Èø1?á§üŒŸó ~ɯø5¿á·üŽßóÆ?ÐÏ›x3oá­¼·óÞÉ»x7ïá½¼÷ó>ȇø0á£|Œó >ɧø4Ÿá?ás|ž/ðE¾Ä—ù +_åk|oðM¾Å·ùßå{|ŸðC~Äù ?ågüœ_ðK~ůù ¿åwüž7þý¼‰7óÞÊÛx;ï་wóÞËûøë|€ò!>ÌGø(ãã|‚Oò)>Ígø,Ÿãó|/ò%¾ÌWø*_ãë|ƒoò-¾Íwø.ßãûü€ò#~ÌOø)?ãçü‚_ò+~Íoø-¿ã÷¼ñ¾á œ7ñfÞÂ[yo缓wñnÞÃ{yïç|ña>ÂGùç|’Oñi>ÃgùŸç |‘/ñe¾ÂWù_ç|“oñm¾Ãwùßçüñÿð~ÊÏø9¿à—üŠ_ó~Ëïø=oücÖŸ7ñfÞÂ[yo缓wñnÞÃ{yïç|ña>ÂGùç|’Oñi>ÃgùŸç |‘/ñe¾ÂÇ×ø:ßà›|‹oó¾Ë÷ø>?à‡üˆó~ÊÏø9¿à—üŠ_ó~Ëïø=o|“~ÞÄ›y oåm¼wðNÞÅ»yïå}¼ŸðA>ćùåcüC>Á'ùŸæ3|–Ïñy¾Àù_æ+|•¯ñu¾Á7ùßæ;|—ïñ}~Àù?æ'ü”Ÿñs~Á/ù¿æ7ü–ßñ{ÞÔÏ›x3oá­¼·óþ"ïâݼ‡÷ò>ÞÏø âÃ|„ò1>Î'ø$ŸâÓ|†Ïò9>Ïø"_âË|…¯ò5¾Î7ø&ßâÛ|‡ïò=¾Ïø!?âÇü„Ÿò3~Î/ø%¿âÿã7ü–ßñ{ÞøÇõó&ÞÌ[x+oãí¼ƒwò.ÞÍ{x/ïãý|€ò!>ÌGø(ãã|‚Oò)>Ígø,Ÿãó|/þÿ Ùñë |çeì$å•íìò–u¶¼²]Þ²;oYÙòÊvvyË:[^ÙÎ.oYgË@Ö—°!$Ã@–„ !F²,lIÙ0’e!KÂÆ’a K† YRÏÏðú¼ü0`Ȉ1¦Ì˜³`ÉŠ_cÖ{9ñÍ™ WnÜyðäÅ›¿V?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐåçéÑgÀc&L™1gÁ’k6lÙ±çÀ‘ßœ¹påÆO^¼ùé'Hˆ0¢Äˆ“ IŠ4²äÈó)Q¦B•u4iѦC—/zô0dĘ SfÌY°dÅš [vì9päÄ7g.\¹qçÁ“o>~¿~‚ü a"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:tù¢GŸCFŒ™0eÆœKV¬Ù°eÇžGNüg.\¹qçÁ“o>þ:ý &B”q$I‘&C–y +)Q¦B•u4iѦC—/zô0dĘ ¿ÌŒ9 –¬X³aËŽ=ŽœøæÌ…+73aÊŒ9 –¬X³á×Ù±çÀ‘ßœ¹påÆO^¼ùøAý &B”q$I‘&C–y +)Q¦B•u4iѦC—/zü†Œ3aÊŒ9 –¬X³aËŽ=ŽœøæÌ…+73aÊŒ9 –¬X³aËŽ=ŽœøæÌ…+73aÊŒ9 ~•k6lÙ±çÀ‘ßœ¹påÆO^¼ùø[ô$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›Ÿ£Ë=ú 2bÌ„)3æ,X²b͆-;ö8râ›3®Ü¸óàÉ‹7«~‚„!JŒ8 ’¤H“!Ë“§@‘e*T©Q§A“m:tù¢GŸCFŒ™0eÆœKV¬Ù°eÇžGN|sæ•w’ú "L„(1â$H’"M†,9ò(R¢L…*5êü MZ´éÐå‹} 1f”s,Y±fÖ{9ñÍ™ WnÜyðäÅ›¿K?AB„‰%FœI~”4²äÈS H‰2ªÔ¨Ó I‹6º|ѣπ!#ÆL˜2c΂%+ÖlزcÏ#'¾9sáÊ;žüo>~D?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐå‹} 1f”s,Y±fï³cÏ#'¾9sáÊ;ž¼xó!ðGõ$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›]¾èñ 2bÌ„)3æ,X²b͆-;ö8râ›3®Ü¸óàÉ‹7)ý &B”q$I‘&C–y +ùIÊT¨R£Nƒ&-ÚtèòE>†Œ3aÊŒ9 –¬X³aËŽ=ŽœøæÌ…+7îÒú "L„(1â$H’"Í‘%GžEJ”©P¥FMZ´éÐå‹} 1f”s,Y±fÖ{9ñÍ™ WnÜyðäÅ›ß÷Çõó &B”q$I‘&C–y +)Q¦B•u4iѦC—/zô0dĘ SfÌY°dÅš [vüŽœøæÌ…+7îþ^ý &B”q$I‘&C–y +)Q槨R£Nƒ&-ÚtèòE>†Œ3aÊŒ9 –¬X³aËŽ=ŽœøæÌ…+7îþ>ý &B”q$I‘&C–y +)Q¦B•u4iѦC—/zô0dĘ SfÌYð«¬X³aËŽ=ŽœøæÌ…+73aÊŒ9 –¬X³aËŽ=ŽœøæÌ…+73aÊŒ9 –¬X³aËŽ=~“ßœ¹påÆO^¼ùøSö'Hˆ0¢Äˆ“ IŠ4²äÈS H‰2ªÔ¨Ó I‹6º|ѣπ!#~‰ SfÌY°dÅš [vì9päÄ7g.\¹qçÁ“o>~L?AB„‰%FœIR¤É%GžEJ”©P姩ӠI‹6º|ѣπ!#ÆL˜2c΂%+ÖlزcÏ#'¾9sáÊ;ž¼xó!ð÷ë'Hˆ0¢Äˆó#$I‘&C–y +)Q¦B•u4iѦC—/zô0dĘ SfÌY°dÅš [vì9päÄ7g.\¹qçwyòâ͇@N?AB„‰%FœIR¤É%GžEJ”©P¥FMZ´éÐå‹} 1f”s,YñklزcÏ#'¾9sáÊ;ž¼xó!ðè'Hˆ0¢Äˆ“ IŠ4²äÈS H‰2ªÔ¨Ó I‹6ºü<=ú 2bÌ„)3æ,X²b͆-;ö8râ›3®Ü¸óàÉ‹7ÿ ~‚„!JŒ8 ’¤H“!KŽ~\?AB„‰%FœI~”4²äÈS H‰2ªÔ¨Ó I‹6º|ѣπ!#ÆL˜2c΂%+ÖlزcÏ#'¾9sáÊ;žüo>þý &B”q$I‘&C–y +)Q¦B•u4iѦC—/zô0dĘ SfÌY°dÅš ¿ÎŽ=ŽœøæÌ…+7ø%&L™1gÁ’k6lÙ±çÀ‘ßœ¹påÆO^¼ùø§ô$D˜QbÄI$Eš Yrä)P¤D™ +U~š: š´hÓ¡Ë=ú 2bÌ„)3æ,X²b͆-;ö8râ›3®Ü¸óàÉ‹7ý &B”q~„$)ÒdÈ’#O"%ÊT¨R£Nƒ&-ÚtèòE>†Œ3aÊŒ9 –¬X³aËŽ=ŽœøæÌ…+7îü.O^¼ùø§õ$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›]¾èÑgÀc&L™1gÁ’¿Æ†-;ö8râ›3®Ü¸óàÉ‹7ÿŒ~‚„!JŒ8 ’¤H“!KŽ<Š”(S¡J: š´hÓ¡ËÏӣπ!#ÆL˜2c΂%+ÖlزcÏ#'¾9sáÊ;ž¼xó!ðçõ$D˜QbÄI$Eš Yräù Š”(S¡J: š´hÓ¡Ë=ú 2bÌ„)3æ,X²b͆-;ö8râ›3®Ü¸óàÉ‹7UýùAÂDˆ#N‚$)ÒdÈ’#O"%ÊT¨R£Nƒ&-ÚtèòE>†Œ3aÊŒ9 –¬X³aËŽ=Žœø-Î\¸rã΃'/Þ|ü³ú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡._ôè3`Ȉ1~™s,Y±fÖ{9ñÍ™ WnÜyðäÅ›ŸÒOa"D‰'A’i2dÉ‘§@‘e*T©QçghÒ¢M‡._ôè3`Ȉ1¦Ì˜³`ÉŠ5¶ìØsàȉoÎ\¸rã΃'/Þ|üsú "L„(1â$Hò£¤É%GžEJ”©P¥FMZ´éÐå‹} 1f”s,Y±fÖ{9ñÍ™ WnÜyðä÷xó!PÓOa"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:tù¢GŸCFŒ™0eÆœKV¬ÙðëìØsàȉoÎ\¸rã΃'/Þ|üý &B”q$I‘&C–y +)Q¦B•u4iѦC—/zü†Œ3aÊŒ9 –¬X³aËŽ=ŽœøæÌ…+73aÊŒ_aÁ’k6lÙ±çÀ‘ßœ¹påÆO^¼ùøõ$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiÐägiÓ¡Ë=ú 2bÌ„)3æ,X²b͆-;ö8râ›3®Ü¸óàÉ‹7?­Ÿ !ÂDˆ#N‚$)ÒüYrä)P¤D™ +UjÔiФE›]¾èÑgÀc&L™1gÁ’k6lÙ±çÀ‘ßœ¹påÆO^¼ù}Q??@a"D‰'A’i2dÉ‘§@‘e*T©Q§A“m:tù¢GŸCFŒ™0eÆœKV¬Ù°eÇopàȉoÎ\¸rã΃'/Þ|4ô$D˜QbÄI$Eš Yrä)P¤D™ +UjÔiФE›]¾èÑgÀ/2bÌ„)3æ,X²b͆-;ö8râ›3®Ü¸óàÉ‹7ÿ’~‚„!JŒ8 ’¤H“!KŽ<Š”(óST©Q§A“m:tù¢GŸCFŒ™0eÆœKV¬Ù°eÇžGN|sæ•w†Œ3aÊŒ9 ~•k6lÙ±çÀ‘ßœ¹påÆO^¼ùhê'Hˆ0¢Äˆ“ IŠ4²äÈS H‰2ªÔ¨Ó I‹6?G—/zô0dĘ SfÌY°dÅš [vì9päÄ7g.\¹qçÁ“o>þ²~‚„!JŒ8 ’¤H“!Ë“§@‘e*T©Q§A“m:tù¢GŸCFŒ™0eÆœKV¬Ù°eÇžGN|sæ•w†Œ3aÊŒ9 –¬ø56lÙ±çÀ‘ßœ¹påÆO^¼ùø+ú "L„(1â$H’"M†,9ò(R¢L…*5ê4hÒ¢M‡.?O>†Œ3aÊŒ9 –¬X³aËŽ=ŽœøæÌ…+7î,â{ïoÿsrž³Îç³öšÙ3³Ÿ½ÏN–ù[ûϾ~¯û.?àŠgú|še òQW<30È1¾xò…ÙV^>úÂìyáä‚ß>aó•—9˜0õÎ?1•³WqT~±ýó[ëÃއǃ_OŸ´í=Á‘Ï«·~éÚ§ÂíNíæoæäÅü™ƒ¼}~ô•Ö:Tç·O[9{y¥öÁgoŠ,1þùÆÜÇ ßÚÞã¥^5>ùÚë­u.†>?1\÷ûŸèUœì SC>8åÐçï ù˜?{‘3Ç翽gÈ¿žýÔÍV®¼qÀ/G]1Þäüê…ÑVÎ^ÅAÞìuE´ŸcþÕOoñKò*òrý=¶ÝÐAƒ[w;Òú»Ÿwrö*òvïxþ ŽÛO½pG_ ?#¯â wó?$<Îœèø¦¼Šƒ¼Ø+>¿€Ó¬ø‡­õw󼊃<^‚Îwunèø¬¼Šƒ<%>~zŽ›§µþìUäÕÓññüúѧƄ|ä y9¯?¶o~A||Ÿ½ŠƒÜ=¾¢ë +ÏÿÙSc¬íË^ÅAží}ÅÃu ¿øÕ Ñy yNÞ§¤ù7?¾¢ëð•—9ðÎÝÂu ßñ¢òü©øúJqW/Ï?’ºo9wßw_í°xÿozëÆãGåà—ï>úë¸ÊÞ‡çƒy–Þ®{S^æ(/ø<9{Gå˜gþ´þ˜'Ï_yÕ<‘7¯\{G¸ÿƒÃ|åUäÅïc>8Õ°ç'ZÇ ö*ò|Òô[L΀çn ï—ò*òæî÷gZüü¨QÑu£_7ò*òìѵnµøåûóßoåìUŸó‚öŽõñyóg¯â o÷‰¯ÀÉ&Ù×oìU•ƒßŽk²Ö‡½Šƒ¼Ø×>?fOÇÇyåUäÙ‹£¯´æY +>{yóG›_ÝgŸßÙ«8>ßü’“¬ëÏ–®±>ìUœ¦w>ªî1Æâ×;Æç/ðÙ«8ðªí[kŸ¶¶ {yîöŸnrÁ­û<Âm_+g¯â Ï®)gZçÙlÅŧZëV‘Wqsï„œ{$wÿ:÷‹½j9­¿ÏŠ×_yýx⤼å7¶™ÎßsÈ›â¸ß‹n˜gNëãu¯g„7‚¸oà­DOUŸûA4åMq2ê‹0Ïú£Ë¯°Ö‡½¯8Üa|yÍ•—ô¹o‚[g}”WrDOUÜûþù_y¹wróê·z*¿Î¯~ÀZååÞ |î‹|þN|ý–ò*÷Tàd¿u³µ>y1æ ç¾yMûÒ+ú(î‹Ào‰œ½È‡û¢½ÐCöõƒò2ÞV]>_?$½‚£ú¢üÈÁ§XûgK^Ì“9>=Uöˆ}|V^îÀç¾y¹Ú6¿0÷Oòb¼âp_„ñs÷‹/½Ôwaæž +¹óð­{~Ù«8>§ž +üf­æVk}Ø«8ȹ/?’]fñÙ«8ȹ/?_3¿ßâ³7É¡ž +üj‹Æ<¿+oNx¹/?Û0¾~CÎÞ$‡z*p²%ŸÜ3|ÿ€Ï…Wõ]µØÿ+q~a/æÏä­àg›Øç/ö*Nƒç/ÔSùuØÔæ³Wq¼—ú"ð«­ìãFÞ‡û"ð³ÍÅõ§ð2^ÕSÍŸ„›òºŸwÏ¿¢w⾜fjŽÅg/øÌA>w¿²8s·£•³7ÉqèÖ½¿â~±× 3Ç#W}áç~ûïqD5¯|î0Ÿš®‘—#ê‡ë\yÇíçÑu8Íp›/½‚£æÓn?gš5åUœZôHíàuÌ÷+¯ä~y@ýãñ¤:ûô*Žê©¶^狯¼ªw*EO• ›3ÁZÿVyGõEÍšï¿R^Å)DOÕn7Ÿ9åUÕWt½µþÊ+9¢/ÊÇ͹Öâ+/÷N8Ö¢§jv9Èì¯Ø›âd¢/Ê·[qXøüÈ7„Wr¨§òóÙ슫Âý9{}.8õT˜§Û£×OÁ©…—9~<õTà×ÛÎñ‘K/qÀW}Q5xóï#Ø«8>Ï×òmìã'{9÷EX‡ü¾c×µöö*rî‹òÞy¼ÞÏ>>³Wq»ùò­sœ/†Í™>~sáUä9õENö‰×!ìUäîø=ÏMñùÎ*òŠÎû~Üù7\åUäÜ_m?¾×äUäÜÓŠíË^ÅAÎ=Ö¡üa|}¥¼Šãsê©À/v˜ó@xüDÎ^ÅA®ú¢öÈ«~fñÙ«8>ŸÇã{yF}ÖÁ}å[çq§Ž?Ìÿÿúñ¥ú¢Æ]ÿÌËã‹9˜¿ê‹š-_»Óâ³Wq«¾¨ºôÊÛM>y9÷En£v¶cùÁûQ½Šƒ¼R=ÕWꇬù³7ÅQ=UqL}@_°‡‚““¹âp_„ñ+¯äÐùÅsvŒŸß!WÞJp¸/'XšÎ?‘Â+9ÔÓìŸß‘+/÷N¯zªÚ]_…ûÆ+¯â¸çïvº­ÍW^ÅQ}Qáúkþ¹ð2Çß_ÑSµCìëOååÞ |î‹|N9{‘3Çýú'^§Þ¿ÿœóyåü¿ß¼8æÃ^Ÿ ÷T˜gö×øñå9«8Üáqš»ý¤ÏAqS^äÌAÎ}‘ãu¯?_Ÿ:%\Ÿ”WqÜþõHð6|Þ|ü–äÅ|˜ƒ\õE¹;N†óOy™>÷EÈ‹Ë^4ß¿Ä^ŒWõ|­ í {‘3Ç碧ª_²÷ååÞ)ïí'ª§Ê.qD¸b>ìMq +ê1°V´}ÁW^æøñîá ü0›ûoäÒË¿0×Wàÿ+ƾN˱þԹߟ§ë:ÅA^QOþ§]ÅAÞÒö¿pÇÏðñ‹œ½)Žê‹q¥¼ÌÁ| +zŠ¼ZiÔäpÿo{×uÒ+8ª/Ê®q„¹>äÅ|˜ƒ\7ÜÏ£毼Ÿ–3¯û¹›Ä<íϘgáŽoáúü»^Õe#ˉ!_y1æøœú"̳Úa«->{9÷Eà—ÝrKÈGÎ^ÅAÎ}òâ¥ùù]ìÅxæ`=U_T,0ÝüûJö&9¢§j®1«ÏM7pØësÁQ}QþíX|åUÙ]0Oå•,@ï+8-=¾gÂKß'p_äÆuïõëñó;ð•—9_SO~õr||@®¼Ì_õEÙËÃíþ–¼Šƒùp_Ôà<"ÖGy™/÷Eðº¯Ñ-åeøÄ}çî{ó8¯8j¼ÊçÕ«8©ùԇώÎûŠƒ\õEÍšWÏÏ)¯âdtN}Îzß +ßÿéçC^äÌÁzrO•c;þDZ7YÇ7ö*¼ª/Ê^Yê°pþÊ›äPO…õÉ~µóî!öúœ8>}Q“{“¹}•WpT_Töýpý1ö"WÕµÛ eñ•WqT_Ôœzimñ•—9ØŽª§Êfu‘ÅgoŠ£ú¢lô¥Ñßga•WqTO•Í¼Üì•—9¸_ª§j¯¹ìk}Ø«8Mï<•‹#ùhóïsÙ›âp_„ùä«ýávkþÊ«8ÜS_Ž‰ŸÈÙ‹\qrÑcä/œ°wøþ"p¤WpT_T2Ûü|<öb¿eæ£ú¢êµ/ØÏßÉ›âp_„ù”|áUÕµk_ý}SÊËœ¯ãˆíR~oö=ÖþÉ^ÅAîæÝ°žQØý¦s}Å^Åq¿b^©<åUóù¿Î+±þóêUÕÍ+Ÿ9XÏÆÍßÚOêƒ?ÝufŠ£zªò³ñõ‰»?Ýçe«8Üùù¬c_ß²㙃ùð:ûñôä y§é=~ óñóÖï;<Ü.àóø§ çјOMë~#¼ÌÁxî‹çýúEýOÊËÜ/Õµo¿½^y¹ê‹ÚW¿`_’7ÅQ}Qµó°¨Ãú(¯âp_N=ß±gZû{±nÌA®ú¢ösÇÞòS^Åᾜfóa£ºopÃ|Ø‹œ9ȹ/r¼îqæsöñGy™~+_ =¾”7ÅQ}Q5X<ÿR^ês0ÕSµÃc>橼ÌÁxî‹—#þgV¸}1åeN#z*pêuÅñŸ¼)Žãñí¯[Øë~Ù/ñ>ÕÞŸîü«8Ê‹œ{¤”WçùƒŸ/ðúV¿QŸÐ?ú\ x‡{*ð˵5ß«¼Ì—û"ð«QüŽ5ö*NŽíN=øÙ^\Ýâ³7É¡ž*ä‡ÏïÂÜòrï„û¥zªf”=ÿ¹÷+ô&9ÔSažíoßfÍSyeï¤zªMg¿”WõNª/*Ïï±Åo”Wô]Üa}òzá -¾ôŠ¾KõEeÿÇ£ÇiÊ«8ª/ʾ9Öü|Qå•ÑS5-t²µ>Ê˽î/÷EÈ«U˜Ïß•WqT_Ôþhñ>kþÊË<î¸/òó¿eÁó,>{9÷Eà—ϽiþýcEÞGöE{ÿñ;áq&åUÕSµç÷>¿üBxGöT[-rÝ@ nëåUÕSµÃûUÖö­„WrDOÕì°ù÷•Ê˽“»ßûË}‘Ïÿ㬙Öü•—9د‚õÅ?»Þç½Ñâ—äMq ¾vù­à oðûøg‡ƒo‚¯ÝüÁÞà÷ñÏOæcÔÇ_?Ñûñ0ÿ¯ïÝÿã9ª§*.ˆ¯3mž8ØîÜyÎ>öñ‡½Šƒ\õEÕ>ýµöÏŒ¼ŠƒÜ¯âÇÿè¬Cóü›{Y×WìUäÜa}êo ˆ> 9{“ñ|6Û×^åU}—ꩪ1ý÷7ן¼˜¿âpO…uÈwXè¤o“¹ÿêlåUÕ•G-n¾Iy™ƒûÅ}æ™ÿì|“ÏÞ‡{*ðˉg™Ÿï¡¼Ì—û"ð³vÑK¬õgoŠÃ}øå…ý/¶øÊ«8µè©ªÞÿ–ò*Žê©òõþl¾?Ay™ƒuS}ÑÜëëñÅÞ$‡z*¬Cs`¿C­õW^Õ;©ž*ßi¡û->{1ÅQ}Q±žè7„WqÜzð­sœ™»ÎÖõ³ò2÷KöTË ˜d­{SîÜ<:óç y&¼j¼ê‹ê){n`­O³X}®•+÷E˜g3uoóóm”Wq¸/ÂzòöJy™ƒñª§ª—Z-úüŸ”Wq¸/òÞ½ÝíN^?žz'äÜažå”=[Ûñ_µÝý9૾¨ZÒ^åUÕÕw¼n¿ÿ¼˜§â”¢§ª½¿åUÕSÕ?yf¼uüW^Åá¾Û7;p†Ù¿)/spU_TOØ{³pþ)¯âp_NûÒ–f?À^Ì“9ÈU_ÔüøݨßHy‡û"xÛ¥V³ßÿF^?^õ]Ôa|¹é©—…ë\y¹wÂxÕS•K­v‡ÅW^Å‘}ÑÒ‚/¼Š3÷zf »3Á­{~üJäŠ#û¢—·´ßÿ&øŠ£ú¢âÖ½o3×_x‡û"ìçå-6_y™ãÖ»³ÎÜ!Ÿ{~çŸò*N)ú¢üÖ˜¯¼È§¤¾óÌÅ:+/sàÍDO•?å•'¢[g»P6÷ÛnN^Ÿÿë/|2çi¼ê‹ò¥W»>ÜRódŽO}òÊ]G…|¿þÊ«8¢§jn±÷Oöúù(Žê©–‰çŽòrï„ñª/j79õ p}0¾^Åáž +ëìx|ëìoÊË÷Ëñª/*ÿüËÂù§¼ŠÃ}8õ½—›Ï_Ø‹y2¹ê‹ê« ƒJzUßE=8ÙÓ¿6ÿþ…½˜§êT_äÎ#Ñû[”|æ W}QþJ|}>{Sî©rœ×Ü~®?8ìEÎäÜߺãpÈG^ +/sÀ羜lÙxþÈÙ«8Èç^Y£šæ >{¹ê‹êÛâ~ Û—½Šƒ\õT­»¾ +×ßóɛ⨾¨™Ïö"Wî‹òÞþYßøjôÿ€£¼ÌÁxÕµ·Çë“ò*ŽêTÄ^ÌSW}Qûîo¢ã'8î+ß:çÅQ=U¶ÿ˜‘V¢¼ÌÁþÆ“qßwæÓ¼÷›iáã9{SœZôEíÉ“£Ï_yGÍ?ðŒU6ŒØ=¿ o<ôãÿ›û"ÜßúÈ×ÌÏ¿b/Æ3÷—{*äÅŠG¯¿€£¼Š£ú¢œøÊ‹\qT_T?qCôùà(¯äˆžª8á:³S^î°žÜS!¯~~¾ùþFöb'¯_â8_g*ê©×´þžO^ŒWÕ¹ßã[g>ìuƒºÛKõ]¢/j/ˆ×–"W½÷E9Öm›¯¼ÌÁvQóá\ySÙíucÔŸ;_gÙ‹œ9𪞪8¿ÿÉáþ NN^Åñ9õTà4ÇŒú äìUäÜSåØ߶}Çüüö*rwÞ‰z*̳þùq÷†ë£¼)÷Eàd'L6¯oÙ‹ù(Žê‹Ê³úGÇ7åEÎä­;n‡ë€ùÄG®¼Ì_õEM5ùáOãUlÕµîühñÙ«8>§¾yþð[™ÏÉ‹ñÜwa=[ê©×Ä×?àH¯àp_NùÝ?°óa¶‹ê©ê¥VŽÞ«¼)Žê‹2ZÌ“½ÈGõNî÷øÖ=> /vßwÆ«¾(ë·ë~}Á/5ø{ùíÇ6÷+ÕwQO…uÎ\÷k‡½˜'÷Nȹ/¿¾çÄèù/råeøª§ÊßÝe¿ðñ >{“ÑSÕƒ?ˆž_ƒÃ^ŸÇÏGôTÕ›ÏÞ§=’[çµ­í«¼Š“+þƒó±øÊ«8ª/*ò]w÷¬s&¼’C=Ö3ûÍÁ„ûøÊ«z'Õ#O>?œ¿ò"Wî©üÝ÷¹'™û'{q¿˜/÷Eàçϯ?%œ?ò†¼Š/÷Eà´×¿gòÙ«8ÈUOU.´ëÎáöU^ÅÉq½M=•ÏW[¸ùà°×'ÆsOå×s¹M£ÿwÕs„—9૾¨Í¤;ÍÏß`oŠãxÑ ëP¸ù‡û¿Ô}ž+¼Ä}“÷Æ«¾¨ê;ñ*kýÙ«8ÈU_Ô¸îÎÖñ™½)÷EÖá” o1×GxGõE8?6«8-õ$ؾî~ð­»}…—9î—»ãE_ÔÞco_–*Nþñþ=ÃøbuûøÃ^Åñ¹è‹šv‰®?•7Å©iýÁÉÅ:+¯â8^tÃöu#sÿTÞÒý¦{}N=øí;ñú W^îòÞö­DO•ßkï?ìMqø~ažœ»ï;÷—½ÈåxѵSï<Ó:¾}Z¼Üùü£].²øìõãEßÅ}Æ×½`öy1ž99ŽÔSaý‹m½>{ǧž +yñê%Ñù7é%¼ÜS!oæv/D^Œgæ©ú¢ê¹ƒí×G„—9àËžê/ñãódoŠÃ}Æ»õy0Ü?‘—äE®8ÜSå½ýªØξ¾R^æ`à¾ü’®ß³Wqp¿T_T6ññ |ö*¼ª§júâþö¦8ª/Ê8Òº¾R^É¡¾óiOÚÐüü@åU}—»ßÑ­=’òªñÚ9_p_”cÿüéµu}X?2hÍ{¢ÙÌGöE[î]?+¯â W}Q<ÅÎwÝë=ò¦8ª/ªÝúXÇå•ê©0ŸêQ±þÂ˽“›Gçþª¾¨}h¿}Âù§¼ŠÃ}8ů6ßÃÚOØ‹y2Çç¢/*¶ÚûªpÿLyUï¤ú¢ìþýv ×óa¯Ï©ïÂ|TO•ZÔ~ý¼)Žê‹Ú+–°?ÿAx™Óˆž +ói6þ0ê°ìUäª/ª7Üè.kû²WqsO•ãq±ì¬s¬íË^ÅÁýå¾y=ë®óÂù§¼ÌÁøŒú¢¶·]òÇÄñAx§¤ž +óÏôÕðü¨¼È‡û"ðëéû®rö"Wœ–®s0¾yà.³ÿQ^É}QÛïÎÆš¿òrß…u+¨§Bîøö㋼Ϭ÷EŸ‹ã§ò2|ÕS9¾ùú{Sî‹0ÿìgöþÏ^ϽSC=†çßcŸ•WrÜ›燡û·Ï•—Æ»o;çwî‹ópÏç$8ª§*Åúÿ+¾;OÅQ}Q+øÊ«89m_¬OëŽÖñ_y™ƒõt;³§jnÙï“O^ÅAÎ}æ_‰õaoŠÃ}Æ«í¨¼óÌÙjï±áú(o*W}Q=c¿ C¾_7áUî‹0Ÿâ?/Œþ® +|åeŽO=øm>ë'}ÁF@.½‚Ã=8ùBwVáú —^ÑwqO…ûUη¯ùú){1ž9y︤zªü´þæù½Šƒœû"¬CóØÂæù—½Š“õæ/û¢…âó{Ê+9¢§jfÙ×? y1Oîp¿¸/òãG÷·{äU䥸~+Åõ[CÞ$‡z*Ìß}å[ç|ª¼Ü;¹_îö ÔSa;Vƒâç§ÏRäªwR}Q¾ÆÑßO%½Ôwa<÷Tȳÿ9Ð|£ò2§=î/÷H)/Ï{ë_¨žjè"Q?~;$ÎSœ†ú"Ì¿ØzÂåáñyM^äŠã~Ý0ÏÊqÂã¿ÔÙß”7‚t¿éŒçž +ü‚øÈ•Wq¸§‡çƒ\zEßÅ}8ùVñú#g¯û¾³ŠÃ=8ù°x?ñ¹ð2Þ‚žg!oªAQÿéùäÅxÅQ=U=減­ý“½à+Žê©šÝV¾Þâ+¯âp_„u(~üÖT‹¯¼ŠÃ}øíÕc¢Ï_BÎ^äÌÁºq_„<ßréèó™Áa/Æ3'ïí·•è©š'k­{Sî©0ÏjÛg®ës“ nÝóð*÷Tà×;,ýý)rö"gŽ›Wg>Üa|¶£Íg¯â ç¾üüÍ™?×9{9÷Eào®zi¸þÈÙ«8ȹ§§øÐæ³7ÅQ}Q&ŽoÊËÌSõEÅ —‡ëƒy*¯â¸<ê©ÀiO0ÿŸbåeæŸÑótŸÿ× k„ýªòúñŠC}QÓ»îj‹ó#y=Ÿ8>w o*OzCH÷ßÝÇï§Ì•×ýú'rJµnŸÒ >s·‚ïŽ3æõç¿j{×'Äñ|ê‹nÿ´Ž?ìÅxÕwq_„ñÍ_V½4ä#g/rÅ©Äý*i}g¯â W=U1gäúÖû£2ò¦8ÜS¹;Ó™Cû 8ìE.9ô<ü²ß蛬íË^ŒW½“ê‹Šê„Û,¾ò*÷Eþþ~yôîÖñ_y‡û"/¿êÐpþÊ‹œ9ÈU_T-´ÛPkþð*÷E˜µÈ Y|åUÕSe:Õ\åeÖ‡û¢¼·ÿ×Û/a~¾7{yM×QÈ˿ݽþ«¼¯8Ü“?ºþxkÿa/øÌA®ú¢š¿)/sÀç¾yöö®£¬ý‡½¯8ª/Ê&Nšd­{=Ÿú®¬·Ÿp_„<ÿâ:Ññöb¼âp_Ôàúë9fÅ^𙃼=•ûytKy™ãï/õE9Ö-¢w¾éž7)W?ê©Ü¯w8¥[Ÿpûæ«8ÞKó§ÙzNÔŸ(¯â`<áç~Û™=âôÂó{ÞË•—9)oé®ßÌÇy¹;.E×ó˜g±ˆ}É^ÅÁ:ÔSyþžöú(/sÀW=U>_|}¨¼)NIëƒñùŸ‰Ž>'/rÉ!>Ö³ý‡}ü”^âÀ«zªvÜUÑëË)¯äˆ ûÎ’w„_̇½>Õ5«Í>Ìâ+¯âȾh•sÍ¿/`/Ö9¸_ª/jŽx<º~öò*Æs_„¼:û}­õQ^æ48OQOåçóúûÑÿŸ¨¼)NK×Wà ÛÏ/ròb±òÄpýÁa/Æ3Ûû"?þš££~ 9{Sî©0Ï|ý/è¾Á-Çý^Å©éñ‹ínðµsÞa¯ûy'gî÷E˜g¶ò_£þAyÇçÔSa>ÕwŽ®¯”7ÅQ}Q~tÌW^äÌÁýmEOÕlo_Ï!oŠã~/ºáþóýê&kÿWÞâ¾É{Ûs÷}wø\ÌWÞ‡{*ð«vjÔß"¯É‹œ9ðr_„<{nêÄðñ{1ž9Ï=òŒÎSà(¯âp_NýüÔñÖöe/æ£8Üùíøùøü®¼È™ãsÑSµKöû’u}RoAÜ/î©WoÅ×·˜{1^qT_Tß~vôùKà°9s°ÎÜSažÕÛ÷GŠƒñª/*¯:z\¸ÿ¤¼Š#û¢UûG½(æÃ^äÌÁýR}Qûó3£ë+p +ò¦8¹è‹²Ï¯]_Ã^äŠÃ}æ™msá•áúûœ¼È™¯ì©êo˜ï¿eoŠÃ}Æ·ÏŠësáeî÷EÈËSÛèüžò2ã ê‹gÿ_Ÿ¤¼ÌÁxî‹À¯çŸÈ•Wq¸/jz×ÿy?›¯¼ÌÁ|¸/Bž}!~~šò2ëÃ}QÞ»~ÈÝq><ÿ*¯âøñÔS!oˆ×'éçnX‡Òñ­ù³ó‰ î›ÜS_lbóÙ«8>§¾ü|Ó¥/ÏÈÙ›âp_Žâ«œ9ðªžÊý<º)¯ÔÙŽŠÓRONùÝ·~ší‹ñŠÃ}‘ÿòy&_z©ïÂýjè:üê?—»ÌšK^ÅA®ú¢l«¥÷·øìUœÛ…z*Ì?»êRóïïØ«8ðrO~õÝÝì~¼ŠÓˆž +ür³·£ÏEÎ^Å—û"pŠ‹wˆ^_FÎ^ÅAÎ}8íswL·¶/{'Çö¥ž +übýe¢ç¿ÈÙ«8Èkê‹Ÿ9{ÇMºs\åž +œ|Û%ÇYû{9÷Tà7Ãl>{9÷Eàçcû—}nnÈÙë~ÞYÅ)¨§§Údióù—ò2^î‹À¯·[2zþ‹œ½Šƒœû"pÚ5¿x‰µ}Ù«89öOê©<ÿÛ6Ÿ½Šo&θþiÉ«8ðrO…ù»ß‹nÈÙ›÷ÖAq¸/òœÍìë·Hê¾ÁxæÀË}Æ×ó}8Òê¯ò*ŽSwÔSïöCóú™½Šƒ\õEõ©ýKkÿd¯âä˜?õT˜v„Íg¯âÀË}QÝ;/Û-½¿uüa¯â W}QÖÿWÑßï+oŠ£ú¢ú–ñg˜ó'/Ö“9𪞪2âJkû²Wq|N=æÓ¼1ö<‹Ï^ÅAÞP_„un†ú+åUŒçž +y6h©èýù)/sà垪A?³úœ™Öú°Wqü}Q)øìUäè©‚ýÿìlöÎ+ãó‰çš¯B†¯ïñ9÷EîçyæSÿ´]øøÅxåeÆ«¾(ûÌâ#B~ÊËðÝ~]Ç‚ÓltÎZáþœ½Šƒœû"Ïóvt~DÎ^ÅA.û¢‡¯ˆÎàgäUœ:ÑSåoN2ÿ¾¬$oŠÃ=æSy*úÿq³¹äPO…uȯ_!ú|p”—{'Œç¾y¹à–Ñë)¯â¨žªxî.Öù‹½˜sêÞöåž +ó,7Ú÷L‹Ï^Å—û"Ÿ?r…ùþCåeN“è©šãç/Ê«8XÕ5Íiæç—²Wqàåž +ó,?7èžðú9{^î©Ài8Ü|}‡½Š/÷Eß¼6É|}Š½IõT˜uc|þR^Ÿ ÷E¯®Ø‹ù(÷Eߺù‡ÛWy‘3ëÆ}Æg¯Šõ'¯â`žŽÇ·ÎùC÷}7'¯Ïéþmþ§ä€Ï}æÓÜÿÝ ­õ'üǯ¯Qß÷EÈ«Y6_y‡ç¾Ê•WWyqÓæñYW9÷En\g?©nZü>Q^Åá¾üvöw/ Ï_È•Wq¸§Â~U­»môúøÊËŒW=U5ß æûg”WqT_”{¯µÿ³óTî‹0¾úåáæëwìÅz29÷Tàç§í5ÃܾÂËϧ¾üzÖÓ,>{ÇçÔßt·ù÷ìU䪧*6Úq†µ}Ù«8˜'÷EÈëÜw{ÈGy%GôTÍ‘³¢ëåõ¹àp_„ñ•;>„óG®¼Ìñ÷WôTÙÌý†[ÏOÙ›âpO…y–CNœbíŸÒK½8ª/ÊÆþ=ê0^y%‡z*Üßê s†‡óGÎ^Ÿ󩨧Bî¾F7pØëuÏG‚Ã×Á»ß|âu‘â4ªGš4oç_Å)?ç÷Fx™ƒõœ×u`¯â ç¾ë_?hŸßy>)÷Tž?iëÃýÓç«8ÜyÎ}ûFý³Ï…Wqd_4YÌ_x™ƒùp_äóaç®Ö¹^Åá¾ür§øø€<#/ræ`>Üa|ýÈw÷ 眽Šƒœû"pÜuæ‘Ý7Á­s|`oŠÃ=•ãu8åà+kþÊËxU_T¼tyýÌÞ‡û"ŒoŽÏ¿ÈÙ‹œ9~DOÕl°½ùþgö¦8™è©Šõ·^¿À<•—9~<õT˜O>òœáÖþ#½Äñ|ê©<ÿü¿›ý{¹ê‹Š¯-o^æäUäÜùù >{SÙSýÄ>ÿæ«8ÜaþÙ–ñöõó$/rÅiÅù½!Žò"g¼ª§Ê‰¿à°7Éù”}øÊË}—ïþA·O¼N£±s¿ý_Ÿïõ7󸪼²/Úëoæûsæ•£ú¢¹ó´Ž?­ð*Žœà(¯ââ:¶qÐk}”WqT_Ôž~Lôú‚»ÿÝëáewª/*& dÍŸ½)Žê‹Ê—ú.³øÊËx¹/Â:dÏ̸«/Þ)º×EäMqTOU¿{Ü_y™ƒyr_„¼¸î€èü‹y*¯âp_~;y¨½þäÅxÅá¾ãók˜nm_åeî¯ê‹ò³?û‹ÏÞ‡{*Ì¿ÙfÑs­í«¼’#zªòÔA‡[|啽“ê©öúÛm_y¹wÂ:¨¾hîqÒâ»Üô*Žì‹Ntà›^æ`»s_„ûU]=þ<‹ß’Wqs_„¼þÅ»t²àÖ9þ°ã™ã~ϼ®Àøš®|.¼Á<ðO“o®ø”c< Áןû"̳|ëËæõ {ÁgòŒÎïàt~G®¼ÌñüàÍý§çŒŠ÷äìUäÜSy­3ò’¼ŠãsѹÏ=žîÿàäMqjê‹À)g½ö"WÕ5bþìÅ|GõEÙš[Þ®æÉ^䊣ú¢ú/›Ç1åe¼Ü!ofÜnn_åUw]õTXÏêˆWÌ÷/±óarî‹7×®ÊËŒç¾üüçKÎùÈ•—9às_„¼ZòÌ:hpëÙ‹ñŠ£ú¢ª½> {‘3ÇÍ«3î‹gï~9z~{1^q¸/Âøê½…w·ÖŸ½¯8Üa|Óo‘-¾ò*Žê‹²;N6ß­¼ÌÁß"ÑöMy‡û"ðËSÄüÉ‹ñŠ£ú¢j»?Q^Åq~¾u¯‹ö¶ûåeˆû¾ÃQ¹¼Ž^5žùØŽÅ_¿±Føþç¦÷~˲ßç[;æ`þ-õ-à´ß46<~*¯â Ÿ{¿BøÙ«7Gç_äìUä˜ýÓe.×|ö*rî‹°Ùkï¾ |ö*òšú"ðó!/Fýrö*rÙðã«Ãí>{9÷EX‡rµ­£^üŠ¼Šƒœ{*pòGn:ÁÚ¾ìUäÜŸM[§/ä#goŠÃ}8Íå—>`ñ•—9ðrOUã}ãß?ê|kû²Wqs_„ù×?}쮯¼Šƒ\öE«O?;ä+¯âøœz*pŠIKDý†ÏÉ«8ÈU_”¯¾uôþÏ'oŠ#û¢Ñ¢#/øŠãŽŸQ_„yÖo,?)Ü?Á©„—9?÷ølqòù§`n_áUœVôEî8föÿìÅ<™ƒ\õEù¤%">ÖMy‡{*pÚ/la>~•WqjêÀÏŽ¯+/s°>9ñ‘· Ú|öb÷Eàçƒãó/rö*rî‹êÞü³‡n>.Àg¯â /hýÁ©¿4m×p}jáU¬gA=r÷5º)¯Ô}žKx¹/§ßHê¾QxáÍ·µ·¯ò2|î‹0Ÿf{ÿgoŠÃ}ø凷FÛ¹ò2^î‹šÞ~RÍ7m«pÿŸ½ŠƒñÜS!¯¯Û#zlÊË丹 +œúÅ›FZóg¯â ç¾üêËFŸ¯…œ½ŠÓb©§ª{yûĤ[¬ã{ÇçÔS5ðžü‡èýÛÊ«8¸_ÜßN^"zþ‚¼"¯â 羜ü'KDý*rö*rî‹>9{¹ê‹ªkŒzEðÙ«8 ösê©ÀÉÿqÔ.áõrö*¼ª/jŸYÛ|}–½Šƒœû"Ì3¤Žþ>9{¹ê‹ª_]õ?à³WqêÞú7ÔSSßzÀæú“Wqàåž +ü¢ß‰?ŸÈÙ«8È ê‹|þµÁæûßØëÇ+Žê‹–Ï£ã§ç×ç‚Ã=Ö¡úÆÑ»XëÓã%GôEÙùOœkn_áåÞ ÷KõTÙfãÏÅ<ٛ⨾¨ÞlxÔŸ{¾ð2^Õ‚Ï^Åñ9õT˜g½œ8>“Wqs_äùùÙÏ°Wq«¾({KðÉ›âp_äçï®O¬ýSy™ÓôŽoÜ_pè6ÖùwîõIèUäÜŸmbïÿìUœ×ÔSßnlóÙ«8ðrO~½Ô€Éá: goŠã~oÝ×ÿò¤ÉW^†À«ú¢²ÿÑÑ燻ß7½ŠÓöÖ_õEõ¦öú³Wqs_äçùîïnµÖŸ½Šƒ\õEÅ +öñ§!¯â4½õáž +óÏç?z˾x£u{Hò*¼ª/ª¦ý;~#¯âÀ«ú¢âª'JkþìUäª/*÷}8z}ëÆ^Å©{ëÏ=U‹ýöëS. 眽ŠÓ`ûŠ¾¨\ùŽÑáþ ~N^ÅAÎ}8Ù‡G™û{¹ê‹j·ZëÃ^ÅA®ú¢ò½ø<‚íË^ÅA®ú¢æÑñÑûÿÛÞöb¯â`¼ê‹ªwìù+/sjì?ÔSaŠ‹ãëȮ½)Žê‹âCOç»îñ‡¼˜s0î‹+>ç¯8²/r×±æþI𙃜û"Üßjó˜¼^æ4ØßÄû¸G_z©wÂxî‹—sN^¿Ãý-ç¯8Üa¼ûÊ·ÎþÃ^7¨“+Žê©ŽÊ‡û"pªÛÿn?ÿúWAgþŠÃ}QÞ»¿Õò‡ld]?+/s0Oî‹|>s£èù]Ê«8ÜŸýaQóùoM^ŒWÕÕïˆÎ/à(/s0žû"äõY·MµŽÊ«8ÜŸm´ôí!9{‘+Žê©êëW¸j ûåàÖÙ•WrDO•ÿבÅW^îܼ:óQ}Qví(óÿOQ^Å)¨/‚·üí¢‡†óÇñ½ÈGõEÕÌ¢ó‹ò"—ÑO|4ÍÚ”Wõ]Üa>ÙEŸÏ\y%GõE·‰ã§ðf‚Ã}æÙ8zR¸}‘ç«8õEà”wü=:~"W^Åᾜâ±SÍç/Ê«8µê‹_y™ƒyª¾¨úY<<Ž2áUî‹àm‡½¯8Üùñâü®¼ŠÃ}øê<^ ¯âp_¾ûÊ·ÎñVyGõE¹8¿³Ô}ßñ*N#zªfþµ¢÷Ç‚£¼ŠÃ}8Õïì÷—*¯âp_~;Ý>>(¯â4Ôßl:f¢u|S^Å‘=U9bgëü¢¼ŠÃ=ŽíÙO›ÇçFx™ƒuà¾üú˻ޮråeøÜ“?v\ôúrö¦8Üa|µì·~®?øÊË?žú"ð‹e_y4ä#—^Áá¾Þ↣÷ÿ€¯¼ŠÃ}8åÁ#ì÷Ÿ“óQî‹0¾=zÄÎáþ£¼È‡û"Œ/Çÿ‚pý•¹âp_~¶•}|`/Æ3^î‹0¾8xÄÖú°7É}QUß|ß…òrß…yº¯|ë>âÏ»…—‡ã~qî¾ÿD>Oqê‹æ•ñŠ£ú"ž'8*Wî©pUÄüÔxÕ1'5ÿyåTç¬2Oýϧîo&øóêåë=ðÛWîúäÒK×¥9/ÔSSY%zþˆœ½ŠƒíÅ}8ÕÞ¿1ùìUäÜ_ŸpæÖñ™½IŽê©~ÿç;,¾òªÞ‰û¢¼·]šgÿõW~žäEÎäª/Ê®Y,z`Ò«ú.ê©ÀiÛ~z¸>~>äE®z'î‹À//#Úÿ‘+/s°Ÿp_„ù4?X)z}|ö¦8ÜSßfβοìÅxÅá¾ólŽÞms‹¯¼Ì—û"ðë…6ŽÞߎ\y™¾ê©²¿ž]ÿƒÏÞGõEùqgÞh­{ÁWÙý×›gZ|åUÕ•çï¶oŸ›\pë\·«8ª/*ÇÆÇçéð¥—úÿ¸ œ`Þøg—OÞ‡û"ŒoƬbö·_;^渟wrÕåçÆü”Wq¸/§ú}|~Ç|Ø‹œ9ÈùúÁçÄOyÇñ¢[Þ[·(ì~Ó]gòºur5žû¢¼7>wœpÿGþi9n\ÇË}8Åî¯->{9÷Eà·kŽ‰Þ‹œ½Šƒœû"lÇâŸ×D >{9÷Eà”'Û×WìUŸ‹¾¨þîn;…ÇOåU¬ƒê‹êËÞ˜òÁa¯â W}Q[,o¿¾F^ÅA®ú¢zÌPûýóäUÜ_î‹°ÎÙ“í~Lx™>÷E˜Où…Ëîµ_ìMqTOU :~|ÈW^䊣zªê†®°ööbþŠÃ=•_ÿswÛÉš?{1æx/õTž?åé‰!ßçäUäª/*O‰žO^ÅAÎ}îo}üŒhý‘³Wq«žªrÇÿpû‚ÏÞÇýœoŸx¾c¯ûåOÏðÿëñX‡Ê]ÿ„ëó¿åîuNÈGþi½?¯={ÿíûµò5ƒ6Œ7Ng;æÿØ/z_VŠ¯ú¢züŒhÿôáeÖ‡û¢¼·¿ë,=¿Ÿ½Šƒœû"pÜ×è– ¯â W}Q9ì }ÂýÇÉÌÇ‘â ç¾󬾲¢ùú{9÷E˜gÛ|?zÿŒò¦8™è‹ªEî×çdÁ­³>ìu?ï®qò^®zª|± ¦X|ö¦8ª§ª¾º¡ùþ(åUî‹0ŸbÈø‹Âý9{‘+÷EYoÝÚ™¯^®8Ê«8ª/*þ¸¬}}H^ÌGqT_TØ z~ŽôRß…û«ú¢zÄìKÂõŸ½Šƒ\õEÕàSÃí >{SÕe3ûfZ|åUÕ5,fÿ…WqT_T¯³˜¹}•WqT_TÑñͯ¿ð*÷TØ^ÅÌøø ¾ò2ãÝ×è–ãñûÑ~Ñû»+oqßอzªò²Ñúƒß’7Å™{=c=ŽòK®ÿÝ”:Çyö"g¼ª§j¿óáÎæõySůMØÉâ+/s°žîþñ­³Íßíë4öæ½ucrÕñx÷½éUäÜ!w<¾uÏã”æ=¯â¨¾¨Ü.¾¾‡ðræ`»«¾¨|ú‹[ÇOö*¼ÜS¹ùuÖ¡½Ï>>°7Åá¾ãs÷øµæ¯¼ÌÁOyGõTíÌï_jÍŸ½˜'s°]dOõèZ7[|ö*î¯ê‹ÊUßfòÉ«8ðrO…û[÷­»->{SÙmºút‹¯¼Ì—û"Ì?Ûþ  -~I^Åñë¦ú¢Ëãó—ò*ŽÏE_T]&Î_äUÜ/Ù­g_ÿ°Wq«¾({ Ï|ÿyAÞGöEÿXÎ~}Sx%Çm8ºuŽŸÅ?íóc¦¼qß~âù¨ü÷W·ÎïÒK|¬›ì‹Ü~îÿyo>ìUäÜ“¯g÷'yG­rî‘R^N&ú¢ìòóÖ½Ç +nÝí~í3çô¡ûgw; +÷Eßî.ž¿/sòž—{*¬gõòmÑùQyãÝ×è~þòmÑõ9rå Ýo:ë¦ú¢r¾-£×Ág¯C™œ¼—«žªùî-áþ>{“z‡ñõ!EŸßˆy²×çÄAÎ}æÙ.»Wôÿ를Ì_õEÅa™¯±Wq0î‹0ÿê‰'¯²GìUäÜyþ¹'EÏO}N^ÅÉzû÷Tžsë’Qåsò*rî‹À)fˆ>—yE^ÅAÎ}òj·ÅªpýÁg/Æ+÷Eàdƒ/1ÿ¾•½à3¹ê‹Ší:Íš¿ôŠ¾‹{*Ì¿þÚ³†|̇½È™ƒœû"ðË—o‹úaäÊËð¹§'ûýmÑù9{9÷Eà´_Ø2z rö*NŽóõTàT+®i~~{¹ê‹êáñùWy'Ãy‡z*Ïé?v‡nnÈÙë~Þ=¹ê©²“·8+Ü?Á¯È›âp_N}õ+Û[ןìŸ9ȹ/¿ºlÿ=B>råeøª§Ê®‹¯ÓÀgo’ãЭ{½G¡û¶›“×ç4>ÇxÊý<_Š¿óÊÁxÕµO œfퟕð2ÇóEO•_½fôÿWâ~±7Åᾜü{·ý8ÜÿÁa/ræä½õW=U¹üØB¾ò¦8Ü“ía??b/æÏäª/*Geþ}ò2Çó©/Bž=´©yþb/Æ·‚Ã}ÆçWïz[¸þÈÙ‹\q¸/ÂúW÷|ÍåeÆs_„¼øÂóöó#áUî©0ÿrûúŠ½˜s—Ô_/mŸ¿”—9às_„¼ùÕÀiáöU^ŒWÕµt}{‘3¹ê©òž±¯O„Wqd_ôÿ¼~ ›Dpëœ_Øë~Þ=ïˆÞIöE#ì~/^æä=/÷E~>¯Üvn¸}}NÞ$‡ú"pª/ÅÇgä™ò^î©°*{óQ½SA=RÊËãÁ瞪é}îV{Œ}~q¿Ç·îþ#z'î©0Ïü¬W¢÷¦¼ŠSQO~öÊè}bÈÙ‹\qrê©ÜïÜßâÌW¢Ï‡Gz‰ƒñÜ!¯¾7=z~šò2ã¹/òüwö¶¯ß„—9yo¸§¿^áÏÑû‹WäMq¸/òœc߈ÎïÈ•—9Xî‹ìÿ³7ŠþþüŠ¼ŠãÇS_„ñÍoÞß’^âx>õEàÔõ¾SC¾ò*ŽÏ©/BžíòtÔ)/Æsï„œû"p²u–=-<a<{‘3÷—û"ðóqeÔo#g¯âÀ«ú¢æ7 ç>{SÙ-tãÁæö%/æÏx¹/B^žµ²ùÿ;däÅxɡ뙦÷øj¶þ¦ùÿ/³ü’8ȹ/òùø÷ +×'åUî‹Àϯ}é«ÈÈ‹ñŠÃ=¶Wµâg‡óGy™ƒñÜ!/î{pXÈOy‡û¢Ûwù£Ï/R^äÌÁ|¸/òã϶¯ò¦8Üï~/º!¯È‹\qT_”»Xt} N$uß —ê‹šÞú3ß¡º×iäõ9q|îþA·.‡Â¤—ÆûûE}8åJ7^>0þÓ«8ȹ/B^>=:¿(/Æ3ÇM­3î‹0>ÛuKóú½)÷T˜gûߟ5_ßQ^æÀ«ú¢r|9%\åU¿ÔSùü¹wÌÿÿ…½~¼à¨¾¨é{ð¤ðøæ9äE®8Üa|öûw×ëÀ^äÌAÎ}øío—<Ùœ¿ð*÷Tà—G­}>råeæ¯ú¢bÊÈèú|ö*ŽO=òö¾Í×¥WpTOÕNÜÉüûGöb>ÌÁýâ¾㋳W¾ÕÚ¾ìMqZº.Âøì^4_—^Áá¾óoOùÒ­÷·°óarÕÕÇÚ¯¯I¯è2ê‹à­ÿ4$zþâsò"WîyšÞù·¼õæèõSp”—9Ï}Ö¿™òà°ðø“ò*{Á/¿l_²㙃ùËÞÉ oà°×1Ïû¸¿ÜSyÎ~ š×·yõVôþ«‡û"Ì'_blôù3Ê‹œ9ÈU_T-<6úÿ5R^æ`<÷TÈËï›l”—9˜¿ê©Êžú·¤—z'ϧ¾yñÁÄ*Üÿ=Ÿ¼Ͻrî‹°7Åáž +|÷•oó¸ò2^î©×'_~µ>,Åxæ4½ýœû"Œ¯ëŠïsò¦8ܹùuÖ¡X̾~P^æ`>|=ÿø·Î1÷OáUÕ#•.]¦¼ÌÁºqî9ÆFïOCÎÞGݯF­ð2^ÕSÕǽ½¾‰ù³WqZ< ž +y5éYûù y1ž{'äÜažÕ£×G0ž½È™Óàú„z*ðë¯ÛÇOö¦8Üßü}úmÖþ¯¼Ìñ÷‹ú"ðÛ÷w¿Ãâ³7ÅQ}Q=ù¬,¾ôª¾KôEÅØQÑù÷‹½~þÄA®ú¢|Å·.ìsÐàÖ=î‘7ÅQ}Quó?ÍþŠ½à+Žê‹²£Îˆ^Ÿu÷£3ö"WÕåÚÏ¿Ø‹ù+Žê‹Ú!EŸŽò2ã¹/ÂýmÜã×ھʫ8ª/j6~l´ÅW^æ`þª/jž[Ó|{Sî©°>|†\yGõEõu«ŸaÄu)sœ_DO•_ŸcþìU¬÷Eà´Üg¾¾Ã^ÅA®ú¢æ„¸çQÞÇýß:Çî‘Ü N®¼<Þ{©§Bž/~Ö™Öþ_-ç_óQ=UqïSæë³Ê«8Üå½uÈûl¾ò2óçž +y½ØYÑû”ã‡{*¬gõÃG¢×/Àa/rÅᾨé='Ûï/"/æÃ丹Êç'½½?VyýxÁQ}Quôä¬ý³$/øÌAÎ}îo{Ú“Ñç«cþÊËð¹/BÞ:':þ(/Æ+Žì‹f>aö3ìŸ9>§¾yµßYÑûs0ÿLxUßÅ}øÅ)Çšóg/Æ3óQ}Q±Ë6æõ9{¹ê‹Š ÿ½¿ódoŠ£ú¢bÌÚ'Xû¿ò2Çχz*Ì'ÿóÔËÂó;ré%ø|N>ô—Ñëï>'¯â W}Q3vÙèù‹ç“Wq—¢§*÷-Ì×gٛ⸟ó­sox*zÿ•ÔÉÙ‹œ!¸¿ÜS!/÷ÜcT¸}Áa/Æ+÷Eàdâó#8ìE®8ÜS?÷þ(oŠ#û¢=2Õz|±×óEßÅׇ~¼ë,~-¼ŠÃ}ø5õÈå}—ê‹ÊåÅü…—9˜÷TØO²7ìã³ò2|î‹Àw×iCÃõGÎ^ÅAνòŠÖ|ö¦Æs_Žû=¾uŽ‡b¼âp_ä~¿ÃÉõŸà(>srp¨§¿|÷öáñ9{“ê©À©Žzà°Wq0î‹Àiû?#ä+¯âÀ«ú¢âû‡GŸ¥¼ŠãÇSOåçyÎé“ÂùcžÒKŒ—}ÑÁÇEïIy™ƒùs_„¼¹töáÝ$‚[çq×ã™ã~¯{ý#zª|l}~)8Ê«z'÷ w/®?øìÅxÅá¾ãËãÿßyE^äŠÃ}æY®·•ùù–Ê«8Üå½íRÜú·¨_U^äÌAÎ=øÕŠññ¹ò2ÇóE_Tÿö¬èõwðÙ«8ÈU_”ýì­[­ýŸ½)Žê‹ò¦Eÿ?EÖÛ.Ê«8ÜS¿:ÿkþÊËÜ/î‹À¯v¿{døøBÎÞ‡û"ŒoŽyܼþW^æ`>ª/ªO\Äüû)åUÕG?n¾‰½~ž¢wR=U3kZÔÏxŽòŠ¾‹û"¬±º}ý£¼Š£z*7ß覼ÈGõEÙ—EŸådæõ'ræ W}QyðÝ#ÃÇ—Ÿ§ð2§IôTåõÕ„ù°Wq0î©À)nºrŠÉ'oŠ“QO~¾î×Í÷‡(¯âÔ¢§j×ùú8ëø£¼Š£ú¢ì¸¸ßÃýR^Åá¾Ès¶_Ó|ýTy™ã· õTÈ›å6¼×ZŸ–¼ϽS-zªûíËÞòÁa¯â`¼ê‹Šq³£~/åeÖ™û"x«vþC¬ù³7ÅqûUtžÂ<óÃíçÊËœº·Îœcþíbñó#åU¿¨§B^];ò´îÜ”×ý¼û|\pd_4̾~`/øŠ£ú¢âûüÛ +¯âÔÔ“`>í±›ý¹ò2ëÉ}¶cYÙ|ö*rÕ•‹Ç×çÊ«8ȹ/ò¹{þî?X7öúñÔwa|%Ößý<ºyŽðFƒÝ7Ϲû¾³?·÷=k¾¿ˆÇ§8Üß<²Â(ëïgÙ‹ñŠ£ú¢v³FïïGy‡û"p²;ÇŽ¶¶¯ò2ëÆ}QÞ[ÿbþKÍëö&9ÔSaþUólôüKy}Nx¹§òùb/MÏ/ÊëÇSß…ñÜù¼\*â{Žð2Çß/ê©À)Wøœý÷õäUÌ“û"äÙ_æL ×'åeÆ«¾([,·¯ÿ…—9à˾è©6Ÿ¼)÷EXÏìÅÿ8!\¬[!¼ÌÁxÕÕß=¿Hy™ƒû¥zªúÍÝN¶ŽìU̇û"ܯöˆãOµÖ‡½Šƒœû"ð«ûž=Óâ³7Åá¾üüÛ_1__P^Åá¾ë™°?ÊË?OÑS;¼gö'Ò+8²/ú}üùH˜{‘3¹ê‹šº1ܾX·Rx™ƒñª/ªÿ…yüT^Åá¾ÞlƒÛ£÷¿ùû+¼ÌÁxÕSëß~ºµ>Ê«8ª/j6¼ýônÁ­sÝÅ^÷óNάƒê©ªoÇó÷ò¦8Áü:ÿÄøöAûø ¼ŠÃ=øÕº·`­?{1ž9¸¿Ü!/èú öb¼â¨žª­2ÿÿöz>õNÈe_äЭ{Ý®¼¢ïR}Q~ì˜ÛÂõw®Ÿœs¿íäŠÃ}QÓ{^_¹Smñ•—9ðr_~uÇÓÃÇråeøÜ!ÏÞ_.:þ€Ï^ŒgNÛ[î‹0¾\|xt~AÎ^ÅÁ|Jê©À).ÚôzkýÙ«8𪾨üpS³c¯â ç¾ÈÏÿൢב³WqšÞúsON5%þÿ³äUx¹§Bîx|ë<ŽØ‹ñÌq¿ÜO=ò²ßkÑû+Àa)Æ«Þ‰û¢½ÜŸìÏÇf/øÌAÎ}æÙŒÏ_)/sÀW}Q½Q|þU^ÅÁ|TOU‹ó,{SÕ¹yñ­³?°× êäŠSþÿì‹°nŸ–“'Î#|§Rã¹/ÂøüÊqexüwÜÎ:09ss_”÷8õ3ïDçwäÊËð¹/ÂþPŸ·ì˜ðø >{¹ê‹²[ÆM ùÊ«8˜÷TàTwŒ+C>öö*¼ÜS!oç|%zˆòbeþcÃõWÞ‡{*pÊ£æ»Ûâ+¯â¨žª(‹öÏ”WrD_T¾øÎ]4¸uŽÊ˽SŽã‰è©ò¯<ý}™ótÃäMq¸/§zñöûŸ…Wq¸/¿\à'Ñßw W^Åá¾÷ÿ²E¿‰\yGöE ¿xš¹ +¯â¨¾¨¼kÜvÖþS+/õ]xÜ©¾¨>ãdkþìMr¨§òëÌÁýâ¾ó¬ŸÇ|}½Š¯ê‹ÊßÅü”WqTOÕ¼øNôþġ½ÈGõEíĵ£×w­ð*÷EàWë6¯O”Wq¸/òüŸí{€5éU}õTmo»gk?}þaÊ˽Æs_~~Ãg£þ +¹ò2|î‹?Yû‚p}Àg/Æ3ãÝÏùÖyÜe/½ý}ŠÔÉ•—!Ï}¼Í×3×_y™Óˆž*ÇqcÏÑë³Ê«8Ï=òâåx}R^Åá¾üú¦øüˆœ½È™ƒõç¾ãsÁgoŠã~ηîþCiÊKÃç~krþ·òüÿŸû"¬C±ìr[ßr¢ëFÌ“9ȹ/?b™èó³Wq<¾¨§§zÿ‹æç'³7Åá¾Èó—[.zÿ°Ï…—9ðÊžj…QèùäUœ¬·ÿ¨¾¨·ÔkûfäUlî©0Ïfx¼Ÿ g¯âÀË=8Ù}yôþ:äìUäÜSýv™ö¹A¸!g¯ûyç8ÀäÜSS Ÿm¾ÿŠ½Šƒœû"ð³ç–¿Ýš?{9÷Tàç|ë\‹Ï^ÅAÎ=øÅ×W½Øâ³Wqs_~û‡[¯²øìUäÜ_äËí?Ð Â 9{ÝÏ;ûssONyÑR‡[|ö*rî‹<¾qQ?æsò*rÕeK/g¾¿½$¯â çž +óÌW¹(zþˆœ½Šƒ\õEÙNKDý?øìUœ¼·Ý¹§§}û×Ñû³Wqàåž +œbÒ¥7Xû{¹ì‹Ü€ð¦¼nLgÿgNÞ˹§§\ÑÞBçÜ+ŽûQ÷qG=øÅJ6Ÿ½Šƒœ{*ðó–3oìUäª/*w\"zýHy'ÇúPONöá/²öö*¼Ü_¾ô¥èó‘³Wqs_NùûúŠ½Š“÷Ö‡û"ð«Yç›çö*¼Üߎ\áFkýÙ«8ȹ/òüåfÍ´øìUäÜŸ}ù³÷™|ò*ŽÏ©/¿|÷”èïÇ‘³Wqs_NqÕß·æÏ^ÅAÎ}øíÏ67Ï_ìUŸSO~±Ó’æûoÙ›âp_~þúÑû÷+¯ä¨žj‘'ÌÇ—òªÞIõEÕ)Ã'ZÛ7#/Ö‡9ȹ/Â:dëˆ^¿CÎÞ‡{*p +wüìs¿ŒråeNÞ;¾å¢§ªŸ[&zÿ?øìMqT_”]¾Rô÷}àK/õ]~¼è‘òŸ\j>—^Åy=Ùæ+/÷]n»u®O°ýð÷ ßã+röºŸ›•ƒ.¾ª\qT÷HÈáÃWäj<÷EðÖ/ Þ?¼Ú°m=®™/÷EÈëµËÑáã |öb¼âpOÕôz­|ÝÁÑë›à°9s|N}òæwC'†óoÞJp¸/¿}öë{†|äìE®8Üa›c¼ÊÚŽÊËx¹/B^¯ï')¯âp_~óõÓ¢¿/CÎ^äŠÃ}Æ·ß=É\áUÕ5×½>åeÆs_„¼m§šï¿R^Åá¾üì¤&[ëÃ^ŒWÕ•³¯7?ß@y™¯ê‹ÚóΈŽØ?•—9às_„<ö¨“ÂõŸ½¯8ª§*׊Ÿà°¹äP_äǯ|šy|P^îÀᾨé'³ßþ~ +ãKáeÆs_äóçÞˆúá”Wq¸/¿zyhô÷#Èsò"Wî‹üøoØ민Š£zªfÜfÑ߇¦¼ŠãöëèNyôþCÃ÷‡ —Þˆòñ稾¨™“­dñ•—9˜÷EÈëWìëåUî©ÜÝì\Oæ/Ûû?{1æ ç¾yõû¡ãÃó{Ê«8Ü_n<8zÿ_ûò*Žê‹Úe®‰øÊ‹œ9ÈU_Ôô?Ë|—ò*Žê‹ê68ßZöbžŠ£ú¢ò3Ïßbñ•—9ðr_„¼øÍÑëûؾʫ8Üyκñó#åEÎäÜ!Ï'\sŸ“·îë5Ê+ú.Õ•›Úϯًù(Žê‹Ê­âã38Ê«8ª/*.ÙìLkÿQ^Åá¾ólÆÛ|åUœ`ûuþ ¾Ê•WWy5öœ#¬ë+5^åÜ;¹qýPõHìUã‘«¾¨ÚvJÔ¯b|»ï§Y Åᾜrç Ì×ßÙ‹íÅœFôEà×ÇMÙ7Ü?‘³WqàU}Q=dÊuæ:7Åá¾ÈÏsØÕÑߧƒÃ^䊣zªâ˜bs}È‹ù(÷EŸo|ˆùú/{1æ çž +üj™ýï´Ö_y™>÷Tž¿ôëÓ->{Sî‹ÀÏÛÓü|€Jx™ã½ÔS!/ºøkþìÅxÕ;©¾¨zï óõMö‚Ϭ÷EMïq]Oøï{Ãýö*rî‹À¯>¯ ùÈÙ«8˜÷Eßœt|´>à³Wqs_~}Èæó/ö*ŽÏ©/jzë_¸Ço¸>Ê›âpO~}`Í9{‘3^î‹0ÏvëbD8pØ«8ȹ/¿ù£èù;rö*òŒz*pò=.ˆžÿ"g¯â W}Q3ðØèõkðÙ›âp_N±‹}~g/øŠÃ}‘ç¯:e‡ Ý7Á­s]Ä^÷óNÎxU_TowõE}œ‚¼ŠƒñÜS5x| žb¾ÿ\y™/÷Eà·g#Âù#/„—9às_„û• ²¯ÅgoŠÃ=øͶS® ¿ÈÙ‹œ9ðr_„uhößf²Åg¯â ç¾ÈÏgÇ«£÷§)¯â ç¾üŒ_È ò*rÕUƒþ0ÊZö¦8Ü5½ý¿Ùnʸ{‘3÷—û"ðóc¹+ä#g¯âÀË=òjÿKL>{1ž9ðr_„yæ¿]ß~y^î‹ÀÏfÞ=¾+/sÀW}Qquÿ›¬õg¯âà~q_„¼Ø|¤Ù±ã™¯ê©ZÇïs¿ܺçåU}—è‹æ>Ž,¾ò–‚Ã}‘›ogžÙzÌ×ÇÙ‹u`rî‹\Ÿë3??Ay™ãùÔSŸoÝw¡µÿÔäUäª/ª†üôd‹ÏÞ‡û"Ì¿ØAßÈ >sû_çŸ>ï·Û‡ýRÊ«8²/Úþóýáy1É¡÷;aÿT=RE^5Þ{©§B^œ¾þjÖúT‡÷;5|Üa<÷Nðr_„ñÅn{ ±8ìU䪧*¶ë]_)¯â`¼ê‹ª‰mÔ/£¼ÌÁø’ú"x‹{í>¾+¯äPON=s”½þÂ[óW}Q±ÓÿÜam_ö*rÙ­ùmûï§È«8>§¾¨ÁõÕF‡ßl­K^ÅA®ú¢ì°øïs•7ÅQ}Q±äÊQ‚íÎ^äŠÃ}æ™}sO“¯¼ŠÃ}æÓVUôú¯ò"grÕ59)º>Iy™ƒí¢ú¢êÉчZû?{9÷T¸_ͽDŸïù³7ÅᾜÒ=ŽÂý_y‘39÷EÈ›+?3)ä·½Çò2÷‹û"Ï_çÛæõ {¹ê‹Ú_®Âù+¯â 羜òˆ~æó;ö*ÖSõE9ÇS^æÀ[Ðóhx«÷3ûö*ŽÏE_TnÑÛ°¿RÞ‡û"¬C1æÝqÖãWy%GôEn^ÑMy}NäÜ9hçùKíökþ‘Ô}“âp_„ñÙ¶ýö ÷åEÎäÜ!¯'´Ñû‹R^æ`<÷Tmï8“m»×áú¤¼ÌÁxî‹àmquÈOy™>÷Eà7+h®{óQ}Qq×ûøO^Åñó¤žÊç—-½~Žô +÷Eà·÷}>ò†¼È™ƒùpOåó¿o`òÙëÇSïä½ÔS!¯g]õ?ž#¼Ü;Ã}‘ßÞ0:|üb<{‘3óá¾yýÚýç„û¿òb÷Tàp„¼^ßööÕµs¶ûªÕ_ï¬uQø¸VŸSO…ûUŒ]_!go’C=8ÅÉgÞÎÓç«z'ÕååP›O^ÌŸ9ȹ§Â<Û½ÏnÍŸ½Šƒ\õEåŸbñÙ«8È ê‹g§þm‚Åg/Æ+Žê‹š‘3' t‹…8ìEÎœ¦·ÿ7ÔS9^çú¿Zné!9{^î‹À)ž¸Óü|rö*rÕåcV‰þþ]y§é­ê©òý/Ž>ö¦8ÜSažÍ­£¢ù{¾ð2ã¹/B^ž³ß kÿT^Åá¾üv‰á3C>rö"gNƒýSõTsf™ý0{Sœ’z*¿þ§þú0kþ•ð2Ç{EO•ôkóý? yÇçÔSµ½u«_ϼ¾eoŠÃ}øí2íµÖú(/sàåž +y¶ÎÑú(/Æ3ãe_D|p”—9àsO…ý''>ò‚rÅAÎ}æÙ¼»–ùùìMqTOÕîuÞànÒ¸)/rÅÁïã+擽¿Vôü9{‘ã÷ƒ¯ŸØSµØ|ö:žÉÁýâž +ó)¾gJ¸>ÈÙ«8ÞK=8Ù¨¡·[|ö&9ÔS_múð_y¹ïÂýR}Qþåâʾ`c)¯â çžÊsv½¾ƒu`oŠÃ}8õµ'›ßW‘óaŽ÷R_äù{ =5\Ÿ“Wq«¾(ÿp©“M>ySœŠú"Ì3ûǘ{B~Û;ï°9sàå¾üæÆ+¢¿GÎÞ'£ž +œz££Ï?A.½ÄÁýR}Q~ÂÖçtÐàÖ=Î7ÅQ}Q5ç×Y|åUî‹Ü|;ó,qðŽ_y%GôTíÚñù=ååÞ Ûû"p²M¾1Ü?‘³Wq°]¸/§Üèô ,>{^ÕS»ÛÇ7ö*æÉ=æSºëpû"W^æÀ+{ª¿Úç_ö*ŽÊq¿º~@^Wq|N}8õc›ï¯c¯â çÞ 9÷HÊ›Ï}8íA÷|;쯗=cî·ŠÃ=UÛ;ÎWO~Q¸ÿ€/½ªw}QöƒÍ£ÿ_)åU}÷E˜gùùý¯¿à³ãGõEU½ÇM!ö"grî‹W‹®0饾 ãU_T~®Œž¥¼ÌÁxî‹·kzk¸>˜ò*÷Eà=ñ‘³¹äˆžªYð¿Ìÿ¿Iy¹ïÂýå¾óÉŸ?)ú|fäìUŸ‹¾¨úpϨ?Ÿ½Šƒñª/ª?:oŠµ}•WqT_ÔþòŒh}0Oå•ÑSå#7?Äš¿òrï„ùp_„ukþR´þ¯¼ŠÃ}øõƒ?=:œ?rö"gæÃ}Æמ~ö@÷Mpë^ß’Wqs_äxNu@üþyäìU䪧*??Ý<¿³WqšÞy0£>óÌç+O×ö¦8…àWkÿíü¯¼È''>æÙ<¾eÔï#½ÄÁýâž +üöÊg¢ç§ÈÙ›äPON]?½¹òÊÞ‰®3=g‚ÍW^î<‡z*¬sþaÑߧøñÂ˽Æs_„¼9h ùú¾ò*÷E˜}Õég‡û§ò"grî©<¿þfôùu>^Åᾜâ‰Ã£×y‘×ÂË?ê‹òÞñÍñøÖ9î±WqÜ/w·Ô!Ïç_í¶pýó„—û.pjê‹7OŽˆ^ßGÎ^äÌÁýâ¾(ïͳØ0Þß {ã¹/BÞŒûrtýòJõT˜OöËšÏØëçC䲧Úç°©Ý ÜR^ÅQ}Q»îSW„|çéìo y‘+÷EySÖñÿŸŽò2㹧Â:õë׆óOy™>÷E>ÿõOÍÏ_b¯/ú.ÕU‡ÅÏï<‡¼È™ƒœû"äm}BÔŸcÝ”—9/û¢ƒÆEï?Oy™~é®+ÂíN••'XyAÞ‡û"ðë_ÿtë>÷Mpë^—*/õNî÷ºqý/0=úûJŒW^îüxÕSí?îÔp}°ÒKœ¦w}«z*Õ#5äÅ<Õxî‹rFì¶WØ_!Ïvúè”ð~ÏÜ_ÙS}æÕ*ä€_’Wqs_Nvóáׄ|?Oò*Æ«¾¨šýÕhÿIy™¯ê‹ò¿ŽŽÞ?‰ù°7ÅážÊÏóó¯FÇð¥Wô]ÜßÌšyV¸þÈ3òbþÌÁ|T_”ú‹èó+ÀgoŠ£ú¢|›Ç†ó‡½È‡û"ŒÏ½¿ÈçÂ+9ÔSa=³ 7½Íš¿ô +Žê‹òWÏé ùÊ‹œ9ȹ/jÐo/x»¹þÊËð¹/Â:·_X=êO”Wq«¾(_ä¼èúGyǧž*_»ÅZé%øª§*g5Ú”7Åá¾È¯óeôùÌà°9ss_”÷Ö§:2î¯R^æ`»p_~ù‹Å¶×9{óW=ÕÿÇÞ›‡ÝrÕeÚ%j„0T%/[Ûv@›¡íó–J«ôe´QØ@%ßÅøA@dB"ÈL‚2“b +(D¢€9å l `3h"]BÑ!$ßZû]Oõªç¬;u +‚4~îôüøå~Ö^»víU÷^µßævÇ<»Æ÷\â¨N¾¨¹øý‹ýϧçGýî‹BžÿæGÿÆyñ?.»õå:G|÷E‘·ã GÝüžÕõ‰åGu÷E3ÿØú:Çs‰£úd¾HüîZ—|Ï-&GõÁr×8䋆ï|ákóO¹ÄqO5æóópõW÷çx®Æïœùù‚/šÞ|½…?§\âÌuðEÝoþÑ©åühœž»Æ!_4~±¾~ó\ñô>Š öØÿá.—/>_4~Ï kóT1kÿºé²§,~ŸVuÏëÄOÕuOzy9ÿâŒëÞ)äq’§ +þá·×øž»Æ!_4Ýú¼ÅþsŸr£×‹<Õô-·{cmüž»Æ!_Ô?þòê÷ã”KòEí»–ëÍæšïÒëâžJõáÔ×çž«~çhÞÜ©šGT×?ž«~çèùNä‹~î/:›ôÇsãÿ¾{?:Gýî‹ToÿîýUÿÓ@®sæ\óTª¿ô3gÔÆO¹î»Äq_òó~öÎ/©ÿžKÕÝS‰?ýÏ£߯©N¹ÎŸ|ÑôK¯]ì¯ßs‰£×Ñ}‘êÃcêûÓåªîÕÉ×¼yõûYÊ%Žû"ÍÃx«ÇvåùSÏ‹r£~÷T3ÿþw¯Þ¿@¹Î™ùà©š¿û H¹ÄQ¿{*ÕÃy×=·6?”ëœ9<Õô°÷¾µä¯åºwÁS‰3|èÅÕÏwÏ%ŽÆïžJõþ?¼xñ½ åªß9êw_¤zó³w©úÊuNÐú<ÕðýÇVçßs‰£çE¾(Üì/^X{}=—8óëbžJóÓ>yé—Äñ\âèy¹/g¸Á›×_”KÕ݉Ó_ë ¿D¹kòEíµêŸ¿ž«ñ‡|Q{äk^t^tñØ­“=7þﻺs‚êæ‹To¯óóÕû§çú%çÞ¡V'Žû"ÍÛø£G-Öÿ3r£þŽ<ÕãïP=?P.qÜ͹§Õç¡·\õ;'è8O5üÆÒ¯ŠÓY.q4Ïî‹Toxçª?÷\õÇ}Ñ<Îÿýš³kï_ÏŸ8ä‹šæ‹ýù”«ºsæºyªQëöŸù¢È¯Ÿ=—8ª“/êžPg¹Ä™Ÿ/xªî¶GU__ÊeßU÷Eí“–ã×8)}ø¢q|â«Êó›øž;σqæ~òTçþZuÿ3æGÇ­{*§·ã\õÁr×8Á|‘žWäùcç™)×9ñ?Þ÷Ò੦g?ᕵù÷Pâhœä©¦?ªê¯(—8î‹”Û>nùù®qR®sÔ¾è¿pfy~XË%Žû"qšßÿî…ÿÔx&ËUÝ9ª»§¿.Xì/Rr‰ã¾H¹ã7Üôyµù¡\䘧8òÄחǧêž;×C¾(\tóÅþq(—8î‹Ä ¹óâû¹N¹ä»ÌSéu>õñêï_Q.y'÷Eg{ÝßYܱ–K÷Eâ÷þUÿæ¹s?ø.òE!®kÇå=ÕCϽkyükœ˜k¾Kóé¾Hõî²·,¾ßŸù–«~ç„|þw_$Îp뺟ñ\â̹àFóHk¹Þ/¾{*qú+~òöµýí}ø“ż­qÜéùv7{Ïk¯/å:G¹î‹4þöÔë7Ê%Žêî‹ÄO?®zþñ\⨯w†Ú<´_|põ÷‘å’w +æ‹4žö~W[xÕ)×9z]܉ӽÿy§×Æï¹k÷TA¯;øÊuŽrÝ;iüî‘Ör½性nÿÉãjþ*¼úŽÕ}î4òTá3ÿ»úý‚ç®qȵ~Qõó…r£ùq_¤zógï|~íü€¹ä»ÀSõ/¸ÑâûkÊUݽ“ŽòT£_Ï]ã¸/R|ÊuŽÆãžJüöÌ7,®U§\çˆïžJœñ»ž½ðª{.qæ:xªá‘¶¸~ßs‰£~òEã·?oñûâP.q܉3ÝúŒ*Ÿr‰ã¾Hüþ~瑵ó3å"|QÿÅ罥Ƨ\ò]î‹4þîÔWý~•¹Ä!_4¾â Õó0å"<ÕðùÇ=²<¿éyQ.y'÷EâôŸyÜSkóC¹Äq_4óOzÑÉ5>åÇ}‘øÍ]þ¶ê·{È%Žû"ñÇݨ¾þ\â/ÿ™ÕïG(—8î‹t^JŸ#µù§\çhÈ5GœüÓ%-—8î‹”Û÷÷¨úÏU?qÜ©|â=êßßA.rÀSõ÷üÛúþsÈuï¤q’/nöù_=/6Ýõå"ýë5È%Žû"qºSþ¢º~£\çèx&_Ô>å²—”Ç?å®rÌS‰3Ýéo¹6ÿ”ë¾K÷EA××­ÿ”ëñÉSµ·øâkÊñ¯åÇ}ÑœûÀÏ,¾¿›ë–«:qÜ©¿»ä5¯+ǯz ¹Ä!_ÔôO¨ú[Ê%zªÛ} úûZ˜ Þ‰|ÑðÂgþ¿µã?P.ù.ðTÝ5ïñóµù§\÷Nzßuæ©T®xÜb©^_ÏU¿s‚ÞGæ©Äi.ÜâûYq=ó‹ýÛâ{®ú‰C¾hxã'«ß_{®øÎѼ‘/ +/[Î8žKÕÝù{ùî?}÷â÷ Ä÷\â¨N¾¨{ì‹×—r×8ä‹Æᯫߟz®ž—sT'_4sù›Ëã'ä"Ç<•æa<ó¿[ò5ÏëÆQ|Q{à^[ò×r‰Cž*<úŠêç‹çÎãïä¾hçý§—žÿãⱃ\çÄÿn×O¾¨ÿ½sÇÿZ.qÈ?ðÕë#ÏÕ8‰ã¾hÒû÷ô?»|}ÅÁ\ð]䋆SÏ^ÌÿZ.qÈS5g¾ººþô\=/â¸/Ò8‡_}`ÕP®s”ë¾Hüö3Zø7Õ)—8ä©Ú[üÖ‰O¹ÄA_ô½ÿð„Úñ㹚â§?û ªÿ 9à‹â¸ü±ÿ~‡\ô]à©Ò:­vþñÐøï].y'òEýù[|7s —8ä©ú~ìѵñS.qÜ=ß_~ȯWùë=_÷Tâ·ÿÄSÊãSõr#¾û"½ÂÏ}tá‡Å÷\â¨N¾¨ýô_½¢œÊ%ŽÆÀSo¿óY%_Ï]ã§ê/ÿ¯¯ñ1¼ù¢ð™G¼½äkœ”KòEí.¬î?÷\ÍqȵW<¸ºþ¤\â¸/ÒqÒ½ã΋ãSã¤\稟|Ñtà?¿¶œÿµ\â¸/RîxÑ7.¾WÝsUwŽÆã¾Hý㽿§zþôÜ5Žû"õO?pÏsÊùYËuŽúÉ…Sï»ðÃk¹È!_ôS}Ü8ˆâ±¿~¶Üø¿ï×C¾¨»÷Cú¿\â/Ÿô‰ŸªÍ?å‡|QsjýósÉw/êðÞ_,÷/…<Ï”K¾Ë½“8ä‘(—ú‹ãCÿïîxh?vyõûÇþ‰'T_ýÇÅÿÝqÈ…·Õï?¥\ç„<Ÿä‹¦?õ—ÊãSï/Ï%Žêè‹îõÚSjǧç®qÐÝèÌ3küžrÍw5y~Ü©ÞüãC«~{„\â¸/ºÍ ¨Ÿr3ê:×<•^Çæ—?¤|})—8ê'_4M?ñÄ’¿–ëõ“§ +×>Pý}*Ê%ú¢ñuUÿ€¹æ»4oî©ô¼úG}Çk¯ïd¹ÄÑü“/jÿúSÕõ3å‡<Õç¿6~ÏÕ83?/ðTÍ/¾gá—ÄñÜ5ù¢éœ¯~?K¹Ä!_^zÞŸkü”ë'xªîŸ^Ï]ã/êŸúcg×^_Ê%ù¢pûcª¿/A¹ÎÑó"_4ÁyØs‰£ºû"½ŽãZÿþÂr×8䋺¿xjÕ/Q.qÈ ùâü¬çE¹Ä!OÕýà ?Užÿŧ\âÄÿÎûëíÃø!×!ñß;Ž{*½^Ã_ýDÕ_ÈuÎÌO5~ôò-—¼zª›Ÿð”Úû×sçqšw +šóEçxü>žåGu÷Eâ7·=æÑåñ£ºç®qÜS5ùyMÿë©‹Ïwñ)—8î‹ÄÞþ»¯/ǯºçªNòEÃßTýþ‚rôú‚§ê¯ÂkÇç®qÜižûG~Ó3j|ÊuÎå:GóF¾¨»ô½ÕÏ_Ï]ã/šnÿšêþLÊ%Žû"ÍOû©±zÿå‡|Q;þVuýO¹Ä!_>ÛTý9å"1×|—^òTþl±¿TÏËs×8ä‹š{ŸyNõõ…\ç(—|QÿÐßyxï¹ÄÑó%_Ô|䛞s^lÒCÌ5ßÿ»ýëhðTÃõß öÜ5ú¢gÜòŽåøÅ¡\â¸/güö‹^ã‹ðEíé'ývíõÅ\à/Ž<ý95>åÇ}‘Ž“îìs«ëÊ%Ž{*ñû[½ðª{®êΙ_GðTÓï]x§òõÇs‰£ºû"qº‹O«~ä¹ÄQ|Ñtõ‹ëOÊ]ãw"ä¹âS¿û"õ·?ó›j÷?6ÏþÞê÷žÄq_òy)¼õmÕý{”ëœyœà©Â_?«¹À!_Ô5ÇŸYŸçªNòEÝ˾ûQ5>åÇ=•ŽÃé„S_V;ÿP®sô¼Ü©Þœxêé%-—8䋆˸º>ñ\‡8è‹n÷…êúsÁw¹/Ò<4¿û¢*?@®sæ瞪}ç.¾ß\Ëuï4óÁSŸ}ß¯ú=WuòNä‹Ú‡-ÿ~8”‹ðTá­euüKÞ‰|Q{ÞÛª~sÁw¡/:åÚo©½¾˜ ¾Ë}‘ŽóáG¾ðì’¯:å:Góà¾HœîÒãî]ã{.qT'_Ô~ý<¿|})wƒ¾èÀgSŽ_ÏU8î‹Ôߟºüû›sr‰CžjúŽó~¹œŸ™¹Äq_4sNÛ«^Q®sôz‘/êoòÄûUÇo¹kòEÝéË¿_6?/È%Žû"güéÏ>¦6~ÊuŽÆã¾HüæÏwñý²ê”뜙žjz܇^_ÿâ{î‡|QwôòúWÏU8î‹4Îþòãê~r‰ã¾hÏ©ËÏwÊUÝ9ª“/êŸS÷-å‚ïB_tðmÕõ¡çjœÎQÝ=•æ§yõ#_R?ªO–»Æq_¤þpÖ#þJ|Ì5ߥ~òNî‘VsÁ;¹/õwÎ<á'UïrÿêyÕ9<•8íç^³ø|T½±\âh~Ü yüý‹-Ïoâ{.qTw_$þøš3Y?ª{.qæºy*qšËî¾8?«î¹Ä™ò<¸§R½½ÕÅ«ßsÕïåº/êsîøû¨žŸ=—8ª»/Å¿õ->_(—8ª»/4o×8n1ÿ”Kœ)sÜS‰ß]pʕǧê“åG¹î‹FÿÓùÓßs‰£ºû"ñû+>p^ÉW}²\â¨îžjÐøß{ɹ5¾çGu÷Egû k¾ªäS.qTw_$N{½Yÿ”KÕ݉?þÞ×½ü¼Ø¤‡êžÿ÷gpŽêî‹4Îéß«Æ÷\â¨î¾Hüæßµ¸~TÝs‰£ºû¢)?íiŸZ|ÿ+¾çGu÷Eƒøøˆê÷_žKÕÝõ:þÿôv‹ïG(—8Sæ/j|ÿ¾|})wã¾Hã ¯:ã¹åûKãô\Õ£ºû"ñûßá‡U§\çˆï¾hÌóÖ?ý[ëñ=—8sÝ|‘8Ý+Ï_¬)—8ª»/g:ê—ë[Ê%Î\7O%~¸ÕÅÇ–ÇêžKÕÝMz·|‰ï¹k÷E⌿ñbÿ*åªîÕÝ©ÞyÆâ÷ñÆü¼(9æ©fλþøÜrþ)w®Góæ¾hæ¿ô ‹ý¥sÝr‰£zo¾hÏ÷ýöÊóÃÌ·\âÌuóEâLï?ûå%Ÿr‰£:ù¢îÉ{O+çŸr×8=ø¢ö­|Z9~qóóTñÉìÖÃánKågÒøÍSÍüîÀâ}7×-—8£Æ¾¨{úñU,—8ª£/zfï¹Ä™òøÝ©ÞÞãÀÙåñ¯ùi-WýÎQ¿{*ÕÛÏsNɇr3äñ“/ +Ÿ;æå%Ÿr‰£ºû"³‰¯ïyZ<ö[Ë%Nüïvýî‹B®O?~ñýõZ®sÄw_$Nø§c~¥œÊ%ΨãÇ<ÕÌ¿éù 5×-—8ª»/R}¼ðŽo,çæ[®ú£~÷EªtìÛK¾8”K÷Eâw×ûïTòU÷\Õ‰ã¾HýÍx쯪N¹Îóëë¾hæ\Zÿz.qTÌSéx ÇX|¿I¹ÄQÝ}‘81Çûï_Ë%Žêƒyªß¿Í= åû‹r‰£~÷Tâw§¿Ø_¡:å:gæƒ/ïûÝ?Pî_ßs‰Óëø1OÕäùéîsÆK¾êž»Ê1O¥qNq}Rοø”ëÞiÔøÁõqSò)—8ª“/ê_ò5~Ï%Žêä‹ÌçGu÷Tš‡Ä/Ïo¿çGuòEC\‡”|Ê%Žêä‹šS–|ßs‰£ºû"³;þÀÙåøÅ÷\â ùøtO%Îø™cÎ)ù”»Æ!_>LÕ/y®Æãœ)Ÿ<Õtü¡¿8žKœQó¾h<åøúý–KÕÝSiœÓgù•Úø=—8S?ù¢©½ßÂ_Q.qT'_ÔpàÁµñ{.qÆ<~òEãêÇçGuòEӳ꯯çgÊãwO5×?U¿çÎýà»È —ëÏ™c¹£ÆI¾ |‘Ÿgtü`®q4òE‘çÝúÊs‰3?/ðEíݗ뫶ϷTâôš7óT!sÂqõÏ_Ï%ŽrÝSiœ“yÊ%ΔÇïžJüæ^õÏ_Ï%ŽrÝ©¿‹£v~ð\â¨îÞI|§r»û¼t/>Y=úó¦¼ôòO–õæ†ï»àÊê­q¦w^9'¼y¼¤äÇ=ë‰ßZ½½û~ÆCœæœ#>Qò§#ß÷¡ÄV¯½_Ç\ë§{ÄÅ+ùí-.øëħ:åRÿøÆ_øhÉ/øèGŸê[9ÃÛïõ7%¿¹Ö«þ.ñ©N¹Ô?<îè—üþ­WÿøŽOuô‡Ïï]Xò»»|ö‰?Z½ÉuqÚKÞþç%¿=òAŸLüþ“õ:å'|Ûeï(ùãGNº4ñ‡o_Öû\§\âL_wƒ³ü÷]ºãwW«×)—8Ãõopv¯cæ‡Ôë˜ œñ¦—½£äk¨S.q¦xûŸ—üéÚû¯o€:å§ÿǽ Kþxçýã3üÓ²Þ©¹Ä™âû¢ä·ùý5ž¼¬oÙßQ.qºø~,ù:?4ïXÖ‡oÞ?oP.q›~á£%?äóÕ)ûyñÇJ~{óýósõ­œá GìÎ7:þÃuö?GÒçN™ÛçÏÊ%N?KN›?«7ú|„\â„øù¾à_ÿóÝëÍu÷ë”ëýmæ´÷9¸;ßh~šï¯¼>~l¿îåz¿8‘»X§Náå‘õpìN;›£\âwÉã^lî¼þ‰ýºs”KœÆæŠë«Ä÷yã|^i.p;NÚãŸõÇêS<~®,—8½ÿc<þg²z“ë~*—8!®¯Fž}\_íÆ uÊ%N[9ÿ$~Z甹S·¬·¹îågŒë¨ƒi¼ù‘ÖW»ñ[=ä:姵uÂ×Q‰ßßd¹®P½\ℯ_®s¦¸þIüê”Kœ!®£vó‘çG|ªS.õwß¹\gjúP¯oå¤uÑbüq}•þÖWµ:å§ë¨’3ÄuTúwZ/•õ´îJÿ¦\â„øþ*9z_Ps3ÚõÎ|€:å§9wyýØþÙþy,¯Ï+Ÿß¶r¦¸Ž*9Ãw[«‡¸îJ}”KœÞ®»ûkí¾Pr©?}•ãïòçàhõp·ýÏÇ­œôù^ò‡ìŽR¿Þ~réÏœ´ž)ùc\_íæÙêýßçõ‰'ç'¾dŸ*ùÍå·yOZGy}xÁ§ß­õUÙ?燼z$ã̹½“ϧ¼–ç¶råþªµã¤ÍëðÞêAës›ÿ9×úÅ vüËSQr©Ÿ|Õ·rÈMæµÚ|ÝG¹Äì<©ëS?éú”r‰C¾ˆê”‹ýà©ú/,?¿¦ì6sÀS…K—Ÿ¿i}u0¾©)—¼ù"ªS.õ“/¢úVN OÕBr‰C¾ˆê”Kýi=“^7=¾T…òTT§ñ@ÿh×/òTT'Eýè‹ìº¬]ñWÈ©\?îÞGVŸâº+Õäë—kÀSQ½7Žr©¿!_äõüýÈVÎ?×Êã³ÉŸƒ^ïïºÿýN¹Þ/N0ï1û"«wשû+å"Ç<|Qoõ)û«rÓúªœqâ!QõTT§\êï,·ËžÊëýŠ¿ò~q|Þä©©çu¦s”{H¿|—?S^ŸwVïsýŽr­_òET§\ê'ïDõ­œ´.*+yªÞêÍ»¯Ü_'­gJ¾®OƒÕÛø½á^<)—8ÿå‹Ò:g‘›ýå"<y$Ê¥~òETßÊ!_DuÊ¥~ôEæ¯Ò÷z»×¼rÀ_….½–øäÀ!_4€¿¢\â/Í_õÙka®õ§uÚn>ÁS‘¢Ü­Þ©75ÅïÓx(7X¿dE¹äЙŸr‰C¾ˆê=äR?ú¢O/¿ÿVüqÈ5ÿ¼üþºÕ¾,È%No×)òTÔ1—úí:KïÇê˜ ý~½&O•Ö9éx×#­¯vÿÞÈ!_4š¿jòþ+Ê%Î`×ÝòT½Õåµ(—8£]ïËQsÓÅÏÓržå©ÒçlYVüqÒz¦ä¿Ò¾,Ê%N<>þJ¾Èëãÿe·/Ë9s.pÜÉ;y}öHÆ™sÍ_©Ÿ|Õ)—úƒ½îíÊýƒ[9ç£<•×7Þ?(ù"ªÈÅ~;ÏÈS¹×J뫃ñ ÚÊI׃åñßäëÐÖêm®S.q;oËSQr©Ÿ|Õ·rÈSõ°/‹r‰C¾ˆ|å‡|ù(Ê%ù¢1®sÒñ¨Ç”ï+¤\â/¢:åR?ù¢1î¯+Çßd?¹™¾ˆî¤\òN]|-Æ™=Uxü².E¹ÄIïë’òy€ê˜ òE=ø(Ê%NžŠê”Ký]<Ÿ—óóÕòWMÜßžÆAãÌW¬í› +î1èþÁœëýò]i=SÎ|‘×Û¸¿=õ9g̹Þ/NüOþJ¾ÈëºÏ9Êõ~q‚_žª³ú´²ÿŠ8i=YÎÏ(Oeõ>×1×úÅiìu³§ê¬®ýT>ÿÊ%ù"òQ”Kœ°Ñ_Q.qÈ5vþYóWÄ vÞÓõ)Õ18ä‹Ò:§<®Zí¿ÚÈA_dû²t_!å}ø«r‰ƒ¾üU¹Ä!_ÔÇßg(çÞ¹È_ÔX]|Êí­_¾‹¼Óp³åýƒò{”Kœ|Q€ýT”KôE°/‹r‰3Øõ‹üU°zº®Ù‹"´‹8M|?¦ÿN¨N¹ÔŸÖE%_ž*­sÊzú¾o÷oqȵæ¯tÿ 姷ëeyªÁêòZ˜kýâŒæÈ_µùþAÊ%Nú|/çYžÊë!ï—vŽr½_œ6®CJ¾|‘×Ózi×gãQ®÷‹Ë…¿’/òú¼ŸÊÆ3ç‡|Õ1w£¿òùÔ¾,Ê%ïÔÚñÓæýW½ÕC®c®õ‹ì¸Õþ+ªS.õ“/¢úVù"¯·+þÊûå»Z;_ÉSÑ~*ç(—8Må<0„éû¾ò}×kˆí§òõ2qÈQsé>DðTä‘(—úÉQ}+‡|Õ)—úɵæ¯Òú*½î[9䋨N¹ÔO¾(­sÒxõÐ}…[9ä‹h?å"<Õd×/òW˜ œÞ®wBá·ËùÑyƒr‰“Ö3%Gû¦¨žÎ3e¿r©¿ù*ù«tž/ÇÙ¬üþUgýò`Cü\[p²/òz/dåz¿|Wpï!_dõ¿LãpÎœkýää‹zó?]öW­q”›ÖWå<ˆ‡´ðWòT^ŸÎ¿âÙé÷(×ûÅé,WžÊëmþ],ç(×ûÅñù—/:¤®ûm<Ê=¤_¾ËŽyªÎê}Þ—uG¹Ö/ù"ªS.õ“w¢úVNcçyªÁö_õ+û¯ˆì|ÕÅóç^¿m性"D¹Ô?Øõ»û¢ÆêÚO ×çMœÎŸì©©_Å÷ºGà÷ÛûœëýMî_æþ+å‡<Õ7sÀS¥õRyÞèWüy'òEX‡\ê'_ÔÙ>¨.ß?¸•C¾ˆê”Ký䩨¾•C¾h0•¾¿Û‹'ÊEø"¼rà/ê7þþqÈq“æC^¿gE¹ÖŸÖc»ù„}V½ý®{ŸïÄ\àtæ䩼.E¹Þ/Nc×Y]>øõ”ÎÎQ.qÈ¥õR9ÿòZ”KòN£y-Ý?H¹Äéüú={*¯7ñº>=Êõ~ù®Ñ=CöT^oÁ_͹Àéâçx9ÏòTéó½¬k?æZ¿8m\”òW#ì¿R.qâ”–¿Ò¾,ç̹À!OEuÏœ Þ‰|‘×üþU—ÿÊûõûë¾Ñ_͹ÀI×åë+_4Äßg(ëÓF%ù¢6®»Jþ˜ÿ.!å'Øy&yòƒñEt¯•¾7LuÊ%Nº®,ÇÙæëÐ`õtþ¼Ò\ëŸ9vþﲧ +T7Žr©}‘ù+ý¾ÐVù¢žöeA.qÐÅïûÊ×eZùûƒÈ¿3H>ªƒ\ê'_D>j+‡¼SWù»B»ã¼qÈ;öûWc\/%>å‡ä¿/@¹ÄÌ;ÉSQr©¿ïÇô¼çG>¤óFY×û}+‡<Õ>Šr‰Ó/j¬ÞeE¹ÄIŸ/å<È5Vïaÿ•r‰3Äϵ’/_äuÝH¹Þ/Ž{y*¯wWÑï·Ë¥uNù¼´ŸŠr½_œx\.ü•|‘×µŸÊ9Êõ~q‚Sžª³ºöS9G¹ÄIëØrfOeuíËÂ\맳㧇ûU÷ùŸsãÞI¾¨·ß¿ +×Ý¿¾ ñ'€¿j¬>å¿KH¹Ä!OEuÊ¥~òTTßÌ}Vä‘(—úÉQ}+‡|Õ)—úÉѾ¬ÍðEÕ‡ì¯(—|yªÞ|”ø”‹ðE#ìË¢\ò]ä‹&ðQ”KòE­ù«´¾Ú‹'gÊ%Ng×)òE­Õ›¼ï‘r‰C¾¨±ë .{-Ê%No×òTT§\ê'_Dõ­œÎ®ß勼>û(ðfÞ/ÎhÞ@žÊëüÕœ œôùžŽ;=䋼žö™§>Êõ~qÚ¸)ùòE^Oë¥]ŸG¹Þ/NÒÂ_Éy]û²œ3ç‡<•×å‘0×ü•úÝ;Éù|¦uÎÁ÷Üü•8­½îÚgÕ[}Ì^ s­_œ<•×Ó÷}iü”ëý³ïOÕZ} ¥\ï—ïšâ~òòø”§òz þJ¹Þ/N°óäì‹ îå"ÇÎóòWi³x^òZ€Ó“/‚û)—8=y*¨OKôEà‘6s¾ÂþŠŠr½_œ`çÏ­þJ¹Ä!_4lôWÄ!_DuÊ¥~òETßÊéÈSY=ý~æÁøæ¥\â/Ák¥õUùy§\â /Šëœ4^=Ò:'ý›r‘Þ‰¥­òE£ù«>û1Ê%ù¢Éö_¥ï1ÓüS.qÈMà¯(—8䩨N¹Ôß/¬ž¾ïKó³•3‚§jìºL^‹r‰ÓÂ>«´ÎIãÕCû²(—8äÒ:gÁÿÎ þ:ý›r‰ÓÛuº<Õ`õ6®¯s­_œÑ<ù+ý]BÊ%Nžª³ú÷*—8i]Tγ|‘×CöW”ëýâÄ)]ø+ù"¯÷?ñ¹wëûÁr<Êõ~qÜÉSy]É9s®ù+õ“/òùlô{VÆàþÁy¿–?䯸pÎN°ãvÕåïÍ[ã(—8i=S¾^òEÕ[ðWÊ%Ž{'ù"ªS.õ;O^ÕþŠ|Ñ°Ñ_‡|Qg÷6ù÷Û)9䋬ÞfE¹äÈQ½§\ðNè‹`ÿå'€w¢úVú"óQÚ'†¹Ö?äýlä©B\_Œ'K=´ÿj0Žr‘žª±zú}†”G¹Áúå»È¥uÎbüù÷Û)—8䋨N¹ÔŸÖ3‹qæßi¡¾•“Ö3%_û¬«wÿJœ.~¾”|ù¢Æê}þ|¡\â ñó¨äÓýƒmöQ”KœÖü‰1×úÓº(õ“/Í_¥ßÝñ£\â/l?UZ_%>å"‡<•Õ›ì)7­‹R¾ò]]ÉSQ½5Žr©Ÿ|‘××xÿ ú"óW!ß?H¹Äìú]žª§:äg´ë}ù"¯§ï ÓëG¹Þ/Nžª±:í¿R.qÒ:ª<®ä‹¼ÞoÜ%N|Ê %_äõ銋«þjÎy*¯Ë#a.x'Ÿgù"ª{n—ýöÛñ#_ÔZ½ßè¯Ä vœË5VÁ_)—8䋨N¹ÔŸÖ3åñ)ÌŸ7ù÷¯6sìü¹æ¯(7 ‡|ù¨­òE-ø+Ê%N¾ˆê”Kýè‹ÀGm槢:änõN¼ÖVù"ªS.öƒ§"µ•C¾¨‡û)—8䋨N¹ÔßÆ÷õÁø¡¡G¯wÒ¿©¾•3‚§Jëœ2wÌ^‹r‰C¾ˆê”Kýé|^ŽSž*}^Ôê[9ƒyù"ªS.ö»?Éž*X½YñWÞ/ï”ÖQå<ÈSy½¥\ï'Š %_äõáFXýûƒÊõ~q‚_žÊëòZÎQ®÷Ï›gÚ¥ûœ£ÜCæ¼Ó”=UgÇUû¯”ëýâ¸w’/ìþÁü•r‰Ì;ÉSy}öQëýâ/¢ºs”Kýè‹À#mæ€w"…ãú"óWÃÊþ+äÄõUy~Ð>« õrèG_dIž„r‰C¾ˆêäR?ù"ªoæ€/j N¹ä»Èuæ¯Ò÷ƒ{ñäI¹ÄA_þŠr‰Ó’/²zXñWȱë&ù«ô>ÝÍGš“øH×e»Cnœ´ž)9òT-Ô)—8=ø¢ uÊ%No×ékþŠr‰3ºgÈžŠê[9î=ä©ZóW-Ü?(…œ¸>)__ù¢ÖêòQ”ëýâÄCoá¯ä©¼.ü†êýƒÊõ~qÜÉSy}öH6ž9×üÕÜoó,åû²ì¿š6ú+ù¢Ö«ì¯0ú;þå©‚ÕÛEœöYQr±ßÎ3òTiS·ÝŠ¿ +À vÞ[óW”KòEÁÎÃÝÊýƒÄ!_DuÊ¥~òEiSοö_målõW”‹òTTÿÿ™¿"_DuòWÔO¾hÚ诈3Ä÷ÑÁøá ‡~·j²ú÷_Q.qÈQr©?­‹ÊñËSy=íoO}[9M\G•|í³òºöSQ®÷‹“Îç%_þªózÞ÷ëåg0Ï@þj„ûûœKœ`þdöEVïÀ_)9qUÎ|Qoõ>û«´¾ZôçÜ´¾ZÔs<$þJ¾ÈëÚOE¹Þ/N°\ù¢êÎQ.q|Þ䋼ÞÈGA®÷‹ÓÙñÓÁþ« þjÎy*÷Qø+å‡|‘×geþJ¹Þ¿æ†û¯¶z§ÞüÕ¯O)w«w"E¹ÔO¾h04ߌ8ä‹:óQÜ?¨\ä€/ê¡N¹[½y$Ê¥~ôE÷_‡|Õ·rÈõýqðT´ŸŠr‰ÓØuŠJÏ[yªê”KòET§\ê'_Ô™×Jë®ô<·rÈQr±Juç(—úðTi½T'i}µ_Ü­œ +sÁw‘/¢ß³¢\â °Ïj´ú—úûíè‹àþAÊ%ù"òZ=ä‡|í§¢\äØõË쩬Þä÷å¦uQzë!N°ë,y*ª·ÆQ.õ§õÌ"7{*ªoå´ä©¬Vürìú]¾¨·ú¤¿KH¹Ö/ÎhÞ@¾ˆê”Ký]ü\.ç_¾(}î—õ~¿]ã!N×!%G¾Èë üþ•r½_œx¼~YþjÎy*ªÓx°ßæYû¦|þUßÊiíø‘§òz—÷_a.pÒz¾|}É_¸P¹Ä!OEuç(—úÉ¥õÒâymôWòN?å©ü<¦:å‡|QZ/•ã—×¢\â/"E¹ÄA_‰r‰Cû¦¦o»ìåühQ¹Ä!_ÔšJ¿ÿy0ž(—8ä‹ZÛ—•~¿4ñ)—8ä‹&óZéûÓr‰C¾ˆ|å‡|‘×åµ(×ûÇü{ï䋨îåRÏi^õHë«Ý<[½Éõ­òE£ù«îT.qп¢\â¤óy9?òT^ó}|[9ƒyù"ªS.ö›÷¸ªýU×WåüÈSQ=Àx¨?—‡å¯¦»|ßî÷¯¶r:¿<Õ}<Ê¥~¾òETßÊéìø‘/¢:æ‡|‘×Ø¥ñxÿšwBe÷*—úÉ ࣶrȹ곿¢\䀧jâunù¾“¿¢Ü´¾ªõ“/êÁ_Q.qÈy½Ï÷R®÷·ê7ï”ÖQ{ñM:ÅïéÊ竺sæ\৚âújÁÏ¿ßN¹Ä!_4˜¿úR¿|Q ‰r‰C¾h°ûõû픋œ÷Rî@ðE-Õã÷•éøÒ#­¯Ò¿©ß¯wÒú*õ§÷{Éér}+'­‹JŽö;µVy)å§_ N¹Äéíú}öTV×ý€”KœÑ¼|‘×{Ø¥\ï§1"_ÔY=Àþ+å§ë“òõ•/¢:åR<Ë_uϺ¼úûíqÈQÝ9s®ýþ•ö_ù¼ÉSM/YúÃö_õùþAâ´vüÈuV³¿Â\ë'­çË×W¾È룾7Žr½_òN½ý.Vú½…ƒqò3çZ›ûÉ;ÿÈGQ.rÀ_‘¢\?§ómz¾è‹Ì_õ+û¯ˆC¾¨±ßoùïNKôEæ‘´?‡r‰C¾h45Áþ+å‡|Ñhþªyÿ¾_¢\â´à‹úë-×oòc”KòEÍwºþLÇå‡|‘û¨´¾J|Ê%ù¢é0÷_)—8ƒ]§hß”×Ç¿%Žû«&¿¯½ô~·ñ(×ûÅÁSõPwŽr‰Ó§JëœÝë™^Óøèòߤ\䘿š=•ÕõyA¹és¡8Cü<*ëm\G¥§õRY×~ªÎ8Ê%N _äõ‡Šr½_¬7ÿ#ÕY]û²œ£\âÄ©Xø+ù"¯7ujúûƒ”ëýâx?ù« rÅñçKþªƒß¿R.q:;N䋼ÞÃþ«98î䋼.E¹Þ/ù¢Ö~×}€¿?¨\â/jüü“¯ï(—8è‹lTŸ¯O)—8oå©Ò:§möWx0âtvœÈy½Ïþ +sìø—/òú þjÎNoÞIžŠê”‹ývžéò>«´ÎYŸ¹¾™cç«._‡6VT‡\ï‡|Ñ`©¥\â/òýTòW˜ ¾«O5]²¼¯Í÷—Q.qÈMߺÜ¥ýE”KòEM\_•Çüå‡|QwåúmÈû¯(—8ä‹ZðW˜ ýä©Z»°É¯/å=ø+ÊEŽ]¿ÈV— w°~qÈQr©¿ç“ƒñÃMí³¬ž¾7L}[9i]Tò婨S.q:ðEé<_æ6ùó…r‰“ÖE%GžÊëéû¾ÔG¹Þ/Nú<-ùòE^oÁ_͹Àéâ:ªäÏžÊêüþ•r‰ŸòÂ_Éy½»ëþþ« ¹Þ/ŽçÊy]÷:G¹Þ/ŽÏ³|QkóÙ€¿R.qÒ:ªœÿîlssãÞI¾h°}Pì¿R.qZðT^³¿¢\ï—ïJë¨r~†|ç>jÔõG¹Ä!_Ôƒ¿¢\â¤uQ9~y*¯§õÕ^<8)×ûÅ!_>¿wa™Ûæ¿?èå"<Õhõ.û+Ê%ïD¾ÈëéûÁ4?”ëýÚ¯E¾¨7•¾L|ç(—8îä‹š.×oâS.qȵßyèús7~ÊßE¾(˜¿š÷_A.qÈ5毚||R.qȵæ¯B~Q.rì:«•§²zºžJóO¹i]´{}Ò1â´v½&_ÔQÝ8s.ô·à©Òzi1žì¯(—8½]wËy]÷R®÷‹3˜7§Jë¥rü ì¿R.qÒçrÉ‘§j¬>ÂýƒÊ%N×3%_ž*­7Êz€û•Kœ ž*b ¯5^|Ånÿ凼y$Ìïäó&OåõüÕ˜÷_y¿8i}Uγ|Õ3ç'­çK¾<•×»þJòE^oaÿ•r½¿Ëýi]TŽ¿Íž*@Ý9Ê%Ncç«AžÊê}®S.qðTTwŽr©Ÿ|Õ7sÈSQ=®ëÊ×KÞŒ¼ù¢a£¿"NžŠê”Ký䋨¾•C¾ˆê”Kýä‹ÜG­ù+ä€/š¬>ßÇÞl°þô}âÁx2Í;ÍžÊêòQ”Kœ´.J9z„| ú ¹ØÏc%_žj°ú¸â¯¼_œZû¯08ä‹‚ù«Iû¯ —8]gu:@r‰ÓÙu¢üUkõ´ÎÙ½¿ —8i=“?÷v~ÚgEuÊ¥þÞ¯ßõ;WV—ÚÊIë™rüòE^oÁ_)×ûÅIŸ§%_¾ÈëòZÎQ®÷‹“Ö'%_žÊëS\_íúl<Êõ~qÒz¦äËSy½yîç«þjÎy*¯Ë#a®ù+õ{¾òE^6ú+q:;~¶ú«98i=_ο|‘×å£h<Þ/N×Q%_¾ÈëòQÎQ®÷‹ì<³Õ_͹Àiì|%_äõt^=÷‹ƒ¾È¼V€ýWÊEø"Ü—¹pÈ;5¶/+}?˜æsÁw‘/jíþÁ1ß?H¹ÄiÓ_ ú}*Êú¢ÃÜ¥\äÀ¾©ê-ä’¿"OÌ#¥õÕîõ…\â/"E¹È_4P<õ·ñü°{ÞéØŽðöWòEC<_•¹ÃF%NZÏ”y*ªS.õ§óyÉ—/òz“}ÔVNZÏ”ü ÷ªN¹ÄIŸã%_žÊëýÆýW3'®¯J¾|Q°ú þJ¹Þ/N<$Ë_µwÿàîþAç(—8­Sžª³º¼–s”KœÆæ_þªµzXÙEœ´ž)ç¿ÕÂþ«98ä©ÈGùx”KòE^Wö_yÿûÉM‡é¯”‹ðT|ÝJ¹Þ?©Ÿ<•ÕðWs®õË;‘/rÕÃþ+å‡|Õ)—úÉ;y=­¯öâ›w+‡|Ñ`^Kž‡r‰C¾(Ø>(ñ1úÉQr©Ÿ|Ñ×Wi¾õXóWÄAO>Šr‰ƒ¾ÈüUº~Ù=È%No×_]~_{=äz¹Þ/Nk×}³§²úþJ¹ÄIë™òu\óW=䧷ëwù"¯Ùkmå¤uÑbüÙS V—¢\â¤Ïå’/_DuÊ¥þ´)ùSöT^Ÿ}ŒÇûʼnïÏ…¿’§òúp«k¼G¿ÏPŽgÎy*ªcîaú+ù¢`óÀ_Í÷-Z¿8'[ýÕœ œ´ž/çS¾ˆê4êwï$_äõ>ï§ÚÊ ö~—¿j Ž¹ÐßTΟÓ‡ŠÕûxþÜÕ7rÒ÷zåü§ó|âx=­—®,×ûÅ!_Duç̹ö½‰öM5à©Ô)—8è©À#Q.rÌ;É5T‡\êG_di‚û5⧢ºsæ\ðNä‹:óWÚE¹Ä!OEuÊ¥~òNX¿ŠüUg^«ÍçÊm­?­‹Òû}ˆç“Ýû>sâCžÊëòQ˜ òE x-Ê%N:Ÿ—ãŸ=Ô)—8i]Tò婨¾•“>ÇKþì‹ Ž¹ÐâúªäËy½ßè¯Ä‰‡ÌÂ_Éy]û²(×ûÅIëºrüòT^ðûWÊõ~qZ›7ù"¯Ëk9G¹Þ/NZÏ”ã—/¢ºsæ\ৢ:åR¿{'ù"ªoå/r5Âþ+‡8î†|êõ´¾Ú‹!åzÿÌ1ï4ÈSQÝ|šrÓº¨Ëüºr‰3Ð>+¨S.qȵñý^Ž?­»Ò¿·r†x>)9òTTÇ\à /2Õm¼pÞÇžÊ=Ò¼/ r½_,­gÊùÙꯔKœô¹\ò¿ÒþjöTæ…æ:úÓz¦¿|‘×Ço½ñîï†òET§\êoíùÊy}öQ6~òWâtvü´WÑþ+qÈMÿŠ8䩨N¹ÔO¾ˆê[9îf_diÐu«íû’7Cx§Ñêi½´Nç(7­ÓÊ÷Ñ—ê¯(w«w"´•C¾Èëºr½Þ¯Þ©‡ºsæ\èGï‰r‘žª…z¹èÁÈSY}ŒûÛÓñ‰¹Ö¯ýZä‹ðH¾K¹Ä!_Ô™¿ +ùýE¹Ä!ï”Ö]i>æG>?P.qz»^“¿ê¬Þd?O¹ÈO…^‹rC¾Èëú*Êõ~y0òEƒy y-ç(—8ùòW#ü~»r‰“Öåq²Õ_)—8ñø[ø+y*¯O¿Ú&%ù"ªcî—é¯ZØ5¼ëˆ1}.{åÁÒúªœÿ­þjÎN0ï*_Duõ÷vÿ |‘×壶r{¿oõWÊEŽ'Óú*½^ Õi<ÐO¾(­sÊ×}öQ9䋨N¹ÔOžª!¯ÞŒ8ä‹&ðW”‹ðTî£ä¯(—¼ù"ªS.õ£/Úè¯cÞIžŠ +s¡Ÿ|Õ)—úðTTßÊiÿù«´ž9?lÜG©>¦¿RúI<=ä‹°~˜þJœÑ¼Á¿û«ý™¦}SòE±k±ÿJõ`>j“Öuåë+_DuÊ¥þÖü•|Õ·rÒúª¿<Õ18䋨N¹ÔOÞÉëCþ=ö­òET§\ê'_Dõ­òET§\ìïDû²¶rÈ æ¯Òzi/¾¹(—8䋼>®ü~»÷k¿ù"ª;G¹ÔO¾ˆê[9䋨N¹ØOÞ ê[9Á¼“<ÕɧQ?ù"¯ËGmåt䋬¾uÿ•|Wg׉òEX‡\ê'_Dõ­œÞ®ß勼.E¹Þ/Î`Þ@žŠêÎQ.õ7æO䋨¾•“Ö鼨‡<Õ)ûÁSż/Ï_ÉwwúJù+ù¢`¯K·Ñ_‰ÓÙñCþj¼û³>Öa˜ œ`Ç¿|‘×å£|Š¼Yú\(õæ þÝ_í¿Ö¼Sìú7å¯ÂÆýWò`i=SWä¯:¸pÎù"ªûx”Ký!þ>C9~y*¯ý•8䋨N¹ÔO¾ˆê[9䋨N¹Ôâ:ªœÿ>߇Eõ­œ<Õ)—úÉy}Úè¯Òzl/ždÈQr©Ÿ|Õ·rÐmüý+䀧"ÔP.p¿²¿’§êìþA탢ñïr%OÕÛuY“÷_Q.qÈy]û²0×®7åÁÈQr©¿·ënù"¯ËGmå æ ¶ú+å‡|Õ·rÈ;Qr± +s¡Ÿ|Q^‹ÆCòEüå‡|‘×ÓºkwüC®÷7ò]æä©:«Oq}•øÎQ®÷‹C¾¨‹ë«ÄÓ#­»Ò¿£\â§òº¼åzÿšwÌ'Èk9G¹ÔßØ>Ú5~ü~»jãï·‹Cû¬¼.„¹æÁÔlþ勼À_]U÷°ÿjεãmö]à‚Õµ/+­¯Ê÷Ýœkýää©zø]wÊ¥þÆÎ3Ú ¾•Ó¦¿êòõ)å‡|Õ£\ê'_DõÍðTîµæýT°ï‹¼ù¢Æþ.á½å‡|Q÷R.qÈQr©½“y$ÍÏfx§ÁêMö“>ånöN°/‹r'è'_4€¿6rZóWm>x=­sÆÊõ~q†xKÿòETwÎœ œ´.*ù䯺|_!å"‡<•Õ›|ºs”›>ÊqÊwæ¶ú+å'}Ž—¹ôûWíußwAêÛÌ1ÿ#_DÉÇ£\êCªú"¯·yµ¯èï_É#QîVïÔÚë"¯µ•“Ö3åë+OEuÌù"¯ËGQ®÷¯y§ÖöemÝ¥~òE^ŸòïÆP®÷¹}Ñ—ùûíS¾>Më™Åë«¿3hõ!×GÈ%ù"ªOKýä©ÈGmå/¢:åR?y*ªoåÐ>+ªS.õ£/¢}Pà¯Þ‰<ÒfFžŠê4èà‹:«k_ù+âôvý•Ö3{ñC¤³z£:ä"Ç®å‹:«ËGa®õÏòTT7Îœ ý䋼Þ\;?²‘3Øõ¾<ÕuÊ%NcþDžÊëòZ”ëýâ¤õ@:^ô ûçß³²ñ(—8‘[õT^žrÍêï_͹À!Oåuy$Ì5¥þ`ÏW¾ÈëòZžKLœÎŽù"¯Ï>ÊÆ3ç']”¯¯<•×‡¿%ù"¯÷°ÿJ¹Þ/ìýÞæß¹j îœ9ú;Ovù:ë9è‹`å"|Qó…½ Ë×=Ä}ïãÁŸÖWe}ëþ+y*÷Hmö”ëý3Ù×éØŽòWì¿Òx×;;(®sÊ\Õ£ÜÃõN<•ù¨¹¹éó¨úÓz¦¬¥ýÕì‹âçl™«:'­jýá_Ù_ÉSÅCiᵺ»~ß&%ù"¯k_åz¿|Wkó&OEuç(ûíøùJû+yªá ËãY>*­ëÇIÞ÷åþJœÝÌ_D‰r©Ÿ|‘×Û|_áVú"Û•Ö9{ñÍE¹È‰ë¢òxKë¨Äñ¿'¨ú¹[½Ó@û©¾½>žžúÁ¨c.ô“/"E¹ÄAO‰r‘CÞ ê[9ø"¯¯Ý?èýò]]5ù<0X=­sÒqë姳ë5ù¢ÖêiÝ•ø˜kýâtà‹Òzi÷>Kïµøhóþ+Ê%ù"¯k?åz¿|WZÏ”ãÜꯔKœÆ|…|Q°zÈp+'­ÊñËy]^‹r½_œøÒ-ü•<•×Ç‹¯x÷XtŽr½_÷EòN^—GrÎœkþJýþ|勼>û(ãh<Þ/NZÏ”ó/OEuç̹ÀI×%_¾ˆê˜ œÞöYÉQr©¿±óù«.{­Í;Ovùú´±zZ_ŒG¹Þ/ú"ðHÎQ.qÐmôWȉë™òø‘/¢ýT[9è‹ÌGÉ_Q.rÀ;‘Gj —ú[ðEÔ·rÈ5àµ(—8ä‹ZÛ5]{ÿþPÊ%ù"ªS.õàF¨oå´ñ<°{ߧ÷~|„|è¬Þæ:ågˆç·’/_äõ´¾J}”ëýâ¤õLÉ—§j¡îå'ÏK¾¼Õ)—úÓz¦äÿ[õWÝß1¦ç™>ßËç+oÀƒÅÿ¤ê©¼>>ÿ’SÓúÊ9Êõ~ù®´+Ç#_äõñGŒ{âåz¿8­=_òWS^ß:G¹ÄIë™rü[ýÕœ òET§ñP OEõ­òE^³×¢\ïŸr?ú"Û•Ö9éøqŽr‘ó¯ì¯ä©Ü#éw±×_‰C¾¨7”¾ïKóC¹Ä!O5™×š²×¢\â/êÁGQ.qÈQr©}ì¿ÚÌO… r©?§¢:Œ‡8è‹Àk5KœÁ®³Òú*ç^orÝ9ò`Þ/Nk×i=³;ÏX}¥\â¤uQâé!OEõr±ß¯»¯µ¿Ïª‡úVNZ_•ã¿ªýÕ!¾"Ž7æ¯äµh<ÄIërüòE^Ÿâúj×¹Þ/N|]þJ¾ˆêΙsCžÊëòH˜{˜ÞI¾ÈçsöQ9i=SÎÿV5ç']”|òWÝÆýWâ/¢ºG¹ÔßØû}öEVo7ú«™cçÏ!_‡6VïT‡\Óx˜þJ¹Ä!_4Á¾,Ì%ß÷óZ]ÞE¹äÐG¢\ä|…ýù"¯ëï60ï×ïe‘/"åœ9|ù"¯7ùõ¥\ï—ïB_×9õ¡ÿ¯~×Ý9Ê%ù¢ÁüÕð–«<å Kœ_Ÿnå¤uQùúpÿ`Úg¾NÊ%ù"¯ËG9G¹Þ/ßE¾Èëi}•ÆïåzÈýè‹Ì_iÿ•s”KòET(|ù¢öSQ.rÀ á²w쎗tÌÄG¯}kûåî¿J륔‡¹àÈõ¶ž×ß%t¦\âtà©‚ÕµŠr‰3ØuV£ó€ÕÓújwüC.rìzMžªƒz¹=ô“/òzZ/¥ñS®÷˃õ~ýþJû©œ£\âŒæ È_¥uN¿s”Kœôyšþ;=ä©‚Õ;Ø¥\â¤uEÉ—/òº|åz¿8q܇密ïÿ¦êýƒÊ%y*ª;gÎ=Lï$_äó0Àï_ïú?ß«–ó,NZÏ”õ­þjÎNZÏ—|ù"¯ËGÑx¼_òNTwŽr©¿±ó†<•ŸÂF%NZÏ,æ'_‡Rr©Ÿ|Ñ`þª‹ë«ƒéMã!ΞŠ¼å'€§¢:åb?x*òQ›9à‹Ü#Íž‡ÆòET§\êG_>j3ÇöYɹG’Âñ ‡|Õ)—úÉy}\ñWÞ/ßÕÆ÷ãî}™Þ›ñ!O•Þ§µºs”Kœ!žßJŽ|‘×Çìµ08i=SòCöT^ïÁ_)×ûgNü|)ùòEé<_Öƒî+´ñ(×ûÅI뢒#_Duç(ûÍ{̾ÈêÓF5sâúªÿ쩨¹úã!¹ôWÙSQ}+§µ\yª´Þ+Ÿ—ê”Kœ´.]p䩬®}Y˜kýò]i=Sò;ðWm®·Æ™sCžŠ|”G¹Ä!_DuÊ¥~òE×ç¥ö_É›ÇÏWòT|}J¹È1%_ÔØ÷ªSîòET§\êïmŸ•|Ñõ­òE¾ŸJû¯(—8䋨N¹ØO¾ê[9ä‹p_ä}‘ù(y$Ì…~òE£ù«&ßßJã!N _DuÊ¥þÞ®wä©Òû}/~˜èÑ®ø+âøõšüU°ëÊ&Ÿß(9q=SŽ³ËžŠ<åRo×ïòETßÊIë¢rüòEÔ)—8îIä©Òç~™ÛdE¹ÄIë’#_DuÊÅ~óWòEñ¸¬z­­òT^—GÂ\óWê÷y“/š^²œÿ.û«Ö8ø+q:;NÈ_ù÷Û)—8i=_¾¾òEÕ;Ø¥\âwòz›ÿŠr½¿Ïý~Þ§òó@þJ¹ÄñóU—ýUZç”ó¦:å‡|Õ)—úûœ +ú+óZé{ºƒñàßÊ!_äõö_)×ûÓ:-‡<ÕÉ9Ê%NcÞIžjºÚ Î._ßñ}—î®Ç(—8è‹®wƒ³wÏ/=Çø˜ù‹ðTÓMý‰”×Bîáz'yª|æZ¿8äzØE¹Äì:E¾ˆê”Kýé}]¾Ži}µ›g¨oå æä‹z«§uוæZ¿8îf_d)­»Ÿr‘CžŠê›>_ó û¯È_5°ÿj«¿’§JŸû‹ñ€¿šs­æÄõUÉ‘¿J뜲>Àþ«sƒõ‹_²ÃòWÍEgíîüÿ¸{óðYªÂ\·ƒŠhPAM9žÄ““˜ä(²w‰QPE°DE1Šˆ…8 ƒÌ A±˜gdpÚ»PL9"Ʊ‚Fà„„hT¸µúW_=k}¬×¢sOž{Ïé`,ÞoõêêêÕoW÷¦^âøxy*ÏËç¿?H½âT¶nòE¾þÍ赨—8a_¯sþªsìù"÷Q-üýƒê%y§Ê¾W(D½Ä!_D9õÒxòE}°›ñWÄ)ìü/OÕ€¢^â /ú·ôúávôÔKœŽ<•ååx=U½Ä!_ÔÚïPÉ_…ýUü|Q/qÈUp=õ‡®³êšîßšaÿ¶:ì —8ä‹ÜGµãõWØ ×q¡/E½Ä!_ÔÁ÷øè%N þª†œz‰ãñŠz‰C¾¨öW1?ì¯ÖO^ê%yªš<ô‡|Q9ì¯Â|u“¿¢^â/jÍ_5ãúP/qÈ…ýR2ÿñ÷¯¨—8ä‹^œ°/Šç/OU[öWaœsÔKœp>ùòEžwÃßÆQ¯§3o _ÔZ.¯åõ'ìg’ùËY^9öÚxy§°/ŠùòTaŸçòQ>õgXÒÄ_ÉyÞ¿hå÷Û©×Ç‹ã½òT¥Í_>Ê9êEŽ­›<•¯Ãäµ ×Ç‹SÛqÒ€¿*Á_©—8ä‹'y~ߤ^â/ªÌ#Õ£¿¢^â„}Qô‡|QmßÔúP/qÈyÞßÄ^òN੪_¥SØç„õ§Þ8ä‹Â>'ðtë‡ëÛß©—8a?sêñ<àyØç„qØ œÚÞ÷•ãy,ìsâÞ°_ZÌß8ê%NžÊóbôWØ œÆÞwËyÞß+Ä^à„}Q²£§ò¼„ïª×ÇËw…×å˜/OUXÞ?äÆ/†qÎQ/qÂ~&æËSy^þŠz}¼8Ô%_äy þjêy*Ïå‘°×üÕ4ÞÖYžÊ×A9ö§²ãGžÊófÆ_ùxqÂ~>~|õ¾Àó +ü•z}¼8ä‹(wŽzi<ù"Ê—åv¾jÇ÷¡”S/ŽOö9Éã2ã¯h<ù¢ÚüU?úe9 x*Ï«Ñ_Q¯û¢µÃ“‘<åΙzÁ;‘/Â|IN žŠrê¥ñä‹jóWaÖsYù¢Î®§ +û«Åã½Ä!_T û«ÀÓM‰z‰ö31G¾Èóvüþ õúxqÂ>*æ‡ýLø3åÎQ/û™˜/_ä¹|Ô²òEÅ=ôWê%N8Ÿ'󗧲¼sê%NkþAžÊó°_ +ó¨¡×Ç‹öEñüå‹<¯Á_©×Ç‹öE1_žª±\^Ë9ê%Îp—%_äy÷•ë¯¨×Ç‹SÚ<å©jË{úýö±—8~å‹<ïà÷ÛÕëãÅ©íø)Á_Õ௦^à/ò¼¥^/ïT‚§¢Ü9êÅñà‹Â>'9ngüUãÉa¾,‡<•åÕŒ¿"ïD¾È}ù+õ§4%_TX^ŽþŠz‰CžªØøî×o¯NÔKôTæ‘ÚÑ/Q/qðT-äÎQ/qп¢^ä˜w’§ê o —¼ù¢ÒüU7ú+ê%NØÏ,Ž‹pl ·ÉSYöKaõ"ÇÞÉ–×òZÐöEñ<Å!_D9õÒøʼÓä©,/—ôWÇÞ¿Ë5”S/ŒïÌ?ÈyöKa}©×Ç‹S˜÷§ª-/—üý+qªa’<ò¼sêõñä䩆¥H¼Vùû.~ÿÊ9êõñâ/¢Ü9Sï’þª³ïV3×_ùã8ù.;~ä‹*ËÛÑ_a¯'¼/HßÑSQN½4ž|åËrÈyÞû«µÃƒK½>^×_ùùª]Ò_©—8ä‹(_–C¾È¯§š»þŠ8ù«ÉYö]aý©9ä‹(‡^ò]ä‹Ú%¯¿"N þª†œz‘¾ˆüõÒxòE­ù«°^<¿`>Ä)ÀSõðýAê%ù¢Þ¼–<öÂø +üUiyØ_-Žÿ%9ä©(§^O¾ˆ|ÔÒœáõ%ÜoÝä©jËy-ðf>^œvx]‹ùòEž7à¯ÔëãÅ)Í_Éy^‚¿R¯§öWñüå©<—×rŽz}¼8ú'þJžŠr稗Æ×6ù"Ê—åøý•/ò|ºž +æããÅ©íø©Á_5௦^à/ò¼¥^?çÐGÙïÆ«—Ƈ}Q||6£§j!_–ƒžÊ®¿ +û®ÕÃÁC½ÈOUØyXÉ9êu¥ñä‹j¸þŠz‰C¾¨þÞœøq û®°>Ø ¾‹|QcþJ×Q/qzðT5|z‰Ó‚§ê,oF?F½ÄA_‰z‰C¾¨6~o!<¾ËrÐÙõTºþŠz‰S Ï£0¯é6z*Ê[è¥ñþ~'ì£}棔/Ë û™xþºÎÊób<ïÑ||üÄ_„^Ëæ£Þ8½'Õ.yý•8yy*Ï[øþ z}¼85xªÂò®¿R/qªa??¾òEžpý•z}¼8ÃqŸõT”;gêy*ʱüù"_ÿÉG-É©ìø‘§ò\> +{C¾ˆrê¥ñä‹û_1þžÕ²÷NòEeæ<°vxp©—8~¾ +û™À¡œziŠzÉ;‘/jÀ_Q/qz{Ÿ"OÕZ>7\œ —8%xªÊòjõúxqÈ…}N|\ÕðýAõ‡|QþŠz‰ƒ¾ÈüU3¾o¥^âvž—w"åõ}‘ù«¾?¨ù‡|åõ‚ï"_T™¿êôûNKrÈ‘¢^â/jÍ_Ñ÷uýqÈ௨—8ä‹ðWÔKòE”S/¯þ/óW“/²÷å’þJœÊ¼ÓtÝ”åtý•z‘cþJ¾¨¡œza|çÞ`ôTž‡}Îêa“@½>¾Çà©<×õTÎQ¯'ï$_T û„0_Ý*ðWêõñâ ÿÿ=òWÍ)wdÿjêy*Ê}>S/x'_7y*÷ZʽW¿ßNœÊŽy*ʱ8ä‹(§^ö3ñq"OU[^Íø+â”vž ç°oë†ýUÜ[9ö‡¼Sx¿óÃ>çwõ‡|QØ_Å|ù+ê%ù"Ê©—Æ“§jÀ#-Ë!_D>Šz‘¾¨²<ìÂãK½ä»jðE%äØ ãÑ™jþ“ß$_Tû«°º…Ïßi>ÄiÈAN½Ä!_Dy½4¾OEù²òEx-ê%z'ðHÔ‹ðTáõ">~Šñºße9­yù"Ïkøývõúxq*ðT¥åºžÊ9ê%N3ì£âu/ +û¥8¯á÷ÛÕKœá)™ø+ù"Ïu]õúxqj›§|‘çòZÎQ¯Ç×Y¾Èó~¿]½>^œÚŽŸüU þjêŽ{'ù"Ïå£|>êõñâ„}QrœŒžª´¼¥^â/"…½à»ÈQN½4>ìgâõ‘/¼'_„> +æCôTÃþ*¾_áúçÕÓ {Á;‘/*À_ÐKòT”S/G_dþJžjYù"ÊèÅñà©ÈG-ËAïdßœ»þ +9à¯jËK]—½•/Æñ…½ÏªGžïáx×Mž™z‰öE1gòES/qðE%äô§ïäy5\ßî'õúxy°Î¼|QØçÄëÖÂ÷ÕKœÂüÕä‹,×õÒÔ‹œaÏS¾(ìsâ¼Ô÷ +¡×Ç‹3,iâ¯ä‹<Ÿ¾Ç½>^÷EúÝ*Ï'dó™zÍ_i<ù"_Ͼ?X¿ßNœÊŽòWüþÕÔ œð>"~õ{Sž×ðûWêõñâÔà©*Ë;ðWê%y*Ï›Ñ_Q¯—ï*íü)OåçÃü•z‰C¾¨…½0ž|åÔKãÉÕæ¯êÿŸ~°"Oey7㯈CžŠòzi<ù¢ÚüÕt}Ú’Œ|]O…½à»ÈQN½8~Ø­^tÓuV½åº.kYNµ¤¿¢^â/ +û¥ø~é:¨e95xªÂòzæ÷Û‰^âyÑ÷Óã¼sê%NØÏÄù"Ï+ðWêõñâ¸÷/ªî¡¿šza|Ø%ó=Uc¹®§¢^â Ç}â¯ä‹(§^_Û<å‹Šz‰C¾ˆrê¥ñä‹ZóHáóÇpü,Ë!_D9õÒxòT x­e9ù"È©—8ä‹(_–ž×áqÓMžŠrê¥ñè‹Ì#ãùmYNIžÊòéº,è%NãïßGOEyE½À û¢xýÛÑSu–73þŠ8ø¢Úò +~ÿJ½Ä©†ýI<ÿÉSAN½ÄŽËÄ_ÉQ¾,‡<•çòHØkþjoë,_„>jINelj|‘ç-üþÕtÝpÂû‚øñ•/*,ïÀ_©—8ä‹jóWáóÁµá$E½6^¾«³ë¬&_d箿R/qÈ…÷‰ñºU£¿*¡—8-x§Ò>ÐõWÔKòN•ý~»~ÿŠz‰Cžª4¥ïR/qðz'øý+êEø¢šrè¥ñä(_–C¾ˆrìßE¾¨²ïÎý~;qÈ5põ§OÕZ.¯E½Ä ÏÇÅy+œ»†›ÎåÅx~ ^ä 瓘/Oå^«¿?H½ä»ÈyÞŒþŠz}¼|Wx]ˆç/_äyþJ½>^œ°/ŠùòEž7ã÷£^/NØÅ|ù«ÒóÝøÅ0Î9ê%NcþgòT–WtýÕØKœaJ÷È_ézª°¿Šï¯z‰SÛxù"Ï壜£^/Ž¯³|‘çÍ’×_‰SÛñ#_äy×_M½Àqï$_ÔÚïPuà¯ÔKòTî£ÚÑ_Q/qȵæ¯Â¾kõðàR/qðT­åÝ诨—8ä‹Â~)>Λñzê%ú"øõ‡|åôÒxòE䣖å/¢œzi<ù¢ÆüÕÿîë¯Zøþ õ’w"_Ôƒ¿Â^O¾¨öWáùª›®¿¢^âÔö>eºÎÊr]OE½ÄéÀ_öþ«Ïô'ì‹âu§ò¼ÿþAêõñâ /2Ô?våï‡uŽz‘cï—u½Sc¹®§j¨×Æ‹Ó™7/ò¼]òûƒâÔæOä© +ËË%ÿJœ°Ÿ‰_òW|P½Äž?÷È_M×SÙ|¦^ৢÜç3õ‚w"Oåy ×_•ÿ¸^^G}?îÕŒ¿"NmÞI¾Èó +®¿R¯§´óJ냽6^×k‘/*áz*ê%ú"ðWÔKœvx…ó«nòT”÷ÐKã›áùóå©Âó=Ϋñü°,§35y*ËÃ>'ôQ/qÜ;Éy^ÁõWêõñâ/¢Ü9ê¥ñ­yù"Ï ¸þŠü•8îIêÑUæ¯Jøý«©×ÆOœa?“'pýU=æÔöW9ÎpH$þJ¾ˆòÆ8ê¥ñµ—§ò\>jYŽ¯¿|åÔ‹ãýø믚%ý•Æ“/rÕÎø+â/ò<ì—V‹O½>¾•ïOEÉ9ê¥ñè‹Ì_…ýU˜ÿ²òEä£ÂûÜøy4õ‚ï"_„>Ê8•¾'µ¤wª‡ýR<Ïÿì÷ɶèÇß¿¢^âôÃç€ñ<å‘*ûýv]E½Ä!_Ôš¿Ÿz‘žª³<ì¯Ç'ô’w"_Ô™šþ^Bè%ù"Ê©—ÆWö>EžŠòe9…½ß©Çó åÔKãÑeÞ†ÇwYN¾¨´<ìs¿‚^â4öþ]žªµ\>Šz‰CžŠrê¥ñxªÚònÆ_§ö'‹Ç-Šz‘žŠ~ÏŠz—õN•]ö?áq§Þ¥½Ó°Ï <ݾ.ü™zÉ;‘/¢¼†^_‚§êàú«e9=ø¢r¸¾=^Ÿzô«ÔKòEå!©×Ò÷©—8xªÆòBç èEÎp>‰×A¾(컲9ôÒøbØGÅù"Ê—å„×…˜/_äy7þýƒÔëãÅiÍ?Èy>ï ópŽz}¼8•y'yªÒòjØ_¾sÔKœfØGÅë#_öKqö9‹ùC/q†)Ý#¥ïñQ/qjŸçø=ÁÒòzÉïÊwù:“¿ÒõTÔKœÚŽŸüUþJ½Ä!_äyþJ½>^¾‹|Q3ì¯âã'ì—V¢sÔKòEa¿óÃçƒO½Ä!_D9õÒxòT¥}®QŽiYyªÖ|T5þ~;õ§&O9õ§ OEù²òE­ù«nü~õ"|Qù°‡^ŽGÝħ^ò]ä©óHáó¾ÐG½Ä!_T›¿úÏþýƒä‹(§^_Ùûù«Âr=¿–æØû/ù«ð<ßð¾lñgè-€SÙûµpýCàPN½4ž|QeþªœñWÄiýýûøýAÏ{øûÕëãå»:ó ºÎÊórüþ sÔëãÅ©ÁS–·ðýAõ'ìgâãD¾Èó®¿R¯g8T%_äyù÷þòªp\Ù|¦^à§ò\ {Í_Mãmå©Èka/p;~ä©*Ë壨—8¥ÿ3þŠz‰Óƒ§¢|YNiçy*ʱ—8vÞûßí¯ÈµKú+â/jïH¯û«µÃÁO½Ä!_Ô¿Ÿ7ôýAê%ù"Ê©—Æ“/"µ4|QeyØ_…õ§Þe½y$ê¥ñä‹Èk-ÍOUX®oëC½äÈSuöþEþ +{Á;‘§ò¼ýõúøbߧ¢Üü•z‰C¾ˆòe9á|7Ýä‹jË›%ý•8­û‡ÑSy.E½>^Þɽ‡<•çÝ’×_‰ö3ñú„}Qø³ç |P½>^œ•ø+y*ÏûòSÇjÏG½>^œÒæ/OU[®ë²œ£^âÜmÇ}¬çòZÔëãÉ;à¯ðWS¯‡â/ò\>ª6Žz}¼¼ù"Ê£^žŠ<Ò²òE]ÕŽïO©—8¥ç§÷ÑvT3ú+êEx*òQa•<¿ô½E‧¢ïñQï²Þ)|ÞÏS×_Q/y'òE…ù«ðùÝêáä@½Ä!_Ԙןz‘žª‚œzÉw‘/¢œzi<ù¢°_ +ë­[7ì¯ÂŸ—åà‹ZËÃuïO½Ä Ïëxž<•½/«Çœz‰SÙû>ù«°Ï‰{Ã熋?C/qÈSu毊Ñ_Q/qZ{ÿ._ö9ÉüGE½ÄéÌ3ÈyÞŽþ +{S˜÷/ò¼¥^/NõªÔ_Éy^¿R¯g8¤%Oåy·ßY5õ‡|åØ þŠ|‘ç%\¥ßÑòñs×_UvêEΰ¿Š9òEåí’ßg8.%_D9õÒøÚæ)Oå¹®§Z–ãë&_D9õâx;~ðW=ü~»æS‡|QaÏ‹nøÜpõ°8ÎQ/qÈ•výU3^E½Ä!_Ôš×jÆ먗8ä‹ZóWÞŸB/rÀ…}Nü¼›¼õÚxù.òE…ù¨v¼þŠz‰C¾¨¿O{a<ú"óWú~õ‡|Qcß+ û«pü‡ýUü¸¨9ä©,Ÿz/ßE¾¨ýƒt?9ÍÓ8ê%ù¢Î®¿j†¿ßy±>ÐKòEù«fôWÔKœC˜?õ’w"_D9õÒxòN”/Ë!_D>Šz‰CÞ©·¿ÿZ¾Žz‰C¾¨ßðxN7ýý’ÐKòEžëú+êõñáóÄ0¿<åÎQ/¯Ì;Uãùòe9ä:óZíÌï_§ U[öWa=©9ö>½¯³ª)‡^߯kñq(_Dù²œ +jYŽ¯[3ú¢»åòQ6õÞm'æ43ß$N5ì£bŽ®³ê,×÷©—8½ï–§*=‹z‰Ó™g¿ª-ûœp?±×Æ‹S€§ª-ï¢×ëx=ÕKœ°/JÆžŠrê¥ñÃ]Nü•|åËrÈSy>y$˜'_ä¹®Ër]Ç%ßUÚã^žªò|ÜŸS/q +;Î'Oåùø¾ƒz‰C¾ˆr?þç®ã"_ä¹®ƒ¢^/ßEžª²ógþJ½Ä!_ö]ñó.œ‡×O +ê%ù"Ê©—Æ“/¢ë©–å/"…½ÿ}|y-òWÄ!_D9õÒø°Ÿ Çnúž åËrÈ•Ãçtqo=^OE½ÈžG1§ŸGåòQØkãÅ)í}SxŸú<×ù{ö3ñüå‹Â~)—c/ŒoÀS–WãõWÔ‹œáu$ž§ÂqžË±Æö>«Ï­}Žß9õ§Îoñ<å©JÏÇóõ§OUY.¯E½Äñ÷Ëáúöp{ÿ.¯…½>~ä„×Áx}ä‹:ËËñû€ÔKœS/pÜÉSy.äó™zíº)'_äë ë©¨—8•'Õè©ËË1Ç^/ŽÿòE”S/'_Dù²÷N“/öWñqÛߤ^âTvþœÞ‡ÚùsÊ¡—8¹óíÚðb9Ÿ‡<ìÓâû¥^¿7EiYù"Ê©—Æ“§¢|Yù"Ê©—Æ“/*á:¨e9ä‹(§^ÿ_ì¯Ð-é¯ˆÓ Ï£Åó)<§†›<åËrJóNÓóÑòvôZØkãÅiìý£üUØçÄ÷«ÏoaŸçê%NžŠrì%xªÚóñóê-|üè»Úáu-¾¿aþ칮ˢ^/Ni¾B¾¨²\ßtŽz‘c¾E¾¨±|òZÐöWñ:ˆ3,Eâ¯ä‹î–_׉áûƒÔ{·ñãï½×Ö+_äyÿ`?öúxq|Ýä‹î–ëóY›zï6^¾ËŽŸ~ôTµå͘ߣ^/ù"Ê©—Æ“w¢|Yú¢%ýqÈ…}Nr<ïO;è%NØÏÄœÉY®÷ÝÔKòE”;G½8¼Sù²òT”c/||QóÈï_‘/¢ïñæÍt]qÈÕ·¥×_µúý+ðiÄ!_TÙ÷øÚñú+ê%N8žW/ºMdzåº.‹z‘cïwºñಜnx]‹×GžÊs]OE½>^œ^òE”;G׃áx[gyª°Ï‰ïo¿ßÞüÃÊß7ä£8?ãþ¼ö|¼.‹z‰SÚq.ö9ñü»ñýö‡|Qeß+ ¿/ºvX|ìµñú½÷°ŸIæ9¾ó<œ—Ÿz}|'Ž÷ô¾2¼OŒ{õ>Ñ9ê û¢xüıóm8ÿ‡y6ö;T͘Soîü8è‹Ìkéï¤^ä û¨ä~éwìûƒúûêù¢~£ô÷3‹ï¯ü»_¦^â/*‡ÏãûU|uå{Ô‹ðTÅúé÷ +}¯z—õNÕcîþ{áx Þÿ·þªöWO½aµèsnÓu\à©Â~)öWáÏÎQï²Þ©žw1¿Ðóz;/ž1GçÒòzôWÔ‹ðTåÅx¾¢Þ°¿ŠçYŽãÑ™jáú+õ§^âÞðù`ø³¿ÖuPÎQ/qZóòEž‡ßý]½>^œjxç/O^¯ã\^Ë9ê%Nc¾EžÊóv¼þŠz}¼8ÃR§þjôEý]w%¾«~ØÃOÊù«©8µÍ_¾ˆrê¥ñ¥­³¾?èëPÊGÁ|ˆSûñ3zªÊòz¼. {m¼|—çºÎª³ï^ùÜœz‰CžªöKññY<á‹7¯ê%NØÏÄœ~8oNoy=æØkãÅA_”9þ®^äØy{zmß û«À÷óp8o/râÀuVÝíéëW3þ~{ ½Ëz§ÊüUØç„yRï²Þ©ztº¿ŸøÔK¾‹ÔÏŸÕ˜S/qÈÕæ¯êñý5õ‡|Qo©öWáø¡^䀧êÌG•òZÐKÞ‰|Qkþªÿ>Aìµñò]ä©Ša•<î£_¢^䀧jœîßÂþ*¬?õ’w"_ÔÙþSëC½Ä!_ÔÂß?H½Ä!OE9õÒxòEa¿´Xï°æíþ~çðçe9áù˜pÆó@q}šwë­|¯z‰Ó˜w*ÆóXkyØ_-æ½Ä!_ÔùûßñüŒ½à»ü}·<•¿n‡ïO…ùS/qÂ~&^ÿÉY^ëõѼz‰öQ1_ž*¼^Çy­ß¡‚^â4æ[ä‹JË+øþ z‰C¾ÈóêÊŸüõúxù®Úç9^gåysëzÝêïõúxy0_7y*Ï;ðWêõñâ„ýLò8Žžª´¼¥^âøq.Oåy8ÃúP¯}ѰωïW þJ½Ä û™˜#OU[Þþªƒ^â„}QÂ߇úù°sê%N ¾¨°ó9¾¿¦^â/*ÁkQ/qÈ…ýR²n£¿¢^â/¢œzi<ù¢òÞéþ'|~·z8þ—å /zHºŸz‰C¾¨$½ÈOÕØï_µ£¿¢^òN=xªÚr]E½Ä ÇsxÜt“/ò\Ï/êõñâ„çcÌ—§jìz€n öÚxù®vxŒ×?ì¯ÂŸ;È©—8áu9æËõg¤y?ú+ê%N5ìOb¾|QØoĹ|õgXŠÄ_Éy^\tÇÂ_Q¯‡<•çòHÎQï/naÿîwÿÒUíš1 ÿ(ÇûQ½tÕ±qÞjüáÏzOœwcÞýæÇÅ9q†ŠÅ:U;­jW Э9Í<.Ωwøÿ²åÅ»œs4ÏöÎߣ^â(¯ÚåÚ,ÿèÓߙͭ—8Ê«£óüz‹w\’å[/qúq«]W]s”×Ï}ÚGã\ëæ½÷߶¹*Ç)¿{øq.Ž÷§÷îömÎÎrn¼Ïaq®ù{ï§Ø%|Vl{òšarºMó·^åÎ)Çù—/zå‡ãy¼ÅñÜ]ú‹ëÄoôxY/qÔ[þj›·åøýÓÿâœxþÔKåõª=.ÊñË?~ëÁ9¾÷Îr>õ‚sc¾Æ7·ïvFœkþÔ[Gã‹O½àÓñ<Å/>}特œz‰Óf—÷Äñ‹“NU|¿”{ï,çg0ÿg|ý}ËôÆÑãR>nÏfçùïéþvš¿õGy·kzþ§;ôÎîI/q”‡ó[nªï|E.÷^â”ãù³<2}ÿ«ù×?¿:Ùÿ+÷^â¨wاϳ«æ?`ÿc½ÄQ>x•dŸ#~û¬o¿åžôGùðÏä¦u(sð!9¾÷ÿsv+Nþ ùw{|fÜþÙ{‰£Ü½ÓÄ74åÖ;å6¾ÕùÜ<•îosקÔëõ-ë'Çq'æ©Ä¯¼~ò¾@¹÷§ùî©&Îû´føCt[<ŽÞKœ)_TÞÿ³äøõG¹û¢r\çþsŸIÎÛÃýXÌß{‰ÓëC¾¨¸è‰— ^â¨×}‘æÙþø —æÖÇ{‰3õš/¿Þn§ä}½rï%N3®{*qúþ’Üü½wŽãžJüîßW%þV9õÇ}‘8ͦOö‡Ê±|ù¢þïŸsDn}¨×9z\Ðí¸áÕ«†IG·Åñï½ÄQî¾hà­pö¼8ñ·Ê ë%Žr÷Eâô/?ðÙù[/q”»/¿Øìòk²|ë%ŽròEõÅéùz‰£œ|Qyô^¯ÌÍß{‰£œ|Qÿ“õ›ß{‰£Ü=•Ö¡?æÑÙó¿÷G9ù¢j·=“÷•ÔKåè‹ ÝÏ ï%N3ž?ÝS Ì•ç×{ýÕš´`‘§Ñpýà §0O%~wÉÿQÞS¯qº±—|Qýµ<ß{‰£}ÑÏÖOö½š¿÷G¹û"qÚŸ­Ÿø%å•õG9ù¢þ7û”{~y/q”“/êïýÙÄ?hþÞKåî‹&Îç·þHnþÞKœ~<~ÜS‰ß~í‰ÿWÞ[/q”»/š8»oœ|n«Ü{‰ÓêygžJœrýg—]ë%N'>ø¢æàÇŸžã{/qú‘ï¾Hóïw}ø>k†?D·ÅùÇ{‰£œ|QñäkŽÊñ½—8ÊÝ•:^ñ„äýép?VΟÖKœv\÷TâTG=é¬xþÔKõº/¿øÁ™Ùý³÷G¹{*ñ›§ýùãÇ{‰£¼_Ômqz—ã{/q¦Ü<•æßï¾qr]„rï%ŽròEÍ—÷È¿¿°^â(w_¤yVOý‡ÄÏ+÷^â(wO%N·Iþñõ^âtãñïžJüúñ¿yeìg”{/q”“/êÚë¹ãÇ{‰ÓëùkžJó¬p@Öox/qÔëžJü¦þ?øØð‡è¶8ÿx/q¦Ü¼S9žÇjóHCÏÊùÙzgÇ›§Ro½Õwω×_yuÑõÙç…{'ÍÇ}Q«ãjužï½ÄQN¾¨>b£3Ö ƒt£Þ`¬›y'åî‹úqþÅ©ßLÞ_h}¼—8åØëžJó,·þböú%ï%ŽzÝ5ãü»‹÷KÞ_S/q”»/§X³ÿñúS/q”»/¿ÛäÏ“Ïm•{/q”»/§\gç7ÇÇ¿rï%Žr÷EâT_|wò¹¡rï%Žr÷Eýøøö·íóùÜü½—8ÊÝižÕ]7­‰ùÔKåî‹&þ ?NüÌ”[/q”÷æ‹:­ÏÞ÷Iöÿßz‰3åæ‹Ä)òëäø§^â(wOÕëüóW~Küü¢^â(w_$N³ï#’÷ÔKåqþåƒv>2>~¨—8ÊÝMœ³®O®/¢^âL¹yª^ëßí|nýë%Žr÷EÍÈonzÒ 1Ÿz‰£|ø§ßV^ï.¸îÞñþz‡ÿy1Þ!Êݵz|¯ÛöÔøñÕøÆz•;G¹û"ñ›÷m¹K<å%ô:G|òEÃOnâ{ï0h±>ÎQN¾¨<ÿúãâÇ·Óq•´.þ°à;G|÷EÓ<¿õÛįŠï½ÄQî¾Hüj¿ï&ûsåõgÊÍS5:~Þ½Q²Ïß{‰3åæ‹:=¿®:2ñKÔKåî‹4Ïæ[O:!>þ©—8ʇ÷¹Ùשú>uM|üP/q”“/êθò´ß{‰£Ü}‘æÙþñ…WæÖÇ{‰£Ü}‘Ö¹½ñ²³c>õG9yªöm«“Ï益8¥öÿæ©úñøl?úµ¬ð^â¨×}‘Ö¡üÊ“ãg®×9â»/Ò:4ý?~,wüx/q”»/¿Xÿío‹_åÞKåî‹Ä©Ÿ|áY9¾÷G¹{*ñûw•Ýz/q”»/¿»ôýÙëf½—8ÊÉw\œ\ŸI½ÄQÕëà5G&þ¡Wn½ÄQN¾¨Ür‡2ö3ÔKåî‹´ÅÙù×wï%ŽròEÕ·{jüü¢^â('OUîÿšäó5ñ½—8¥öEæ©&x$ìµñâ¸/šzøFvÿÙ¶÷yN¼o$N«}‚y*ñ«w¥|åµõgê5OÕ½ýy$þJ|ïã¸/*ô¸Üµó¹ññC½ÊÓŽótO%~¹ù翤¼¶^â4#ß=•8囿ø±)·^⨗|Q¿ÛqÉþmâ[/q”“/*ïüŸ¯¿øÞKåä‹ÊMþ=y}ß{‰£œ|Qõûò|ë%N¯ãÜ<•æY|öÉu¿Ê½—8S/ø¢öö?¿¾‹ï½Ä™rðEí?ÿX/q:­y*ͳûÈ!ÙÏ—½—8êuO%~¿öºä:UåÞKœ~œažJœª7ï%ŽròEåÚëšÜùß{‰Óéñî¸ÝV|ÑÇóÇ÷G9ù¢êã×e¯òä¸%N«ã|Q³Ûq‡åÖÇ{‰£Ü}Q¯uÛâöäóa ëæ½Äitü˜§*Å9ïÉçÔKœNëcžJó,îz@òù õ§ß<•øÍÚ7&ÞI¹÷G9ù¢âk;ïž{|½—8Ý8òEý½žš|yš¿õG½î©Ä©6¿ý͹ù{/qÔëžJüæ¸ OÌñ½wŽã¾Hüþ1kÞ°jøCt[9þ¡×9ý¸þä©ŠVgÏÞKœvä“/ê6~ë¹ù{/q:ÿ橦ùœ°á‰9¾÷G9ú¢mÓóõG¹û"qº³Š÷原Îz‰£Ü}‘øý+K®Sî½ÄQîžJœò±7\Ï_¹÷ÎqÜS Çûâ8/ÎþÃÄŸˆO½ÎiÇã§0O%~}"쬗8º_ä‹šëò¯¿ÞKåî©zݯèÄ0þëÊùÁz‰£Ü}ÑÄ¿è€äó¯)·^âhÝ)ï/NýÉÄ·^wÎÔkÞIãÝ#)÷^å>¾”‡1_4ÍóÉ'$Ÿï‹S]zMrÜG¹û"qºïŸìo©—8ïžJü~˽Úìùz‰ã¾HüºÚ+ûþ”z‰Cžªyì“Ïçz‰CžªÿØ^ïÏ­õ"í×W¯þÝVΟÐKòTÕOoH^‡žŸz‰ã¾Hœþ//Îú+ê%Žû"ñ»ŸvïÍ?ÔKòTewAÖc¯y'ÍÓ}‘òbë'žœ›?õ"Þ«œ8䋪¯?3»ÿ§^â§ê°*»þÔKòEÅÇ/Ͼ?¢^â¸/ÒñÓ¼é1̨×9z\È57ÿ윘?×KòEÅW]ó5ïUNòEÍó¿|eŽO½Äq_¤u(¯Ú*ù|MóÄ^ð]ä‹š³×œÏ¶|ù¢î€ “ï_Oó·^åÄq_¤y6Û¬›õKØ ¾‹|Q½Õ6æÖ‡z‰C¾¨;æÙçÆ|­ƒ÷*wŽÖ½Wã‰Cžªþ«m²×OR/qÈS·Þy|¼>š'õ}Ñz·d?¡^â¸/Ò<›Ý™}×P/ø.÷Eâw·z£çù¢æEy?à½ÄQN¾¨þÖáY¿ç½s÷TÓú˜GRN½î4ž|QñÓÿ–ø‡iü¯÷Î{ó]Óý2_TŽû½úÏ~ž}í½Ä™æcžJüæ±?}|~PN½äÈÕ']–ømñ½Wó$ù¢êïöÉ~?Â{'¾ù.­ù¢î¯Îúïã¸/Òøâ¹·dÏÏØk¾K÷‹|Qÿ'˜ø¹^â/ªßrWöú"ïÕ<‰C¾¨:ãæìïÓb/ø.òEåïüpîõ…z£õtOÕ×Çvçž“ýýIï%ŽÖ|QýŒ§$ߟë%ù¢f¿»²ç1ïÕ<‘Cžj>ûþŽzÝ;iÝÈS[œø½ižÖ;ÇqO%Nó8?C/qÜi>ÝGÿõÀøü<×KòEí??O½Ê‰C¾¨8û¢ä÷%4ïUN÷Eß]û“ãù+§^â/jþôçY¿D½ÎѺ‘§*¾wöûkÞ;Çq_Tjÿ°Û­ù÷§Ðë­'yªbÏ}’ïïÌõÇ}‘8Å+n;>z¯æéåè‹îØû„øø™ë%ù¢æèW¿7æk>õ*wŽw÷EÊ›ýö|GŽï½OòEÍméúˆã½Ê‰ã¾Hë\W·¾sÕpç£ÛŠç´Þ`|^o¾K9ù¢òoìÏK=/ —8ù¢‰sÛ·²¯/Þ«y:G9ù¢úÓ;&¿ï=Û ¾Ë}‘8Íœœÿ5ïUîåä©Ê_ìÿéøøœëuŽŽ+÷TÊ«‡£‹ùš÷j¼s4}Ñ]¯KöŸâP/qÈÕŸÙ19>§ùX¯rçh>î‹”÷[<í¹õñ^wŽzÉ•Ü=¹¾Wê%Žû¢nÜ?÷ë¾î°ÜùÁ{5OçL9xªòÕÛ&Ïß¹^òN䋆÷ÑÙÏG¼Wó$Žû¢r<5Ûÿà ÜúP¯sÔKžªÊÏùs½Äq_$ÎÐï·ÅyÞ{‡A+çò]æ©Êq|qÜe‰?œroÕzG½ä‹ú§žgâ[ï½x$ᅢñî‹4¾:d׬Ÿ¬¾¶¶Ê]7åÝ_òEýoJ>ÿ¢^â(w_¤óL»õ…Ùï—y/q4÷EâW¼è¼øü©œz#>ù¢öœ}/Ëñ½—8Êѽê“Éùš¿õGãÝS)o¾ðÙüç§Ðëõ’/*Ͻ2Ù?ÏõÇ}‘8ý“N<7^ÍÇ{•;G9ù¢ö€/œóçz‰ƒ¾èQ§&Ÿ¯i>Þ«Ü9ÝŒ§ê6}Â×üëã/ªo¹ô€UÃä¢ÛÊyÞz‡ÿ¾È‰C¾¨üí©Éñ©—8ø¢æ¸ó?–ãS¯st¿ÈSU(/ùÓúC/qÈS•÷>ø€5Ñâk>Þ«Ü9šzªö«ÉùMïã/j.Íÿýk ô‡|Q{ÞW³Ÿ/P/qÜéþV??èEñã«õ¡^çh¼û"åÅz?;~|çz‰ãžJœ¡Ço‹ç©÷ƒ¹sJ=¯ÉS½ôû‰¦Þ9ù¢¾}xöýWi½š¿sÔKžª}Ýã’ù‹ã½sòEåÛwÍ^_G½Äq_¤y–§~5ñ{S½ÎÑãå¾HœöÛ]œ;þ½wŽCžª="¿¿¥^çèq!OÕyNr~Ó<½wŽã¾Hã« Óç¯ÖÍ{•§OU½òûoˆÏÔ«œ8ä‹ÊCóëz¿sÔKžª|Üo/Žç/Ž÷ÎrÌS‰Síù‹ë²|ê5ŽŽòEÍ/Î^_í½sœ +|QÕš½>{ã¾HëÓovÓE¹õ¡^çè~‘/*Ï9§Íñ½w–cžJóo÷~þY«†?D·•×©sò½îºOÕ¾ÎÏÖ;Ç!_Ôô¾ìï3P/qÈuOÏzSÊ«§ÚîÂsëï½sôE»~?ëkèuŽz‹»ßÇ ù“Îz‰3åä‹öÎï¼wŽC¾(prϯz‰CÞ‰<õþ®ñ¹ã¤?~··åòâ _ÎÞ/_·áa]<Žè‹ö¸WvH½ÎÑy‰|Q¹î†/Ž×_cc½ÄQN¾¨þÚÉßï£ûë½ÄQîžJœö¿?éêxþʽwŽS™/§ºê£Y>õ:G½î©”·GïüþÜü½Wã£yº/Òø®ÿɹññ©œz‰Cžªù©ÉùM|ê%ù¢æyç¿&ž¿î¯÷*wŽæã¾Hyñ?IöÏâx¯Æ;GãÝS)/ŸþŽdÿ&õÇ}Q©×µ}³Ë?Þ«ù8G9ù¢òÙÍ{bþl¯ù.Ý_òTýÇŸþÚ˜?ÍÇzç8䋪›’õ«ÔK÷Ešg·ÍùÉ߯¤œz‰C¾¨þú ‰¿Ÿz‰C¾¨?ö;§æÖŸz‰C¾¨~̶Ù믨×9zÜÉSuå?f?Ö{ç8ä‹ +x}§^ç¨wxÜü¶xÝoÿåìç_Þ;Ç!_Ô<1ϧ^â/êþéÔ¬_¢^ç ‹²XòEí1éþªÇS/qÜS‰S¿ú^ÙãÇ{5OçL9xªêé¾xÕ0H·rœ?õºwþ¿•õOÕüÓÉõ!ï½ÊÝ;é¸r_¤ñÕgþõ¼xþʽwŽC¾¨ùõ/Nʨ×9å¸>ä©hŸì½sòEýßlxUn}¨—8î‹´Îå š|þ¢œz‘¾¨=eƒdÿ/>õ’ïr_$NqÉÆ—æÖ‡z‰ƒ¾è{\ãS/rÀSU—™=þ+è%ïä¾HëÓoß¼'7ê%yªæ+’ýÛ\/qÜSéù^>ôËÛçæO½ÎÑ|܉_ýÇÏY3 ÒM9õ:gøÿçO÷E¥ÎÇì|HŽï½Ä™ròTW®N®ß¦Þ9ù¢îµë&×MëUŽóEßÂþ{CÞ£8.}}Ÿë%ù¢ê‚ ž“;>©9æ©J?_=5¹~[ó§Þe½“{¤¹^¯ùøë‘žGÅ!ÏI®ÿWÞýê#Ù}‘s4òEõ/¿—øUñ½—8š?ù¢úµÍ;âÇW|ï%ŽrôE›¥¿ÉÄ·^â(w_$N·Ë5ïÊZë%Žr÷EÊÛCÊäûƒÔ«ñÎÑxòEÍw.ÎúêuŽø䋪»®:%^ÍÓ{‰37OÕŸ›´½aâoÅÁ^ãL|ðTýK.»2>>©—8šù¢bç'\óÅñÞ9Žû"ͳúöÇäÖŸzSŽçÉÆ<Õ4ŸWüsr|R/qtÝSMü7­“üý¿Sn½ÄQN¾¨Û÷MÇÆë3ñ­wŽC¾¨n®M~IïUNôE;]ó¦xþâ`/ø.òEí–?I®Ÿ¿¡^ð]苶볟ÏR/qÜMóüÀÙ÷§-ôÇ}‘Ž“þ—&×·Ïõ:Gã ðTý¡ÏIüÌ\/qÈÕÏÈÿýSÞ«yÇ}Q7žŸ›Û¿—œŸÅ¡^ç”Úÿƒ§jw¾&ÙRï,Ç<•Ö¹´ý•æï½Snõº/šø¿ø^òýÓ)·^â¨×}‘8í«›wÄçå¥õG¹û¢)¿ÿ¥Éû#ñ½wO¾Ë<•8åß•õõŠOÞÉ}‘Æ—kßzíªáºÍö‚ïò}µ8Ãó(}ˆõý‹÷¹Î™rðT퉇ž—{|©½“y*Í¿yæ†o‹ùš÷*'ïD¾¨9(ÿúŽ½à»Èµ¯}~òù©æé½Ê‰C¾¨øØf¿ŸB½Äq_¤õïßÿÅÆÇç4OèuŽÆ»§¿¸Oú÷G+§^çˆO¾¨ànÉ÷CÅ÷^âh¼û"åÍ7—ý|z‰ã¾HüòŽôõK¹÷*wN)Ï žªßïyÉõâx/q´nù"qª[ó¯/ÞKœ)7O%~ùæç%Ÿ_(÷^â(wO5qÖË¿¾x/q”»/?ìsâó›òÊz‰£Ü}‘8Í°¿Êñ½—8¥ŽðTð½w–c×;iþ䑨×Ç‹ã¾H÷·¿z} ÆW·½t§Üº9GãÝ)ozqÞƒA/qÜSMó?êñÙç¯÷j>ÎQN¾¨¼ÏiÉñ3×ëñÉSuïZ'ù~–øÞKw_¤¼¸ßiÉçkz‰C¾¨Ø¨Î^_佚qÈ•½¥Ž_5ïUîœnÆSÕ¯yIöó/ï%Žî—û"åõþ¸ÍÍŸz‰ã¾¨ÏKÍšgý•÷j>ÎÑýrO%~µß ç¯Ü{‰Óë_˜/RÞ}ûô÷åøÞ«ñÄ)ÈýÑégÄ|q¼W9qÈ5Û¾(yýÕ:÷Ö«œ8è‹ŽûáéñüÅ¡^â/êþlÞQ/x'ôEÏùqöûÔK÷Ez¼ªõÿ"ûýˆz3­'xªnzëxýçzãhõ†}Qn>µy*ݯn½Ó’ϧæzÓ§¿}ðv/ˆÇ@¹÷Góq_$N¿núú®Ü{ç8î©ÄižRo½føŸuSN½Ä!_ÔÞïúäñŸz£ñî‹”×Ãþ*w>5OïUNòEÕº§%þŠz•Ç}Ñ4~ó{]™›¿÷jþÎQN¾¨Ûï·ÙëÏè%yªrÕíŸÉÍß{5Oçhȵ7¬Iæ/Ž÷G¹û¢)_÷>¯ñ½wo¾KãÉ_øIâ÷&ôÇ}‘z«;?óüxý'>ô:GãÝ)¯p}r}È\/qȵ}K¯?õ*wŽròEÕÆ×'ßOÑü±|ú¢û¾¥‰×_|ïÕ<£œ|QµáöÙïµÖKåä‹š=ìÙù[/q”»/R^š'Ñúx¯Æ;Gã óTåøº\û·xþâP¯s4ž¼“{¤¹^¯ù÷¶âÏÜ&y}™òòo©s4÷Eâ´ÝÁÉçãʽ—8Ÿνy*qÚûßrlüürë%Žr÷ES~žÉþpâ[ï4Þ|—îyªú’};q¬wŽã¾Hó,Ë÷^¯øÔëõº/¿ÙuŸÇ|åÞKÍÇ}Ñ”ïð åøÞ;ß徨ß7•[ïx\ÌŸ8Ö«ù;GãÝi|õàë.]3 Òm®×9¥öÿà©ÚgüeòùõG¹û"ͳ¾åÝkrëã½ÄÑ|Üi|ÿ«“õ§^â:?€/ê×ûÓ£ãùSï‡|Qñ ã“÷Çz•§3_¤yÖ—\ûþxþâP¯s4ž|Q¿ù6gÇü¹^ä€/ê÷ú@öû Þ;ÍÓ8zÜÉSU'}òŒ5ÃÿÝV®C°Þ9Žû¢RÏ»Ï>1{ýõ:g˜×Ê|ÌSi>ÍfÛ$×Íõ’wrO5q^pçÛãõ¡^ÍÓ9ï¾Hy?¬Oîøi —8è‹6|ÜKsþÊ{5ç(w_¤û[ÀãÛR/ø.÷EâWÃ:Äë£Ü{5Oâ/j^÷¬Ÿ¤^â/*Ö¹%{}©÷jþÎQN¾¨¹ø!YÿL½Äq_¤Þö‘Oÿûxý•{¯râ¸/ÒãØüöÉ÷§&ô§0O%~½Yz~Vî½Ê3ÍÇ<•ò~³½“ë“Åñ^'ßE¾¨­;;wþ¡^ç¨×}‘òòÀÿù阯ùS¯s4Þ}Q9ž·ëM×|$æÏõ:G|÷EÊ« 7û`̧^'Žû¢iü!wæŸÊz5Þ9º¿ù¢/}â¨UÃÿݯw¥õgÊÁÕ/?'ûûº½õg˜×b>è©î·ÍñüÅ¡^⸧§xaþõ·€^çhþ䋺ï}õäÜü½—8ÊÝ•Ú·ìù·ÉþS÷Ë{‰£Ü}‘øÅ‘uòý#å½õG¹{*qÚÏ¥û7åÞKåî‹”W/J_ßÅ÷^wŽÖ³4?£¼Z•úq¼Wã£ù¸§§Ü.|z/qÔëÞIã ðHÞKã§ÜõÎrÀu_9"»>½õNóŽû¢iž›þKöüC½ÎÑý"OU>cìõ¥½õÎqÈuûÜ›ãõ×:x¯râ§j¾òËKrÇ?õ‡|Qû«‘ãS¯s´ny =¾ÝIŸû›ÜúxïÇ=•Ö³¶×YêU×|‘øÝûò¯¿ÞKõº/¿ùòÆÙÏ—½wŽC¾¨|o~þÔëÍ}ÑÓÇWó¤^çˆO¾¨Ùò¼—|l¤›øõÿ}å}–ù®izïÇ}‘æ9üÓo+ï ×9z\ÜMùÞðøZë4|—û"/Ïú§äóSåô:§/òTî‘Ä÷Þáî,ÖÍÇ+w_¤¼}d‘øÏn|¿ß}~ÏäsU'Žû"¯_ºýɹóƒ÷j¼stÝMó<ôïòþÁz‰£^òE]½ýÕñüçz‰ã¾H½ÕŽÇïó•{¯râ¸/ÒøþÅùë託8ä‹ú—ÿ·¹óö‚ïr_¤ù×õ'’ëC”S/qÜMœGnšü~…rê%ù¢ú+J®¿‡^䘧ÒñÜ¿û’ë»Ä§^÷N¯rê%ù¢úÂÓ(~½È1O¥Ç«Þòï’Ï¿¦Üz§8ä©úG›½>Šz‰C¾¨zX±GîùE½Î)åCÀS5ŸÞó1_ëï½s÷EZÏ~“=²×‡{¯ÆÇ}‘ÆW»ä¯?¡^â§*î—G½Äq_4Íÿù÷¿ÔK÷TÓãø¥=³×?WÐëÍsø§ßû¥Êøs½™Æƒ/jnHÏÿÃÿÿ»{#>ù¢zاÅÇ¿øÞ;ÇqïÔÍx$ï¾èü>™¿8íE}ò¹€îqÜSéþ¶[ƒ?±^ñ£ùtà©Š-_ž}ÿè½s÷E_ÿ|Ÿäý¯æé½Ê£Ü}‘Ö§|ÖËw‰Ÿ¹^çˆï¾Hœrã¿;/æS/q¦Ü<•øÅ>/ßfÍ0H7åÞ;ü÷Åó½“y*ͳ¸v›kâù‹ï½â“w"_T½xí‡c>õŠO÷Eâ4< ùüKïUNòEÝsÿGòý>êUîõº/êÆóOÿ”—^™[ï%ŽzÝ)o>ÿß’ëæz‰C¾¨¸×’ߟ§^åÄ!OU|÷œìó‹z3­xªê¾{'þVóô^â(w_$Nõ{Mòùþ”[/q”»/§=ðWÙãÇ{ç8î‹:Ÿ»ý6ù|p¶×|—Æ“/ªœþýïs½Äî_r§Û½ä:çaÐÊþÄz•'áÓü͵ãúÞúÄøûwÔKõ’/j.é?F½ÄQî¾HólþúAÏÍúë%ŽîW¾¨þöѯˆù³½Æß}‘ò~¿õ²Ÿßy¯Æ;G÷Ë}‘ò~Ótÿ õÇ}‘8å·¯>5>ÿS¯rç(w_$~{~Ÿ=R¯sÄw_$~µú廬é¦Ü{‡ÿ¾xÞÇ}‘8ýýw=3ǧ^稗|Q»:Ý_Qï‡|Qý§ä?¿°^ñ3ÍÇþÅñ^åÎÑýu_¤¼ùΉߣ^wŽzɵÿøáäú@q¼wŽC¾¨^ßsëã½â‡|QÿØ£Ìñ©—8î‹´õéùgš'ô:Gã݉߾2ÿúE½Äq¤Þæo_¾ÍªáºÍõÇón<¿U§þdèY¼Žx¯rç(w_$~±Eºþʱ|ù¢bÿõ’z'qüz'qÜ#)§^¯ÞÊ|Q¯õßæ²äù¥¼Ûö²ü¾8î‹Ä©w= ûûô:Gó'_Ô¯ZçÐøùK½ÄéÆu OÕmqPÖ_y/q4÷TÊ«íÎÌî¼Wã£^òEÍAÕ¶¹ç¯÷G9ù¢ò…'óµÎÞKœ^ûóTâô/>à5ñã«Ü{ç8î‹4Ÿ~«Ïí›ãS¯sÔKžªÜíÆ£âõ¡^â(w_¤¼Üÿ=]ÌŸÖÇz5Þ9ݸþä©ê³žw]ÌÇ{ç8ä©Ú¿wEŽO½ÎÑ|Üi>]sŸ³b¾rêuÎÄ7O¥u®w¿1û÷'z/q”»§¿Ù)ÿüò^âL¹y*ñ‹­ö>3^åÞKåî©Äé_S]šã{/q:Ÿæ©”7»V»æøÞ«ñ½q4O÷TÊûW]¶{̇z£ñxªö%ùÇ—zÓêüižªój‡ôõ]÷Ë{ç8î©Ä©O½ÊÓótO%~yå¶ý’rïã /ºîI»äøØk¾K÷Ë}‘æÓŸ^íºf˜´nßY¯rç ÿßÊç>æ©Ä¯·øá[sǧ÷G½î‹Ä¯^rÀñü•{/q”»/§Øî²ìþÙ{‰£Ü}‘øí«·M¾¿¬Ü{‰£Ü=•8Ýg&Ÿó*÷^âèqqO¥¼Ø1=?ˆï½O÷EÓø#/{aüø*÷^åÎÑ| +óTº¿í°ÿÏñ[ëã¸/Òøê^_K®o¡^åÎQî¾Hyyr—ý|ŸzÓéüžªØeç·ÄÏß¹^÷]z\Ü©·¼þ¨äûâ{ïÇ=•øío¾ü¡xþʽW¹s4÷EßüåË’ßVî½ÄÑýr_¤ñí³^–ø7ñ½—8ÊkðTÕ‹N<<>þ©wŽãžJó¬¶úá[c¾8Þ«Ü9šû¢‰ÿÑôýã”[/q”»§Ò|ꇥ¯ßzç8ñÃù3·>Þ«ù8gšy*åÝ ROB½ïÞI¹û"qŠä__¼—8SnžJ÷·®î8#~þÎõÞSï$y$êõñâ¸/šæÿÝí“ï*¯Žzqöw)#¾{*qšCM>ŸR^[ïÇ}‘8íw·Ï^K½Äq_Ôé}Á¿äùÔëÝ/÷EšË“_?¿¨wŽã¾Hüú û'ǧrïUN÷E_oR'¯ïS½Äq_¤ûÛmù‰ìõçÔë­§{*ñ‹]a¼þʽ—8º¿î©”wë?*¹þJ|ïÕxçh¼û"åíº[e_ê%ù¢þ9ï='w~ó^ÍÇ9Ýøù¢òOŽñ½—8ÊÝ)oo\'ñcâ{¯Æ;G‹û"qª÷þYþû§ÖKœ©×<•øÝæ_Í~“zÝ;‰ï¾HüÖΟʽwŽãžJœþ‡éë»rêuŽz݉Ó}?Ï÷^â('_4ü÷äF½Ã …çqÎ4|Q_ùÃÊu8öˆÓÏGòEmshöø7|Aå䋪ç\šõÃÞKåù­x³Ÿnÿ®Üùß{‰£œ|Qý¯ÛŸó©—8ÊÉu[§ëÓëüi½ÄQî¾hâ—ß'{/qt݉?õ*wN7Ïî‹´>ýÞG$þG¹÷G9ú¢·>#Ë÷^â(w_Ô÷«½×w²Ÿo6Ö;Ë1O¥u(¿ù³ìõíÔë¾KòEõÓóï¼—8º_î©´>ÍÖ›&ß?Ç{‰3åæ‹”·ßÛ=ù|z5¾2Î4óTS~Xúú(Ž÷Nã£ù´æ©”—Ãúçž¿µõj¼s4÷Eßü(ÿúè½s÷Tâ·ÿšçS¯s¦u3O¥ùôÇä_¿¼—8š§{'wD½4^9ù¢r‡‡e_¿š3Ö^n_áñÝé~µÿëÉu\ʽ—8Ê݉Sl”þ¾Ÿrï%N7ž' óTâôÌó½—8êu_$~ñÐõëx•{/q”»§§;yƒìùÙ{‰3åð>«ÙõÑÉïKPïÇ}‘8õÿ¸1ñŸÊ±×|—Æ»/R^¾©¿8>¿)§^çè~‘/ªwþLrý³øÞ;Ç!_Ô}k㫳ó‡^â¸/šæ¹ÙŸgÿþ)êuŽîyªê„%×/Q/q¦Ü|ÑĹõ†csÏ/ïã¸/¿z£^ã—ÐK÷Eâ÷'l°oŽO½Äq_$~}ï““ëÓ”S¯s´nä©ú}žå{ïÇ}‘æY|ë±ïÎÿÔK÷Eÿù×/ê%ù¢òâÓòŸC/qÜiþÝÆÊ~E½ÈOÕ=òQÉç›s½î»ô¸ÿLnâ4üåêøú(åÞ;üÏ¿Ó;%ðáâTð¨ÃsÏ/êuŽz݉_üz£Srǧ÷Îq܉ßýr£ór|ìßÕƒ§j7ʯ÷jþÄqO¥ùW7?6ñoÊ©—8î‹Äiž˜ß_Q/q܉_]wBöúê%Žû"ñû—=úÂÜñI½ÎÑãB¾¨>üÍÉïRïÇ}‘8ÍIgeÿþ2êuÎÔ ¾¨Ýð[‰ÿ¤Þ9Ž{*qªv‡}rëO½ÎQ¯û"ñÛÏ?ëìÜó×{‰£Ü}‘øý¦øPŽï½s÷EÍ…]ŽO½Ä!_TþþW²Ï¯z£ûå¾Hó/ß¾ó¹Ç×{‰£Ü}‘øí?>$y­Ü{ç8î©Ä©žöÐìúP¯s:yBòTëæ÷‡ÞKœé~/ê_ÿØXïÇ}‘Ö§»ä´ìçÔKòEí°¿ÊÿÔ‹ðTÃýNnº_ÔëÞI zª&|&¥Ãˆ3ü§Å¾Ë=•æéIy ½4Þ}Q©Ï×®¿î¤xý5ŸnÕŸœçêuŽròEÝS¿xrÌ¡^â(w_¤¼ÿÅÉçÓü­Wã‘žªyê³~À{Åwï¤Ü}Q7ž7škO®ãõÑxêuŽÆ»§¿¾á ‰ŸTN½Îß}‘Ö¹>ü‚Ä/‰ï½ÄQî¾hâ?ÿ’õŸrë%ŽròEåï–ø«‰o½ÄQŸ_í÷Î~þè½ÄQî¾hšgýúäóGê%ŽòÒ<•øíÍ·'¿¦¼¶^â('_Ôoqa²?ß{‰£Ü}‘Ö¡xýa'­ Ñmåºë%Žr÷EoÁiîwéÕ1¿sï%Žr÷Eâ·§¾.ñ?ʽ—8ÊÉõ¿sâÄ÷^â(w_$Nõá““ý›rï%Žr÷Eâ»ïÑñú+÷^âL¹ù"qÊîääóåÞKåî‹Ä)Oyä1¹ù{/q”“§ªÖæ×Ç{ç8䋺«O~ÞšáÎè&Ž÷*wŽr÷E¥ö'ëÝœø¥¡gñ¼£^çˆO¾¨þîíÉç/ÔKåî‹4ÏúO^—\ß;åÖKåè‹.Ü$ù|dâ[/q”»/§\ý'ÙóOo½ÄQî¾Hüú„7%¿Ï£Ü{‰£Ü}‘8ýW$ûXåÞKå䋪ú£‰ß{ç8î©Äi·=v«œ¿õ^ñ£Ü}‘øÍKŽË¾¾S¯sÄwO%~¿ÅÃ>‘;¿y/q”“/*Žý÷æøÞ;ÇA_ô®ßf_Ô{ÅwŽròEÕæïL®Ï׺ÕÐëñ݉S\ñÈçÆçgåÞKœ)_ÔÿüàÄŸˆï½sòEõù¿wE<ÿ‰c½Ê3åà©ú‹791wüP¯{'ñÉ•·Ý~DvþÖ;Çq_¤uîßû¦äû)âP¯s4ž|Qõ€üë/õ:G|÷Ešó¼c·ÚbøCt[ñ!ÖKåî‹ÞÊ>a»;O‹×_¹÷G9ù¢êÃ÷Í^ÿÖYï'ºÿú×ÅüõýSïU®qú§r÷EÃ_ðËoÉþý¼úÿõOâ(wï$¾{$åÔëãKíÁSUÏ¿ãœÜã[îÿ„—ÅùÇ=•æÙ®ýzòüRN½ÎÑú¸/Ò|ºO}={|z/q”»/Ò<ëóŸ}تẕz^X/q:ðTâT÷=í²˜?ô,Ž+ï%Žr÷EâÝדý!õÎqÜSMüõ¿—Ý¿y¯Æ§6_¤ñý÷6;7>•ÐKôEgýaöø§^ç”ãã…žê'7$ï/úñx¨­wŽã¾HëÐ<¸<'wü”Ö«ñÄq_¤ñÕ§.Ïò©—8î©t‹Ó?ños½È1O¥uîÿùåGÅÇõN¹q4÷EÊ»Ÿìô¶xý©Wã‰ã¾hà!ïˆç¯Ü{•}ÑÇ¿~dŽß@¯sÔë¾HyÿOØ.æOë½Äq_$~ý©üü½Wã‰ã¾Hã«gß•ÝŸP/qÐ=)}ë%Žû"qŠO¤ë£õï¬W9q܉ßzýßÇÇ¿rïUîœRûóTÓ|†ùçøÞKõ’§ª6¿:ùý„¹^çL|óEÊûÒã_óô^'ßE¾¨zêÕïÊ®õŠïåñuªøä×O‹ùÓú@¯sÄw_¤¼xhº>Ô«ñÄq_¤ñ凎{g<åÞ«Ü9Óý5O¥yöMþø÷^â¨×}‘òáŸÉm®—8î‹èbŸY½æðü÷ë“ÖÅã‰ã¾Hüþ=ëž’[êuŽÖÍ}‘Ö¡½æ~ÉõcÔKw_4åw<*y7×K÷EâWÝ9»ÿ¬­w¾Ë}‘Æ—|Ñ[³ë½ÎѺ‘§ªNÙ1ûûÀÞ;Ç!_Tíù´Ä_é~Q/qÈS—=û„5T7ÍÓ{•;G¹û¢·x¾ˆýs%‡^â¸/¿ßè ÛåߨOÿºè%yªæÓðú ½ÈOÕî~ÒËrþŠzÝ;iÜ)/Ÿš_êuŽ_÷Eâw°ÿñÞ9Ž¤èŸ+çÛ}u‹ÜúPoôÿë_òEõåéþpøŸ~g/qÜ;‰ãI9õÒx÷Eå8ÏîÀ/%ßß¿zû³ï[£ñü~§&ûÛ¹^çLã͉ß\ðþ¬ÿi©8î‹Äo÷ÿÒŹóõ:Gó'OUÜtÛañù“zg9ä©Ö?5ûû™ÔKÞÉ}‘žÝƒNM>_˜æI½à܉S¯möû×Þ«usŽæ龨÷çÝk>²eüøÎõ:G½ä‹ú=N^©wŽã¾hº_§|fßxþâx¯rç(wO%~y\ý˜¯¼†^ç”z7O%NwLJÿʽwŽãžJ÷«~Ì'ÛÜü©—8î‹4ÏêéÏ93æS¯rç('_T_ùëÄÿÏõ:Gã{ðEÅ:éóWó¡^â/ª/h’ï/‹O½ÈOU=$}}ŸzÉ;‘§ª>yUòþ]|êuŽÖŸ|Qóƒû“;~¼—8šù¢á¿'7q¨—8î‹ÄéüÒQ¹ù'¥+XÙ?Û~OœŠ<ÕWnzf¼ÓxïUîœr<ÿ/jÞü¥ÄoS]™§õÎqÜSi>ÝÇóÇöšw=ÕŸ”|>¥ñÞ«Ü9x*­C·ûY[~løCt[Yëã/jÊ?ÔKòEíÁùý-õ:G÷‹9ÿý ê5ߥu#OUüˆ«ãóõÎqȵÛ=5ùþ‘î¯÷*'Ž{*'Ý£¶X»føŸ£ÛâñÂ^ðNî‹t‹Ï>ø1®×9üVŽóTç=Ÿ91æSï‡|Q}Û}÷ŽùÔ«Ü9ê%OÕ¿aß3r|ï%Δÿß´ÝçoK®ÿÔ<½wøçó×=•8íùMrý õŠïåî‹Ä/^}ÖŸÅçåÞKåä‹Šg>à…¹×wïã¸/Òøòàüë»÷NãÁw‘/jÉ¿~Q/rÀSõ7¦ûÍ“zà¸/ÒqR=ù—{ǯøÔëGïdi®×½S9>/ÈS•ë•½~©Ù½J>—œã¸/Òýê~xyÖÿP/qÜišo¼+ùû/æz£ñè©6H×g®—8î‹zù“Ý«äûéšOc½ÊSêõÅ|‘æY¿ù’ksççÎz‰3ÍÓ<•øía·%×)Ç^ã¨×=•8Õ·ï·j¸óº)÷Þr\⸧§{Ü.[Å룜z3Ìkñºã¾¨ßòoÞý¾Üü½wŽã¾Hüâ_¹"æ+÷^åÄq_¤ñí«ŽJ¾?¢{Áw¹/Òýmß~PvþÔK÷TÿEÛf¿_à½ïÝ_òTÕI¿M~¿EœÖzç8î‹Ä©ÞµÉ¡ññ9åÐK÷EšO½Ñ.ÛgùÐëÍÇ}ÑÄßÿ’ïGL9ô:G|÷EâtßÿBò9‹òÚz‰3åà©j{ß{‰£ññüP}ü¦üõ]ÐëõÿLnSïCJ®¯›ëM ÃÄq_4ü§Åy¯{HÊ×øÆz•§7_$~±~ÊWî½Ê‰ã¾Hó©ŽùËõãý³8ÔK÷Eç–Ë“Ï©W9qzóEâ7Glr\|þW^X¯râ¸/Ò|Úg>æM¹ý-õ:G½ä‹Ú‡•\_7Ûk¾kožJy³qÊ×|°×8O¾¨º5ÝßÎõ‡|Q»Sêg4ïUîœRûóEšg÷£ôøÇ{‰£Ü=•8Õ-—'~›zg9æ©ÄožrØrÇ¿÷j~f{Áw¹/êô¼Þ(ÿú彚'qÜSMüáŒoSn½ÊÿŸêÎ<ÞŽªÎöÕ­€2[e ­¢L +´J,&QH˜Â”0cÍc–."„f”Pa ˆ’P EE°EJ„E™DTúí{ÎYÛ½W~ëî\žïó^×¹9ëîó]¿Úµk×®u†ËÿÜ~¾M9tΑÀ‰=ÿïq¸=8œuèŸW®9'î´¯þbëÌA{•Sµ/]sÎèAC?r¾ÌÁþrNN;f¹ýb~¨‡|í9/ßUËí÷tå«8œÁ·øÁ¤SâúÁ—¾”;a¿T^Ô¼pMó•¯â@ç¼(Ô¹ÙýÇZýþŠó"ð‹Ý–¼¿º#_Å®ò¢æ½Ëm÷øì«8hÏyú¹}b óú¨|™>çEà»_?(îèì«8Ð9/§®ÿ隸 ³oŽ#ó¢ew¿Ëâ+_ÅQy‘ÛõÕ$Cý•ðeÚsN…ýí6¾ßü~fåËœÀyQ}ø‡fÅý£|íUNåþò-3ßS¾Ì |Ê‹ wÝǯŠëGì‹öœ;AWyQ=cƒäýŸhϾЇs*ÔYï‘ÎÿA'_èÌi39U»ÊÔ$ß ‡}û¥ò¢úß_H¾ß|öUœÐ^äTí‰)?p”/qÀ—y‘೯â Ω‚¾òTóýWµðeNðUyÑåöø,…o!8*/ª—9jÎB_D´õ_O!_ÿûþúò.ôƒÊ©º•§š×/öÍqÊ©P»4íèÊ—9ðU9UuÔƒÉûÀgßGåEåŸÒõ-øÊWq8/B=͇—ºÒš?•¯âpN~ußíÉëkÐÙ:s°¿*/êý€¹~cßGåEõ¬3¯¶ú‡}ÁW΋ÐÞMÝ7¹þBW¾ÌA¿q^½Xã…ó­ó—}Ñ^q8§BîËÏŠùà°/tæ]äTÝÓöúVùrî„:9/‚îî»Ý¬_ù*çEàwc/¸&îèì ]q*Ê©Ðoî„Î2ǧðU΋PO¹ÉýÉúJùBgt•u³~f¾>¢|§¦œ +õ×õ ÓÍþ¾ÌAýœS9ä*'.7Î:¾ì«8¨³¥œ +z³}ÊÏù2§ECyøÕd{ü°¯âÝië­*75y}Á·éëä›ã¨ÜIåHÒ—r§ýC9U¨ç«O'ãzwFª+öWæTûÌH^¿ ߇ó"ÔS®û¦„½ _èŠÃyêq'¬l~þHù*çTÛÝçYç/û¢=s°_œA¯_ÚžÉ'_´W΋о}ïs3b>tö…®8œaݼÒõ38ÊWqT^TþhòýóÊ:s s^ÔλvÚnŠçOÔ¯|™>çEÐÛæÀäû”/Ú+çE¨³Ùõóúžà3:çE¨³Ûå‘ÙÖøQ¾ÌAœýã¿Mò«œ¯âpN…ý*o¾ÛÌ?ù¢Åá¼üjÔµ‡Åã:ûBW•Õ.=ÁQ¾ŠÃy8õš×^×~`_è’CyÚ×ÿ¶ró•oЉtÊ©Àoï»;y}ºô%øœA¯lóÙí™꡼ºoýCørÞçE-r¹5®ýªuþ²©âøvýzD^äÖLùÊ7Çá¼õ4ÿ¶ròútö…Îøv”¡ÎŠÆ'8ì«8ÐU^Tïtú¹ñøW¾Š]åE•_ÿÄ|ÔϾ9çE¨SGì >s «¼¨[pwòý6Y_‘wq^„~(Æþú¸PûBW΋о[ïMÉ÷#)_èÌ®ò¢î†»ÇÅçoÎWr(§§¸ãîËL¾ò•u·Ýý«ÿ•¯â¨¼¨zꥃÍú…¯âp^úçñUOŽëÇ‹|¡+ŽÌ‹ŽßhAÌW¾ÐGåEåû$ëOÔY‘/tÅQyQwûÝ—Yõ³o¨Ÿò.è*§j®Ù%ù~³Ð^ø2ûÅ9ô꟯ýªU?û¢=sPÊ‹º?–|þåËð9§Çût2¿Ag_ÅÎyôbm{}ȾhÏ—É©ªWNÞ?ûæ8œÓ}Ùæ+_Åᜪ¬¯êµìñ#})wBœá8úœ!韜/sŸr'pTŽ¤|¹=8œ¡þn÷4ŸA=ݳóÍýR΋Ài÷™Íhÿ ›ò…Îè*/jŸmÌ÷>½õ°òeÚûþ4sªöªG“÷¢åËœÀ§¼(èJòÿÀ'ßО8hÏyÚww¾œÜ¿Cw—9ૼ¨<úõäûÍÀg_ÅA{Ω ‡M˜Ïÿà(_æ =çEлէš¯Ï*_æ´™œªyð!³~öUôçE¨¿8ç+I¾}s΋ÀqsWfõ¿ô¥¼ ûÅ9êq3¾Ÿä‡ÊWqB{‘U›¯51®?ëK´ç¼¾õ˜‹’õtåËðU^Tî<é?âúÁg_Å í)§‚îʵNíŸm½ùSúÇ?¯Ÿ?PN½XwêþVýÊWæ]"pcŽù˜ùù/áË÷Ëè΋ —/½>Õ¬Ÿ|Ñž9è•SuûÎ?-îpØ7Çñ¿ç­\¶9f§¸ÀW¾ iENåÛõøîét ½&_ÅA=œSì™^—¡³¯â@WyQuí£æëãì«8í *Ÿ¡Î—÷?töUør^½Üq’ùþG¾hÏœPÈ©ÜÌG“×7ÁQ¾qZ¬Ã©À©¯°ùì«8¨_åEî³/Ç:¿ØWqP'çTлO^?Gù2í9§‚Þ6ÿ8kþQ¾Š£rªfÕ©;Å|å ]qT^äöLïÀQ¾ŠÃ9ú¿Úëødý ¾ò•Ê‹À)îÙâƸ”oЇr*ð«KÇÏùÐÙ7èÄ ¾"/jîÙ°µøì«8ðUyQµÛÏoŽùà(_Åᜠ+œrÛt}…zØ:s s^ô•¦î4Ú?À–óeÚs^½[´èª¸¼OïºÙ_É¡œ +?ÎÍñɾ¡â@—yÑ3ó“×/r¾ŠÃy8Íkéú +z-|GæEþúnö¿ðU•ÕcÙº¾7—9-®"§ªßgÏÏì«8áøRN½;òWö÷/Ú/iî„ãÈ98ÊW¶§œÊá¾ã¯“û_ø¿Úî¨þ¶àKÿûÞùÈyôæèïŠç—ñe|9/§XõNóýÕì«8AyQùÜÑÉû«•oŽÃyú§üìŸvµÆ?û¢½âp^„öÝÞ;3îèÊ—9Ø/•5w™|,øì›ãp^NùL{¹U¿òe|9/rƒqØ=}è–ÖüƾŠó"ðË÷o’¼? :û*t΋À)Ç^xAÜ?A'_ÅÎ9U1èŸòÎß$ùUà“oŽÃ98õ©›%¯)_èÌ/çEào™rK||¡³¯â@WyQ³÷¢äï#€Ï¾9çEØßrÌ*ÉûÓ ³/tæÀWåEݯ^ŸÀ!߇s*pºoÜz£ÅW¾Ì ¾”¹ÁølÖ¹lB|R¾Š]åEŧ'íׯ|:çE¨³ØçmÉçk‚N¾9çEàÔÕkã¬ë‹òU΋À/_ùJŽÈ©µ>¾œ;¡N΋æ·ÿ¶×?Ê—9às^ø»l·sÜÿA¾ÌÁqWyQýÐÑÉëûO¾Šó"ìW÷ÄÑÉû'¡³¯â@ç¼uvÏÛ|öUÔÃyôfËIÇXç¯òe|9/BýåÏWÿzÌW¾ŠƒöœSAww¥ë«œ¯â¨¼¨þæ­Éë¶Êºâp^„:«oÞzŽÕ?Ò—ò.ô›Ì©î<2ùþå›ã¨¼¨½ï7Xõ;òEÿ(çEh_­3f¾ÅW¾ÌÁ~q^„~è^Ÿf¾ÿ}'ÔI9ôâíï1û_ú¾*§j¶Ÿt¾Õ?ì›åP^„úÛ‹o5óå«r'΋ÐÿÅ= “÷Ç*_ÔÏ´çœ +üzÛI,ô°¹ÁuMù2Ç?¯ÿ:åEà4»l·j¼¾‚ξŠs*pø:tòUœ ‹¼¨ô×Y«Ø7Çá¼uVÿðÇ âë;8ì 9A§¼zY”ä3np¼”/ç]a\QNNQÚ¯/°¯â NΠsŽ”óUík±t½?yÿOà?sgò¾z芣ò¢î´ É÷ûa¿Ø:sà«r*÷ëUo‹ç·ÐÏä›ã¨¼¨>ûCöû—Èõ+çE¨³õý׎òeÚ«¼¨ùÅGÄçoΗ9às^NWŸq­Åg_ÅÎyt·Ç +æ÷ ±/Ú3Ç Îw΋оØlÂç¬þg_ÅÎ9U;ÈÕÛKW¾.îå«8A§¼üúÄ’ïç‡Î¾ŠƒzTNU\üûd|‚Ͼ9çEhßµÆܸÿQ'ûBgt΋À/ßt¹ùùnéKy8œßöøQ¾Ì_åTõr›%ïÌúRî¾Ê‹êýnæ'ì›ã¨œÊM>Ã|¬òeö—s*èÝÓöüɾhÏìçTÐËs>”¬?ÁQ¾Š£ò¢Žøʺ⨼¨úuzGù*çTÝ`~+}ÿ[ó›òeêQëÉî©”ŸóeŽÌÿCëÉxžo¹ÃgÞa­?ÙWq‚®ò"ßÿKâ«8¨“ó"´/¾óÅÙqÿ‡þ¾Ì_æE“ÏøvÌW¾Šƒö*/*×ûCr}DýµðU•Sµÿ1ákqý¨“}¡+çT¡Î¿^63æcÙ:sàË9ôÂÏŸ1_ù¢½âp^„zÜvíŸm½ûYöõ¿ïßçRÞåºÊ©Ê‹cÌG{ö…®8*/r›¾»ù¨“}¡+çEèçêœÍïÇV¾Ì/çEлåg%çWΗ9nÐÿœS/óÍÛâñ£|íU^ÔlùïÆüœ/sÀWyQuí[Í÷²oŽÃ9ö·¹jÂ.qýà°/tÅá¼ýPœrkòþå 9ÐU^T}ìö÷‡ _æ€Ï9U¨¿XlëÍì«8A§üAñ•®8¾º^=œ¡½ÿ}²)¾o4,‡ó¢À¡ûw7à$¦þtæø_õ})§¿¡ë8ô‚|¾œSSÞúÅäýÐÙWqà«r§¡:ãó |ö |j¾Ê‹ªÑ—̱øÕ›ÚïË¥¼ õ¨œª¹é/çŽöED[ü _ÅáœÊ Ž»;d¯‰_ù2Ç×Õ«‡ó¢°_?œ’|þ+ç«8*§*©”/tæ@WyQù™KÌüMù2|΋Ðͳ£ìõ9ù*úŸó¢ _{sòù¬œ¯â¨œª9s~²þW¾Ð™ÓfrªjÓÕnŠÏ/pØWq «¼¨ºê=Éü>û*ŽÃ|K9U7دâÇšëCöUÔÃyøíû&ï߃®|™>çEóÔ¨#âù:û*NØ/‘Su·mšäàä›ã¨¼¨|ðõyÖøa_Ô¯8*/*ï²çyå«8œ¡7ßžÿ•/sÐo*/ªiþT¾9çTá8z mýë…ðeŽn¯½Ê‹ˆý·¿o¿ÈpT^ä|ÖøY߯“9è•SÕÿ¾×®Ÿ}s΋ÐoÍ‘6_ù*ŽÊ©ªOI^ŸÍù2'ì­3Á©Åøg_Åq˜Ÿ)§ +üæÈiVÿ³¯âÀ·¦¼üöÙQæûsjòÍqT^Tý÷–7öfÑÖ;_”/sÜ 8/ò¼þyúø”ÿeñÙWqÂ~QN~uË_ìüŸ|s•u[œ|ÿFΗ9Ø/΋À)´Ï/öÍr(§¿8ûûýÿÂWæN”S¡?‹µÆ›ë[å˹8œSA/î?ÑÌ—Ø홃~àœ +zý® Ÿ¿à°/Ú3íeNµúÓ÷Å|p”/sÀç¼z}Õ{Íï×êÈ홃z8/Bûâ°½’ÏßAW¾Ìqƒy@åTÍ~{íÏ೯â„ö”Aoß×&ù<öWúí9/¿˜•ÞAW¾’ãhë¯[nŸ³[üúøÊ—ÙõLõÐèOÆïïòÏÞ— Ü =ÉCûב¦˜¯[±¯â„ý¥¼z}³½¾mÉí9w‚Îyê/oIùhϾЙó"ð›9)ºòeNè7Êà«r$öÍµçœ +uº­NØÍšßš ¶®8XÏ»Íö0×ÏÒ—8è•SÕëÞœ|þ:ìù*ú­£œ +zùn7×êöE{æ ž’ö z»yÚ?à(_ÅQ9U}èדüMùBgŽÃü/rªêö “×ÀaßÇQN8Ëœ°[|}®|‡ó"ôsñ³O^o_áËœPÈ©Ê{›äõ»œ/çN/rªò§3¾mõû*N¨GäTÍ܃o1ùä«8ÐU^T¿uòQVÿ³¯â@ç¼û[pL²þ :ùæ8*/jßíγêW¾ŠÃyêq+Ûó°òeöWæEÓLò眯äˆûôz‹=Ì×/ù¢N•wÕbþôÏã­ß*|™ƒýeˆÜã,©þF9ÍçìþYR_Ôé|ÿXã°˜xĶñú핯⨼¨~ñÉó¬ùAù*ŽÊ©Ê÷8óó/ÊWq8/B?t¯çEÐË?oŽöE{æ 8/‚^®”®¯ÀQ¾ÌA{™Ÿ®¯r¾Ì_åEn {þ¯ÈWqPO'rªö' ¶¯_à(_æ€ÏyôòÁÛÇëðÙí‡ó"´o–·ïÙ홃z8/B{ç×oæü@¾9ŽÊ‹*ÁW¾ÌAœA¯‰:•/sB{ñ~'•#±/êQí9/ +¾Ï?Ú?[;xßEõzªûß÷ÖóÌ :åEà׫Ì_èù*t•¹ßÜp…Ågߧ¤œ*Թ͗[|åËøÊœê#ßJÖWÊWq s^8›Œ½Åª¿$_ÅÎyøÍ '$ï^‘¯â@¯)/ +œÓFÕ£}#lÐÙ×ÿ¾ß*8œSSﺓ¬þ©„/sàËyøżZ|öUœ ‹¼¨¹øwY|öUè*/ªŽ<>¹?Å~±¯â@çœ +œòû÷'ùtöUœ SNÕ„ylöVÿ°¯â@o)§Bí>;$ç¯òÍq8§¿^óõGöE{æÀ—ó"´/Oe¾¿—}:çTÿuÉû[‚N¾ŠÝÿäÍÌ—Ÿ|ý“ÍöJ§[~«dü«ö9½9U;ëíÉ÷ûå|‡ó"pŠ·neæ3ìêyçEà—¾¬óKù2¾ê~¶Úö‰i£}#lÊ×ÿ¾w|‡s*pÚåìã˾à3:çEàWć®|™>çEàÔoŸ—¬ß ³o–C98îw7$ßO]ùª¼‹ó"pš±O˜ãŸ}Q?s s^~±ÂVÉû·¡³¯â@缨\_Ê íõû*t΋PgçÇO|~)_ÅÎçø-­Ã¡³¯â@ç¼uVÿ8ï Öù˾Š]åEÍ•{Þhõû*NÐ)/B?¸§®ÛǪŸ}s΋À¯Ÿz×éqýЕ/sàËyQ3ŸÍƒ3çX|öU蜵àŸüLò÷›”¯â`U^ä®{2ÿ+߇s*ÔSþc:Bg_芣ò¢nÅyÇã'p„¯â¨¼¨=ì¸äsRèö…Îè*/jiþDýÊWq8/jãÇóxë]Ç•/sü“{í9§ßùõC<þ¡³©â@w”ó€£ø¬+N7臊øÐÝX»~æ£=sà[¿ï6)öUèœ;µàSŽ¤|U{Ô£ò¢úÅ5“üõt‡üùüø¸+t•µ/¬™¬Àg_ÅÎy8೯â@¯(§ß}eë$¿‚ξŠó"èÅ kÎû|öE{ÅQyQWÎ4ïßÙ|æ@WyQ9ãBóýÊ—9ૼ¨ûÁŒkÍùŸ|s•åÌSãþ‡}¡3ºÊ‹Ü +ÿ뎘ã«|™>çEÐÝË'&ù$øì‹öŠ£ò¢òʃ“劉}¡3ºÊ‹Üõ;~Ó<¾Â—9M˜'Óœ +ýÐ<ý°9~ØWqP?çEà×sOþºu|ÙWq «¼¨¼`ÛäûÍ”¯â@W9•{è'ö÷ç“oŽSŠ¼¨ÚÿÏÉõö…®8~¿y6b_ÿd³=|UNÕî÷çó­ñÉÅd9”S¡Å—:qàËyôF\ß™öŠÃ9ê¯^J×à°/tÉ9UqòÖÉúSù]pT^Ô¾¸ÂîññEì 9Ð+Ê©PO)Æòeøœ_ˆã˾Š]æE‚ϾŠ]åEå䭓׿°_-ù*t•uß¹)y}|öUœvp}ᜠ+œfÇQI~}¾åTÐËÓu8øì‹öŠÃyÚ»—íó—}Ñž9-®¿”S¡Îvé·‰¯à°¯â ½Ê‹ŠìyZ|þæ|™>çEà4—_¸o\?töUè*/ªï_õV‹Ï¾ŠÓ ú_åTÍêgœdõû*N >åT¨§ª.4¿˜}ý©ò¢æ¥5“ë¯òÍqdNEãö…ÎÔ#ó¢—Åýù*|9/‚ÞœùoÉüŽ?¿ÌûJÅá¼(p^YáPs|’/êaN;?þ÷É~û•­“|º#_ÅÎyŽ7v½Ç¾Š£tÅWºâtƒþQyQÒiýÃîsšßçÉ: +¾åiÿ«ú§Ÿr*pTŽ¤|¹=85­ »ë6Jò èÍ2 ‹ß×]q8/Bûn›É7Zó§òUœFäTõX›¯|‡ó"Ô_ÍÜ(yÿtåËŒ“BäTÍu6Ÿ}s΋BÏH^¿ƒ®|GåTõk$ï¯ ¿¾ÌÁ~q^NµóY{Xã‡}s΋ÀoŸŸuƒ5?+_ÅQyQµýÉæ÷c(_Åá¼õ»Ÿ}IÜ?èö…®8*§ª9óN«Øõ0:çEAÿÜ%÷¨SúŠ¼KåEÍûÞ•|ÿ­ò…ÎèœS¡Îê¨Éû‡¡+_怯rªæâ³öˆû|öU´ç¼íëmíùSù*ŽÌ‹VeÎÿÊWr|Á´õ®ãõ·_2?ŸU_b =ìq8Ï^ÝqHò:tå«8¬ã¸t‹IÖçà+_ÅiÄõ½œ™^ß•/tÅᜠ+u6ćξЙ_΋оÜ+ÿÐÙ7ÇἜêú´ +_Å)UNuûÄuãÏ_€/}§PÇW¬ßZá«8­àWÅcæ}P©|‡ó"ôƒÛû,óþ]úŠ¼‹ó"ðËŽ\ϟЕ¯âp^Ný©íìü_ø2ã–ó"ðÝ݇دÿ’¯â@ç¼ür§)Éûß ³oŽ#sªCίOÀW¾ÌA{΋ w“LŽù¡Ná«8œ_Œ\[ã‡}Ñ^q8/BûöÚšó¿òeö—ó"èîöõ—}Ñ^q8§Býõ¬Ž5ûŸ|ÁW•U/ÛësöE=ŠÃãõ”ÿhÏoÊWqT^Tžö’™/±/êQΩ°¿Å¶;X÷éì‹öÌ ¾”¡}yÃFWÅÇ:û*t΋ wþúkñÙí™êñÿ¡mØœGùcèá°œ%m¯8#ÕÑKê‹ö2/ºÒîæg9ô~'ì—Ê‘:á«Ú«¼¨x}•ÑÖø¯§›l­»‡ó"ìo{÷ô›­ñ©|™ƒ~PyQu拳c~ÎWrDNÅÇõ°oÐGåEŠ¯tÅá¼ýP_yÎÕ S˜y>¢~ær*ð‹)““¿_ ]ùrî¾Ì‹>|¯™Ï³oŽ#ó¢õw2ßßR/øÌÁþr^„öÝ—¦$Ÿ/ƒîÈ7Çá¼í»‡/2óIé+ò.΋Ào®ÿjrÿ}¡3'ì¯È©Êï¸8Ÿà°oŽ£ò¢öõ…æø”¾”w¡΋ 7ÓÞšðQ§òeÚs^½½úóýoÊWqT^Txtòþå ]qT^ԹݾÏÏà(_ÅQy‘çñ֛ߔ¯â¨¼È-šn¾~Á¦þqÏ—9'*§*ßö™½¬þaß,GäHªNå«r'΋°¿Í³3¿fÕ¯|GåEõ÷¦›ëgå«8*/ªÿkæ×âùû¥|‡ó"¯ê¿fšù†òeê)E^ä~“òs¾ŠÃy8í-«™×GöEÌÎyQ;xݶôó[ÜÿY_‘wqNNÑŸ¬•/êdtΩÀïDýì«8ÐU^Te¯oÙWq s^„~(V»ùöøüÅ~±¯â ½£¼zñÔ§·oΗ9ð弜r¹ï˜ïïe_ÅÎyêï^¸ã«Výì«8Ð9/ +õ/ú~òúŽòU´çœ*èk}?™?s¾Ì/çEà7Ÿ¼~ Ý‘¯â@缜âW›Ÿd߇ó¢Ðþ4ûþEù*çE¡þuÓûå 9ÐU^T½ém£ãûôœ/sÀ—y‘º¾oŽÃyQ;˜ÿëçÒë/êo…/sàë&8‰è(_ÿ+ó¾XqFÚþr:¿¾Šçå›Ó9/B=í_÷=)Π+_æÀWåNœ#Ͼàp{èœSN{q;«þö†W¶ŠÏ‹‡s*𫯞|~ºôyçEà¸]VMŽ/töEýÌî&8Í–«™ë+öõO6Ç¿ÒÁOLýèì›ãp^ŽÛ|µ«­õ‰òU΋À/>õÎk,¾ô¥¼+ìåEàwkýSrÿ }ºÌ‹Ú ’||öUèœã&o4/ž Wä›ãȼè ß°øÊWq8/Bõ–/^fßZø*ŽÊ‹ºç¦&ïOËù2ý¦ò¢úøÝÌñɾ9çE¨³Øäšý#|™|ENUŽ~u?k~f_ÅÎyêïN[©²Æû*t΋Àš‡->û*tÿ3ÙÀ/¶XÍÌ÷Ø×?yØùYæE'Ùýþà3:çE¡þm~G¾ŠÝÿL6ð+Ñ?ùú'Û?œ_|ÆžÿÙ|æ@ç¼üòÓ6Ÿ}'è”Sþqvÿ³oŽÃ9øÿ¥ðe|9/ß}Ò>¿Ø7Çᜠ+üvܪI> ]ù2§ÍäTÅÜW¶²æ7öÍr(§BõÄúAørîçEЫ­ìõ¡ò•‘S•Û‹õ­ðåÜ ý¦rªr½w™ÿ—}s΋šÁqwg®´½u}T¾Ì/çEøk<˜|¿‡òÍq8§¿z~êdëúåÈí™|ENÕ®6{†Õ?ì›ãp^„zê÷ÞhæcÊWq8/¿òý`Õ¯|‡ó¢fp|‹mß‘|>(çËÌ{åTí€_ý~Ꜹ~å«8¨§9UwØ*sc¾òUèœSS^ôâÖ}:û*t΋°¿<Ï+_ÅA{Ω‚þÉÕ/ZèÍ¢­·Q¾Ìoô|ü×\Ï(ß‘rоú\:ÿ{sÓWéàp^Ô`~ûxÚ?hϾЙ]åEÎ_Gâñ™óU΂¯È‘ØWµ‡Îy‘ôsùØlóýÕC³/ŒÇ•â@º_ˆûzñŸ³“û;å‹öŠ£ò"·Ákæû7Ø|æ@ç¼z=î}ûÄý€q¨|Ç?/ÙÜ ÿ›ÇÒþQ¾Ðˆ ó"ÿ«þy´þkÇÇ%çËð9/‚^­÷¾}b¾òE{Åá¼íë¥jæ3ì‹öŠÃyÚ7ÏÏ>8>¾Ð¥/åNhÏyú¡ÚãVûõ#áËð9/¿YçÉëЕ/sŸrªv06÷\’ä{೯â@ç¼È ÆgÛ”7Çý¯|:çT¨³zjöøx|*_Å®ò"÷àÚöüI¾Š]åEõe'Ü÷ö‹}:çE臦´Ï_öUèCó¶U§¯7Ùæ=òU蜎ŸâãëÍÌõƒâ@ç¼üö…;“ëô†|:çEàT‚ϾŠ]åEÕRiÿ(_ÅÎyQÐ7³Çû†ö"ïRyQùá”8ä 9A§¼¨Œ“êÅôøBW¾*wâ¼ý\ûõ•5>Ùu2:¯çQgë×ñy§|:çEà»ó>?æCg_ÅÎ9•â@g_ÅÎy‘ßúÍéú|U?sÀçœ*ð—IùA'_ÅÎyQ¨“Ö·O¾ŠtÊ©Àw~ü›Ç—|§Á}åTàwÏ6×⳯âÀ—ó"ð«›¾šäÐÙWq s^½üÓ æûoÙí‡ó"ÔéÖÝ3épØ:s s^~sû;’ûSèÊ—9àsNN»åîÉëãÐÙWqšÁøQ9U{ç;L>û*N;àsN…zŠ·üÔÌoÙWq°¿*/jÔõ‹|¾œS¡þæ€w·òöUøòõí«Õ–Ý!ÎÇ”oŽS‹œªxç²ëW¾Ð%Ço¨ÓMXg\\¿oÓ_’oÐcˆÿ?8œ¡·l:ÿ£=ûBgNƒù“r*Ôã~™æÊ7Ë¡œ +üúwöú‡}Ñ~Is'´ç ºòåönp¼J•S}wÅ&¾¾ Ÿ‹ÍHr!Å í)§BÕu3gŽö¢­7~*å+8œy^Ó^)ø—9¨_åTõV$ùòU7¨³¡œ +œjŒÍgߧ œ +üblz¡+_æ`¿8/§öõÇã:û*t΋À)ßzªyʾŠsªÀ¯OšoOöÍq8/¿xÿ©»[ýS +_Åá¼üúâGXõ+_æ´ƒùSæTËMØѪŸ}Çá<¥œ +õw+^m®?òÍq8§¿|yŠÙÿÊWq8/¿Þáíf¾¤|%‡r*ìoýç«ÍüPùrîçT8^å÷?}a<~О}¡3§_ÿ“·þ:a¹ôüU¾þÉýöDq˜?E^TÏ\}|¼þ òUè*/*ýü÷O78_ØWq sNU ö«ž™^¿Àg߇ó"ðýOÞzý̾¾QOgê)D^4t±æ6Uør^äpÜgÍœóÁQ¾ÌŸó"èÝ+ã÷¯òE{æ }-rªv›fÅ|p”¯äPNN»Ôóû¥•o+8*/ªûÇëãþÏù2'´'_‡ñöÜø¤~_é+82§ZþÔäõ/å 9A§¼¨Å}1ñ‹Á~µ¤+NhOyÚ»wmœ¬O²¾ÄŸó"ôs÷×´ÿ•¯â@缜ò‚æýû*t΋ »Ï®š|?‰òE{æ 8/ +í/Z*yÿtöÍq8/§üÂÉf¾T)_Ê»Àá¼zwÌ’|ºòU΋À©wÝôs~¾ÌA¿q^~{Ûé&Ÿ}:çTà»ê´¬õû*t΋ÀoÞjÏÏì«8A§œ +üvÅt}}§Å–ßP¿ðeNà‹¼¨9ûÄäú>ûæ8*/j'¬|ÿ 8ì ]q8/BÕq/$ßïŽòeÚs^~yéÙß´ægåËðU^Ônµšýú#ùæ8œ¡~wèÌsâóö…Îè*/êv\ñ«”/sÜàüå¼õW;­h®ŸÙWqÚÁú„sª ekûó äÚSÞ…þ)(/‚^=ž¿C¾hÏœNäEhß¼ÿêµÌëù*t΋À/68÷ ‹Ï¾9çEhïèú›óeNhïÿoí ßbmèÿY_zÚ«¼ˆš‡ï—`]qÜ`ü7"§j¿c¿øüò\óú¨8hÏyQ¨Ç¯Ob>tåËðU^äÆ^žä{àûó:ñÍqTNU¾ùNsýþOyêQyQójzþ‚þŠãÇ«¢œ +œbg{}Ⱦ9çE¨§xióõ/åËœ÷w”Gßü>åCg_ÅÁ~qNŽ£y:ûæ8œÓÑü]ù2¾*§*γ×Wì«8Å`ü¨¼¨ ëêg_Å®ò¢úúN‹×O¾9çEàøuBrÿûBgt•Sµ't'Zõ+_Åá¼¾nìóýuì‹öŠÃyÚ—{®¼?ºôyçEí༚'ãþ_úŠ¼‹ó"pxžÉù*ŽÊ‹Ú_Ûó3û¢æ@÷?“ 㳓^¿P¿ôM([o¨œÊý$­_ùBgt™S}ðêÍ­õ›òeŽßÞzCåT­ŸŸ­õC)|™¾Ê‹JZ'`Ù7ÇQ9U³ž½¾bßÀ_ÂÜ u"Gbß\{ΩÜà¸twÙg_\´õŽWûò%§X:süóúëIÊ©POûý’ùÙe| ÁQ9U5âÖøa_Ô£8Ñþ㿽ý*©~ì/ûBÇ“ñ¾xýìñ»{·~¿ÙÏä›ãȼèóû›ù†òeNðyQ3{âÖü_“¯â@ç¼Èa\-wK2?øþëõû*NhO9ø墉;ÇõC/”/qÀWyQ¹ï¨Ëâñ >û*öKåEåv]×û*t•S•—~X\à“¯â ½Ê‹ªM6ývÌÿÇöeÚ«¼¨\þ–$_B=ÊWq8/ +¾÷¯`ò•¯âTâ>¥üÁ +É}®ò…Îœv°N+Åz»ùÂþ3Ìþ'߇s*78OËÛÒùýϾЙó"èÎ×—óy—Ê©†øqÿ(_èÌÁqqâ>±öó¼âǺâà¸xÿdCûDô ³¯âø§ô¯ï :ø‹7·9hÏyôÊÏøøªzÐ^rÄ:°ºoë-ãõ-8ìtâ ΋ОÇ9töUè*/rקçøì«8Ð9/§ý†Íg_ÅÎ÷Sàûß'töõúãò.´ç¼ºï‡dý=1õ‚Nyt΋ Ww}ÛüþFå«8NÌÿÅýéüóU΋BRG€¯|™ÚSN~û…ý§ŽäüåÜ)ðÅõ«»uâùŸ}s•5ko¾ÿYù2¾œAoÝwÍ÷7²/Ú3'ô³Ê©–¿¥Žûå«r'•uo>0ùûAà;òEŠ£ò¢îÔ•.]˜ŽÑþ}ù‚ÏœVäT¨³¼É¾a_Å/ÏoÐ+qþ*_æÀ—ó¢PÿÖéúMùæ8œSS_ùBW•ÄW¾ÐGåEþyɆ:Ù:s ·"§JàýæzIqüSzíK±®`>8¬ç8*/ª7_²õøŠ£rª–r$Ô¯|¹½ôçTàT·NNևйr΋°¿í)›$ß¾òU΋Àq¯ï61žŸ•/tæ@/)/‚ÞŽyÕ\Ÿ(_ÅQyQ» íå ]qT^Ô~w™±V>¦|™_΋ WÛ¼š\_p\”/sÖ¥”Ó_ù*t•kß5¾>*ßGåEÍ6ÍŸì‹ýbNÐ)/‚Þ¼~òùÜP¿ðå¼ í9§jñºó²‡%ßßžóeÚs^ôÇ?ä“9_ÅἜîþ#“|LùBgúÇQNå0n§l’Œå«8Ð9§B=Å?ŒŸOå›ãøû)3§Ró û¢æ ΩPO1Öž?ÙWqàË9ôb[›Ï¾h¯8œS¡žÊ×÷?8ì 9臚r*ð;âCg_Åîýy3×Qëò)Ç›™ü‘êð­DNÕ‰ë#ï¬âr*ÔY/œœäÐÙWq óy½[h_ßÙí‡ó"7èÿFŒöŸ9Ð9/jó?¯ßr¾Ìß÷+o½ñã-sX¼>Q¾ŠÝ÷›y›—~·wœOú"L_ÅÎ98åvöüÀ¾Š]åE¥?¾ÖüþŠƒ:¹ó¡»ÛÒñ ŽòUœv s*å ]qT^Ô̹å s}µx¡½ã.9"§ª^ßí*«ÿ•¯ÊT^T¼Õt‹Ï¾8.ÌÎyôæK›™ßžhÏΩ W¿¹È¼?R¾ŠÃyøíÓ¯'ß? }¡3û%ó"q~±oŽÃ9•Ì3C÷ÖñZ?X:s‚¯ÈyŠÛÒë—òÍq8§B6«º©5²/Ú3¾œ¡ÎâU{~f_ůÿÉ[ï|/W94ùþ.‡u‹ðeHðå_àúëçOë8²oŽ³8~øõU#|™_΋ s{ÿ¸×o¬£=sо9•âŒTç¼(ø;ëàÑ u–ÿ´ëéñ¸….9”S_¾òóËc>ô–|ƒNøª¼¨=}¥yæø!ß,‡rªPÏ{6KÞ?táËyWh/Öá²”/q°_*/*ÖØÌÌØ7ÇQ9U÷Åß&¿û«|GåT屿Ý·ì‹úGåEõƒWϵÆ'û†ýRy—Ê‹NºÒüüû†úGåTõϻŬ_ø2§ÍåT37¿"æ£NöÍq*Ê©ÀiFO˜m¿-ù¢ÿ™_•S¹åg}ÁªŸ}Ça>§œ +õ4_š5ÞªŸ}s•µ§¤ósΗ9èg΋À)O·ùì«8ÐU^TùùÇêöÍq†Ö{ñqDýþ'o½ë¯òeŽ_•1Ü?6¯ïŠs*Å ýàÄ›ø.)Ç?׬ó北Ïãí ùr^ä¡=Nùjº~p™ýR΋À¯xì•Ö¸bßОò./΋B{qþ²¯â`ÿhï}xëõ[M¾nÐoÌiEN~uÆJóâþΦŠãÛõêᜠ+õt¼ÿ|öUèœß¾7 ³¯â@ç¼z³êÚã6ñ°¹Áþ²¯ÿ}dÊÖø¬È홃z8/BûúñÉëwA¾Ì_åTÍöß4ß?Ͼ9çEhßýú'æç/Øí‡ó"´Wó˜ò•±N+VÙü)s'_0mýëÅœ½×µ®SÊ—ûÜÿ×£¹û'÷G¾™é‹qµ8Æ^WŽâ }¤üfÎÞ{XýS.!߉uêoçìoÎì›ãp^úSÔ©|™ƒ:e^ô«Ï'!çËœÀ§¼z±Å”Iñü~G¾hϹÚûß'tÕÊ7øàp^½ñço…~S¾ŠSˆû r¹ç·²òå+9"§*ýùkõò-Gä$nße°Æ§ôœRèÅÞ6_ú +çE8Žõ~Ï~Ö:¾ÊWq8¯üƒ–=ÂêåËœw…دb’Ý?5ù*t•¹]m>ûæ8œ¡ÚO2ß+}EÞÅý~'øì‹ú™½¡œ +|ÿ“·Þõ}:çTÚã”ìñæŠt•‰þa_Åî(§BýÕkË'ùô†|s•¹uW™iÍ?ÊWqø~3Ô9Í^*_æ`¿øx_Ÿ¿Ò×­úòUè*/j¿zÎ5Ÿ}:çT¨¿¼ñú$߆ξŠó¢À™¹Ü¹Výì›åPN~õÑm’ï‡Þ +_Îà«rªâó+Ní¡ÑÖ_ÿ“oŽÃ9•çõ8®Z¶²úGù2¾*§ªÖ_%ùûDÊWqêTyÑ +Ïoe]Ù7ÇáóuŸÝÀZ_ÂWq8/¿úå¨äï+AW¾ŠãŸÇ[ïø²è÷Çò]ü ýq"rªò‰QÉë×à/ŽŒ7âื"/*º?$ï¿Ÿ}Ç ö—s*p:_¿9þÉ7Çá¼üjº=ÿ+_æ„ýRïw9’òU¹“£<¾Ýî㎌çèõÑ‹fYýÆôCA|èí×6L®/à³/Ú+ŽÊ‹Üîù®U'û‚¯8C¾§9TôƒðUœ‚rôCsˆÍW¾ÌÁ~UÔÿ?ÍîåËðkÊ©Àw¿yKòù8è ù*t΋Üà¼n>qéLk|²¯â@wÔÿàÛ;2>îÐÙWq Ë¼èø&?|öÍq8/B?wwA\?8ùBgt΋ ·S¾qNÌÏúŠ¼KåEn—qçÆÇWùBgt™­¹~òþ%Ô¯|GæEŸ¼Ô¼¿hÈ7Ô)ò.•uë<ó5«:å+ò.•5ﺵ¾R¾ŠÃyú¹xx×Ý-¾òeúó"ðÝa‹ì¿¯*|™>çEàW‚ϾŠ]åEnãKo¯òÍq8/§ÜèÞ]¬õ-û‚Ïœ S^}ˆcÍÊ—s'p8/‚ÞÑú:ûBW•¹±éúé+ò.΋Àq‡§ã3èÂWqd^4Ið…/sPÿ™l?‰è@o„/·÷{÷œAoüùeŸsD^Tÿ«Ý?ìê!t΋B?œ»óÝÖù«|™¾Ì‹è8*߇ó"´ïöL×?Ð[ò…®8*/j.ÚÐ|ýKù2¾*/ª÷üHòþØÐ?—9às^ôÙ»|ËŸìÚ«¼KäEÕzϘùXI¾à«Ü‰s*ôƒ[ÿ™¯Åõƒ£|™ƒö*/*ÖfJÌÏù*çTà?ÜÕ¾'_ÔÉèœA/?eß_(_Åá¼õ·oþ²ùú2û¢ær*ðýï“ ºò•¹“È‹Ü›¾|u|Óþƒ7”;uÄ÷¨~%tåËy8ª½ò•Ê‹r|å«ò.•5KÙãGñGåEÕÒöü¯|‡s'ŒC•#±¯j]åEÍ{$ïO@ûú…¥Í\BqT^Ôî]Ýwö…®82§úíìY|å«8*/*ÿ´ô&_ø2ý©ò"Åg]q‚NyôZÔ)ù‚ÃyQ;øÞŒòù÷Äý£|¡3Çårª‹ö:`tt²*_Å®ò"÷äÉçCä›ã¨¼¨9h™„ïw¥??“/tæ Ω —wìµsÜ?à°/Ú3íUNUŸ9ï‹1å«8œS³Qòú5tåËÔÏy8îÐùæú“}ºÊ‹üù•ÌÊ7ÇQyQ÷È2sâþ‡}¡+çE¨³}5çGø*çTàZ:ù|tö…®8œ¡}÷Ç´~èÊWq*Ê©ÚÁüVÓü¾òeúSåEÝÍ{_å«8¨‡ó"püóxëÍ?ì«8þÉýùŠr*ð;?-Œ GþkrÀWyQûä·[|öÍqTNUû¢}é?è÷FäTõkiýà°¯G Ï9Uçëoà+_â }C9êq¯¥|èÊWqZÊ‹à[ù:ãúÁW¾ÌA{•µ¿²×?Ê—9¨“s*èŽø¨Gù*ŽÊ‹Úûç$ï_R¾Ð‡ó¢óÿN{šß»È¾Ø/æ@ç¼üêþ9Éõz-|™ƒý✠+œîú¹ÓFû"°Ag_ÅñÏëw*§j¶Lò½Rà³oŽÃyêi]fN<þƒN¾Ð™_••O푼? öUœÐžr*迾Äý8ÊWpüó’ üâÏöüɾ¡}Bé=è_—E^Túó×êöõ¤a9*/šb>8ì ]qz{’þÓ·©6ô¨_§ð]¼ù`ü/þ‹aù‹7žÃyŽWõT:?£~ÅgÚs^Ôæ7÷B:>s¾ÌA{Ω‚N9RΗs'Ô¯ò¢z»÷îg½>[ï¸Ô]Öy§8*/ª¶[ê.k|*_ÅiEÓî6É|ýBù*NI÷)è·úàæ8«~å«8J/Æ=0Ïâ+_æ„q¢úçK‡ßoñÙWq0Þ8§Bÿ4‚ß’®8ðu”ßm9=¹¾@gßlj¼¨³±ùýíÊWrDNUь틎¶Þ¼§|â`¿8/‚^ì°ÔåÖñe_´W΋|½½:Ëé“Ìï?a_ð™]åEõÑ;ηúGúŠ¼‹s*Ô_jŸ¿ì‹:GåEnbs°ÕÿÒ—ò.Ô©rªò‹3X|åËìçEðm·˜n¯ÈWq tŸ ~5~ÒMÖñe_ÅÎyøÅøæ8‹Ï¾ŠÓâ>EÌÿÕööõ‹}s΋P¿â+9ðõ<Þzço5vcóó­ÌWè*/bSÿØôÍq8/rŽâ+9¨GåEÅNéõ7ëKyö‹ó"ø¶yÌüûwì«8Ðýù•äTÖŸ~|ZãŸ}sœšÎ_ôCyüá÷Ç|å 9AyÑÐ:$æç|kâ Ÿ;Ê© '¤ëÔþh¯82/Ú~©ú'G[oü³¯ÿ}OgêQyQ#柖|s΋POT7þÛ«SúRß¡ûÐø8æø0ÃÏGæEÙë+p£Ÿ½ýbN‹ù_äEþs‹YûU’¯â@ç¼È×Õ«§þÆ%æõ‘}ºÊ‹Ú»§ÜbÕϾŠÓ ú‡s*è妛ëgöE{Åá¼íë¸<®:ûBgú™s*èÑøèýöE{æ =çEhßùëK\?ôžYôâ@ç¼z»§½þa_´gêQyQ¹]º~ Gù*ÎÐü°0Ú_ø¦RïQï¼`_´_RêTüÿS]ñ•ŽúÙí9§‚®Ú+9-Ö "§ªÇ¦ãSùf9”Sa9GŸ}Uû ‹œªøÁã­×Û-‹o[çÊd^ä9渾’#r*÷9»Î¡ú-_•;©¼¨ý |‡ó"ÿ“·þuMø*çEÚã›æûßØí‡ó"´¯>Z?`õ³òU•Õ-jk*_ÅQyQ½u‘|>û¥|‡ó"p܆uòútåËœïœÎæÅ5Vÿ³oŽÃyø庵ùúo-|‡ó"ðÛŠ“­ã+}EÞÅyQØ_5?_æ N΋À÷óCòùzè…ðeøœSÓÑù }ºÊ‹šÏß‹Çøì«8Ðe^äŠÚ⳯â@ç¼u–[¥ó<ôŽ|:ç9à4[¤ó'töU¥ƒS >û*NÐ)§¿XÛîöUèþg²_nZ$ß}ý“û×£„RNè#øì«8Á—rªÀ߬¸'ž‚N¾Šó"pªMŸ|sG9øÿVýÊ—9nÐÿ*§ªÞ—^•oŽÃy8n³Â|¬òeúó"ðý<“¬¡³¯â@oE^Ô­]œ#æ·ÄWq 7”S¡Îšæ1èì«8ÐýÏd§ñýoöõO6Ï_¥ƒï6,î°øì«8Ð9/¿. óõ5öUèœï¶,’¿¿}:çEà4+¦Yã‡}ºÊ‹Ü¶u²¾U¾9ŽÊ‹Ê­‹äóqà+_ÅἜróâj«”/s°_þg²ï×96ŸtÿäaÇ¿Ì‹׿}þš}ÁW΋P¿ó÷GVÿmøÜ7sàËyøå‡l>û*tUÒÙ÷rÿŠÞŠëãHëç¼Ç·|åËΩ ·”c(_պʩÜw_Hþþ)øþy¼õÏ_‘; ÕŸGþɽö%ñ¡³/tÅqâ~‹Gú +NMý NsWÚ?Е¯âpû¯ûœ»è_­üp¤¾Ýç‚ïÖÙÖüüE-|™ƒýå¼üîËcÎ;töUèœu蟫.IòðÙWq‚.rªâÄ1ÇÄõ+ßGåEÕ:ÛÚ¯;/øÌ^‹¼¨8kÌVýÊWqJ‘SÕç/‰ù¨‡}¡+ŽÊ©ª¦›ßŸ©|™ƒãUˆóÚ×Å[o^b_ÅîÏëdzè°ë6Uè¿à7tþBW|怯ò¢âʱÞ˾Š]åE¥¯tZl¿ßÈWq «¼(E÷õ¯;ä«8Ð9/‚ÞŽ°ÿ‡ó"ÅÏéŠSPNå{¢×õ¢Ë~÷ŽÏ´ç¼ü†øЕ/sÀ/D^ÔÑqŸ}'è"/òüÇý>û*t•5šŸøæ8*§*¾µÁÎñúö…®8œ¡ +|ãùåË´wbìŽo‰ù9_ÅQ9U#æöEŠÓQN…:ݺéø áË´WyQ{Ò˜S¬ñ©|™~C9êo~±õ½Ÿ}ºÊ‹ÚÍ^6ùì«8ÐU^äüñ2³~òUèŽr*ôO÷úÅÓ->û*tΩÀoV}%ù~Tèì«8Ð9/§ùÚÅ·-ô¢­w]`_Å®ò"7g››­þaߧ¤¼¨ÅûFþå ³b>8ì 9ÐýºÈΩÖK×ç9_ʼnú·÷_pXG=%ùBWí9/¿]7]_A_R|9/‚^ß“®Àg_´WUÒÙ|Õžuÿ¸¿üÞ Éø)GµÿïåËyøÕzéý;töEÌÞÑõœÚk~`ߧ¥üí¹Nå›kÏyQƒùá¼îk~¨îûå"k¿˜ƒz8/B=%ñ•¯â@÷?“ üDô ³¯ÿUo¢÷oÄ/çEÿÑøøFzâ«8Ð9§§¥óºß¯Ä7Çá¼ççÏxüCW¾ŠÃy8Õ­ŸmõôyçEàÒõtå«82§¢ó |å«8œÓŒ{ü«á«8œß8Ñü|œòU΋À/®zx;küH_‘wq^Ôæ¥â‡4??®|™ƒó‚ó"ð«Òû#èì›ã8Ê©Ð?Š¯tæÀ—ó"ðýOÞzó*ó'ì/Sós+Æ!7Wèœùç÷çÿGÒëtöUœ÷§”SS~7½¾C/ÈWq ûçñÖïçÿø¤øþÔ7êéì›ã””SÓŠëW¥|‡‹¿¤~€®|‡ó"pjÏ·æå+9"§êÞó¶ÙVÿ+_λÔq®r$öUí›Áøt”#¡½Ûwº™?¸ƒ§'×÷‡ó¢ó§â 9¨“{àÓ/‚.øÔ<ä]*/âöO¿@Ì®ò"Â9>sÀWyÑHùÌ_åE#å+çTè‡vßéæ:–}Q§â¨œÊí—Žså ]q8/B=¨Ÿ}Ñž9~?ûó¹È©ê§®¸ ^¿Ã¾Šƒý✠+œòŒO%Ÿ„ξŠß‚ò"pʾÔ~]Œ|¾þ÷É~"úÐÙWqüSúëCrà³®8ð­)GBûrÿt|*ß,‡øC|åtâ@÷?“-ðõoý__jæC^$×qðþÆ×wèKÊi±~£û\pª§®Hòèì«8¾ŽÞøᜠ+œVðÙWqàË9øµèöUœ S^~Kó'töUèœãÇɳÖüƾŠúMÜG ÕiñÙ7Çñ¿O¶PÿÓW<Oߨ7Øzé?vþ©ýø‰ù9_ůi8ôèìë›õ÷‹8‘n÷³à“<ôü„ó"ÔÉ¥+t΋À©üû¢Næ@ç¼|w€=þŸ9às^~Móó³œ'OÝ;îgp˜ŸãTûN¿Ðä?Çñ÷_‹årCã‡ù9Nõé=·³Î_æç8Ýþ¢âç8¾žäó°ègæç8¥qßÝëâç8þ÷Ɇz˜ï™çÚ;ú÷ϵ_Xã‡ù¹z¸~ÔÉüÇ“ä~æç8…‘3 /æ+ôJÔÃ|´—×/#7èâç8|ŸŽþ:^ñqÌqüï“ æûFÃŽÃâ€Ãºâ@çö#åäÚ3¾êxqûÿÿ6§}úŠ›ããûFë)ms˜Ÿë7ó[‹½Ž04ž™Ÿã´ßùãÖ<Æü§¸ïs-ó³ß ÞB?ß·ö¼è°¯_1{ðÿ7Äa~®ž’îk°_#åO,~ÿØ;îÄÏÕÓ>ks˜Ÿå|î¢Å>/Л牯8í`ÙŒÞóì¾6ôOK|ÿûa÷³âç8C÷ƒÖùÎü‡ïË°_ÌÏqøýà08Îgý/-NO§û…!ÎÞ­´ÆÕÜVû¡~Ò‹%ä¨öAb¥›Yj¯tüÍéÐÏiß =2÷KµGÿ´ôzºâ¨öà;c5ìø¡öà4KXjݯ£’×ñÕ~©öÐùõú‡Û½.ŸåP{püóxÑqÿ{q|=ß’^€ÎótnêYBŽjtîžà4~|ÆóêçýRí¡WôztŽÃíÁiGÈáöàÔ#Ü/nNKçon¿¸=8Ö}Üpó†j?Tg¼þTõ@çö¡ã>nØz¨=85½Ž _5~¸=8þy¼ý?9ßÿÞõTô:¯ßÉa÷‹Û£Öß(G½~ªŽ·G=õç1nôÜ~q{p:z½5Çáöàðëª9·‡_?Íq¸=8¼¿9·ÿÿ–cÜÇ ;ÿP{ì—z=QgnŽzÝPq¸=8êõAÅáöí×½ª=êºÿZ’ë…jë#Y'ð}8Ö}Ü°Ç]½Îh¼®8ÿP9y€ „Ó   LayerElementUVI f¬   VersionIe €¬  NameS map1·¬   MappingInformationTypeS ByPolygonVertexî¬   ReferenceInformationTypeS IndexToDirect{M  ~  UVdf;  q  xTyÜ•ÃÿÆÇ^I¢i±Uh¾¤±´©”}IL¨d + ÙB"-Š˜´EÚ¥)Ú´JJJ&ZˆìKYç|®Ïõ¼~Ï_ß×û;sfùÌõî¾ïsÎscrç*¹©1&Ôþåýâÿ¦¥‡ §Ç¶ ûå‡Û~&ln¯,l__žq^¿ò}ôŸPIØlŸ¾ð a_å-áøöàÇ' }[9¼þŠ1Âö›ý„ã / +›e{ çnÏ ‡ç÷vËG }Éß_×]Â7þ.ÌþñÄ…9žk¸C8è|éé-`]íøX×ë&}&Ìý˜!kÑ®ûµ5>f=\çUÂYëo\!ÌzÚFËñzÖ{Ù2áÂ>(ý“òÂ|½ë]E˜ãÛ)Ç ¿ÎŸ/©/\²¾zg¢?×_¥9úsÛ..ÙÏËПõyåjaÖÏ_ßIØh}í°ÀZÿØ ‹0χÌócž/Çó<Χùº¯ù º^Ï|é~ ó§ûe>Yæ—õb¾YÏ’ü³Þ#àÏ#/m€ü]¢> ¯/ì+.—ü¥‘' Çç§ çÏë +ÛËF!Ÿ·œ l^zý/:¼â.ôÙ +ç× »Û r1ú/;ýßj.ìW(ìNo"lž++œ>n >u/á8²!xðnÉ9¯üN8k×! s<ße ò¨óÅêKÐ_×ãÞy¬ë WMGÝ=~’°ÕýÚóÆ ;­Gø0 +³^ö£„ƒÖÓÝ8RØ\ŠzÇ#ÀêÛíëð¡äõß7@þt|CkaΟ&\Öõe7úsý žæþìòQÂÜ¿ýv"ú³>íf¡¿Ö/-œ/ÌúÚºK„Ößw^Öó)a=?öçùr¼Äóç|š®'k~¸ÞÄ|é~Œæûe>Yæ—õòšï õdþYo×°!ò¨ç‘ê·öýÖKÞìõç Û‘SÁ7¶@û7O ç6ç +»=nW?K8ÞÖýÿ>U8O;QØýZýÛ,œŽ…OçË¿—Sá/»C8¼«×«O6›*ÈëS“Õh_­×“®ËÑÞA¯ÊùÔ¯$oìŸÓÏu¼8ù:ŸŸ‚¼{]O8ìEy½çz÷{ùŽýØÙý1¾î×u¹ýµñäîÂAë•N¿YØi=à ]Ñ_ëí»tæ¿WláXÉ_Ÿ:·süÊÝ…9ú÷Ya®Ï?3 ý¹þÖ«…¹¿8õ;aî?ù½Ï£¤>¿*l ~¶v-aÖ×Í?íZó\á çC¶z~ìÏóåxVÏ?è|ÌGÔõ0?\¯Õ|ÝOÖü9Ý/óYÍoÐz1ß%õÔü—Ô{|ày¤á‘¿ Ë÷“®G¾kŒ§\‹|ŸÚ íï^)ì'þ¼î"a{Öè?~åç·K~S³³¥=uþ@Øoj >a<ò>¢Žpî4P8Ž=ZØßÙGØÖ;X8¾r«°¹m_awJWp­_?åôÒzaö3’pÐñò²W‘Çë0Ÿ;w°pÒõÄ÷u½fúMèÿöcÛ_%ìt¿î±6Âõr¶°×zù—OÇëk¢žqU#á¬õ¶ ¢]ÿ½b»½¬!ò«¯·ŸwÎ:~Z|¬çCæù9íŸô|ƒŽôüÎÇ|p=ÌÕõÍ—ÑýdÍ÷›5ŸAëÁüF­WÖ|­'ó_Rï.]$_ô#þs?ò¶f.òýg_äñõ€üïÙý>\ûayYðÀ®èÀÇ’×|AGáüàhä{ø…¶_OäyØyàiíп|ñïÔJÖ£ùáz™/£ûÉš?î73ŸZ¬ùe½‚æÛi=™ÿ¨õ.<‰#ü÷êúç„ã¿S$ïnáaר«°_õ”p^}”pñˆpØóSäóÜ{ÑÿóaÂn×íèß­òüu'ôîXp[\oÂY»ç¯ç¾ ®/¹ÒaÓ[Ÿw^[Ø.>¯ï;íãð<’WŽÎÓõyC9Þ¾Pò´®8Z8êx®!®æ`Ì—nè€v]O>éLáÄõh…ÍMØ»{?a¯ûõË~ÞTÜGÒzøk¿6£^᮵ÂAë™O[)œµÞiÙ2ô×ó`»Û£­ä¯KŸƒÿÄ/Á:¿ÿç8äY×—jtŽ\ÿ°±Âܟﺬû÷óö](çÁúì¬#ÌúùKZ +'Ö÷¡ÂfêoëuëùKÎýõ|ŽÇó7:_Ô|8]OÐü8]/óe¸Í_Ôý2ŸŽõÐü­ó´žázäŸõ.<JÞøïUXòø„ñ’3x’pžÝ>Œ|Ú]’ïTfxîòãÄ«¤=Ž~P8µ?TØüïNáüÖ:ä}öÅ/ §6¸ßs7÷vÏ/¦åeè?¤ºôw[› +·¿°ÕH8ßÿ ò«×Í.éßôa«ã….¸ÿç|ñ·¦xý¬Ç‘üfî'NöºßpòYúK{ÔzÅóîÂëYÏÑÝЮõ.<Ÿ Ó«ín"Þ/åëÍ;KŬã»gð|ÌùÍ+¸_òº¾Ð3|àúÕ“ü:ÝŸoÔyæþ'NÎZsæVô×ú™#ö_T<Ö7L®%lZjý‡Öó|”žû{=_ŽÇóÏg`¾’|èzJò£ë5š¯¬ûaþ¼î—ùd=˜_Ö+j¾ó,ÔÓkþ­Ö»p=—|eõÃݾïIñÁŸðò·¢*ü9m­°=×mK„ã^ç;¿ný%òýë+àjàÃÆÁÂiËéhï¡Ï7Ÿÿ–ŠõU®“v{ä{àx¿Ì=𬰭‹çw3«Ú{ãý¬xêÂù ¼_E¯L€Ú?ÄûI^Ç3ËÏv§ó¹ÃÊ +g]kþòºëu‡MF¾u?¾Ñ`Ýohp úïz˜A {­—›t¶pÔzºO ÛûQïÂó9^¯÷W^ÛÓw‰|½«¿U˜ã‡s/–üGÎÿ÷»ÂA×g¦%ùö\îÖýåª ‘Ý¿©QùÖú„¯Îάßý·G­ol> ý+¢þfñpá çCvz~ìy¾:Ïßë|^ó‘«c=™ùÑõzÍWÖý$Í_žŠýFÍgþKë¡ùõZ/æÛj=æŸõö]¶åb.é‡ûëa÷j?\/~ûCØ\¾‡pÞç{ô/û¨ø/ÍÂéJð㈕Âöˆñða”ú²Ï¹Âî¤1hÿwG*Îkê67¾$œÿ»E8öè$œŽh'œj ìváy$ר$lÆçyï=…óz|žgö‡ñùƒ©‰þ~q'É¿©†ñ¬9V8é|æÕ’O§ë cf {]oøàqá¬û)Œ't¿ñ’¦ÂæMÔÃýZSØ•C½Ò¡ {­g(»·pÔzÎás©‹úÁvyøúðê¿ðEÇ¿Ý->$?·ß ?t}~Ë•’ÿÈõïž-Ìý…=•<[Ýî…ÖÇ<ñ"ò®õK›— G­oÚ¸SØ|†ú§?ÿëùy~Qûó|9Ï??Žù˜Ïõh~¼®7i¾’î'iþ÷Ë|j=˜ß õ²šï’z2ÿZïBB7—ò£ÓaÂiõð!þïgº÷_Þ ~|ð»ä7]¹y^qœôÑWàÝ„m‹åÂñ»¿%¿±ßTápØ Âá«aàŸ[ +»m½…Íò½…óÞ¸ßÊ=FÏ-Žï>h$í±JáðFEá0öTáüòFÉ;Ù÷&œ´¿ý÷S¶'Æó ’v§ó¥ÓVK^“®'½_Òõ¦î¥=ë~ÂÕ§ ›o±ßÔ«’°½ +õWþ*y·W ^þþMàŒzÆ&?F½ ×óR~°=×(>ðõùh¼?Ëñó+/Â?«†üëúò!ij®ß¼—ä7éþÌ×× gÝ¿=àmá õ þv¬_³“Ï#°¾w^$lÆ þþÄЮçCæù%íÏóµ:Ïßë|̇Ñõ0?y;ÖË|¥JºæO÷5ŸQëQ’_Ö‹ùÖzZæ_ëGT‘¼óúaÕ¶ÿtÆýÔ“'‡WÀ‡xxÜà†àõ{Ož'~<ºKòêÞ9Q8üˆû³øñ É»ýè}i7õÛ‚Ÿ+œvo‘|Çex>1­Û ›ï¯Aÿ76½'~<}ºpØùŒ°9ÿ`´7½Y8ÝŒÏ;¬²ÿâIÉÔþ©æ9Â^Ç‹]ôùBç‹KfH¾ÝŸXOêx7X×kŽvÂY÷~¬ u¿é¹­’o·êßû yzåm…³Ö3uQ8°Þ#F ¿^?JÚ÷‰û©íx½^>pü«>Î:ü³®º>×lµ°Õõ›º­àƒî/¬˜"œtÿñÁ$ßIëc>»\8ký«O#ÿZß\æmas êoü‡Â–ç£ìôüØßêùr<ž^ù¬æ#èz˜®—ùJu°Ÿ¤ù³ºß¨ù ¬‡æ7_‰zÍ·Ñz2ÿNë]øü|s1w%~œx¾p<îJñÃ]qŽ°ýišø`n;EØÿ‚÷£âË5…Íäûç‰MàKðSñ3òüΡÆá4äoɺhŠp¬p|˜:PØü=ì=ña]a·ýðÕgç-žSl[Áë׿(œáûPIÙµÀçÛAûû ˆAÇK#¶H¾ƒÎç¯z^؈õäw.GûP¬×-«*œ¹Ÿ‡àƒ}\÷ûÎLÉ·×zäšC…“Ö+´ë+µžyÜÍÂæx­w—.`¾¿ËöOÇ‹|½¯ÐZ|0µ0¾+÷£²ÎÚ= ?t}©gÉ¿×õ›fƒ„ͻ؟¾òÎýïºy©õy`Úµ~¦üÏ`­¯yéˆ%ÅóȬÿàzÂQÏ'){=¿ü"ú;=ß¼?Æ3zþ^çc>¬®‡ù1ºÞ¬ùJça?Qóu¿Aóéµ̯Ñz1ߎõÔüçu¨wZÖFòM?̳׃/l#~˜Z„Ó=Ï‹þŒ¶ÂæìçI>+þý¯j+©.l¯œž$ßçâ~Ì®-œïÂó¿_tøàË%ä½æïûûxÿ9Mü|Žpº íöJawü¹Âiȳ‹íæʦÇjáôÏjÉ¿UvoÞ#l†jÿ~5à‡Žg–¯€“0Ÿû¶ŸpÒõ˜ÃO¶‹±ÞpÏo’ߤû‰‡ÏŽºß¼ñ aßõ°: ­—ÙJØõA=Íg§¡ÿE¨wáù\¸ä<Ø>iªøÁׇ‡o?œŽïÞ;P|0Ÿëüc§']Ÿ¾øuý¹ã'ÂV÷žo/y÷Üÿ­ï[­9¡¢äÝjýÜí {­onà‡Öß-†þz>d¯çÇþAÏ×êxç<æc>‚®ÇôÐüèzæ+ê~˜¿<û šO«õ(ɯÖ+×D¾½Ö“ùwZïÂû‰’ç¤ï_™Ý÷ +‡{›Š釻„㞊¹Lga3èÃyÅ|†Ð^Øî{¤pœÐX8O’öïð">d]¿é}|àþ| >èþýW!ÿ¬Ïª[…“Ö/­ž†v­¯]ºE8kýí®¿…ã‘8²×ócÿ’óÕñ²žÐùÌ|Í×£ù±ºÞ ùJ½°æ/è~KòÉzh~½Ö+j¾“Ö3ïBþóƒ¨w!á’gþ{•¯†|o ~øwŸvOÜ(~¸µx}܈ϯÃð˾…÷£âµ­Ñ×™©xÎyhmŒ·éLñ#UÆõÄžXSü÷l@¾ÛÔŸSìo»¼!*ÜŒ¼¾<øãw‹í.µögÞ*lfVvNNƒ–Iþɶ_á¨ýÝg{Âg1^h8ù?Pç+ßJ8´Åzüj\/²®×¬yMò¿À~¢ë&œt¿¦z´k=ÂÅÈ¿ýõr¶IþëyÎÇÂîÔ;.[&ÌóðÚ®X.~ðõ¦Çpñ#êø±>¿¶:¿½ ïG%]ŸÙï}\/týyP'ñ!èþÒß ›°ÿtEWä[ëcîþP8°~+X<¯õµZ g­ª}½°Õó‰Ê^ÏÏ°¿žo>ã9=ÿÔ[çÓ|D]ót½%ùÒý0i_ì—ùÌmõý9ͯ×z1ßù.Ô3iþ½Ö»ðù9ò«×ôÁ›È÷GLjöÑqÂù`|?*Ž"ìk÷›W¬O¸æ>a{õ¬Täx¨N‹Œ°kÚD8Nœ,>¸6þaøPÿÉwêôøÛÌsß’¼ç¾ }éAÂþI|Ë4ö™ÿb|?>{«pºb òØn¿Z8hÿ¼ß/ðaÆ‹] +Û„ùâ¨áÇuXO8ùä_×ëxùŸ„ý¤5M…Ýbìל»úk=Ò̵’wSõJ?M‡ ž¡WNZïÂççÂôƒíæ¤ÏĬ¯÷ßâûQYÇOk‚\/¬ÎoÆ4ÇõB×NýOØëú󫯈Q÷çÚ5‘ü'Ý¿_1G8k}ÂÑÇ!ïeP??¢·°Óúº?&Á­¿ï¸D8êùy~Vû›{q¾NÇãù;Χùpºž’üèzKòÅýhþ÷«ùL/£Aó´^FómµžÌ>õ.|~Ž<ÓÚKÀ.~ä‹Þ¿p +žÏ»Oöw_9OþýXþ,x¿Ç渴úŸ4`®øòu;áܧ–øg#lžÝ>»Øž¾Ö÷‡{­Ãõ áðáŽ]’wÛù)a·ÏÂþŠËÀ[>›U|½ùßÇJ›¢pª¾P| ›vÃíOùJòu¼<¢·°ïŽùüIx6ôÆzâ“Ó$ïfÖNò¹/ö“n¬ >ûµ?•|›2¨‡©ö +ø­×Uý…ý(Ô3¾v+øoÔÛué‚þzÅö´×vñ#èëÓuÊõÃêøöÑñâ‡ãü»zÃ]Ÿ¹ñ ñ!éúÍü`î¯ñ“¸^èþÍy‡À‡‘¨]Ô_8iýòߟ +;­¯Xiiñ<²Öß=}²°Õó±Ê˜ØŸ?rƒ°×ý‡Y7!ÿZŸp[öZ?ëÿ'ùwZ__³7üÐú§ùC…£ž9èù9íïõ|ŽçyþœOóát=Fócu½ÌWÔý0V÷Ë|­‡ÓüæÓP/æ;j=ƒæ?Šz>?—|&úñû_±ýxÞØñƒ°}cOá´ÿFasH…yâÇëI8t<~œú"Úo}N®þŒžÂ©ryñ#\ݼëuÜ?]^ ¯÷áþè¿õ’÷¸úaøpê‹àÞ‹%ÿþÇk…ó-…ͱVØR~L ” ŸW»'Ñ??ý¾øaïÆxδÁõãcÌgÚoüûÑXOn~—pÚõš‡ +›Ã±ŸÂx’gwöë&ܾFëñu á¨õ +u¬pÖzæJe„ý…¨wá¾jC±®Vý0£=½a𼡯wþ#t|ÿíOâ‡×ùóèÏÄó Ö—O?×ÿë=âƒmý™½jÃÝ¿;yžpÐúØÊMp=xõ‹ï?Öú†Yà‡Ö?üöÚõ|ÈAÏýƒžoÐñ’ž¿Ñù²æÃp=ÌÏžXoI¾~Á~ +ãIž"÷Ë|j=˜_«õ²šoÃz2ÿZïÂQ|Y<’ûÝ«¶}ÌŒ2hoüÍ<9·õ¿ ß¾NEvUq}q¿ž[ä°sŠ´›òVüH[Eÿ-ýfË<“.ש ~„­°Ÿ¾J|°Ûðþ]ì¿Lòíxø0yø1ûátm¿·e¾yø>o|ã áx/¾¯›”ó#Åëµÿ{SáÃ[/4Ä÷ŸÂC˜/ç¹’7C×3ö"øQëu”<›mºŸZ#…Ýد_ŠëCª„z¤¶‡K{¸õ²C¾—üÇSQOÓâá¤õ.<Ÿ—òÃj»è ñÁéëÃâÊâÇ£çÿ}\/ŽÁúüî„×@?œî/|s·ø`6cÿiìa’ï¤õ‰sF€µ~æ¸ÿGQßÐÎ-“óÕú»ã¯Žz>V9èù±âù«ãéù{ùºž¬ùqºÞ’|•Ç~˜?«ûe>=ë¡ùuZ¯<ùvZOÏük½ ŸŸ—öcþIÂqÜVñ#>P]8ÍÅ÷oÃøýÁo·v"ï]†c!ﯿ2§X/ûÔHa3õñÁý‡÷»Ò5wÈõÂ,:QÚÇ5q¿´ìøÐè`\Êâý,¿ãÉ¿¬ÚΘQßt¬)ZÝ.›Í¢rþ¾®°k„þö»1âGÖñR+œNÁ|±ûXñ!,ÅzÜx?Êx¬7|õ!|˜†ý˜Yw§‰Ø¯ßY íÝP3õkÉ{˜Œz¥¿gƒêéú¾,ìÇ£Þ…çsaÇ÷wµÝ\UUüàësS|ÿ–ãçvMà‡ÎŸZ7¬®/ŸPW|Hº~s쾸>èþܪEÂY÷ï«Þ&ù7]Q×ùwa¯õ _#ù·? ¾iëXø¡õ7£]χôüJúó|u¼ çot>«ù°º¯ù1º^æ+£ûÑüEݯÓ|z­óY/ÍwÔz:ͺõ.|~.y/$Mîoýñ-…í*ü½“oû?áÐrÆ<ù÷ᮚàðý)·k/¼þ½ðãJÜ…óO?©“àÇ]ß-¾>µï-œžY->ÄûÏ€_ôò”?‘ÿ­WŠæ—é±fü‡KðyaÚoçôâxaW-i·[^Žfˆ^9]VSØ–AÿTeˆøàja<3²ü؆ùžàGÆzü5…ó`¬7==ùû1mqÿ”[ë~Ü…üÏE=Üá³ÿµ^Ÿ@þ[¡žþÍÛ…³Ö»ð|Žvž‡¶Ç“ñ÷N^_oßn…ç ßì‰ï#E?ÆÛà‡®Ï_u£øažÁúMÓ6âCÔý¥•%ÿQ÷ožþ@ر>å/–¼›ª¨_Þ9|9ê›ú–].ùÐúÇ' G=Ÿ \r~ÚŸç›8ÞTœÐù’æ# Âz˜Ÿ ëe¾ÒYØ×üݯÕ|:­GÒü¦=P/§ùÎ3´žš§õ.|~Ž|óß«§: Ç?—Î/î×V¹XØ}ô‚øáÎ>C8´îŠí®kUð!é½"ûBþ¿™1[ê•ç +»väza_ÆýVþ ‘øá·’öøëñÁÐÏG†GñÁnœƒüwœì]ÂyCMa3äX´÷[;­8_\7× åô^ðFô-‚:ž[Žïšç0Ÿ{öVñ!þ†õ„wõ~j!ÖkÎ +âGlý˜ÍGÁ—o±ßP©äÛTÖzÜ7 yoƒzååW +ÛÕ¨gøêLáðê]x>özQÛÝ>äúaVàõá¤ëÅ ãûiÉõ#éüñ7|Þçt}ùñ±¸ŸÒõþþ[üHº??ª³øtÿaŸ#$ÿAë㦽)œ´~þÂê’3õ5•nƒZŸ†[=rÔóc§çët<¯çot>æÃéz˜«ë-ÜK~òåØóu¿VóéXͯÑzæ[ëi5ÿFë]øü\òméǯ}ÀÇÌ_Ì[Úr³°¹ªÿ<É_õeÄ…â‡][OÚãMáÇ‚}„ócg‰îñÕðã¨vâGøe¸púc®;ñ<Ê…ç‡~ø¾°m¹]òï,üûaJþÃw½…ã›WO>^8U)?â›âCVNÇâû¹v2úÛž=Ä3ãyó…ø`Za>S Ï¡Ö“_%ù7»±^ÿíUð£öc{þŠ|?ŽýÆ‹_v· ñKõa$ê/íYë™+'lŽE½ ÏŸëL?Øž>sâGÔקq÷âùCÇ]Þ€:8ÿ#¹~8]Ÿ7‹A×o»ãýÙÌý=4 × Ý¿íÛ>h}R‡ò’w¯õKÓ„Ç¡¾æÕÕðCëo~ùS8êù”°žû{=ß ã%=ÿ óeÍGîƒõDÍOì¯ëÕ|å;°¯ù3º_æÓj="ó«õŠšï õ4šÿ õ.Ü¡Hžé‡½jòÞnÊüâ9…É!ï_âûÛfãMÂn{øѬ…°™÷ç9×¾¸ž¸ã¾+>5Ü*>„oçËõÂ4{U8×Þç‰q7Çjwày¢ËÂ~÷‰¸^¼ï䕧‡™øûöÔÿ™©ÅñÍÒàË´&±ÛDøA~j_\?Bÿô2¾?Va¼Øp‰øáÿÄ|yZcát4Ö“{¾‰ëC]¬7>w +|Ù‰ýز¸^ä°ßÔ³»ä=ÍG=r‹ÚÂök­×K¿KþÓW¨gn½N8´G½ ßoë¿W%í“Ûâù\_ïŽÂ÷ÕMKŒŸ_#~d?¼´§ø๾oÄó…®ß=^M|°½°¿xÓ^⃮ûÿq‘pÖú„½ºÁ‡1¨Ÿ;| |`}Ï:uEñ<²Ö?ÓIØêù£žŸÕþAÏ×èxVÏßé|Aót=ÌÓõFÍ—ÑýxÍ_ÐýͧÕz0¿Aëå™ï#µžš«õ.|~Ž¼ëy˜4IØö7¿¸_wï(áxsûyEö6§ì+~˜i…Ýaø<À×?¼¨­øa>ÿCòf5?ü°™Â©c<_t¼í ß|›c…ýk=p=þ‰äß–í)ù= ._<¥¸žÐOèÛuŽ ð÷‚üûßr½°W ¿_u î¯t¼Üe*üx]çkv„pl„õ˜ŸìµXonvüxûq£FKþÍì7 ?\õ°“þ”¼›Æ¨WÚoò êiÂX´÷E½ Ïç¥ü(iä*<ŸóõCÞÄóÇ_º[ü0Ïa~ÿ+>ßðº>ä•â‡mŽõ»17àzÁý]x‘ø`šcÿ®K5É¿íŠúä×'­_èÛ >h}ÝšçÁ¬ÿ‹„£žO ëù±Òóõ:^Ðó:ŸÕ|]ó“Ûëz5_†ûÑüÝ/óiXÍoüPë¥ù¶ZÏ<ùO£Þ¶áTä™~»H8Œ}n¾ü{Ðb†°ÿµñ¼"§^#…Ó>óæÙÔìþ·ž2§Ènû¹à.Ÿ¼SdÿH9ð£¯áý¨í‹%ÿñé9x¿é ZV?RƒúàïŠ)|.>øs¦À‡öø>B¨óß[2ÿž'J»Ù1V8þ5N®V9\ƒïC˜ºÚÿßópu.Ƴ#GÁ«1_X‹ïÆVX­wüŒõÚ_v ÿ°Wÿnaw#ö›g¾õð•–JÞÓ~¨—»ãYa÷êé¦u‡ãPïÂó9˜÷»lïÐUüðúú´ÿ<èøö¾£å~ʼ£ó·êŒû)]_j3Tüðº~7û5ñÃëþÒ©£q?¥ûÏzˆžõ¹¨†äݳ~_Œ‡Z_“YY<Ìú?q¢°Õó±ÊQÏϱ¿žoÚ¤ãéù[/j>‚®'k~¼®—ù2ºæÏë~™ÏÜõ(ÉィWb¾µžéäßi½ ×sɯãõü‰,lV>1¿¸ßxðJð}G‰î¼)Â~tOø1øqáø>¾_îF]!öéøNñõéä£À—V?ÜéëáÇûG‹nÙ@a×±›\/l•3áGù=qÿtÓV\/úþ ùG>_þ;<ê$´?ôéäâ|თÅL^øøµ¬sŠ°¿ã¹åÂ0ŸëºE|×`=n`[\/`½>.€—ë~\ öÃ~ÍÆÈ÷Ô#ö~^ØA½ò§„Íý¨§ÿú,ð*Ô»ðýv¼^σí¶~ñì××÷ÿÏ:¾;¹Þ¯Òùí‹ø~yàúîûHüˆº~÷ÉâGÔý¹j?Š‘û¿p©øµ>y÷ý⃩‹ú¹sÊHþ“Ö×›ÎðCëŸæ<+õ|ÈIÏÏi«çku<§çu>æÃêz˜Ÿ|ÖË|å5Øó—ïÅ~ó3Èg¥ß·×ü­WÐ|ǵžšÿTõ.|~.ù-ñã§ÝÈûîûçóæ¾Ø.œ÷Ù[ü?Dÿ&µáÇ£…MÕ;fKÿ‹oEÿ±[ð¼±÷[©æ`<?þä?ýþ ®ýŸ‡wÎÆýÓø|=Îi)× {ñNÉ¿^ׇ¯ ‡oÌéõàÇÑåáÇÀ—ÄD>)ãz±ýý•ÇÀ/˜;ÅôžÎ·k±øîÒõì¨+ìva½±mü1ØOa<á4^÷ûïÉ·=õÈovMQ¯pv=ø°ŸÖóÈòÂñOÔ»ð|¾¾XǨ~mOû> ~ðõþÏ¿Äó9Æ›oÂó8çÿe‘\?"×7é ñ!ëúÝ÷q½Ðýå½›âz¡û7‹ªãú õ £7Æ“ú¥qÝà‡Ö7 [?´þáÇÝÂVχœx~Úßéù/êù;/k>ÒB¬'j~‚®×h¾ŒîÇiþ<÷kÏô3êQ’_­—Õ|­gÔü{­wá(¾*ž‡×óH—,ljÝ9¿øÿ›×ÑŸÂ÷×Í›‘ÿOñ÷®ùö·…ÝÀ²ú|rÞ-xÞxði?íƒç»Å‡x¹^ø3&»GÄõbÛ…h¿møàÎüMòï¿ï&ùÓ†§ Z¼Y\_XS¾ôè÷†ðe/ˆ¦'Ø[‹ól‡þæÑC…í/5¼~ÜŽùòc“ćøÖ[”¶u°Þügøñ öãwþ%ùÎÍ°_kŸöw¢æœ3áÃÔ˼ö¯ä? Ò¿h¿^؃z®ç¥üHÚî6?¬¾>vÇ÷µŽŸžÅß»:ß´Ü ?t}nS+ØF¨iušäݳ~e— +'­¯«|تbý³Ö?V¬'õ|ÈIÏý½ž¯ÑñŒžj‰ùóÁõh~Œ®×k¾ŒîÇjþÒçØ/ó[ yòëµ^ù5äÛi=ó¯õ#ª”ò#Ω+.è,~¤^Ú~ØG©¸?×—ÐãÙ÷¤›–KþÃÂ×Þ-²;LØ|õ ž7ê\ +?æÞ#÷SáÄrèusñÃü2C|°/\'× ¿ìjøqôZ\ŽùGòïÚ] >Ä0>ü>mRq>sGCá4aÛÄ"‡£Gˆî5°ÿ¿Gþ@ÿ8møÒã™®Íá‡Å|©Ê`ñ!ŒÂzÒØoÅ{ Ök_½T8ÌÓý<°ùߊýÚsnŽ‹Q÷ +®©ê+-—ü‡ÃQÏôÐxp;Ô»ð|.œx¿«íù­‘âGÒ×ç¯O’çñ ã›æ3äúáu~3 +ßOJº¾Xáñ#èú}_ü0ã°?³z£øaªbÿnÊ +ñÃk}ÂCÄ3õs+Kþ“Ö×wj?´þ¦ÎõÂVÏ'×'=?§ý£ž¯ÕñxþŽói>Ò[XOI~>Âz“æËè~˜?§ûMÌç úý2æ·ê4ßõdþµÞ…ûÝÒ~Ôl.œï¾b~1oþœÂ&¾-~¤{* +ÛƒZ¶[$ïéÈ–ð£çëÂöÁ¾â‡ý¤«pˆÏ¯óýxÿ×z÷S¯é÷ßš.׋4¥+üXu¤ø+àóÂ4o±øÛàûŠîÅðaÿSàÏm_?¾*~e×å}ñÁ½„þîKü½“{㹑õÄüæ ¯õ‚S°³'Þ¿5Ïèz/­?a?áÐ âƒ{ûu7œ*œ«¡¡üçÈ%ÔËõ}^ØF=ͬ»„MÔ»ð|^ʶûG_?¼¾Þú–ø¼CÇ·»6ˆAçO?uç¤ë3Mç‹I×ïNÇçÝN÷fÖ²î?wŒø´>湟„£ÖÏ|Ý\òµ¾~b_ø¡õwç C;ÏG9ñü´âùnÇx%ç?\çÓ|x]é‡üX]/óet?VóÏÒýj>½Ö#j~㨗Ó|§kQO¯ù7ZïÂçç¥ü®cZ‹¶Bká|ü‹â‡mq‚°™ø÷œb ¿· îÚúN‘m$ªï%~„ûûçäyíªöùåÄ{>?´ ˈvÞïM{-’û¥ôGyñ%5:W|ˆ‡ãïoCó§_+Îg^i,~˜C§O?Þ ?”Ý +ýûÙèŸÜ&>„ÆÏ/¯*ìöÅ|þŒ¸¿Z¤ë¹ö5ñÁ}€õ¦=÷αŸ0¡Ÿøjb¿î‘r¾'ꑺO’¼û7´^_u¶µµž;p«õnØP8ëõÃi»é8Mü0[ðú°®ÞϽSÇm¼_¥óçæŬ닷ÿ+~˜½°þpQ;¹^xÝŸ}©øuÿ~T_ñ!i}ÒÑÇIÞÝA¨_Ñùg}ÿ˜?´þ±ãa«çCNz~^û›]8ß ã9=ÿÈù4F×ã5?éE¬—ù2ºæÏé~™O¯õ0̯ÖËh¾­ÖÓiþãÕ¨·ïÒ>ðyð‡»…Óò³æó–×_ö·?Â!gƒ[¼?êàzb–<?6¯‘ü»ô¸‘û©TßOq¿Ý"÷S©JFþ?ë0YòÝè:_‚û§Í‡ }üñ!nyE|;ÿyUúŸsšpju$¸Ï Ü_¶ñ{‡é{íßd-üxUÇ3ú÷~]1Ÿ]ÖTüð±7ß1`½fòVɬƒýÄ&—ÁùدU¯KQ³î>É{j…zù6§§ ž®za³õ.”íz^ÛCƒyâGÐ×Ç úŠNÇW‡ç ?>ÿüÐõ™ø?¹Ÿrº~wóPñ#èþÂÃKÄ ûO•Vã~jÔ'Üu©äÝœ…ú¹Ö¯ +G­o8' g­¿éý·pÒóɽÀYÏÏk«ç[2Ï_çËš ë)É®—ùÊ7a?Fó^Â~£æÓj=¼æ×°^šoÇzjþÖ;ÿ×Oòîy—ïª?_ò7î^ðÿn?òæ+„ÝWáÇÈã„ÃÑVü0ÿ×V?ÜG/ ç?ZâýÛ»Z ûãWÊõ„ïÿšÜñMñ±ócâCX´Yî—ì‡GÂ*§Éõ!Nž†ÞüJ±¿Ùt:¸_ÿñ²ÞsŸ?L ÛÇËý•Žþîæ…ð㌗þ >¸1Ÿéˆïßš¯°_¥›\/lm¬×uLâCÞý¤ê‚;a¿áÃÉÈ{ ÔÃyò¾õ2Ó÷Žg žáÒ Ÿ×w£Þ…çsá̯´Ý–Y!~X}½Y8Dü¿B[ñ#éüñÇÄ³ë «z‰A×ïÚ ~$ÝŸ»åpñÁéþÝy‡H¾]#­Ï¢þðAëgþùT8h}ÃÀJÉùiý ?(ìô|ÈYÏýž/Ç3]pþ…¿W”ñKòÁõh~Òͺ^Í—Ñý0F÷5ŸV둘_­—×|Ǩ§Õü§ýPïÂó ò­çáÞ}]8Õ8Füp݇ +Û÷ñý!÷æÂ…û@ñ#–= ý{Ι%ymû¯ä?ý;ŸÿõÁç%y¾_úAiwê‹ù1ü=V*»·ÜO¹6ø{ÝpÂír½ðSk‰îÉ)âCº÷-ñ!4Y?N|¸ç a3}ÇXáòp¥l÷…çñ³Ð??7Cü0Oa<Ûu=ž7êb¾´dÀzB¯–ð£#ÖÊáó ³ûI÷?Ì#ñþÃwý%ÿînÔ#Œ®&Ðzõ‰ä߀zƯ +›Z¨wá†þUWξûá¼ô*ø±ÞΣªK^L­âC~¶Þ¿­|‹°}êÙÉ’gWV84| Ï ð÷_ቿq¿ôB]\?þ­+ׇÔr†øà¶6Ì¡MÀ;.SÏò°ø‘”ÍmÏŠaú‡…ãqý0'Êxn$þ¾.<¥óÝ¿S|H±žôñqÂæi¬7½Ý> Ã~Òn¼?ë"ö+\V iß$ïî(ÔË=2FضE=ÓœžÂáÔ»p¿[ʬínêvñƒ¯ÓÉõ#ëøæ®çĬóû‘‰öO¬Ï×ÿAü°3±~?£«ÜO™5ØŸ;}î§úéþgÝ$>$­Oágª„Í"ÔÏûÿÁÖ·foø¡õ7ïvz>ä¬ç´Ôóu:^âùë|‘ùÐõÍO>M׫ù2ÜóWû ÌçÔ#0¿w¢^éLäÛj=æ?MA½ ×sä]ý°nŽ½÷?b™Eh_SMü0çGa7£?üØ~“°­±kf1Ÿfî·ò™ð}ªåëàG§±xÿ¶ë½ÂæÁoå~Êîª,ì:¶—û)SŸ‡„äzn„ëG÷WćtÈ»âƒ8íeñkòYÂéèY£ÅÄ󇛵ðþÕSèo†ëÇ]/,ÇûýáGÌç\->õäzûÁG°^Ó¹=ü¸ûÉq?å›b¿©^mñ#ÕÒzÜ2yŸ‰z¥ï»ƒ?Ñzþ|Ž°¹õ.¼Ÿˆv=£íé±_ÅÌ××Ù,~Xßóžøaêc~÷CøñÖ—:ÕÁó¸®ß­œ$~¸úØ_´'|àþ +Vh}æW¼G­Ÿ­t³°×úÆÛ&ÀÖãbá¤ç㔳ž_ÐþIÏ×èxVÏßé|Nóáu=Aó“t½^óet?y&òçt¿Aó™¾G=r+ä7ÕB½‚æÛk=ó#È¿×z».ÛžÇÎ?÷—ÿ'y[ó|è¸øá›)œ.4ª!>˜6¾\j£¼¾k?Ü_)ç&ÏÑ?UÇ÷IÒVÏ<‡û«‹0Ÿ‹3àÇãXyj›ø¾Åz]¥:¶ö“«?ŠëÅ&ÝïEÿ ï}Q÷Ñ áp êå/wÂñÔÓ{ÚÇ Þ…- +gþ{¥íîš=÷ôõvÌŸâ‡×ñýº¯àÇŘߞ7]üp5°>7¸«øuýîë_įûs{Õ¢î¿ð÷çÂnÔÇUn"y/Œ'ÿ¾¤÷Ÿ‡g¡¾qÖø¡õ¿ý…þz>äÂßïÊyþþ\ÚÍí8ßÂß³ =ÿÂߟ 3Vד5?…¿—‡ÏÌ×vì§äóì—ù çj=4¿y-êe5ßñeÔ3}‡ü玨wáû 2^ WÜ"ç°ì'ñÃÆ]Èû²us%Ÿ[V¢ÿÎïÞ•~ †ƒW4˜Yä\ëBôï;ÏãöøðÏoÛ]9|8´í1I¸ki“_û©´¿'äÞ‹û§+ÎÛ\ìg.{A|H?€3~©øÿ‡ígƒ9pT‘}½{Ås(8ë?ÞÕþízãúqÆ3„Ót¾úÏ‹nÖc¿ÕïÛ^ˆõ†¹ûàúaž”ý˜Åxö›z¬’|»Pß؃D½Lª œV žîªÏ×ÉþV Þ…ë¹pÖó`{nXAüàë}ÕC_uü8 ,žÇ{b~3büÐõ¥ùcĬë÷{üOî§÷×ëBÉ›×ýÛ›¾k}ÌM¸^d­_è¹LòëÇ£¾iï +«‹ëɬÿ' 'ž²™„ó‹Úßêùz/ëù§nz}Ò|änXóãt½Vó• öÃü9Ýo`>ŸC=¢æ×h½òKÈw®‚z¦‹¯õ.|~ô<òÌÚÂæ-âGºYû>Vü°S¶#ÿFÃF¸‹µVáýÜÏ:K»­êÄ°ä@á´ô¿Éržðýa7õ4yÞÈÕœøá>;Gî§ì²%âƒ;¸Á˜b{váÂïÈõ!ݽ>”ùëùb»é.¸ßç#Šìwß ?8p+ü(‡þö¾®âGøãÙ®·Àʘ/Íë'~˜MXk9N|oc½é–,>ØØ9¿‘p:ûÍÃð|ŽC=âóõÄó¤Öëxøà2êéŸzM|ð»PïÂóy)?ÛË!~D}}|æDñ#ëø錓Å;ó›ï“ç §ë³¿|!~Ø[±~W5ˆI÷—¾¹[|pó±ÿ<ö0ÉÔú¤9#„ƒÖÏ÷°«€ú¦v>hý ¿Ï ìô|Èæœ_Ôþ^Ï·ð{OÏ?è|…ߟ‘|D]OÒü~OBÖË|å*ØOÖüÅŸ±_¯ùt;Q£ùuZ¯¨ù¶ZϨùÏePïÂýni?ª®þ©øNU_~è.~„~¸Þ˜c.ƒc>€}o…O÷³Éóxº³†°y—øa&ÍÁõ¢Ê?òþTXÛ¼÷7x?jÊñ!õœ;Zò^ûaÓ»†\Òy+àÃkŸ+¶‡jÍÀ;^&ýç÷„ßSÏëáGôO¯]ŽëG_ŒçG^&~˜{0_¼èñÕÑõŒ{÷WGa½¦ê»âƒA÷³©|™ýþ»Vðá~­‡ÙC8‡zÙg^—ü›Ÿµžó{ƒk¢Þ…çsðø=€Èö/Ž?__¶…øa÷ÀøæûKÄÇùÏm%~x]_ªy$î§tý¡áBñ#ëþLÇ(y3cÿé‹s$¯Yë*ây½ŽúåOODþ{¡¾iäðCëŸÎ +Öó!›f8?öz¾IÇ‹zþ^ç‹Ì‡®Çj~òÕXof¾t?Ióç¸_ͧ;Gë¡ù ;µ^šïPõŒšÿ¸ õ.|~.>D½~¤‡: +çÖKÅ·×¹ÂÎ4?LÛÃÀ©œøá+m@þ?*?švW´ÃçãGž_V®çñð/¾¯•îŸ'Ïæ)¼ß›N4¶˜ïüÜâƒ[×&JþÆ÷±L‡ÃFJûAÇWÞZdóNsð%}ž-²âNøq)8}~%ü˜€þþÓðãZŒ—;\?>Ã|þ+¼Ÿ›êc=qO|ŸÊõÇzÝ¢¡âCXƒýØ;7ÇدÙÐ +¼õ°]>’¼»÷Q¯´ûð^¨gúý’÷@?vôö½Þ?òŠ©byñÃU=YØ\=÷Éã?Á‡ã^•÷sÓßc„ýk§ÛÂðãæò<žÛmÂõbËïÛc³nÂéòSÆÙõÛëÅ]ÓäzÿÆoÁ¸òËíyã:øðû“ƒeüK[‚ç¶|ºÈþ’ÛáGÇfíáÇnô7ûâ¿'`ÎÓñL½~`>×ãD¹~„XOºö\¹~˜o°ÞÐãøqöc÷)>¸?±_ûÏ‘àÚ¨‡_:y¿õr×µN‡ ž¹v%áÜõ.lýÕSíæñ³Å ¯Ü#~ß]ůó‡ï^‡º¾ðÐñÃôÄúcƒ/ý…sŽºw)î§üZŸYµ$ïAëçÎ$l›£¾©Þ:á¤õw=þëùÍç8?öÏ<_/èù§™˜/i>Œ®Ç´G~œ®—ùòºæ/÷Ç~æÓh=¬æ7^ˆz%Íwþõôšÿ0 õ.|~^ÊØþiáß?âȾæú÷ŠùKÛ› §?î‚?î'ïk?¦èû[î™"y¾í*ñÔyQžÇýèïÅÓú|yÞpÿô?¸a´Œßù7øqÚJ\/¶Þ >v!2Þ«áÃS«ž*²ù©•^?Nz¼Èî¨[àÇà8©9ü‚þ±áñ¸~ÔÆx¦Ñ¡ð£)æ3ûT?Ì#X™SCüí°ÞT½µøaÀ~Üȧć8ûuGÿˆüÔ#Ö»yÿ õÊVÇ¢žæÚ/Ö×^F½ Ïç–~h{ºöñÃ,ÅëÓmÏŠIÇ{/?‚ÎÎþ~èúÌôU⇫õ»¦mįûË3*Ë¿×ûú°Ö'•¿Xòîiý¾Ÿ+lß@}sß²÷‘´þiàIÂNϧð{?Âvίð{@Âfηðû>2^Öó/ü¾°×|~ßGÖÃüD]of¾t?Ió¦é~5Ÿ†õÐü­—×|;­§×ü[­wáyùÖëG˜1>,+~¸.áC£ñ⇙~pxöxñÃ][M8ü%ÞϽq¹øOÙö–äõð[áÇ؇'Jý~ÖÏ×'W_ä<í!\?^ Ù¶1ðåïo†Ù¬¼ ~ìÿ»\rÍð¡î£ÛÓ­Áµ—ö/²Ûv#ü¨ Ž‡6 ÐßwÂÈñ\×ÿàÃ^;d¾4T?áM]OÕ=áÇt¬×¬¸Qóî|Ô˼0Uò[¡žnÑ=ÂþÔ»ð|^Ê í©Ürýpúzßq¡øátü|cEy?7êüþ[ü=`äúm…÷«¸þ+‹I÷Wøý+ñÁ‡ý~ÿJòožG} +¿%´~…߫¿ÿ÷k}+Ý´þ. vz>d{6Î/WD¯çku¼Èóç|šÂï_ÉüNóSøý+Y/óet?Qóçt¿Vó™v Nóë´^©>ò®F=­æßi½ã²e’ï¨~ø7Âû„ø‘þyO8]îÄÜî)ð‡ÏÀ&­Ñ??ÖüŽëEß&K~oÆ÷Ó†K^+rz´´»{‡‘öZ~üûüóE·ãótóÐу‹ìG÷‡¯Í}XÚË Ö|Ý»Èáý Àí¾¥Èîîëà‡‡­'ÀŒþqö.ÜOMÃxiùÇðã ÌÞž ?ö{AÖã×$øñ ÖOÀ÷ ÝfìÇ_VIü°½±_ÿp7ñ#ôG=œÿJònV ^iï‘ÿ¨gø«¹p®Žz»† Kû¡í>÷?øú¸æ ñ#pü#N?’Îï\w¹~$]Ÿkþ°øajcýé†éâGÖýŃJÞÌLìß¹æÈã +­O™MÂvŽÖo¯‹àÇ6­oÇ?´þiý"°žOT¶àü +ï?I{ÐóM{êxUpþi?ùÐõ0?žëÕ|yÝOÔü¥fدÕ|†¦¨GÔüúª¨WÐ|­§Õü§/PïÂçç’ï¨~¸¯Ÿ¿ø–¬Cþ» ~¸£ôzÒ¥9ü˜ØIÚÃÚwäóŽøøþÂöàûÄÈ8ñ!õ>ïWm?þ|Ùáåbžã|b.úú9É÷¾<ÝCž/ÂãOÀ¯/êWl7ëñû¼ÆNì"|m{øáNi$¯?ûZøÀ¾-~?Ö8ôw;¾†ëx{¼?^Ä|®åXøÑë õ£øa¶c½yítñ!܇ýø_ãzQû ¯œ)œÖ£a®©›ÖëÖö’ÿx êO>DØ·A½ ;,åGÒö<ýñÃëësëÝâGÒñÝò«á‡Îo‡¾ ?t}©×<ñíÃú]w|ÿÖ4Ðý=4MüHºÿÂïÉAëSø}8ÉsÖú~NØ\ õ}u5|`ýùSØñ|”-Ïýõ| ¿'ý½žá÷á0žæ#õÁz¬æ§ðûp²^æ«ðûpâ{Iþt¿†ù‚zÍoX†z9æ[ëi4ÿNë]øü>¨…ó‘ó/üïšbÞ·–b³N?bûüßJ·¿Ñyb»þ½(Ç3[ºýŽ&È£ö7W*Å¡ÅæRlô÷79^¨ö0òÍ×—[WŠÃoÇöoîSŠƒþ÷Ì8ž™Y ÷_\ÿ˜;J±4¿‡>‡àúÄñ»t)ÅᙥØ4)9þñW—bsÈ¥8ü÷_iþ ¿ÉõºoñßÓ"›Í}ô~ç—ÖâïÉØ^Øo©v7ßÏöÂþñï‘®/MjQŠÃ˜;J±ÓÿþXÉëÍ/Õžú¶ê…ÿt|wG“Rlô÷<9^ê0¨T{¡ž¥ØµÀß“³¡¾ø÷—ëo€¿e{8þêRí®ÚÃ¥¸PÿRœÊ®+Å…ó(Å…q%ÿ¶^ßR¾é 9¨/d£¾ ϟ♾ƒúB¦/dúB¦/dúB6ê ™¾ y_Èô…L_È…|ˆdúB¦/äÂy‹dúB¦/äÂù‰dúB¦/%¬¾é ™¾é ™¾é ™¾é ™¾é ¹PñƒL_Èô…L_Èô…L_Èô…L_Èô…œÔ2}!Ó2}!Ó2}!Óç/å ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾éK «/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúâŸîþÉÿ¿#Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2})aõ…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Bú®”/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/%¬¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾éKü±«¼/ôyŸL_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô¥„Õ2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}IŸ Ð2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó—V_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô%·¿Ÿ«éõ…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô¥„Õ2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}1¬/å ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾éK «/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúbߺD>‡áý™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾éK «/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúâ6¯,å ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾éK «/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúâ+âïx}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2})aõ…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_ÂÙ å{,ô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô¥„Õ2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}‰ÝÏ–ï9Ò2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó—V_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô%ž]Ê2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó—V_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô%tª|/ž×2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó—V_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_ÈôÅì9µ”/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/%¬¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é‹mp’ü¯/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/%¬¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é‹»nB)_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_JX}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó?¸–ü]!¯/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/dúB¦/%¬¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾é ™¾éK˜ÿR)_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_JX}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó—øsUù;t^_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_JX}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó—TcX)_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_JX}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó2}!Ó—|QEùÝ^_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_Èô…L_JX}ù¿ªÎ:l«b}ۃ݉ºu©ØIØ5&X˜XË tÛØŒ±UlQQ°–‰…Øn»À[Ç­bbw~ïᆵsßû—Çu\sÏš¹ç:]ë‰÷ /hxAà ^Ðð‚†4¼ á /hxAà ^Ðð‚†4¼ á /hxAà ^Ðð‚†4¼ á /áÿwªá /hxAà ^Ðð‚†4¼ á /hxAà ^Ðð‚†4¼ á /hxAà ^Ðð‚†4¼ á¥Õâ /hxAà ^Ðð‚†4¼ á /hxAà ^Ðð‚†4¼ á /hxAà ^Ðð‚†4¼ á /é­iíwÝà /hxAà ^Ðð‚†4¼ á /hxAà ^Ðð‚†4¼ á /hxAà ^Ðð‚†4¼ á¥Õâ /hxAà ^Ðð‚†4¼ á /hxAà ^Ðð‚†4¼ á /hxAà ^Ðð‚†4¼ áÝòr¸ÿ»‹-/Ò-/øú½¾„¯ßëC·¼àë÷-[_¿×‡nya~ý¾eëë÷-Ñ-/̯ßëk}ý¾%ºå…ùõû–­¯ß·D·¼0¿~ß²õõû–è–æ×ï[¶¾~ßÝòÂüú}ËÖ×ï[¶^4¾å…zý¾%ã[^X~ß¿å…zý¾%~Ë õú}Kü–êõ{}ø-/Ôë÷-ñ[^¨×ï[â·¼P¯ß·Äoy¡^¿o‰ßòB½~ß¿å…zý¾%~Ë õü{ªŒ×ï[¦™‡w¾¿H·¼àà >¼àë÷-™¯½¿àà õú=XÆ·÷|x¡^¿Ëøöþ‚/Ôë÷-ßÞ_ðá…zý¾%ãÛû >¼P¯ß·d|{Á‡êõû–Œoï/øð‚†é–éöþ"ÝòB=¼P¯ßƒm¯/Ôë÷`ñÛû õú=XüöþB½~¿½¿P¯ßƒÅoï/Ôë÷`ñÛû õú=XüöþB½~ß¿½¿P¯ßƒÅoï/Ôë÷`ñÛû‹üöþrõCy‘nyÁ‡|xÁ‡|î/øð‚/øÜ_ðá^ð¹¿àà >¼àsÁ‡|xÁçþ‚/øð‚Ïý^ðáŸû >¼ áEºå…zî/Ò-/Ôà õðB=¼P/Ôs¡^¨çþB=¼PÏý…zx¡žû õðB=÷êá…zî/Ôà õÜ_¨‡깿P/Ôsa<÷—µ~ïÌ‹tË >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼ áEºå…zx‘ny¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^//¯a¿ô{JIºå^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^Ðð"ÝòB=¼H·¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Œ‡—†tæEºå^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^Ðð"ÝòB=¼H·¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Œ‡—.wuæEºå^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^Ðð"ÝòB=¼H·¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Œ‡—ÑßvæEºå^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^Ðð"ÝòB=¼H·¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Œ‡—+Û¿ã”xý"Ýò‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/hx‘ny¡^¤[^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡ÆÃ˳væEºå^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^Ðð"ÝòB=¼H·¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Œ‡—½oêÌ‹tË >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼ áEºå…zx‘ny¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^/¿MéÌ‹tË >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼ áEºå…zx‘ny¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^/t·6ñúEºå^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^Ðð"ÝòB=¼H·¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Œ‡—åöéÌ‹tË >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼ áEºå…zx‘ny¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^/^Õ™é–|xÁ‡|xÁ‡|xÁ‡|xÁ‡|xÁ‡|xÁ‡|xÁ‡|xÁ‡|xÁ‡|xÁ‡|xÁ‡|xAËtË õð"ÝòB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼0^v}¯3/Ò-/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚†é–êáEºå…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zxa<¼|·ÐÇÿÿ¿'ž¤[^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá /Ò-/ÔËtË õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðÂxx±Kg^¤[^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá /Ò-/ÔËtË õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðÂxxY|Tg^¤[^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá /Ò-/ÔËtË õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðÂxx¹ÿÕμH·¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà ^¤[^¨‡é–êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…ñð²ÝÜŸtzý"Ýò‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/øð‚/hx‘ny¡^¤[^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡ÆÃËç[wæEºå^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^ðá^Ðð"ÝòB=¼H·¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Œ‡—“ÎîÌ‹tË >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼ áEºå…zx‘ny¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^/ÝžëÌ‹tË >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼àà >¼ áEºå…zx‘ny¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^¨‡êá…zx¡^/wÎ8¥Óëé–|xÁ‡|xÁ‡|xÁ‡|xÁ‡|xÁ‡|xÁ‡|xÁ‡|xÁ‡|xÁ‡|xÁ‡|xÁ‡|xAËtË õð"ÝòB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼P/Ôà õðB=¼PÿÙOö¾X3r¯/Œ—gß0]Ýúèçÿ§ã¿®7'.ëzÜÞ®\òÙÿùÍ™³š®¯™Ót=ïXÿžÀÓ~ú~øtÓÕÃK™nÞ¹Õ¿½ÑÓÆgü§2_9Æy=ó,û;Ïgéº_e¿›5>~ñ™ý;PázÍ×åaÿwu½¸ùuöïÜ­'õhüßU×zËä»ßü¿}í§þâ³7þOgí7Ý°®é¸›÷#=y×äÿóã$õëàmM7êg³Ê¼¦« ½ßC}|_Ú¼òÓÁéZõ¡ÿú_™Ïü½ÞpÍõÇî?Õ|Ö·Ç·¦ã¾þf̓¾þ??ôôý…Þ6µÿôß5¿ù??©?e¥ÓLõ¯ð¨é°µ÷7ìð¹é¬þ§cþ2u>èJç׎×ùFÍWëü³®—•Zë©”Ÿ¼¡¯·Í—öCþ’ö”ÏJýÊo¥~Eå;oïý ÊT¿Ë?ÿxþuõÉïšÏìc|ä¿v=ë3ÆCÙæ\ÏÿZ=õ¶rÿŽk‡üÚÏÎÃm‹šŽ4ûu.^Ìõ°µœ—îñÊ»–ï²àü¦«?Ï7]_}ŠñÑü½“û³}é<¼¼ŠéôøÖ¦ã<‹˜ŽGïc|ÔÒé“匬ñÍC¿YóåI¯µ®—î}ÄøˆZOýZ6>ª£}½ÍrïÕÖ¾Ÿz§®Î‹ö[ÿç ã#©±þÈòžÕ¯<Ýɦkõ3ý±™é¤~Ç^½:ñ_­y…ó¢úê§5Œ‡ÄüOMr>tý°íî·֗¶ûÐtXÞ×_`<í/žñ”órŸï¿ª–ô|¿àý Ójºú¯÷/u¹Ét˜âýM+¿d:«ÿå«\ë|²t5»Ÿã“ηf¾n~þeZ]|h=òÓ®WùŠÚOCþ´ßJù,Ûx?å·Q¿ùV?+ò¯~ÇAS,ß•øH‹Ðø@§zùýƒñçÍdÿÎS£ùҘϨë5K¿c|4ZOö¡ñ‘µÞx|0]k?ñ±uŒð ï7î;ÊøhÔðGW¿Ÿ\ïý +—ë~r€÷3>}ŒñPÔïzРÎ|ÈÏÓŒ1>¢êëKz‘ùyvÏÿeÞŸêíM'úwãùîŸèý 3ßë<¨ÿUýœé¨óAWúù1¾æ|5_Ãùs=å£Ñz¢ò“´Þ6_ÚO£üEí·R>³ú•ß ~åžï¨~Vä_ýn&NìÌÇ=7yþ{`|ÄAç˜nžzÍxwïi:uÝÔùØkQ×r>öŸä÷‡§Ö5<ØtðŒñ¿ÿÛóÿemºL8Õt^h&ç§o0]¶yÄóÿâ‘ÆG}ÇéÎÇQy‘}L§³·2ݬ¸ó1e¾’næ[Ïï_ï½ ÿ;hš/þÇø¨¶õëå‹6>ÂÂZÏBÓ˜®µÞðâRÆG£ýÄ•úýäiíwÃLJB?.Þȵú•z}bùO{?ã…㜇^ÞïŽßîÄGëOe|4ªOk­`<„Q>žú€é¤ë7c7v>´¾z­ÇM'­¿Œ]ÃxHÚ_˜ï*Óq”ï¿þäçGý‰wDË{Qÿò6G›®æ÷þ¦®p>Ôÿôê®u>èjˆŸ_­ñQçË|Qç_ézánÏGd=ä‡õ*_YûÉÊ_Ô~#ùT?ÊåWýª”ïZýŒÊT¿C¯»,ßÜ?šmÏ7÷?ÈøhÆeºîþŽñ?ÝÌt¾µéúÛMçÛŸq>Æßg<”W¶2]`:•·ü~qõ×ÎÃuG™Ž 5]Ý÷/ÓyàOþzã˜ÉÎÃ'šŽ37®o|×ïg:|·…ëû÷w>þu?_I7·næ÷oz-k|0_è=Ÿ¿9Ö¯¦ïêÏ[ZOøïÎËX_o^|+¿Ÿh?q̹ÆG|Õ÷ûÖx¨îð~4«aºV¿Êsó›ÎêgØëã¡Q¿óĉøÀ—^h|„çUÿNwã!kþê¤;]¿Þv çõ­4Át\Â×ß,¶´å¿ÖþÒng9/ÚØü®ÕŸú´å,ï±·÷/ü²—óq›÷7<|ªó þ—Í.ññ:Ÿ,]ÝäçWþëãÃ?ßò³ÏWtþQ׫•ÒÇ×S+?Qëmó¥ýdå¯b¿Êg¤äWýª•ï¤~ÖʾÄûÝñÿ+Ë7|ä/üù©¹âP㣼°›ùñäý~±Ð*¦Ó—;;'}ç}±ñµŸêˆ‡Zû ïla:©Õ —-ïµú•;Ƶú™ÞÄ5ýîÕ«øÕJçÔ‡jAã!jþpã•®uýpý¢Î‡Öæe:kýaži-ÿaZß_õÙ¾¦‹ög¿×tõ‚úÓó÷Õ¿¸é*–ÿø¾÷·±½ó þ§•ös_çƒsûùµãu¾ÌFëüu½Jù¨´ò´ÞH¾´Ÿ¬ü•y}¿QùÌc½¹¯ç·Üàý +ÊwYÌû™È¿ú êÄGYtÓõLC´Æò¦Ëz_iø?–÷扻¾ö ÓõíSó59Út>b ×GÎa:Üú_ã¡yùvÏÿä~¦ãù{ºÿšñPÿ²°ézùLçy>·üçM^ðûÇø§L§E7u^öºÛùxlˆ?_Iç!ûEãóÍ;EóÕcv2>’®×l¿Ÿñ‘XÏØS¢õ†…4>ûy×Úo¸¨ñ‘éGèb:<éýª.¸Åó¿¾úùØ0ÓYýîx}Þ‰ÿ—ÆG¤þ±¹‡ª‹ÏŸÖ¹ØùàúÛv5j­/Ì|ºk­¿œýé¢ý¥•·u^úûþË¡W;êOžécÓñï_új~ÏÿPïoÝo-çCý/Í–®u>è°©Ÿã“ηÖ|Οë5ÊGÖz*å‡õå+k?YùË3i¿Êg¢ÊoM¿”ïJýl”ÿFýÎûvæã>ç!¯wŒñ‘œÛü沇jü§–÷ªÇQÎGïÛL7Óýî|¼=Ðy˜ö ÓéY¿*ý¶˜éf7ÿ¼#žõ¸å¿,—•üù¾šø¬ñ÷ç­jþ¦ÓA]l|>úYçáÍŒ‡pÊƦÃW/8¿íÏWÒeöƒýþ¡ñÕ ƒFóUƒ2>j]/?:Üø(ZOÜ|¬?_i½ù b’üú±ÓŒFõõ~³Eó‡Ïr^.ñë§?¦·üG­/ÿ9Ìtu°¯?ÍPLgí¯µ®çÿ1ßzÅ_4êOyߟ·’ú—.üÛÇÏáý-ËT΃ú_ÍÛÃùÑù Ã1~~YãkΗùtþY× ‹y>¢Ö“•Ÿ¬õ¶ùÒ~Šò×h¿µòÕ üæ¼_òÕÏFùêwÕ«W'>Bç¡:òxã£j~µ¼§ß~7òÇ/šÎWœà|V=ÞŸ¯¤ËØ¡~ÿ`ü6ÃŒ¤ùBï“Èõz\f|D­§úòIã£ÚÔ×›™ÞtH¾ŸpÏ΋ö›zÉx¨x?êÕkçåJïWÈs˜.êgà¼$õ»ãõy'>ðÃ9§Ô73Lo<4š¿ÞçdÓaˆ_?^ÿ›éÈú¾õÏ ‹Ö_§Œ¤ýÅ—µ¼×ÚXm¨kõ'Ü}·é¢þ嵧¸½÷·žfF㡨ÿéôœ:Üêç5¾Òù2_Ñù— ~½š|h=ä§ÒzÉWÔ~È_Ò~“òY©òÕ¯r•ò­~æí=ÿålïwÝ­3Sqnn|Ô¯}`:îÜÅõþþTœåtçc§“Ì·w5]×ë¾ÞxÈC¿ðüÏ°±ëûÎ6þþÂó~{w×û_eºþÇG< ÙÛt9d]¿Ÿ,ÚÓÇ—Güþ±dWÓ¡ot=ý4^?x¸?_I—õ’ñQk|^ütã£f¾p©ñQéz±¹Çøh´žpîã!k½±ë +¦£öS?Ýù`¿Ûÿeù¯Õøòy¦“úUïM7êgµô\΋úÝñúÜ4¯ÏñÓÎÉøHªÏ7þmºÖü姣þ~ý°ÝTçc __úxWã¡ÑúÃï™®µ¿¦Ë|–÷†ý_R›Ž]ÔŸ³®t½„÷¯|8ÉùXßû›ßjº¨ÿù÷¿|¼Î>ôóc|G^ì|³æKœ¿®—ɇÖSÈÖÛæKûéÈ‹çOûMÊgÙVýP~³úU)ßú™¿RþÕïŽÏÏm¾Jï—T§¿oº¼w²ñÐÌô´ûwÏh:lÙ˜ÎCÏ7šOÿm:N·˜óqÿ2¦›eî6êIoXþãÙ;¸|¼é꾿-ÏÕ¯ú¼tú»=ïÝn²~•+6Ýü§·éj˜ßOò¼úýcóÌOw¬o:ŒÔë•+Oöç+é0y„ß?4¾úq”ñ5_št«ñ®òëÕs¾b|„|=eÕM×Zo¸­ñ‘´ŸrÎÆGÑ~óªËûóý8èË{5Ìû•¿>Üt¢Ÿßoä<¼ïýwâ#à/q‚ñPT¶úÕt¥ùãˆC~ýüG1]ëëKonéè¢óc|Öù2_¥ó¯t½¨|°ž¤ü”>¾^òÅ~Ê}ž¿¨ý&å“~”-<¿ô+)ßeKïg9Íó_©ßŸŸ{þÅG\üIÏû<§9ëùë‹0ÏÎËñg¸ÿÑhçãèL§]Wp>¦Çtîõ„ñº?é÷‡®ƒ\Ïé|xWÓ)Îìü\ûœóÐóJÿÿÉ3çyþ/_ÑyyqÓyó{Œ‡úML‡ùÖ3Ý,ºšéúõÿøó•t8äB¿h|zêzã#¼äóÅ1…ë8ÕyÐzò«Ë8/Gøzó½Cü~¢ýäßÞ2Boßo3ÇÎ~?Q?ò ßXÞõ+žæ¯¢ú™ÿ;Ä}õ»ãõy'>ŠüüÕ1ÆõÕÔïœÍŸd<]¿¹þ5çãw__=q㡺Ï×ßLm:¼æû‹çNu=Ü÷_v_ÍyQê5s^žöþÅU¯0Ôß|ÁƒÎ‡úŸ>|ÎtÔù ‹ÎñηÒ|Yçu½FùÈZOP~Úõ’/ö£üEí7‘Oõ#)¿ú•×U¾ÕÏ üÓïŽç]Ë3÷øà-žïÍGñð‹]6¯ëÛ3]¶¹Öù˜y}÷o[Ãùè矗 ^µü7ÇŽw.æ<<áïçÖ+,mºœñ‡å¿‰Åòû^èúûë=ïwuw^–=Ît>þNã¡\¸‡étÌ:¦ã-[»žm„?_IW3\á÷/—Þc|ÍW ~ËøȺ^ž:“k­' õ÷{­7Ír™ñFû~òÀiMWÑ÷›¾:Åy¹Ýû‘®^ÔtÜVýú×ë–ÿêpïg3âFÓa ïwÇëóN|dùõ½C‡¬úú¼/M7ÌÇîÆCÖõëíž1ùúb^ÑòŸµþzð¦‹ö—_{Ëtõµï?=²˜ç_ýI³ïêyíý«ß8Õ}õ7té¢þçî4u>è¢óc|ÒùFÍWëü¹^áù¨µžFùIZ/ùŠÚOPþ*í·Q>£úQ)¿•úU)ßQý ÊT¿«^wY¾á£ÞÑ¿OXx¶ñÆo~óÂB¦Ë‡»˜®g<ä1~? Ómâ|\ò¹ñúþÏò_¾Êõb#LWGnåú“µL×/Oµü‡÷²|—g˜N‹ÚÐt£þ¥ýû¿IýÍ›p>Ôÿê™K¼^çƒ.:?ÆG/ó…A:]¯Íë!?¬—|i?üi¿ ùT?²ò›Ô¯Zù®ÕÏJù§ßÿ¿êÄGúæhÓé®óœ‡·öuV\Üy™wCÓa¹{œæöú]·5]}øšç—ïüþ°Ì9¦ãØ1¦óâë˜n®ìçº[±ü×ÇÍj: ?Áõf¯{þ?œ×õÛ·˜n>¾Áïïëùk£5M7Oœä|{ž?_IW«ßá÷Ư7ÙøH̦w­ëU70>’Öa|­7Üñ‰ñ´Ÿf½œí·¾ñ=ËR?Â'øýCýªû®é¼¨Ÿqñ9\«ß!ø÷£žwkùMßÃœÕ7¯¾o:jþê-Œ‡F×/×ßnºh}áÆ9<ÿZ0ÐyÑþê½Ç»Öþó©?š]¼?ùþå-ïa}ï_³Ô΋ú÷篢þ§uN4?ë|ÐEçÇøJçÛΧóot½¢|4Zù‰ZoQ¾ØOPþÊ ¾ßFùÌêGM~é—òè'ùW¿;>?÷|ë<Òˆ½L—ÏFÕ[™Žg.ãºÏr¦ÓÅ8ýny¯oÛÝùX!›ŽûÓéÄcM§ÆYþãKË»¿ËÞ¦«}^±üçw=úÓñ°¯,ïù—Ù\÷zÂùXðZ¿Lw“épÃê¦ãv—9wŽôç+éøÂý~ÿÐø2çã¡Ö|õ¤…\ëzõ:»¡›Ö³×ÍÆGÒzó4³šÎÚOºi¸ó¢ýÆÓf1ݨùð[=ÿôë£L'ú95š®>W¿{õ2 Q~\à`ã!|ìõeÈ›®ðù›Gã!éúy»k­¯\öé0­¯¿y­¿å¿Öþò Wšn´ÿúÓ÷Mgõ§œ7ßæòþ•‰ë8êoþc'ÓEýÏ·ígºÒù ³ÎñáW?߬ù¢Î?s=å#j=µòÃzÛ|i?•ò—µß¬|6êG ¿êWP¾³ú•ÿJýîx=؉fÉÍœ‡EGõF=M‡ÏV2ñûE˜æYËé÷±å½™ö çcÈ-žÿÃætýú`ÓùÎÿZþˉ ™.s1n~Âò_ݳºé<~°ë1Óšnæ˜ÞõÙï:}¯ôûÇr9³®f:¼?Áõgûó•tô¸ñ–÷ññ?QóÅ1«ºÖõÒÍCýùJë ÓC'>ðˇµê¯˜Îš?ü½ºó¡ë§?G™ÎZ_>ï[×ZÜz#Ëd_ŸiºhÿaËgM'õ' úÓt£þ…£–t>Ôß8y=çCý¯–ØÊ}:ëü*Ï:ßr¤ÏÇù—ºžòQ¶ðõ„ស õVÊû©”¿†ý*ŸµúÑ(¿å/ïW$ßêg­ügõ»ãóóÎ|üwEÓMÿÑÎÃÐn¦Ë¦½—q¿Y¾Ó!¯8ïû÷©ò.Cœ‡GF™_¿¨é¼ÂŽ¦Ãš/:+ÍâõÏûçëá‡{,ÿ©_óë‰þ}«ðÄB>~©¿<ÿŸüè|¤Ñ¦ëmÞ1ëeºù÷ ÎÇb£ýùJºþ{¢ß?4¾™0½ó¢ùÂàÍŒJ×ËÝFYëÉ×}é÷ ­·ºqGÓ‘ýœôŠß/´ßj#}ŸiWïG¼a6çEýjºN²üW›y?ó©×›.êwÇón'>Šü4nó úøÀó¦“æO¬dù¯uýxÙÎë;åCÓIëϬjyc}©·¾òý§qw™_ÓŸu?ññw{ÿª…gµügõ7ßÑÝùPÿÓÅ=LW:tÖù5ßp¾š¯=®G>´ž¤üÔZo›/í§Rþ’ö›•ÏJýˆÊo­~%廢ŸÊ­~w¼ßÞ‰¼³¿?F\n<„[‚óríÚ®?øÐò]½ãßw/‡Þëù¿í$ã!Î|²çÿŒ•L×'od:>\,ïáÝߌ‡øŸË‡uôyÇ·þ¼¦lg~™ªÏÛ×ýÉòŸ×›ÝÆ7.2]Žr^Òk=LÇ_>u>vºÜø@×£&;C||8}>ÓEóå^»ák¿^9Ãßﯾóõ4}f3^j­·ü~¬ñQk?õÔ?,ÿYû­ª LGõ#l´®éZý +7ÿmù×y?›mýýר~w¼>w~ô¼›å‡aû•êëÝŸ45XÊ¿ïuý°ý‰ÆC£õ¥a¯˜Žøúó†‹YÞ‹öWŽÝ×t¡ýÏéÏ[UoïOìꟷ×ê_|ì{ŸÕßê,票ÿy¦ýþ¡óAgãk/óqþ\/)õ(?Yë%_ì§"Ú/ù,Ûy?ÊûžßÒÝûUnö|Gõ3‘õ»ãóóN|”ïüþP?|•ñ?øÔóÞeCÓiîçL7}>±ü‡.W{þ§=×ùè°û­ëþ[«xý&ß{¾ÏüÜó¿¾þÞð”Ëœ—sõþï?›™Î laã«þSýþ0j)¯ÿì<ÓiŒóÖZÕt8µ‹ù霫üù +½rñû‡Æ×».e:k¾Ž0> +×ûõã!±ž/V46ðõ6ýã£Ñ~:æ3]Øïßÿ5’úQÞ=ÐtQ¿Ò†«šÎôs¿¿4êwÇçµøHòó†µß/Tßüý°éðžÏ_ß·ç_×Ïî|h}éÀÇM­?=8»ç[û‹úßÖÚ>\ïÿª?õg÷ØøFýK¼íõêo3Ðy)êuüßæW:tÖù1>ê|kÍ×èü£®W”ÖÓ(?•ÖÈ—ö•¿šýÏ'ý ¿QýªÈ·úÙ(ÿúÝñ~Ig>Î*–çüÃ5ÆC3Ï‹žÿ½ú8/›øçÕÿþiy¦ç—1ÎÇ»x}³•é¼Ê¿\?7­ûk½eùO¿>nyŽÏ1ݬpŽóÐÍ¿o6¬M‡â<|³žç‘³L—Güó“tÅʦ›¹vÿ‰küù +ýÔç~ÿÈ>¾Ya5çEóÅIþ}‰Ž~X}ü±?_i=ñœ~¦­·nžtØÏ“[»Ö~û_xþÕf˜^R«_åͽõ³þl}ÓáGïwÇýÜtÅûWòãl{8oy}nî35ÞJßçÕõÓ ‡¤õŽ&8/Z\íO×Ú_šq]Ï¿ö_¿v„kõ'=|•é°¢ú7×c¦³ú[Eÿü¤¨ÿ雽^çƒÎ:¿ ñç«ù¢Î¿ãÿÏVO>¢ÖÉÖK¾ØOTþØo¹@ùT?*å—~%廡ŸÊ?ý®ù¿£ØÁ‰÷é§-ÏÕr×¥Ï=®ÿÛÏt:Æó^ýê÷‡%r}ëõžÿO7v=n€éú4½¶›Ïtþôã¡ÿ†å±™7™Ï^c:÷ìaº>PŸ¿¥÷,ÿqó<ÿÛžæ¼|²é0ÍJî_ÑÛçûc¬?_I§=pÿ÷&¦kÍW¹ÂîI×K“ÿ1¢ÖS­zˆk­·úá ã¡Ò~b£M‡[}¿åþœõ£îú¼çqïW<ìBÓQýŒ7]«ß¯Ï;ñ_&ïjçS«>l<ÞtÒüñƒ-ïá¿~Ü~WçCë‹ýÇš®µþpû®µ¿°õ²žwí?¬±‡éZýi.òûI­þå{o2¿¨¿ÍBÙµúŸ÷yÞt¥óA7œãu¾í|:ÿ¤ë‘²º¯§(?¥Ÿ¯·Í—ö•¿Jû Ê'ý ¿ô++ße#ïg^ÊóŸÕïŽç]ËsËGö=oòûÅñú¾íB;˜®oò×ñÿ¾b˜°‡Õ—iîrzøóT¹ÏßÏ +ïýbyo,íþ¨ûLç¿ô|ïáïç¦A÷™®û.íã/>×ó~Éë–ÿêêCL§SO2fÝÕõ L—å¶öñ=oòç«å¥þÓï_¿´ƒé¨ùÊ »Œšëmº°éFë ¯žk|­·l:—éZû‰W\í¼ÜïûÍ—lâzZïGuëï–÷¤~åõ}à…½Ÿ!]g~V¿;^Ÿwâ?]½“ß/¨ÿäÓQóç#üûŠáR]ÿ¯¾žÖ×ÇßϪ6óõçeß2?jñ¢y-Ïa3ßÝÇó=Øû“ÿ}¸é¬þ•=/0]èïO×»Vÿ«Éwšnt>­æü4>ë|™/éü]¯"ZO­ü´ëU¾Úý(Aû%Ÿ~(¿ ýR¾ƒúYQþÕïŽÏÏ;ñQ ¸Èó~á8ã!Ý¡ßO8z€éðî¿ÍÏ¿ÍbºÚ´éjÿ<¤>Nï¿=y´ñÐñ{–÷´Çš¦Ã¦7š®—úÇò\ÝÏt™öÓaЦ«GÆzþo›ä<ü~šëûŽ7V=ÂÇ?¿œéæžÁ¦›ÆùóúÜL3>_³Ÿó¢ùš^ÏQ×+V7¦óõ”!·Iëm.]Ít£ýT3ûû¿QûÍC7>jõ£ôYÞtø]ýºJ¿ÿpŒ÷³lõ†óp‘÷»ãÿWøhýƒú;ª§56÷ùã ?™.º~¹Á?©µ¾°ÎéÆCÑúÓ5O›®†úþš·ƒå¹ºÛ÷ÿìáyWJ`:\«þÍpŒûô÷Ås\«ÿi‹KMW:tÃùi|â|5_¥óϺ^R>*­‡ü$­·Í—öCþÊھߠ|fõƒüVêW­|·ýTþƒúÝŒ݉ø㱦㳷[þóÇšN“kÓÍýÝ4¯ó1yUÓõ­ÏûýáÉéMW/û÷ßã™þù_óÑæ§.±ü‡üûðeêN¦ãÕy¾‡Ïåþçþ{(ñÉ'-ÿyû«œ¯†9/;åz•eMÇOòúæv¾’ÎKÏå÷¯†e|ÍW‡Œ‡J× Ý·w^´ž¼àKÆC¥õÖ_0]´ŸjÈ–ÿ¨ý6ý¯4Ô滺V¿ÒêËšÎêg^`÷ÕïŽ×çøÀÏ«okùoTŸ–»ÊtÖüÍè/]ëúÍö½ýþ õ••ýûïIë‹Üã¼haq}ÿ[ûÏ{.bùÎêOXÀ¥Vÿâ­µùaõ÷棜õ??t¢éFçÓjÎOãko¥ù²Î¿Ìï×#¬§Q~J¥õ*_ì§Vþ²ö[)ŸIý ¿Iýj”ïZý Ê£~wüBžå™ç«xîÞ¦›¿Ç{þ»‰‡ÞƒMÇ ýû!啹ì÷‹4Í›ÎÇœßyÞßeº”GL—v3]]sºéæRÞŠ«oázýß,ßq´Xº¾fºz÷¿~¸å^ç¡:Òt:î:ÓᢥM—ýû+Íãt~¸›ß?4>õ9ÕøÈš/NúÑïóøõâ…›ÎZOzð[ã!k½aýä¼üÛ÷>ü—éZûM=ü~’éÇ þý”ðª÷«L/êgúh]㣨ßA¿§ÊëóF~ìÒÏò^ðúæùKM'Í_­ô?çCׯÿZÆùÐúò¸ÖúèëLgí¯ìÏ[Iû¯ÁòèÏÔLgõ¯ÞasÓáõ÷ÔÝLõ¿ZÕ¿¿Ré|Ð ç§ñQç5_­óºùˆZù‰Z/ùb?µò×h¿•òé‡òÔ¯ |'õ³Rþéw­ß?…zÙÍ—Þ÷Xþë~kûý`äÁ¦;>ç4]oàß7‰¿Nk:ïü±ßv}×ùø|¬ë5n5]}{é¼í0÷·_Ûtsâ:¦Ã»s˜.ã·¼çuõú䇻‡é^r>v8Ät¸ZŸ_ÿÚÝýÝ'˜ßÌqó wZÒ]d|$ÍÆÌâ÷]/M3ÂyÑzê=ç6]k½ùü±ÆCÔ~B¿>¦ûóWË{ØÅû¼ßtC¿že:ªŸõ퇺V¿;^Ÿ{=ï_É/Ïoaù¯UŸišùSöï›4º~uã–ÿJëkæ`:\àëÏs^hºÑþò­OºfÿÝ¿3ÕŸø¸^Ÿ,¤þý±Šó±³ú»—_ÔÿúÚ­Ìot>èÄùi|à|™ï.?ÿJ×ËäCë!?Ö›”/öS+Iû­”Ï ~då—~Eå»í§òŸÕïŽÏÏGzleÏÿ÷ÍI‹»ÿ푦Óõ³º·ªé8Bß¿½õ[çáÚ§-ïõOLWçŽq=ôDÓñŸA¦Ë¬[›O¯d:ÓÝë'úïë6ƒ¦1g¾Íò÷øÌò_Ÿq€óðÔd¿챤ûŸOr>6½ßxˆÒå믾ºÖx¨5_ä¿›u½æð댇¤õÄ.=—Ù|½é£çœí'ܘéFû­§ú÷+õ#Üõ™å½R¿òŸ¹V?ãqטnÔïŽ×çøÀO£6óûƒêÃ\g›fþ°Ã‹¦“®úÏiù®´¾4ËV¦3ëq’éÄþ~¼ÓtÑþ›ÓÞ1{âè¿L×ê_sÍ–ÿêõw­åüþ¡þçù{º¯óA'Îñ:_æK:®W)Ië©•Ÿ õ’¯Ä~ÈŸöK>ËöÞò[ú«_Êw™Óû•ú{õêÌÇîó™ÎW>dù÷Ìäºß±¦«·~°<§ýó߸Ц«iþò|Oï~—'<ßëyêÏóL—[ýõFzÒ(ÍYÙøf~¿ŸTS>öüŸßÍÆ7Õõ¦«{üûŽõCû™_}c<¤G7]†|ê|ÿñ€.§­î÷Æ?|—ñÁ|©×ê~?Ñõ:î×ÆCf=×ùë‘Fë«ëy‹ýtã|h¿õóÛ™®ÕÜoA÷կꢯ-ÿEý }^w®ò~7'v⣒_í½±ß/T_ÿó¢ùëOýóô¤ë翦ñ|/åë«ÿ^ÇtÒúã´‡™ŽÚ_½¶~ïæCßüÜï'Yý©bã³ú—·ðï;V§{Ë?×#•ÖC~¢Ö›•/ö“”¿¨ý’φ~(¿Qý*w{¾ƒúY+ÿAýnFwëÄGó³ÿ=JõÚ#~øâÏû-ÉtžÕŸŸÂ66]ߒͯwžÙtZÃÿþ¯™ýUËw½ÎóËÉW›N»ûçãÕpÿ~RÙ¹«ùaÂ6æçÞ²¼×¬êõkø÷ÃœÎKýí^槹g6?,]¹ž¦‹×ßõˆß/¤;~ÿµƗóõ}EÍC_¿ŸèzaÛwŒJë)›i:j½aÄ|~?9Å÷Ó1Ÿå?k¿ñ¦M'úñ™?UêWZ¡òñêgéêT«ß¯Ï;ñæÑßk­‡Fõq‡á~¿Ðüå؇L×\ÿÆŸM‡ |}ñûÖž¦«>¾¿œüûZQûÏ[Ýa~RÒ¦/úø ¼å[ç¥Rë¯6¿¨ÿõ_ûx:éüß‘ÿÿ›æãü¹ùh×£ü°^ò´òW±_ò©~߬~UÊwÛOå¿Q¿;^wtæãüÿ93?îy_Ôïõ̧;ëû÷mÓw}]¯{³oÆÍçãOa:wûŸçwä>žÿ™ýó€0ëêî¯9ÂüØLgºÞn éºÛ‹Ö¯êã>îo=ÊtÜÃýî»™k,a:¹¨?o!Óù‹ÇŒ‡J:Ü»…ß?4>îûªñP4_5ioÓ‘ë=ò³å?i=ùó Mg­7¿³¶ó¢ýä?¿²¼í·:ýÏ¿úOæZý +ûý%©ŸùýµÝW¿;^Ÿ›æõ ~üy]Ï;õ?í¾ðýUO5¿ÖþëÛƘŽêO³ð}î«áÒÜWË3ï™.ê>ìÓÎt~Yãk/óqþíõ”¨õŸ õå«Ñ~’ò´ßZù¬Ô¨üÒ¯D¾ÕϤüÓïŽÏÏ=¿zý‘—ÖõOYÞËöþ{;qð9¦Ãáã̯öÜÉù˜ä[º,aºyþ(óËRßY^›Ï¶1]ŸçÏ[ÍýK¹þþrÏóg?[¾Ë×Çš½ü÷_ª9ö2] <×ü&ûûÃõ.;™N»¯ãã¿YÄëîíó-þ”ñP¤Ã6ýýþ¡ñÍjYó•ÑÃLs½z宦Ã7¾žæì ΋֛V®]k?yÿùM‡¥}¿ÕÀ7=ßÓx?¢7˜ŽôkÀ)¦kõ³¹ù`Ó•úÝñúÜëuøáѵ,ïIõùÒ#LWš?_}“óÁõÿ~Ïù`}oÏayͬÿ0ÞÊìoö}=Ïìîÿ˜®Æxòw׫q8ª¿õµO˜_Ôÿðñó^¯óAs~Œç|™óo¯§|­‡ü$Ö«|%í')Aû­•Ï@?óüÒ¯¬|7êg£ü—ìý.'Z^Ûÿ_=q»éxÔ³–÷êô±î?y¡çÿÚ‹L7Ïù¿ç’öô¿÷ ;¯ìþ|µïLÇ ÖóñóM¶üÆýçsÜžÿŸ[¾ãÙç›núÞo:¬9Ôt9Nß'é¶éúìíÜ?yÓ©ÿ¦ÓýLç]žu¤«Ow÷û‡Æ—õ}Í× :ÇyÐõš+V2ÍzÒ*¯[þ+­7žôÓYûɯmà|h¿acÿ{»¨~äû&[Þ³ú•¿›à<¨Ÿihc:©ß¯Ï;ñÑúg­îyW}Yû ך?®Ö˜®tý|ãËîk}eÒ?¦k­?~±œå·Ñþrÿm<ÿÚsä¡žwõ§<=Âó>“÷¯žr…é¨þænññê½óxÓÎÍù1>ïç5矹žò‘´òÃzÉWÅ~”¿Ì~•Oú‘”ßJý +ÊwV?³òŸÔïØK¿7¥ÿ_•=GY~óM-ßõƒg»^bŒç}òñ¦«50¾ñ÷£â8½Þ쵕çý9Í//oº\æ¿ß›ç÷Ï7š~?IǼcùn–óïoUƒüýª¼÷9ž÷‘'šðÿŸÇÜ×y¸á`óÃ}ÝLW« öñçM4ÐÕðA¦oOcºÖ|©—¿ŸU¸Þl[Yë©_ñ¿§ÊZoxífçárßO0µß°¸¿ßU«©ÿ î«_qÄÏÿ’êçF¯š¦ß¯Ï;ñQ˯vêeùnëßhºÑüÍ3£LWº~êï¯×³Ö—ýÖ}Ö¿Ÿ~oVû‹cü~f÷ýÇÉþý­Fý WayOê_:Çï/µúwé|¨ÿù¹KMW:ŸFºÖùµãu¾Ìuþíõ”Jë!?•ÖK¾‚öCþØ/ù¤•òK¿ÈwP?³òO¿;>?÷<‹ð›òÿÁ‹–ïüÍ‘æ7©ñ¼Ï4Ðt¾Ö¿:¥mM§.þýÞæ&}·\Ôùùjó«%~³üÖOþèy_Ì?O,êû#O?èùî?›ÏºÎtsÓPÿüHÓñÇ>ÎäÓL§E4]M^ÿÔ‹–t\à0çEã›q]MGæ þ÷·\/ïߟ¨´žjÈüÆK­õæ¥_ò¼k?͸‘®µßðÏž¦õ£þz5ÓEýj*ÿ÷G²úYÍ!~ÔïŽ×çøˆòsµªå;«>ßË4óW»ûïWsýúo}¿WëkîþÐÆ­?¿7ƒå·ÖþRñÏ+í¿¬¹‰ûêOuÔn¦³ú—{ì¾ú›{cº¨ÿaýᦛEü|еÎñœo£ùŠÎŸë…Ç<™õ(?¬7)_ì‡ü±_òé‡òK¿å›~–_=ÿô»ãósË/ÏWáBÿ÷Ò¼¯Z¾C÷Ý<ÿïû÷yëuú™Žsù惡×6wêoã›w'ÿ{ܸ±ß/êýûGåHÿ¶¼ù¥å¹ž%[¾ëý^v=úRÓÍÝÎKõy`÷[ÌËúïí6ß_e:œ4¿O[1ÿzÅòŽ·cº?| ÓAó…I/Xþ¹^ür¸é¤õ„×0Þòõ¦cü~’´ŸfÁ‡,ÿµö[Þ=ËyP?ªÝW¿ªû¶0ÔÏð¶ÿ{ úÝñývóÛó_¹¢ÿÿ_õõâþ}Þ¨ùÓ7úýÑ÷üúÕMãœ'­/ÝôŠé†õïìßת´¿²ô¼žwöÙʦ+õ'né¼Tê_~g¯þÆÙkÓEýwôzºÖù1>é|™/éü¹^›­'¥üh½m¾´òÇ~ÉgP?È/ý*Kz¾é'ùêwÇçç–gΣZiKÓe‹É–÷¸ËFž÷uou^YÍýãÿã<\³¤×ó×#çg:í³®ùyô÷ž÷•1–xÍõÈ<ÏÛ7]ºøóJ¸ëÏûþ÷»ñAîÿ¸ó±ûú¦«ï7>™×t|Çß˽'ûýA:ö9ŵÆ×Ûõt>Nðùòè]¯p™iÖSØÙtÖzãÄ…\³ŸS?ñ¼³ßî3]©eÉ‹=ï'x¿Ò6Ç™®ÕÏ2ö@÷·T¿ rÍó.þ=ËY¾©oßÞtè®ùO9ÖtÑõK=Ò°¾+7¿ÖúãËyýƒ¾¿xp°<'í?üíÏ_aŒ÷§®üïwý;e]¯þvü»I·úŸ»ûûcÎ]ëüÏùÍÇùs½¬|°òÃz‹òÅ~å¯Ö~“òI?‚òÔ/òè§òÔïŽÏÏ=ß:êéUMÇáoyžÏ^Ît5æ.ç¡ù—éúós]÷rb—ƒLçÓõ|²•×ûç{‚ßOª—÷<÷Çüê²ë\_õ§å½™x²ézæ/L‡¯÷4_Çù8-×ë9?aËyL—Á“ÌϾeùGלm:k|^r#ך¯ô»ó¡ë5ÏÞc:j=y£]k½Ÿ§˜wû~Ò·s˜n´ß|©óB?š‡Ÿ°¼'õ«Lg:ªŸùð+M×ô{ôèN|à7iiÏó§^Ÿö5™þÃM]¿ùûBÓÖ/˜`ºãó +_ÿV~?)Ú_s×W>ŸößÔÓZÞ3ýùy>Ï¿úW-ßÝùPãcÎO8Èû.íi~¥óAGã+/óqþI×#¬‡ü°Þ¤|í‡ü±ßFùlû¡ü&õ+)ßô“ü'õ»ãósË;÷¸·¿^ÈÞµü–¬ïÓþêß7‰¯úóRØéRó›'üýÙ´ÓѦóËy~àùïãÏÕ:øøáwyž§÷ïo¥F™nÖíj~œâßϽüïKÊt;»¿²ÿ{ ñ‰Þ¦ã¾zÞ¹mnÓéÇ)ÆG¹æ]Ë?º6Ê4ã«Ÿ·3Ýh¾º—ÿ”ëå5_±üd­§ £=O3øzóáMGí'í¾¦×~óP˜~¤]õýGõ«>ñ}Ï¿úÙ¬÷²iú'NìÄ~ÜjIËo[?“ߤÿæÁžo®Óé¦Y_üÏXÓEëÏOdÏþ~÷ïoí?>>ÕëÕŸf¢ÿ}ITÿâ˳:êo¾ÜŸÏµÞÿzÖnîë|Ðœã9_æãü¹ù`=ò´ÞJùj÷£ü±_òY«m~éùV?+åŸ~w|~Þ™?ô{!_|àùþéË_Þ1›.Óíy|ìjÏûŽÅý[N5öÏ÷òiþþV¾âóëG·5?®ì¯¿Ó#þ~WXq„ùámÏ_ùç ÓÕ j¾mL§Ógóú_W1ϘÎt˜g.Óñ$?¹¼õó ælL3¾~foÓÌW…¥}¼®nœêû¸ÿîHÏó1[ûüGgº¶žéÔmŸÿôU\÷ô÷«bénºZÑÿ^0ÞæßOÃæðëϾùe®ìüŠtºÁÿžñyÌáæך/LZÇtÐõâ3ûùk=q³·-¿Që øï1fí§î}–ùáBßoêyë.Þp^Ï¿úoÝÐt£~Æ×õý/õ»ãõ¹×ëy·Æ/‹Xþ¨}ýó+æ//íàyåúÿb:±¾ƒý~Rkýñ>ÿ÷Ôkí/Ÿv§ÏÏþÏxÌ4ý)G¿dº¨Íbï˜nÔßf;ÿ~}˜Ûû¾ÿÄ|Îu~Œot¾Ióqþ\¯V>’ÖS”ÖK¾ØOVþ‚öÛ(Ÿ~(¿ô‹|ÓÏHþÕïŽÏÏ=:´Êóž·¦XÞòO™®çžäù<ðaÓÍeÜæÏKÕNW¸¾}¬ÏwÕé¦ÃV»~áHÓõYþú"÷/l~ž×ßÿªzùóT¹c3¿ÅæWk9?U½´uuŸÿÝÙL§1½L—>S,ßt³Á]¦³ÆWŸd:j¾<ÚŸ·ÂºÞiÝÍ/¬çs}R´Þðï×=¿ì§™àù×~Ó\þ<éÇr§8êW³É‘¦ý¼ú ÓEýîx¿Ä4Ï»•üpK7Ï#õ_÷ô¼jþ¸ßVžG]?ß´éZë+µ¥bý=Ï6?jÕ$ç%iÿÕ—þþW¡?ÛÜïãÕ¿ü”óC«Ÿ5?lîý¯Nt­ó‰ÒQçÇøZçË|œÐõ²ò´ò´Þ6_ÚOVþØoV>éG¥üÒ¯FùNêg­üÓïŽç]Ëç‘žõßGg~îùy«ùñÐWMç+®7]Íô°ë™®0]ßr“çó·óÝ¿e”éæjç!îàïß„µ0?}5ÄüjúÚt¿¿Ï××?ÿËoïa:Ök˜Fîèã/òïëÆ߶1â¬^¿L?ÓåÄÏ=ÿÒÍþ}Þvü˜Ï|iÐ`Ó\¯ùi¯×zÂÙ ›f½¿Wiùe?q¶÷]k¿éë'M'õ£yb¼ûêWx÷:×êg8ør×êwÇçç¦9üXO›Ö«|±Ÿ¢ü±ß¬|&õƒüÒ¯ |7ê'ùoÔïŽÏÏ=º4ûêó‡G¾ò|>u‘û“üý¬ú¥sM磞6?>Ítîñ|nìïëõ¿j~zÛyIŸímºº~„ù©ßö^¿Í‰¦ëAšÎÓ9?a˜¿Þ(_l~õŒ¾oµ¨¿¾ cg¶ña óËÝ_yþ¥›CŸ2]4¾Ì}µkÍ{`šëåýv3Ýh=eåuMGÖ;gešýÄ£g4]k¿õÄï-ßYý¨÷úŸkõ+9Ùt¥~–5_t_ýîøÿ•iøÀqÏ›êKO?‹ùãYkšÏõë¶0ÍúòæL7¬)ñ¢ý•]‡š_´ÿúŽ“|>õ'þáüпj¾‘ægõ·úÐ_ß„{Ôÿ¾£ÍoÏGšókÇë|ƒæãü¹^£|D­‡üd­7’/ö£ü5Ú/ùŒôCù¥_Qù¦ŸIù§ßŸŸ{¾àã/ÿ>GøéÏïïþú ,_<Ó ³ññ×\/˜é²ãc®Ïlº~ÜŸ¿ÊÖ{˜ÎõæW—ø÷§ò^þ<Fmb~˜z¡×_Ýt³òÙšo¯ßø4¯ÿsÓõ&'›N3Ïäãcòñ_}ãù–Î3¾äùÕøøñ¦3ó… }¼®^jšõä—w÷ñZoÜgS×ÚOüxUÓIû­o^Ì4ý¨~ŸÛtÛ¯Yf2Vð~æéüû.•úÝÁ…û:ü0ë\ž_ÕW¯/fšù󢫘æúÕÍë™n×·®?±þxÕÎ泿ØìcºÝÿ<™®ÔŸúå#5Ÿ÷/>tŒ×«¿Íƒ'xýTïýÈpÓœºÒù1¾œãçË|!ùùs½6¬Gùa½ä‹ýå/i¿Eù¤Eù¥_Iùêg£ü—Y¼ßŸŸ[¾øÿU¾d é´üž·•÷5Ϙây\m/×ýÞvÿÁ]MW·¼àú ¿¤õýø±[š>õ÷‡ó¦~HÝî´ñõûÞt¦?Ÿ¥Ñþú;ír­ùÍu‹Y}sù•¦«UõyÇ—™‡Ì`~œ4Úu÷<Òù*}¢ñÍ=Ù|æ+o4ÍõâÆ#]k=ÍQ~a½áî›Ï~ªmøxí7žÑ×tÛ‹64]Ô¯úšµLÓÏæ¥Þ^¯~w¼>7Íy´þë³YÞ¨ÃüõHÑüqüRæsý²C׬oU}?žõwó÷‡ÛýMÙÚdzÿ!þ|Ööç†Ýͧõ¾{›.êo5j?ÓAýÏ=¹Öù 9¿ ñYçË|íùëzm>´ž6?Zo"_ÚO!ÚoQ>éGR~+õ«(ßô³Í?ý4ÈóËÿ¯zøóÙëgÏ㾞ï4ÅŸ·ªýýý¤ú«ôÝØóÞ±ñeqÿ|»yç¯ÿÓ_?ăŸ7Ôï¾ú„é¼ôrVŸ—yÄÇßU™®O~ÀtzÐïé'~ ûùûUé<¿?¥W¦óõ¸ËƇÝ~ö|I—5üýÆ—3ü~Â|Íè‡m<׫Çßjºh=i+MW¬wÆóM³Ÿê!ÿ|>k¿qÐ1>ŸúѬ¢÷ËÔ¯¼ÖæÓÏt¹¿þ¡ß¯Ï͇üª™ÙòÖÖwóç­¬ù›Mõþ–®ŸÿénãY_Ý}%¯×úóÈÞ¦Ù_YqÓì?¾MÓŸæ„MM‡êß,þüÖö÷0¿?µý¿¾¯ÏÏùHWœŸÆ·ç«ù*?×#•ÖC~Xo¥|±òµ_òÙÐå—~Uä›~*ÿm¿':œGy¾§çýâß,oõ%=<¯›øý$Ñ륧š_Þ[Ñü´ã§žÏƒ”÷O?4·_Êýôyã5žÿ|ö›æÇCýûéñÉ×|üÄùüúã^6]¿2§ë­ýû’áR½Þ¸ÛßO kLk~3e¢#³|¡Ë‹zÖø¸[1?j¾zÐk®u½fñg]k=ñç‡õ¦w›Ÿ´ŸjYç)k¿Õ&×»¯~¤çÓEýª^¾Üt­~ÆýǘŽêwÇó®iÎ?ÿ{Ëõ̓~?aþê­®îsý›t­õÅõ¼²þÙüóFö\Æ|öŸ×^ÁÇ«?¹ÿʦé_¾sUÓm·ò÷ÓèÝ­—ùœO«9?ç|™/ëüÛë)¬§(?¬·Í—ö”?öÛæSý ¿ô‹|ÓOòO¿;>?·|qe _¼yîOÏëó z>¯/“ôÿó ýþßü|³óîñïC•¾õ|ßÔÕýc¾v½žWoæ÷£æÞÙÍoöùÂý)³˜®&fºú|F×7ˆ¿‰~¿Hoëyï².æÇ#]‡gÿô¼¡÷÷û 㛕¾5¿Ò|±×®u½|þǦYOµ‡ÞÅzã­o›ŸµŸpÑdÓì·ZâU÷Õ8Pÿ¿U¿šý_0?ªŸUïI¦Û~OœhšóÀ¯W›ÖòF}ÞÃyiç?Èï/\?îèü°¾j¶9=ßZ¯þ”åðë«eç/Ðߥüyþ7g»N:tàü4žóe¾Zçß^Où`=µòÃzkå‹ý?öK>éGM~Õ¯ü¼ç›~’ÿ¶ß£Σ㿞·^½ß C ;ÞWùbƒÿäs"äwÓ  è… UVIndexiÌt  Û… x4ÝC…iºá¶mÛ¶mÛ¶mÛ¶mÛ¶m[3m»ûÖS÷DT¼ùå>ÿê 0À  ˜ÍœÍT(w–:ã°nÈ8¼vcÆá²›2˜Ýœqø ì–ŒÃg·f>$»-ãð¡Ùí‡ËîÈ8|xvgÆá#²»2™Ýqø¨ìžŒÃGg÷f>&»/ãð±Ùý‡ËÈ8¬ƒ³Ê'ä>”qøÄìáŒÃ'ed>9{4ãð)Ùc‡OÍÏ8¼IvZƹ§gOfO”ÏÈ}ªŸ™=]‡ÏÊž©ÃggÏÖás²çêð¹Ùóuø¼ì…:|~öb¾ {)ãð…Ùˇ/Ê^É8|qöjÆáK²×2_š½žqø²ìŒÃ—gofÖÁ[‡uðvÆa¼“qXïfÖÁ{‡uð~Æa|qXf”uðQÆá³3ß”}’qøæìӌ÷dŸe¾5û<ãðmÙ‡uðŸŒÃwdÿÍ8|göeÆỲ¯2ß}qøžì›ŒÃ÷fßf¾/û.ãðýÙ÷‡È~È8ü`öcÆᇲŸ2?œýœqø‘ì—ŒÃf¿f~,û-ãðãÙï‡OËžÈ8÷ÉìÏìòS¹Õ᧳¿ëð3Ù?uøÙìß:ü\棆ÃÚ0o¿ æð‹ÙÀa¿” æðËÙ a¿’ æð«Ùàa¿– æðëÙa¿‘ æð›ÙÐaë`˜0‡u0l˜Ã:.Ìa æ°FsøýlÄ0‡?ÈF +søÃlä0‡u0J˜Ã:5ÌaŒæ°Fsø³lŒ0‡?ÏÆ sXc…9¬ƒ±ÃÖÁ8aë`Ü0‡u0^˜Ã:?ÌaLæ°& sX…9¬ƒ‰ÃÖÁ$aë`Ò0‡u0Y˜Ã:˜<ÌaLæ°¦ sXS…9¬ƒ©ÃÜÿ7¡ÎÕÆ´ái2¬éÂÖÆôakc†0‡u0c˜ÃäΔqX3gÖÁ,‡u0kÆaÌ–qX³gÖÁ‡ÏæÌ8¬ƒ¹2ë`îŒÃ:˜'ã°æÍ8¬ƒù2ë`þŒÃ:X ã°Ì8¬ƒ…2ë`áŒÃ:X$ã°Í8¬ƒÅ2ë`ñŒÃ:X"ã°–Ì8¬ƒ¥2ë`éŒÃ:X&ã°–Í8¬ƒå2ë`ùŒÃ:X!ã°VÌ8&»¯kãþ:¬ê°¬ÃëeZà\m<œ=TÖÆ#uXÖam/{¡kãÅ:¬—êð…ÙËuX¯Ôam¼Z‡µñZÖÆëuXoÔam¼Y‡µñVÖÆÛuXïÔam¼[‡µñ^ÖÆûuXÔam|X‡µñQÖÆÇuXŸÔam|Z‡µñYÖÆçuX_Ôamü§kã¿uX_Öam|U‡µñuÖÆ7uXßÖáû²ïê°6¾¯ÃÚø¡ëàÇ:|B¦ÎÕÆÏÙOemüR‡µñkÖÆouX¿×amüQ‡µñgÖÆ_uX×amüS‡µñoÖÆ ýÏam ˜7‡_È +sX‡9¬AÂ~94Ìam æ°6sXC„9¬!ÃÖÆPakcè0‡µ1L˜ÃÚ6Ìam æ°6†sX#„9¬ÃÖÆHakcä0‡µ1J˜ÃÚ5ÌamŒæ°6FsXc„9¬1ÃÖÆXakcì0‡µ1N˜ÃÚ7ÌamŒæ°6ÆsX„9¬ ÃÖÆDakcâ0‡µ1I˜Ã:˜4ÌýZà\mLž,ÃÚ˜"ÌamLæ°6¦ +sXS‡9¬iÂÖÆ´akcº0‡µ1}˜ÃÚ˜!ÌamÌæ°fÊ8¬ƒ™3ë`–ŒÃ:˜5ã°fË8¬ƒÙ3ë`ŽŒÃ:˜3ã°æÊ8¬ƒ¹3ë`žŒÃ:˜7ã°æË8¬ƒù3ë`ŒÃ:X0ã°Ê8¬ƒ…3ë`‘ŒÃ:X4ã°Ë8¬ƒÅ3ë`‰ŒÃ:X2ã°–Ê8¬ƒ¥3ë`™ŒÃ:X6ã°–Ë8¬ƒå3ë`…ŒÃ:X1ãðÙJ‡'ÌVÎ8;{¶kã¹:¬çë°6^¨ÃÚx±kã¥:¬—ë°6^©ÃÚxµkãµ:¬×ë°6Þ¨ÃÚx³kã­:¬·ë°6Þ©ÃÚx·kã½:¬÷ë°6>¨ÃÚø°kã£:¬ë°6>©ÃÚø´kã³:¬Ïë°6¾¨ÃÚøO¾#ûoÖÆ—uX_Õa|]‡Ê´À¹Úø6û¦¬ïê°6¾¯ÃÚø¡kãÇ:¬Ÿê°6~®ÃÚø¥kã×:¬ßê°6~¯ÃÚø£kãÏ:üTöWÖÆßuXÿÔág³ë°6økcÀ¼9¬ÂÖÆÀakc0‡µ1h˜ÃÚ,Ìam æ°6†sXC†9¬¡ÂÖÆÐakc˜0‡µ1l˜ÃÚ.Ìam æ°6FsX#†9¬‘ÂÖÆÈakc”0‡µ1j˜ÃÚ-ÌamŒæ°6ÆsXc†9¬±ÂÖÆØakcœ0‡µ1n˜ÃÚ/ÌaŒæþ¿ -p®6& OamLæ°6&sX“„9¬IÃÖÆdakcò0‡µ1E˜ÃÚ˜2ÌamLæ°6¦sXÓ„9¬iÃÖÆtakcú0‡µ1C˜ÃÚ˜1ÌaÌ”qX3gÖÁ,‡u0kÆaÌ–qX³gÖÁ‡u0gÆaÌ•qXsgÖÁ<‡u0oÆaÌ—qXógÖÁ‡u°`Æa,”qX gÖÁ"‡u°hÆa,–qX‹gÖÁ‡u°dÆa,•qXKgÖÁ2‡u°lÆa,—qXËgÖÁ +‡u°bÆýÔ¹f+g+•'Ê]¥Oœ­Z‡'ÉV«Ã“f«×áɲ5êðäÙšuxŠl­:uXûÖaìW‡u°ÖÁuXÖaT‡µqpž ÓçjãÐì²6«ÃÚ8¼kãˆ:¬#ë°6ŽªÃÚ8ºkã˜:¬cë°6Ž«ÃÚ8¾kã„:¬ëðÙIuX'×amœR‡7ÎN­ÃÚ8­kãô:¬3ê°6άÃÚ8«kãì:¬sê°6έÃÚ8¯kãü:¬ ê°6.¬ÃÚ¸¨kãâ:¬Kê°6.­ÃÚ¸¬kãò:¬+ê°6®¬ÃÚ¸ªkãê:¬kê°6®­ÃÚ¸®kãú:¬ê°6n¬Ãd7ÕamÜ\‡µqKÖÁ­ux¥L œ«Û³ÛÊÚ¸£kãÎ:¬»ê°6î®ÃÚ¸§kãÞ:¬ûê°6î¯ÃÚx kãÁ:¬‡ê°6®Ã'eÔam5{¼kã‰:¬'ë°6žªÃÚxºkã™:¬gë°6ž«ÃÚx¾kã…:¬ë°6^ªÃÚx¹kã•:¬Wë°6^«ÃÚx½kã:¬7ë°6ÞªÃÚx»kã:¬wë°6Þ«ÃÚx¿kãƒ:¬ë°6>ªÃÚø¸ß”}R‡µñiÖÆguXŸ×áC2-p®6þ“}QÖÆë°6¾¬ÃÚøªkãë:¬oê°6¾­ÃÚø®kãû:¬ê°6~¬ÃÚø©kãç:üHöKÖƯuX¿Õádzßë°6þ¨ÃÚø³kã¯:¬¿ë°6þ©ÃÚø·kc€Aþç°6Ì›ÃÚ(Ìam æ°6 sXƒ†9¬ÁÂÖÆàakcˆ0‡µ1d˜ÃÚ*Ìam æ°6† sXÆ9¬áÂÖÆðakc„0‡µ1b˜ÃÚ)ÌamŒæ°6F sX£†9¬ÑÂÖÆèakcŒ0‡u0f˜ûÿ&´À¹Ú;uXûÖá±2-p®6öÏö+kã€:¬ë°6ªÃÚ8¸kã:¬Cë°6«ÃÚ8¼kãˆ:¬#ë°6ŽªÃÚ8º¯•S‡µqlÖÆquxÝìø:¬ê°6N¬Ãd'Õamœ\‡µqJÖÆ©uX§Õamœ^‡µqFÖÆ™uXgÕamœ]‡µqNÖƹuXçÕamœ_‡µqAÖÆ…uXÕam\\‡µqIÖÆ¥uX—Õam\^‡µqEÖÆ•uXWÕam\]‡÷Ê®©ÃÚ¸¶kãº:¬ƒëëð2™8W7f7”µqSÖÆÍuX·ÔamÜZ‡µq[ÖÆíuXwÔamÜY‡µqWÖÆÝuX÷ÔamÜ[‡Éî«ÃÚ¸¿kã:||ö`ÖÆCuX×am¬ÃûeZà\m|œ}TÖÆ'uXŸÖam|V‡µñyÖÆuXÿ©ÃÚøoÖÆ—uX_Õam|]‡µñMÖÆ·uø¾ì»:¬ïë°6~¨Ãf?ÖamüT‡µñsÖÆ/uX¿ÖamüV‡µñ{ÖÆuXÖamüU‡µñwÖÆ?uXÿÖam 0èÿÖÆ€ysX…9¬ÃÖÆ akcÐ0‡µ1X˜ÃÚ<Ìam æ°6† sXC…9¬¡ÃÖÆ0akcØ0‡µ1\˜ÃÚ>Ìá÷²ÂÖƈakc¤0‡u0r˜ûÿ&´À¹Ú5ÌamÌæ°6f sX3eÖÁ̇u0KÆaÌšqX³eÖÁì‡u0GÆaÌ™qXseÖÁ܇u0OÆaÌ›qXóeÖÁü‡u°@Æa,˜qX eÖÁ‡u°HÆa,šqÿß„8W‹g‹•u°DÖÁ’uXKÕa,]‡u°LÖÁ²uXËÕa,_‡u°BÖÁŠux‚l¥:¬ÃÚø¨kãã:¬Oê°6>­ÃÚø¬kãó:¬/ê°6þS‡ïÈþ[‡µñeÖÆWuøîìë:¬oê°6¾­ÃÚø®kãû:ü@öCÖÆuX?Õamü\‡µñKÖƯuX¿Õamü^‡µñGÖÆŸuXÕamü]‡µñOÖÆ¿uX ö?‡µ1`ÞÖÆ@akcà0‡µ1H˜ÃÚ4Ìam æ°6sXC„9¬!Ã~#*Ìam æ°6† sXÆ9¬ -p®6†—amŒæ°6F sX#…9¬‘ÃÖÆ(akcÔ0‡µ1Z˜ÃÚ=ÌamŒæ°6Æ sXc…9¬±ÃÖÆ8akcÜ0‡µ1^˜ÃÚ?ÌamLæ°6& sX…9¬‰ÃÖÆ$akcÒ0‡µ1Y˜ÃÚ˜<ÌamLæ°6¦ sXS…9¬©ÃÖÆ4akcÚ0‡µ1]˜ÃÚ˜>ÌamÌæ°6f sX3eÖÁ̇u0KÆaÌšqX³eÖÁì‡u0GÆaÌ™qXseÖÁ܇u0OÆaÌ›qXóeÖÁü÷ÿMhsu°`¶@Y Õa,\‡u°HÖÁ¢uX‹Õa,^‡u°DÖÁ’uXKÕa,]‡u°LÖÁ²uXËÕa,_‡u°BÖÁŠuX+Õa¬\‡u°JÖÁªuX«Õa¬^‡u°FÖÁšuXkÕa¬]‡u°NÖÁºuXëÕa¬_‡u°AÖÁ†uXÕal\‡u°IÖÁ¦uX›Õal^‡u°EÖÁ–uX[Õal]‡u°MÖÁ¶uXÛÕal_‡u°CÖÁŽux¸L œ«³ÊÚØ¥kc×:¬Ýê°6v¯ÃÚØ£kcÏ:¬½ê°6ö®ÃÚاkcß:¬ýê°6ö¯ÃËeÔamX‡µqP^1;¸kã:¬Cë°6«ÃÚ8¼kãˆ:¬#ë°6ŽªÃÚ8ºkã˜:¬cë°6Ž«ÃÚ8¾kã„:¬ë°6NªÃÚ8¹kã”:¬Së°6N«ÃÚ8½kãŒ:¬3ë°6ΪÃÚ8»kãœ:¬së°6ΫÃÚ8¿o—]P‡µqaÖÆEuX×á2-p®6.Í.)kã²:¬Ëë°6®¨ÃÚ¸²kãª:¬«ë°6®©ÃÚ¸¶kãº:¬ëë°6n¨ÃÚ¸±ÝT‡µqsÖÆ-uøàìÖ:¬Ûê°6n¯ÃÚ¸£kãÎ:¬»ê°6î®ÃÚ¸§kãÞ:¬ûê°6î¯ÃÚx kãÁ:¬‡ê°6®ÃÚx¤kãÑ:¬Çê°6¯ÃÚx¢kãÉ:¬§ê°6ž®ÃÚx¦kãÙ:¬çê°6ž¯ÃÚx¡kãÅ:|AöRÖÆËuX¯Ôa¼Z‡wÊ´À¹Úx={­¬7ê°6Þ¬ÃÚx«kãí:¬wê°6Þ­ÃÚx¯kãý:¬ê°6>¬ÃÚø¨kãã:|SöIÖƧuXŸÕá[³Ïë°6¾¨ÃÚøOÖÆë°6¾¬ÃÚøªkãë:¬oê°6¾­ÃÚø®kãû:ü@öCÖÆuX?Õamü\‡µñKÖƯuX¿Õamü^‡µñGÖÆŸuXÕamü]‡µñOÖÆ¿uX þ?‡µ1`ÞÖÆ@akcà0‡_Ê sXƒ†9¬ÁÂÖÁàakB œ«!ÃCdXC…9¬¡ÃÖÆ0akcØ0‡µ1\˜ÃÚ>ÌamŒæ°6F sX#…9¬‘ÃÖÆ(akcÔ0‡µ1Z˜ÃÚ=ÌamŒæ°6Æ sXc…9¬±ÃÖÆ8akcÜ0‡µ1^˜ÃÚ?ÌamLæ°6& sX…9¬‰ÃÖÆ$akcÒ0‡µ1Y˜ÃÚ˜<ÌamLæ°6¦ sXS…9¬©ÃÖÆ4akcÚ0‡µ1]˜ÃÚ˜>ÌamÌæ°6f sx€Ü™2ë`æŒÃ:˜%ã°fÍ8¬ƒÙ2ë`öŒÃ:˜#ã°æ̸ÿoB œ«ƒ¹³¹Ê:˜§ë`Þ:¬ƒùê°æ¯Ã:X ë`Á:¬ƒ…ê°®Ã:X¤ë`Ñ:¬ƒÅê°¯Ã:X¢ë`É:¬ƒ¥ê°–®Ã:X¦ë`Ù:¬ƒåê°–¯Ã:X¡ë`Å:¬ƒ•ê°V®Ã:X¥ë`Õ:¬ƒÕê°V¯Ã:X£ë`Í:¬ƒµê°Ö®Ã:X§ë`Ý:¬ƒõê°Ö¯Ã:Ø ë`Ã:¬ƒê°6®Ã:ؤë`Ó:¬ƒÍê°6¯Ã:Ø¢ë`Ë:¬ƒ­ê°¶®ÃCdZà\ml›mSÖÆvuXÛ×amìP‡µ±cÖÆNuX;×amìR‡µ±kÖÆnuX»×amìQ‡µ±g^"Û«kcï:¬}êðÒÙ¾uXûÕamì_‡µq@ÖÆuXÕam\‡µqHÖÆ¡uX‡Õam^‡µqDÖÆ‘uXGÕam]‡µqLÖƱuXÇÕam_‡µqBÖƉuX'Õamœ\‡µqJÖÆ©uX§Õamœ^‡µqFÖÆ™ux‹ì¬:¬³ë°6ΩÃ:8·Ï•isµq~v^YÔam\X‡µqQÖÆÅuX—Ôam\Z‡µqYÖÆåuXWÔam\Y‡µqUÖÆÕux¯ìš:¬kë°6®«Ãûf××amÜP‡µqcÖÆMuX7×amÜR‡µqkÖÆmuX·×amÜQ‡µqgÖÆ]uXw×amÜS‡µqoÖÆ}uX÷×amuXûÖaìW‡u°ÖÁuXÖaT‡uppÖÁ!uX‡ÖaV‡upxÖÁuXGÖaU‡uptÖÁ1uXÇÖaW‡up|ÖÁ uX'Öáé2-p®6NÎN*kã”:¬Së°6N«ÃÚ8½kãŒ:¬3ë°6ΪÃÚ8»kãœ:¬së°6ΫÃÚ8¿o—]P‡µqaÖÆEuxÇìâ:¬Kê°6.­ÃÚ¸¬kãò:¬+ê°6®¬ÃÚ¸ªkãê:¬kê°6®­ÃÚ¸®kãú:¬ê°6n¬ÃÚ¸©kãæ:¬[ê°6n­ÃÚ¸­kãö:¬;ê°6î¬ÃÚ¸«kãî:¬{ê°6î­ÃÚ¸¯kãþ:|\ö@ÖƃuXÕa<\‡7È´À=’=šý–ýZ~,÷÷:üxöG~"û³?™ýU‡ŸÊþ®ÃOgÿÔág²ëð³Ù CýÏáç²óæðóÙ@a¿ æð‹Ù a¿” æðËÙ`a¿’ æð«Ùa¿– æðëÙPa¿‘ æð›Ù0a¿• æðÛÙpa¿“ æð»Ùa¿—æðûÙHaæð‡Ù(a”æðÇÙha’æð§Ùa–æðçÙXa‘æð²qÂþo6n˜Ã_fã…9üU6~˜Ã_g„9üM6a˜Ãßf…9ü]6q˜Ãßg“„9üC6i˜Ã?f“…9üS6y˜Ã?gS„9üK6e˜Ó„6¦O•amLæ°6¦ sXÓ…9¬éÃÖÆ akcÆ0‡µ1S˜Ã:˜9ã°fÉ8¬ƒY3ë`¶ŒÃ:˜=ã°æÈ8¬ƒ93ë`®ŒÃ:˜;ã°æÉ8¬ƒy3ë`¾ŒÃ:˜?ã°È8¬ƒ3ë`¡ŒÃ:X8ã°É8¬ƒE3ë`±ŒÃ:X<ã°–È8¬ƒ%3ë`©ŒÃ:X:ã°–É8¬ƒe3ë`¹ŒÃ:X>ã°VÈ8¬ƒ3ë`¥ŒÃd+gž0[%ãðDÙª‡'ÎVË8ªÃÚø¸kã“:¬Oë°6>«ÃÚø¼kã‹:¬ÿÔamü·kãË:¬¯ê°6¾®ÃÚø¦kãÛ:¬ïê°6¾¯ÃÚø¡kãÇ:¬Ÿê°6~®Ó„6~Í~)kã·:¬ßë°6þ¨ÃÚø³kã¯:¬¿ë°6þ©ÃÚø·kc€¡ÿç°6Ì›ÃÚ(Ìam æ°6 sXƒ†9¬ÁÂÖÆàakcˆ0‡µ1d˜ÃÚ*Ìam æ°6† sXÆ9¬áÂÖÆðakc„0‡µ1b˜ÃÚ)ÌamŒæ°6F sX£†9¬ÑÂÖÆèakcŒ0‡µ1f˜ÃÚ+ÌamŒæ°6Æ sXã†9¬ñÂÖÆøakc‚0‡µ1a˜ÃÚ˜(ÌamLæ°6& sX“†9¬ÉÂÖÆäakcŠ0§ mLž2ÃÚ˜:ÌamLæ°6¦ sXÓ…9¬éÃÖÆ akcÆ0‡µ1S˜Ã:˜9ã°fÉ8¬ƒY3ë`¶ŒÃ:˜=ã°æÈ8¬ƒ93ë`®ŒÃ:˜;ã°æÉ8¬ƒy3ë`¾ŒÃ:˜?ã°È8¬ƒ3ë`¡ŒÃ:X8ã°É8¬ƒE3ë`±ŒÃ:X<ã°–È8¬ƒ%3ë`©ŒÃ:X:ã°–É8¬ƒe3ë`¹ŒÃ:X>ã°VÈ8¬ƒ3ë`¥ŒÃd+gž0[%ãðDÙª‡'ÎVË8uXûÖaìW‡u°ÖÁuXÖaT‡uppÖÁ!uX‡ÖaV‡upxÖÁuXGÖaU‡uptÖÁ1uXÇÖiBÇgÇ•µqBÖƉuX'Õamœ\‡µqJÖÆ©uX§Õamœ^‡µqFÖÆ™uXgÕamœ]‡µqNÖƹuXçÕamœ_‡µqAÖÆ…uXÕam\\‡µqIÖÆ¥uX—Õam\^‡µqEÖÆ•uXWÕam\]‡µqMÖƵuX×Õam\_‡µqCÖÆuX7ÕamÜ\‡µqKÖÆ­uX·ÕamÜ^‡µqGÖÆuXwÕamÜ]‡µqOÖƽuX÷ÕamÜ_‡µñ@&´ñPö`Y×amÌamŒæ°6F sX#…9¬‘ÃÖÆ(akcÔ0‡µ1Z˜ÃÚ=ÌamŒæ°6Æ sXc…9¬±ÃÖÆ8akcÜ0‡µ1^˜ÃÚ?ÌamLæ°6& sX…9¬‰ÃÖÆ$akcÒ0‡µ1Y˜Ó„6¦OžamLæ°6¦ +sXS‡9¬iÂÖÆ´akcº0‡µ1}˜ÃÚ˜!ÌamÌæ°6f +sX3gÖÁ,‡u0kÆaÌ–qX³gÖÁ‡u0gÆaÌ•qXsgÖÁ<‡u0oÆaÌ—qXógÖÁ‡u°`Æa,”qX gÖÁ"‡u°hÆa,–qX‹gÖÁ‡u°dÆa,•qXKgÖÁ2‡u°lÆa,—qXËgÖÁ +‡u°bÆa¬”qx‚låŒÃf«dž([5ãðÄÙj‡'ÉVÏ8¬ÃÚø¨kãã:¬Oê°6>­ÃÚø¬kãó:¬/ê°6þS‡µñß:¬/ë°6¾ªÃÚøºkã›:¬oë°6¾«ÃÚø¾kã‡:Mhã§ìDz6~®ÃÚø¥kã×:¬ßê°6~¯ÃÚø£kãÏ:¬¿ê°6þ®ÃÚø§kãß:¬†ûŸÃÚ0okc 0‡µ1p˜ÃÚ$Ìam æ°6 sXƒ‡9¬!ÂÖÆakc¨0‡µ1t˜ÃÚ&Ìam æ°6† sXÇ9¬ÂÖƈakc¤0‡µ1r˜ÃÚ%ÌamŒæ°6F sX£‡9¬1ÂÖƘakc¬0‡µ1v˜ÃÚ'ÌamŒæ°6Æ sXã‡9¬ ÂÖÆ„akc¢0‡µ1q˜ÃÚ˜$ÌamLæ4¡ÉÓeXS„9¬)ÃÖÆTakcê0‡µ1M˜ÃÚ˜6ÌamLæ°6¦sX3„9¬ÃÖÆLaë`æŒÃ:˜%ã°fÍ8¬ƒÙ2ë`öŒÃ:˜#ã°æÌ8¬ƒ¹2ë`îŒÃ:˜'ã°æÍ8¬ƒù2ë`þŒÃ:X ã°Ì8¬ƒ…2ë`áŒÃ:X$ã°Í8¬ƒÅ2ë`ñŒÃ:X"ã°–Ì8¬ƒ¥2ë`éŒÃ:X&ã°–Í8¬ƒå2ë`ùŒÃ:X!ã°VÌ8¬ƒ•2O­œqxÂl•ŒÃe«fž8[-ãð$Ùê‡'ÍÖȸɲɳµ²5ËSä®]‡§ÌÖ©ÃSeëÖᩳõêð4ÙúuxÚlƒ:<]¶až>Û¨Ïm\‡gÌ6©Ã3e›ÖᙳÍêð,ÙæuxÖl‹:<[¶ež=Ûªë`ë:¬ƒmê°¶­Ã:Ø®ë`û:¬ƒê°v¬Ã:Ø©ë`ç:¬ƒ]ê°v­Ã:Ø­ë`÷:¬ƒ=ê°ö¬Ã:Ø«ë`ï:¬ƒ}ê°ö­Ã:دë`ÿ:¬ƒê°¬Ã:8¨ëàà:¬ƒCê°­Ã:8¬ëàð:¬ƒ#ê°Ž¬Ã:8ªkãè:MhãØ옲6Ž«ÃÚ8¾kã„:¬ë°6NªÃÚ8¹kã”:¬Së°6N«ÃÚ8½kãŒÿ£¹c¨=ÛnVomÛ¶mÛ¶mÛ¶mÛ¶mÛ¶=G¾¹œ¹Æ}4iš>IWÛÆmlg¶±mœÕƶqvÛÆ9ml綱mœ×ƶq~ÛÆml¶±m\ÔƶqqÛÆ%ml—¶±m\ÖƶqyÛÆmlW¶±m\ÕƶquÛÆ5ml׶±m\×ƶq}ÛÆ ml7¶±mÜÔƶqsÛÆ-ml·¶±mÜÖƶq{ÛÆmlw¶±mÜÕƶqwÛÆ=ml÷¶Ù„mÜŸ»¯¶ÚØ6lcÛx¨mãá6¶GÚØ6mcÛx¬mãñ6¶'ÚØ6žlcÛxªmãé6¶gÚØ6žmcÛx®mãù6¶ÚØ6^lcÛx©mãå6¶WÚØ6^mcÛx­mãõ6¶7ÚØ6ÞlcÛx«mãí6¶wÚØ6ÞmcÛx¯mãý6¶ÚØ6>lcÛø¨mãã6¶OÚØ6>mcÛø¬mãó6¶/ÚØ6¾lcÛøªmãë6¶oÚØ6¾mcÛø®mãû6¶ÚlÂ6~ÊýXÛÆÏml¿´±müÚƶñ[ÛÆïml´±müÙƶñWÛÆßmlÿ´±müÛƶñ_ÛÆ Ãý_cÛ0ßÛÆ@±Æ¶1p¬±m klÿ‹5¶Acmc°XcÛ<ÖØ6†ˆ5¶!cmc¨XcÛ:ÖØ6†‰5¶acmc¸XcÛ>ÖØ6Fˆ5¶cmc¤XcÛ9ÖØ6F‰5¶Qcmc´XcÛ=ÖØ6ƈ5¶1cmc¬XcÛ;ÖØ6Ɖ5¶qcmc¼XcÛ?ÖØ6&ˆ5¶ cmc¢XcÛ˜8ÖlÂ6&'ɱmLkl“ÇÛƱƶ1e¬±mLklSÇÛÆ4±Æ¶1m¬±mLklÓÇÛÆ ±Æ¶1c¬±Ì”ÓØfÎil³ä4¶ƒYsÛÁl9í`öœÆv0GNc;˜3§±Ì•ÓØæÎilóä4¶ƒysÛÁ|9í`þœÆv°@Nc;X0§±,”ÓØÎil‹ä4¶ƒEsÛÁb9í`ñœÆv°DNc;X2§±,•ÓØ–ÎilËä4¶ƒesÛÁr9í`ùœÆv°BNc;X1§ñø¹•rO[9§ñ„¹UrO”[5§ñĹÕrÚ$¹IskäV¯'Ë»fOž[«§È­ÝÆSæÖiã©rë¶ñÔ¹õÚxšÜúmlcÛø¨mãã6¶OÚØ6>mcÛø¬mãó6¶/ÚØ6¾lcÛøªmãë6¶oÚØ6¾mcÛø®mãû6›°s?Ô¶ñSÛÆÏml¿´±müÚƶñ[ÛÆïml´±müÙƶñWÛÆßmlÿ´±müÛƶñ_ÛÆ Ãÿ_cÛ0ßÛÆ@±Æ¶1p¬±m klÿ‹5¶Acmc°XcÛ<ÖØ6†ˆ5¶!cmc¨XcÛ:ÖØ6†‰5¶acmc¸XcÛ>ÖØ6Fˆ5¶cmc¤XcÛ9ÖØ6F‰5¶Qcmc´XcÛ=ÖØ6ƈ5¶1cmc¬XcÛ;ÖØ6Ɖ5¶qcmc¼XcÛ?ÖØ6&ˆ5¶ cmc¢X³ Û˜$ž8Ƕ1i¬±mLkl“ÇÛƱƶ1e¬±mLklSÇÛÆ4±Æ¶1m¬±mLklÓÇÛÆ ±Æ¶1c¬±Ì”ÓØfÎil³ä4¶ƒYsÛÁl9í`öœÆv0GNc;˜3§±Ì•ÓØæÎilóä4¶ƒysÛÁ|9í`þœÆv°@Nc;X0§±,”ÓØÎil‹ä4¶ƒEsÛÁb9í`ñœÆv°DNc;X2§±,•ÓØ–ÎilËä4¶ƒesÛÁr9í`ùœÆv°BNc;X1§ñø¹•rO[9§ñ„¹UrO”[5§Mœ›$·znµzÒ¼k´ñd¹5ÛxòÜZmjcÛø¸mã“6¶OÛØ6>kcÛø¼mã‹6¶/ÛØ6¾jcÛøºmã›6¶oÛØ6¾k³ Ûø!÷}m?¶±müÔƶñsÛÆ/ml¿¶±müÖƶñ{ÛÆml¶±müÕƶñwÛÆ?mlÿ¶±mü×ƶ1Àÿ×Ø6̷ƶ1P¬±m klƒÄÛÆÿbmcÐXcÛ,ÖØ65¶!bmcÈXcÛ*ÖØ6†Ž5¶abmcØXcÛ.ÖØ6†5¶bmcÄXcÛ)ÖØ6FŽ5¶QbmcÔXcÛ-ÖØ6F5¶1bmcÌXcÛ+ÖØ6ÆŽ5¶qbmcÜXcÛ/ÖØ6Æ5¶ bmcÂX³ Û˜8ž(Ƕ1I¬±mLkl“ÅÛÆä±Æ¶1E¬±mLklSÅÛÆԱƶ1M¬±mLklÓÅÛÆô±Æ¶1C¬±mÌkl3å4¶ƒ™sÛÁ,9í`ÖœÆv0[Nc;˜=§±Ì‘ÓØæÌilså4¶ƒ¹sÛÁ<9í`ÞœÆv0_Nc;˜?§±,ÓØÌil å4¶ƒ…sÛÁ"9í`ÑœÆv°XNc;X<§±,‘ÓØ–ÌilKå4¶ƒ¥sÛÁ29í`ÙœÆv°\Nc;X>§±¬ÓØVÌi<~n¥œÆäVÎihcÛø°mã£6¶ÛØ6>icÛø´mã³6¶ÏÛØ6¾hcÛø²mã«6¶¯ÛØ6¾icÛø¶Í&lãûÜwµmüÐƶñcÛÆOml?·±müÒƶñkÛÆoml¿·±müÑƶñgÛÆ_ml·±müÓƶñoÛÆmlŒømcÀ|klÅÛÆÀ±Æ¶1H¬±mü/ÖØ65¶ÁbmcðXcÛ"ÖØ6†Œ5¶¡bmcèXcÛ&ÖØ6†5¶ábmcøXcÛ!ÖØ6FŒ5¶‘bmcäXcÛ%ÖØ6F5¶ÑbmcôXcÛ#ÖØ6ÆŒ5¶±bmcìXcÛ'ÖØ6Æ5¶ñbmcüXcÛ˜ ÖlÂ6&Š'̱mLkl“ÄÛƤ±Æ¶1Y¬±mLklSÄÛÆ”±Æ¶1U¬±mLklÓÄÛÆ´±Æ¶1]¬±mLkl3ÄÛÆŒ±Æv0SNc;˜9§±Ì’ÓØfÍil³å4¶ƒÙsÛÁ9í`ÎœÆv0WNc;˜;§±Ì“ÓØæÍilóå4¶ƒùsÛÁ9í`ÁœÆv°PNc;X8§±,’ÓØÍil‹å4¶ƒÅsÛÁ9í`ÉœÆv°TNc;X:§±,“ÓØ–ÍilËå4¶ƒåsÛÁ +9í`ÅœÆãçVÊincÛø¤mãÓ6¶ÏÚØ6>ocÛø¢mãË6¶¯ÚØ6¾ncÛø¦Í&lã»Ü·µm|ßƶñCÛÆml?µ±müÜƶñKÛƯml¿µ±müÞƶñGÛÆŸmlµ±müÝƶñOÛÆ¿mlÿµ±m 0Òÿ5¶ó­±m klÇÛÆ ±Æ¶ñ¿XcÛ4ÖØ6‹5¶ÁcmcˆXcÛ2ÖØ6†Š5¶¡cmc˜XcÛ6ÖØ6†‹5¶ácmc„XcÛ1ÖØ6FŠ5¶‘cmc”XcÛ5ÖØ6F‹5¶ÑcmcŒXcÛ3ÖØ6ÆŠ5¶±cmcœXcÛ7ÖØ6Æ‹5¶ñcÍ&lcÂx‚ÛÆD±Æ¶1q¬±mLkl“ÆÛÆd±Æ¶1y¬±mLklSÆÛÆT±Æ¶1u¬±mLklÓÆÛÆt±Æ¶1}¬±mÌkl3ÆÛÁL9í`æœÆv0KNc;˜5§±Ì–ÓØfÏilsä4¶ƒ9sÛÁ\9í`îœÆv0ONc;˜7§±Ì—ÓØæÏil ä4¶ƒsÛÁB9í`áœÆv°HNc;X4§±,–ÓØÏilKä4¶ƒ%sÛÁR9í`éœÆv°LNc;X6§±,—ÓØ–Ïil+ä4¶ƒsŸ[)§M›0·Jnåz¢¼«¶ñĹÕÚx’ÜêmncÛø¤mãÓ6¶ÏÚØ6>ocÛø¢mãË6¶¯ÚØ6¾ngäü?ZnÙÜrõXy—iã1sK·ñ¹¥ÚxôÜ’mm¼dnï6^"·W/žÛ³ËíÑÆ‹ævoãEr»µñ¹]Ûx¡Ü.m¼`nç6^ ·SÏŸÛ±mc‡6¶íÛØ6¶kcÛضmc›6¶­ÛØ6¶jcÛزmc‹6¶ÍÛØ66kcÛØ´mc“6¶ÛØ6jc;Ø°í`ƒ6¶ƒõÛØÖkc;X·í`6¶ƒµÛØÖjc;X³í`6¶ƒÕÛØVkc;Xµí`•6¶ƒ•Ûx‚ÜJm<~nÅ6/·BÛÁml´y÷Ïݘ»©Þ/ï ml×·±m\×ƶqmÛÆ5mlW·±m\ÕƶqeÛÆml—·±m\Öƶqiï”»¤wÌ]ÜÆ;ä.jãís¶ñv¹ ÚØ6ÎocÛ8¯mãÜ6¶sÚØ6ÎncÛ8«mãÌ6¶3ÚØ6NocÛ8­mãÔ6¶SÚxÃÜÉm¼Aî¤6^?wb¯—;¡mãø6¶ãÚØ6ŽmcÛ8¦mãè6¶£ÚØ6ŽlcÛ8¢mãð6¶ÃÚØ6mã•r‡´ñŠ¹ƒÛx…ÜAml7·±MÜÔæ½1÷qî“ú†¼µ±m|ØƶñAÛÆûmlïµ±m¼ÛƶñNÛÆÛmloµ±m¼ÙƶñFÛÆëm|Iîµ6¾8÷j_”{¥/̽ÜÆä^jcÛx±mã…6¶çÛØ6žkcÛx¶mã™6¶§ÛØ6žjcÛx²mã‰6¶ÇÛØ6kã“s¶ñI¹GÚøÄÜÃm|Bî¡6¶ÛØ6hcÛ¸¿mã¾6¶{ÛØ6îicÛ¸»mã®6¶;ÛØ6îhcÛ¸½ÉÝÖÆçnmãƒr·´±m|ÚÆ6ñI›÷ãܨ£äwCŽ?Êkl#ÇÛÆH±Æ¶1b¬±mŒklÃÇÛÆp±Æ¶1l¬±m klCÇÛÆP±Æ¶1d¬±m klƒÇÛÆ`±Æ/ç5¶ÿÅÛÆ ±Æ¶1p¬±m klÆÛÆ ±Æ¶ñ_ÛÆ¿mlÿ´±müÝƶñWÛÆŸml´±müÞÆä~kã‡s¿¶ñC¹_ÚØ6~ncÛø©mãÇ6¶ÚØ6¾ocÛø®mãÛ6¶oÚØ6¾ncÛøªmãË6¶/ÚØ6>ocÛø¬mcôüÙhl¶ yí`ñܵ,ÖÆv°hÛÁ"ml ·±,ÔÆv°`ÛÁmló·±Ì×Æv0oÛÁ6w“»¯ÎÝÛÆGåîicÛ¸»mã®6¶;ÛØ6îhcÛ¸½mã¶6¶[ÛØ6nicÛ¸¹mã¦6¶Ûx¿Ü m¼oîú6Þ'w]ÛÆûmlïµyßÍ ?j~7äøÜp±Æ¶1l¬±m klCÇÛÆP±Æ¶1d¬±m klƒÇÛÆ`±Æ¶1h¬±mü/ÖØ6‰5¶cmc XcÛ0ÖøÙÜ ±Æ¶ñ_ÛÆ¿mlÿ´±müÝƶñWÛÆŸml´±müÞƶñ[ÛƯml¿´±müÜƶñSÛÆm|_î‡6¾7÷}ß“û®mãÛ6¶oÚØ6¾ncÛøªmãË6¶/ÚØ6>ocÛø¬mãÓ6¶OÚØ6>ncÛø¨mãÃ6¶ÚØ6FÌŸ½Æ6a š×Ì-TÛÁmló·±Ì×Æv0oÛÁ5÷xŸ’{¬mãÑ6¶GÚØ6ncÛx¨mãÁ6¶ÚØ6îocÛ¸¯mãÞ6¶{ÚØ6încÛ¸«ÏÝÙƇåîhãCs··ñ!¹ÛÚØ6nmcÛ¸¥mãæ6¶›ÚØ6nlcÛ¸¡mãú6¶ëÚØ6®mcÛ¸¦mãê6Þ#wUïž»²wË]ÑƶñfÛÄmÞ×sCŽ–ß 9~-7D¬±m klƒÅÛÆ ±Æ¶ñ¿XcÛ$ÖØ6Ž5¶bmcÀXcÛ ÖØ6þkcÛø·mãŸ6¶¿ÛØ6þjãÇs¶±müÑƶñ{ÛÆoml¿¶±müÒƶñsÛÆOml?¶±müÐƶñ}ÛÆwml߶±m|ÓÆwæ¾nã;r_µñí¹/Ûø¶ÜmlŸ·±m|ÖƶñiÛÆ'ml·±m|ÔƶñaÛÆmlï·±m¼×ƶñnÛÆ;mlo·±m¼Õƶ1tþÛÒØ&lAóÚÁܹyj;˜«í`Î6¶ƒ9ÚØfoc;˜­í`Ö6¶ƒYÚØfnc;˜©mcÆ6¶ÚØ6¦Ï·Æ¶1]¬±mLküWnšXã?sSÇÛÆT±Æ¶1e¬±mLkl“ÇÛÆd±Æ¶1i¬±mLklÇÛÆD±Æ¶1a¬±mLklãÇÛÆx±Æ¶1n¬±mŒklcÇÛÆX±Æ¶1f¬±mŒkl£ÇÛÆh±Æ¶1j¬±mŒkl#ÇÛÆH±Æ¶1b¬±mŒklÃÇÛÆp±Æ¶1l¬± klóæ´ÿ¿ [춱mn»Ú6¶icÛغmc«6¶-ÛØ6¶hcÛؼmc³6¶MÛØ66icÛظí`£6¶ƒ ÛØ6hc;X¿í`½6¶ƒuÛØÖic;X»í`­6¶ƒ5ÛØÖhc;X½í`µ6¶ƒUÛØVic;X¹í`¥6¶ƒÛØVhc;X¾í`¹6¶ƒeÛØ–ic;Xºí`©6¶ƒ%ÛØ–hc;X¼í`±6¶ƒEÛØic;X¸í`¡6¶ƒÛx¸Üm1÷pŸ{¨Ï=ØÆÇåhcÛ¸¿mã¾6¶{ÛØ6îicÛ¸»mã®6¶;ÛØ6îhcÛ¸½mã¶6¶[ÛØ6niãs7·ñ¹›ÚxÿÜm¼_î†6¶ëÛØ6®kcÛ¸¶mãš6¶«ÛØ6®jcÛ¸²mãŠ6¶ËÛØ6.kcÛ¸´wÊ]ÒÆ;æ.nãrµ±m¼ÜÆ6ñR›÷ÅÜ £çwCŽ_È klÅÛÆ€±Æ¶1@¬±mü×ƶñoÛÆ?ml·±müÕƶñgÛÆml¿·±müÖƶñkÛÆ/mü`îç6¶ŸÚØ6~lcÛø¡mãû6¶ïÚØ6¾mcÛø¦mãë6¶¯ÚØ6¾lcÛø¢mãó6¶ÏÚøæܧm|Sî“6¾1÷qßû¨mãÃ6¶ÚØ6ÞocÛx¯mãÝ6¶wÚØ6ÞncÛx«mãÍ6¶7ÚØ6^ocÛx­mãÕ6¶WÚØ6ͻۄ-h^;˜57[m³´±ÌÜÆv0SÛÆŒml3´±mLŸomcºXcÛ˜6ÖØ6¦‰5¶©cmcªXcÛ˜2ÖØ6¦ˆ5¶ÉcÉMküsnÒXcÛ˜$ÖØ6&Ž5¶‰bmcÂXcÛ˜ ÖØ6Æ5¶ñbmcÜXcÛ'ÖØ6ÆŽ5¶±bmcÌXcÛ#ÖØ6F5¶ÑbmcÔXcÛ%ÖØ6FŽ5¶‘bmcÄXcÛ!ÖØ6†5¶ábmcØXcÛ&ÖØ6†Ž5¶¡bmcÈXcÛ"ÖØ65¶ƒÁbí`öœöÿ7a š×66ÏmQÛÆfml›¶±mlÒƶ±qÛÁFml¶±lÐÆv°~ÛÁzml붱¬ÓÆv°vÛÁZmlk¶±¬ÑÆv°zÛÁjml«¶±¬ÒÆv°rÛÁJml+¶±¬ÐÆv°|ÛÁrml˶±,ÓÆv°tÛÁRmlK¶±,ÑÆv°xÛÁbml‹¶±,ÒÆv°pÛÁBml ¶±,ÐÆv0ÛÁ|mló¶±ÌÓÆv0w‘›«ÏÍÙƃåæhc;زmb‹6ïæ¹3sgÕ›å=£mãô6¶ÓÚØ6NmcÛ8¥mãä6¶“ÚØ6NlcÛ8¡mãø6¶ãÚØ6ŽmãµrÇ´ñš¹£ÛxÜQm¼zîÈ6^-wDÛÆáml‡µ±mÚƶqHÛÆÁmlµ±mØƶq@ÛÆþmlûµ±mìÛƶ±O/™Û»—ÈíÕÆ‹çölãÅr{´±mìÞƶ±[ÛÆ®ml»´±mìÜƶ±SÛÆŽml;´±mlßƶ±]Ûƶmû7÷_ýTÞÚØ6þncÛø«mãÏ6¶?ÚØ6~ocÛø­mã×6¶_ÚØ6~ncÛø©mãÇ6¾/÷Cß›û¾ïÉ}×Æwç¾mã»rß´±m|ÝƶñUÛÆ—ml_´±m|ÞƶñYÛƧmlŸ´±m|ÜƶñQÛƇml´ñµ¹÷ÛøšÜ{m|uîÝ6¾*÷NÛÆÛmloµ±m¼ÙƶñFÛÆëml¯µ±m¼ÚƶñJÛÆËml/µ±m¼ØÆçå^hãssÏ·ñ9¹çÚØ6ãÿÛÄmÞsÓç¯ÏãrÓÅÛÆ´±Æ¶1M¬±mLklSÅÛÆ”±Æ¶1E¬±mLkl“ÅÛƤ±Æ¶1I¬±mLklÅÛÆ„±Æ¶1A¬ñ·¹ñcmc¼XcÛ7ÖØ6Ɖ5¶±cmc¬XcÛ3ÖØ6ƈ5¶Ñcmc´XcÛ5ÖØ6F‰5¶‘cmc¤XcÛ1Öø½Ü±Æïæ†5~'7\¬±m klÃÄÛÆбƶ1T¬±m klCÄÛÆà±Æ¶1X¬±m klÿ‹5¶AbmcàXcÛ(ÖØ6Œ5¶sÛ„-h^;Ø0·Qm´±¬ßÆv°^ÛÁºmlë´±¬ÝÆv°VÛÁšmlk´±¬ÞÆv°ZÛÁªml«´±¬ÜÆv°RÛÁŠml+´±,ßÆv°\ÛÁ²mlË´±,ÝÆv°TÛÁ’mlK´±,ÞÆv°XÛÁ¢ml‹´±,ÜÆv°PÛÁ‚ml ´±ÌßÆv0_ÛÁ¼mló´±ÌÝÆv0WÛÁœmls´±ÌÞÆv0[ÛÁ¬m,wGš»½ÉÝÖÆçnmãƒr·´±mÜÜƶqSÛÆml7´±m\ßƶq]ÛƵml×´±m\ÝƶqUÛÆ•mlW´ñ®¹ËÛx—Üem¼sîÒ6Þ)wIÛÆÅmlµ±m\ØƶqAÛÆùmlçµ±mœÛƶqNÛÆÙmlgµ±mœÙÆ›åÎhãMs§·ñ&¹ÓÚØ6oc›x¬Íûhî÷Üõ#ykcÛøµmã—6¶ŸÛØ6~jcÛø±mã‡6¶ïÛØ6¾kcÛø¶mã›6¶¯ÛøŽÜWm|{îË6¾-÷Eßšû¼oÉ}ÖƶñiÛÆ'ml·±m|ÔƶñaÛÆmlï·±m¼×ƶñnÛÆ;mlo·±m¼ÕÆ—çÞlãËro´ñ¥¹×Ûø’Ükml¯¶±m¼ÒƶñrÛÆKml/¶±m¼Ðƶñ|ÛÆsml϶±m<ÓƶñtŸ‘{ªOÏ=ÙƧåžhcÛø³mâ6ïï¹)ÇÌï†ÿ–›"ÖØ6&5¶ÉbmcÒXcÛ˜$ÖØ6&Ž5¶‰bmcÂXcÛ˜ ÖØ6Æ5¶ñbmcÜXcÛ'ÖØ6ÆŽ5¶±b?ÏklcÄÛÆè±Æ¶1Z¬±mŒkl£ÄÛÆȱƶ1R¬±mŒkl#ÄÛÆð±Æ¶1\¬±m klÃÄÛÆбÆo䆊5~=7d¬ñk¹!bmcðXcÛ,ÖØ65¶ÿÅÛÆ ±Æ¶1p¬±m klÆÛÆ ±Æ¶ñ_ÛÆ¿mlÿ´±müÝƶñWÛÆÔù{kl¶ yí`íÜ:µ¬ÕÆv°fÛÁml«·±¬ÖÆv°jÛÁ*ml+·±¬ÔÆv°bÛÁ +mlË·±,×Æv°lÛÁ2mlK·±,ÕÆv°dÛÁml‹·±,ÖÆv°hÛÁ"ml ·±,ÔÆv°`ÛÁmló·±Ì×Æv0oÛÁ&ï}ml÷¶±mÜÓƶqwÛÆ]mlw¶±mÜÑƶq{ÛÆmml·¶±mÜÒƶqs»©÷ÏÝØÆûånhã}s×·ñ>¹ëÚØ6®mcÛ¸¦mãê6¶«ÚØ6®lcÛ¸¢mãò6¶ËÚØ6.mcÛ¸¤mãâ6¶‹ÚxûÜ…m¼]î‚6Þ6w~o“;¯mãÜ6¶sÚØ6ÎncÛ8«mãÌ6¶3ÚØ6NocÛ8­mãÔ6¶SÚØ6Nnã r'µñú¹Ûx½Ü ml¶±M<Ðæ½?÷cî§ú¾¼?´±m|ßƶñ]ÛÆ·mlß´±m|ÝƶñUÛÆ—ml_´±m|ÞƶñYÛƧm|Sî“6¾1÷qßû¨¯Ï}ØÆ×å>hcÛx¿mã½6¶wÛØ6ÞicÛx»mã­6¶7ÛØ6ÞhcÛx½mãµ6¶WÛØ6^iã s/·ñ¹—ÚøüÜ‹m|^î…6¶çÛØ6žkcÛx¶mã™6¶§ÛØ6žjcÛx²mã‰6¶ÇÛØ6kcÛx´OÊ=ÒÆ'ænãrµ±müÜÆ6ñS›÷ÇÜÄcåwCŽÈMklÆÛƱƶ1~¬±mŒklãÆÛÆ8±Æ¶1v¬±mŒklcÆÛƱƶ1z¬±mŒkl£ÆÛÆ(±ÆæFŽ5¶‘bmcÄXcÛ!ÖØ6†5¶ábmcØXcÛ&ÖØ6†Ž5¶¡bmcÈXcÛ"ÖØ65¶ÁbmcÐXã—rÿ‹5~17H¬ñ ¹cmc XcÛ0ÖØ6ˆ5¶ÿÚØ6þmcÛø§mãï6¶¿ÚØ6þlcÛø£mã÷6¶ßÚØ6~mcÛø¥mcÒü³kl¶ yí`ÕÜjµ¬ÒÆv°rÛÁJml+¶±¬ÐÆv°|ÛÁrml˶±,ÓÆv°tÛÁRmlK¶±,ÑÆv°xÛÁbml‹¶±,ÒÆv°pÛÁBml ¶±,ÐÆv0ÛÁ|mló¶±ÌÓÆv0wÛÁ\mls¶±ÌÑÆv0{ÛÁlml³¶±ÌÒÆv0sÛÁLml3¶±mÌÐƶ1}¾5¶ébmcÚXcÛ˜&ÖØ6¦Ž5¶©bmcÊXcÛ˜"ÖØ6&5¶ƒÉbí`õœÆ6a š×6ÏQÛÆaml‡¶±mÒƶqp¯;¨—ÏØÆËåhãesû·ñ2¹ýÚxéܾm¼TnŸ6^2·w/‘Û«ÏíÙÆ‹åöhãEs»·ñ"¹ÝÚØ6vmcÛØ¥mcç6¶ÚØ6vlcÛØ¡mcû6¶íÚØ6¶mcÛئmcë6¶­ÚØ6¶lcÛØ¢mcó6¶ÍÚØ66mcÛؤmcã6¶ƒÚØ6lc;Ø í`ý6¶ƒõÚØÖmc;X§í`í6ž"·VOž[³'Ë­ÑÆvpdÛÄmÞÃswæîªË{GÛÆíml·µ±mÜÚƶqKÛÆÍml7µ±mÜØƶqCÛÆõml×µ±m\ÛÆ{å®iã=sW·ñ¹«Úx÷Ü•m¼[îŠ6¶ËÛØ6.kcÛ¸´mã’6¶‹ÛØ6.jcÛ¸°mã‚6¶óÛØ6ÎkcÛ8·mãœ6Þ2wvo‘;«7ÏÙÆ›åÎhcÛ8½mã´6¶SÛØ6NicÛ8¹mã¤6¶ÛØ6NhcÛ8¾mã¸6¶cÛx­Ü1m¼fîè6^#wTÛÆÝmlwµyïÌ}û¦¾#ïWml_¶±m|ÑƶñyÛÆgmlŸ¶±m|ÒƶñqÛÆGml¶±m|Ðƶñ~_“{¯¯Î½ÛÆWåÞiã+so·ñ¹·ÚØ6ÞlcÛx£mãõ6¶×ÚØ6^mcÛx¥mãå6¶—ÚØ6^lcÛx¡mãù6¶çÚøìܳm|Vî™6>3÷tŸ‘{ªmãÉ6¶'ÚØ6ocÛx¬mãÑ6¶GÚØ6ncÛx¨mãÁ6¶ÚØ6îoãcr÷µñѹ{Ûø¨Ü=ml߶±M|Óæý:7îØùÝã¯rãÄÛÆرƶ1V¬±mŒklcÄÛÆè±Æ¶1Z¬±mŒkl£ÄÛÆȱƶ1R¬±mŒkl#ÄÛÆð±Æ¶1\¬ñÛ¹acmc˜XcÛ:ÖØ6†Š5¶!cmcˆXcÛ<ÖØ6‹5¶Acmã±Æ¶1H¬±m klÅÛÆ€±Æ¶1@¬ñ3¹ÿÚøéÜ¿müTîŸ6¶¿ÛØ6þjcÛø³mã6¶ßÛØ6~kcÛøµmã—6¶ŸÛØ6~jcÛø±mã‡6¶ïÛØ6¾kcÛ?ÿn4¶ [мv°|n…Ú–kc;X¶í`™6¶ƒ¥ÛØ–jc;X²í`‰6¶ƒÅÛØkc;X´í`‘6¶ƒ…ÛØjc;X°í`6¶ƒùÛØækc;˜·í`ž6¶ƒ¹ÛØæjc;˜³í`Ž6¶ƒÙÛØfkc;˜µí`–6¶ƒ™ÛØfjcÛ˜±mc†6¶éó­±mLklÓÆÛÆ4±Æ¶1u¬±mLklSÆÛƱƶ1y¬±mLkl“ÆÛÆ$±Æ¶1q¬±mLklÆÛÁ±Æv°bNc›X!§y—Ϙ;¨^.ïm¼lnÿ6^&·_/Û·—ÊíÓÆKæönã%r{µñâ¹=Ûx±Üm¼hn÷6^$·[/œÛµÊíÒÆ ævnãr;µñü¹ÛØ6vhcÛؾmc»6¶mÛØ6¶icÛغmc«6¶-ÛØ6¶hcÛؼmc³6¶MÛØ66icÛظí`£6¶ƒ ÛØ6hc;X¿í`½6¶ƒuÛØÖic;X»í`­6¶ƒ5ÛØÖhc;X½í`µ6¶ƒUÛx¢Ü*m ïMml7¶±mÜÐƶq}ÛÆuml׶±m\ÓƶquÛÆUmlW¶±m\Ñƶqyï’»¬wÎ]ÚÆ;å.iãs·ñ¹‹ÚØ6.lcÛ¸ mãü6¶óÚØ6ÎmcÛ8§mãì6¶³ÚØ6ÎlcÛ8£mãô6¶ÓÚxãÜ©m¼Qî”6Þ0wro;©mãÄ6¶ÚØ6ŽocÛ8®mãØ6¶cÚØ6ŽncÛ8ªmãÈ6¶#ÚØ6oãUr‡µñʹCÛx¥Ü!ml·¶±MÜÒæ½9÷iî³ú¦¼Ÿ´±m|ÜƶñQÛƇml´±m¼ßƶñ^ÛÆ»mlï´±m¼ÝƶñVÛÆ›m|Yî6¾4÷z_’{­/νÚÆå^icÛx¹mã¥6¶ÛØ6^hcÛx¾mã¹6¶gÛØ6žicÛxºmã©6¶'ÛØ6žhãSs·ñ)¹ÇÚøäÜ£m|Rî‘6¶‡ÛØ6jcÛx°mã6¶ûÛØ6îkcÛ¸·mãž6¶»ÛØ6îjcÛ¸³ËÝÑƇænoãCr·µ±m|ÞÆ6ñY›÷ÓÜèãäwCŽ?Ékl£ÆÛÆ(±Æ¶1r¬±mŒkl#ÆÛƱƶ1|¬±m klÃÆÛÆ0±Æ¶1t¬±m klCÆÛƱƯæ5¶ÁbmcÐXcÛø_¬±m klÇÛÆ@±Æ¶1`¬±m klÿµ±müÛƶñOÛÆßmlµ±müÙÆåþhãGs¿·ñ#¹ßÚØ6~mcÛø¥mãç6¶ŸÚØ6~lcÛø¡mãû6¶ïÚØ6¾mcÛø¦mãë6¶¯ÚØ6¾lcÛø¢mcÌü»×Ø&lAóÚÁ’¹¥j;X¢í`ñ6¶ƒÅÚØmc;X¤í`á6¶ƒ…ÚØlc;X í`þ6¶ƒùÚØæmc;˜§í`î6¶ƒ¹ÚØælc;˜£í`ö6¶ƒÙÚØfmc;˜¥í`æ6¶ƒ™ÚØ6flcÛ˜¡mcú|klÓÅÛÆ´±Æ¶1M¬±mLklSÅÛÆ”±Æ¶1E¬±mLkl“ÅÛƤ±Æ¶1I¬±mLklÅÛÆ„±Æ¶1A¬±mŒklãÅÛƸ±Æ¶1N¬±mŒklcÅÛÁÒ9íÿob©6ï’¹½sûÔKäÝ«ÏíÙÆ‹åöhãEs»·ñ"¹ÝÚxáÜ®m¼Pn—6^0·s/Û©çÏíØƶ±CÛÆömlÛµ±mlÛƶ±MÛÆÖml[µ±mlÙöÿZºÏå,È0à M¢ÿ@‘" H UŠ0´ ÷(X€€Riâ²×7›áûÞüÌ>™a á¶q¨·ƒí¸müØŽÛÆvÜ6ö·ã¶±¯·ƒ½í¸üÐŽÛÁžvÜv·ãv°«·ƒí¸ìhÇí`{;n#í¸lkÇí`k;n[Úq;ØÜŽÛÁ¦vÜ6¶ãvð};nÚq;XߎÛÁwí¸¬kÇ?ËnÇçç µãóòÖ¶ã¶qº·‰SíðdÞ›¼·õáëvÜ6^µã¶ñ²·ÛqÛxÑŽÛÆ?í¸müÝŽÛÆóvÜ6žµã¶ñ´·'í¸müÕŽÏû³?–÷¸?š÷¨?’7ÞŽÎ{ØŽÛƃvÜ6î·ã¶ñG;n¿·ã¶ñ[;n¿¶ã¶q¯·»í¸müÒŽÛÆÏí¸mÜiÇmãv;¾3ïV;¾#o¬ßž÷S;>’7ÚŽÛÆÍvÜ6n´ã¶q½·kí¸m\mÇmãJ;n—ÛqÛ¸ÔŽÛÆÅvÜ6.´ã¶q¾Î;׎åmÇ×æiÇmã¿vÜ&Þ¶›oï>Þ%Ê|b(óI¡Ì? e>9”ù”PæSC™O e>=”ùG¡Ìg„2ŸÊüãPæ³B™Ïe>'”ùÜP柄2ÿ4”y~ï óüê Aæù1ŃÌýH$™ç¿— 2Ï?edž¿6džoуÌógù‚¸Ì?e¾0”ù¢Pæ‹C™ÊüËPæKB™Ê|i(ó¯C™/ e¾<”ùŠPæ+C™Ê|U(óoC™¯e¾&”¹™ûúz“÷ùºŽn­ÝYŽn,G÷•£ÛÊÑ]åè¦rtO9º¥ÝQŽn(G÷“ãã:º›z¯£{©G·’£;ÉÑäè>rt9º‹ÝDŽî!G·£;ÈñNo×Ñíó98VG7O£utëôèÎqtã8ºoÝ6ŽîG7£{ÆÑ-ãèŽqtÃ8º_ÏÖÑÝÒ£›ÅÑ× Ý sÔ   LayerElementMaterialI ÃÓ   VersionIe ÙÓ   NameS Ô  MappingInformationTypeS AllSame?Ô   ReferenceInformationTypeS IndexToDirectfÔ   Materialsi  ìÕ   LayerI £Ô   VersionId Õ LayerElementäÔ   TypeS LayerElementNormal Õ   +TypedIndexI yÕ LayerElementPÕ   TypeS LayerElementMateriallÕ   +TypedIndexI ßÕ LayerElement¶Õ   TypeS LayerElementUVÒÕ   +TypedIndexI OÜ  ! GeometryLД* S + GeometryS Mesh±Ö  m Verticesd `  Û²ÿ¿ CÀ¼ C @  Û²ÿ? CÀ¼ C @  Û²ÿ¿ CÀ< C À  Û²ÿ? CÀ< C ÀíÖ   PolygonVertexIndexi    ýÿÿÿ×   Edgesi     =×   GeometryVersionI| Ø   LayerElementNormalI z×   VersionIe ×   NameS Á×   MappingInformationTypeS ByVerticeñ×  ReferenceInformationTypeS DirectrØ  m Normalsd ` ð? °< ð? °< ð? °< ð? °< ÚÙ   LayerElementUVI ¸Ø   VersionIe ÒØ  NameS map1 Ù   MappingInformationTypeS ByPolygonVertex@Ù   ReferenceInformationTypeS IndexToDirectœÙ  M UVd @ €,0ï? ð? €,0ï? ð?ÍÙ   UVIndexi     ÉÚ   LayerElementMaterialI Ú   VersionIe /Ú   NameS ^Ú  MappingInformationTypeS AllSame•Ú   ReferenceInformationTypeS IndexToDirect¼Ú   Materialsi  BÜ   LayerI ùÚ   VersionId cÛ LayerElement:Û   TypeS LayerElementNormalVÛ   +TypedIndexI ÏÛ LayerElement¦Û   TypeS LayerElementMaterialÂÛ   +TypedIndexI 5Ü LayerElement Ü   TypeS LayerElementUV(Ü   +TypedIndexI ¥â  ! GeometryLЪ* S + GeometryS MeshÝ  m Verticesd `  Û²ÿ¿ CÀ¼ C @  Û²ÿ? CÀ¼ C @  Û²ÿ¿ CÀ< C À  Û²ÿ? CÀ< C ÀCÝ   PolygonVertexIndexi    ýÿÿÿrÝ   Edgesi     “Ý   GeometryVersionI| ÕÞ   LayerElementNormalI ÐÝ   VersionIe æÝ   NameS Þ   MappingInformationTypeS ByVerticeGÞ  ReferenceInformationTypeS DirectÈÞ  m Normalsd ` ð? °< ð? °< ð? °< ð? °< 0à   LayerElementUVI ß   VersionIe (ß  NameS map1_ß   MappingInformationTypeS ByPolygonVertex–ß   ReferenceInformationTypeS IndexToDirectòß  M UVd @ €,0ï? ð? €,0ï? ð?#à   UVIndexi     á   LayerElementMaterialI oà   VersionIe …à   NameS ´à  MappingInformationTypeS AllSameëà   ReferenceInformationTypeS IndexToDirectá   Materialsi  ˜â   LayerI Oá   VersionId ¹á LayerElementá   TypeS LayerElementNormal¬á   +TypedIndexI %â LayerElementüá   TypeS LayerElementMaterialâ   +TypedIndexI ‹â LayerElementbâ   TypeS LayerElementUV~â   +TypedIndexI ûè  ! GeometryLЬ* S + GeometryS Mesh]ã  m Verticesd `  Û²ÿ¿ CÀ¼ C @  Û²ÿ? CÀ¼ C @  Û²ÿ¿ CÀ< C À  Û²ÿ? CÀ< C À™ã   PolygonVertexIndexi    ýÿÿÿÈã   Edgesi     éã   GeometryVersionI| +å   LayerElementNormalI &ä   VersionIe <ä   NameS mä   MappingInformationTypeS ByVerticeä  ReferenceInformationTypeS Directå  m Normalsd ` ð? °< ð? °< ð? °< ð? °< †æ   LayerElementUVI då   VersionIe ~å  NameS map1µå   MappingInformationTypeS ByPolygonVertexìå   ReferenceInformationTypeS IndexToDirectHæ  M UVd @ €,0ï? ð? €,0ï? ð?yæ   UVIndexi     uç   LayerElementMaterialI Åæ   VersionIe Ûæ   NameS +ç  MappingInformationTypeS AllSameAç   ReferenceInformationTypeS IndexToDirecthç   Materialsi  îè   LayerI ¥ç   VersionId è LayerElementæç   TypeS LayerElementNormalè   +TypedIndexI {è LayerElementRè   TypeS LayerElementMaterialnè   +TypedIndexI áè LayerElement¸è   TypeS LayerElementUVÔè   +TypedIndexI Qï  ! GeometryLИ* S + GeometryS Mesh³é  m Verticesd `  Û²ÿ¿ CÀ¼ C @  Û²ÿ? CÀ¼ C @  Û²ÿ¿ CÀ< C À  Û²ÿ? CÀ< C Àïé   PolygonVertexIndexi    ýÿÿÿê   Edgesi     ?ê   GeometryVersionI| ë   LayerElementNormalI |ê   VersionIe ’ê   NameS Ãê   MappingInformationTypeS ByVerticeóê  ReferenceInformationTypeS Directtë  m Normalsd ` ð? °< ð? °< ð? °< ð? °< Üì   LayerElementUVI ºë   VersionIe Ôë  NameS map1 ì   MappingInformationTypeS ByPolygonVertexBì   ReferenceInformationTypeS IndexToDirectžì  M UVd @ €,0ï? ð? €,0ï? ð?Ïì   UVIndexi     Ëí   LayerElementMaterialI í   VersionIe 1í   NameS `í  MappingInformationTypeS AllSame—í   ReferenceInformationTypeS IndexToDirect¾í   Materialsi  Dï   LayerI ûí   VersionId eî LayerElement<î   TypeS LayerElementNormalXî   +TypedIndexI Ñî LayerElement¨î   TypeS LayerElementMaterialÄî   +TypedIndexI 7ï LayerElementï   TypeS LayerElementUV*ï   +TypedIndexI §õ  ! GeometryLТ* S + GeometryS Mesh ð  m Verticesd `  Û²ÿ¿ CÀ¼ C @  Û²ÿ? CÀ¼ C @  Û²ÿ¿ CÀ< C À  Û²ÿ? CÀ< C ÀEð   PolygonVertexIndexi    ýÿÿÿtð   Edgesi     •ð   GeometryVersionI| ×ñ   LayerElementNormalI Òð   VersionIe èð   NameS ñ   MappingInformationTypeS ByVerticeIñ  ReferenceInformationTypeS DirectÊñ  m Normalsd ` ð? °< ð? °< ð? °< ð? °< 2ó   LayerElementUVI ò   VersionIe *ò  NameS map1aò   MappingInformationTypeS ByPolygonVertex˜ò   ReferenceInformationTypeS IndexToDirectôò  M UVd @ €,0ï? ð? €,0ï? ð?%ó   UVIndexi     !ô   LayerElementMaterialI qó   VersionIe ‡ó   NameS ¶ó  MappingInformationTypeS AllSameíó   ReferenceInformationTypeS IndexToDirectô   Materialsi  šõ   LayerI Qô   VersionId »ô LayerElement’ô   TypeS LayerElementNormal®ô   +TypedIndexI 'õ LayerElementþô   TypeS LayerElementMaterialõ   +TypedIndexI õ LayerElementdõ   TypeS LayerElementUV€õ   +TypedIndexI £û  . NodeAttributeLpŒž_ S persp1 NodeAttributeS Camera8ú Properties70Tö  > PS PositionS VectorS S AD D @D O}hb*@ ö  > PS UpVectorS VectorS S AD\3&¦¡¼D ð¿D ôö  F PS InterestPositionS VectorS S AD*i£ìcõñú•QüF^e¿iË^ß|„{öOÄGÞù _9NÄ5Ïd<ð›|˜gá}ì×~èWv]¾Ãòp}ã# +?ÑGø|wӌ y™>;N]óuáfåmܾð†û_¼óÑÉùÈ7_D,O\zý þ§/¿â×-®x2ðaýV¼›.pµLýôëóQ¸ø>;~mÓoŒÂy•>Â+óïcó®<">ò®ýÂq"®yã9Ÿ>Ò/¼uœÿ +þ¾Â›å~:ÜŸL~¢ø‰úóêÙûŸÅc?ñ3uÍ×}„íÿìÒ_á?~þ?Çøüwo#öÏ=ýöŠ÷s_ºã¸ÅoÆsÜú­x5]àjÒ/÷?û7ñwœüBŸ§~fžÈKì'¼0ÿqnó®<">òNýqß6NÄ5ÏùÙí¾ÈGúãùí>ÖsÏ~Íë—÷³[®¸?]|úHGúƒ>Â;yý„gꚯû×xçG—ß…þé­|ü¾–îü}ÅÛgÊ[¸Ž¸âÙxÀ»¾_Ôé¦ \Múíö…»â# +?ÓgÇ/núQx"¯ÒG¸êÍêÉ}„+ˆÿ ]¬ýyï6NÄ5Ïb<ðå#ýÂû˜n_¸ìõËû`uzüùGþî¿ÓG:V®Ÿ…ñ¯Äûn¾î#¾Æ;¿~ëŸ>¾{~ù/Œ£>þÜ«ˆåÕßøß½W8âÊÏùÖoŇéW“NúÔæSè#¼“_é#òýÄq"bòÏùô^L¸}þþ¾Â›ù/Æçu¿Ï™üqåìýìÔoŒÒ™ä©Ÿðºè®úf¹µï_8þþ'DΧóÛ_ô|…«NWþ0úMÎâϧ®¿ïzÐD£þÔïç;áƒüÁ:Þ¨_…wòš|¨ù¾>â{À>ÆsÔ¯¬D‡ôy_ä#ýbºÐ±úùþ¾;ny œO…gò}vœúIQ¾äíýt?5OÓG:Hmüð•}|š¯ê&ÆÓîÍÿ^ñòè ÿ Ž¸âÕxÀ‡õ[ñfºÀÕ0?8ïçyú¯ä¯n>Â3õ£ðN^f?ẅ>•GÄGÞóÓÛ8į¦ïã9ä3Œ\>âÏl÷Ñæ¿+^¿o¶<Àχû3ÈOò!¿KŸQú…¼Î~;N]Ì»ž/u4ÞòÉï9^¸ÞZ²®…OÎsˆÐžŒw²Ïëº7]àj;þÀ¶N×…ÏOlüNáõÖ…7òû ¯Ôm\¯ Wã9êWŽqͳ²îä#ýjy@'_¼sß·<€§Ãý)âÓGüBý̸ãäeöž©k¾î#–híO;>ÄçÒ›oú}ϯ_ñßáó©{ü÷ù +OÆÃøç7ý9Kx5]àjÂǹí9|ïGßBþñþÚ¦¯(.ÞåÍgÇ©[å£q1‘ð1žFé4Žqͳü~È¿›.p{þ¼†¿¯t²å¼îO#¿ÐGüBýÌ(¼’WåÃqUéÚs¸ûÆkëäíûe9 e>Ÿæg¶ycCí÷—¿÷ˆÐÙ›ñNø`ýÎà¬ÓÇÿŒk—þ'¾Gâ“õÖè£~ƒóh×|Ê •<Õ©ø¿CU>ºÀñ‘÷>_“W8NÄ5ÏÊyN>’¯¬{n}Âç_^È–ôQWˆjåãº>s? õ3£ø™ùdõã…J]óuñ×úuÿ ~O}—ï›óƒúÕ/ð¨~Gõ ¼³®ñ}v\ù,õèxP¿ÀÕÖú±ÑGú¨[ÇåCßʺZë×uTWKýê×uƒú^¨Ÿ•OT¿àGõ \mÎ_y™OÎCˆø¼ƒù×õƒù×ñ`þu}Σ>Òïœw£ðFÞ:ŸB§ó¯ûÚ5´ˆëGýÊq"žìº|+çEùì¸æÓeþõ|ToËü <š§~f”~a>ëü ¾Õõ¾ÿèý¿cY?ãúäús]?{¿`ý ÈËó&tõ×çSà¼&ê”àù|µˆëGýÊçMÄ:KŸÏ¥òÙq֛͛ûó/t5Ÿ®Ï¿À3ù‰>ÒÉzîU”/y{?â6ïú~ø>_GÊhóã}ßg‰ö¯Ïà>">cÿÄóö¯œÏ}"x ‰í_ßɯË~ðhÿÊ}ÅS?æ3‚ý+×–µðq}Ý¿r>ǹî_‰çqÙ¿Âçbºˆ6Î}ÿ +Ÿ›îÓaŸ)“¿î_í_ö¯Üï »ßgëƒ6õ»ÎõÚ öŸ=Ï`ÿ¸êº/ûÏÀ;ç-x éûÕìûu²Ïà# +ÝvÖOc?Ú¿(úì|»†V™—pðÑOu*<Úv}Ö‘|Ä/¼V‡ûþ3øYu¶ì?»ùëþ³ó©¯º–~´ÿ ~bþ{ýÖÝëùøÑùðèüxt~<:?9œ9œÎœœ9}Жó&ñýúr~„ÏÑùpï¬çGÎ×yÐr~¼Û~bZÎ9?.ýõüÈùÁùðèü¸Ú8¬¿&Ï5×ó_÷e]L~_²Ö…Áù¯çÃu¬|v~pþ»ò;}ÄïšO…7ò*}„Gç¿ëx#>®×ƒ~á8Ov]ú˜w¿œÿâsá}¬Ëù/ð¦õìrþ <“Ÿè#ýDý}^å}ÎⱟøÑù/ôÕæò>€ûïo ŸzayßÀq¾÷–÷7€¾W±ûp%züN~—ùÑûà7ò*ûá½Çõ^Åòþpµˆëëûø\9NÄ“}–~ôþø…÷q}xôþÆÊOô‘~ôþ†óÉËô¿ïo€lØÿ8Aû |çÿ¬7˜¤S2   PolygonVertexIndexi  ô xØsÔØ÷Gñ"UjÛ¶mÛvj»]µ­¶mÛ¶RÛ¶yk×®Ù}å9çžÏ½'ùçyÿ¾ÿ$à 3Ì0ÃÆøñý!Cøp1A|WóácÂø¶æb¢ø¦æ#ÄÄñuÍGŒIâ«š“Æ—59&‹/j>JLŸ×|`LŸÕ|Ô˜2>­ùh1U|RóÑcêø¸æcÄ4ñQÍÇŒiãÚÓÅ5;¦÷k>NÌïÕ|ܘ1Þ­¹ŸñâÚµÝÌñvÍm7K¼UsÛÍoÖÜv³Å5·ÝìñzÍm7G¼VsÛͯÖÜvsÅ+5·ÝÜñrÍm7O¼TsÛÍ/Ö|ª˜/^¨¹íæçkn»⹚ÛnÁx¶æ¶[(ž©¹íŽ§kn»Eâ©šÛnÑx²æ6›)ž¨]Û-×ÜvKÄc5·Ý’ñhÍm·T ®¹í–ŽGjn»eâášÛnÙx¨æ¶[.¬¹í–jn»âþšÛnŸ¯æ¶[)î­¹íVŽ{jn»UâîšÛnÕ¸«æ¶[-íV;jn»5âöšÛn͸­æ6[,n­]Û­·ÔÜvëÄÍ5·ÝºqSÍ—ŠõâÆšÛný¸¡æ¶Û ®¯¹í6Œëjn»âÚšÛn㸦æ¶Û$®®¹í6«jn»ÍâÊšÛnó¸¢æ¶Û".¯¹í¶ŒËjn»AqiÍm·U\RsÛm×ÜvÛÄE5·ÙZqaíÚn»¸ æ¶Û>ί¹ívˆójn»ãÜšÛn§8§æ¶Û9ή¹ív‰³jn»]ãÌšÛn·8£æ¶Û=N¯¹íöˆÓjn»=ãÔšÛn¯8¥æ¶Û;N®¹íö‰“j>(ökn»ýâ„šÛîq|Ím·Ws›mÇÖ®íŒcjn»ƒâèšÛîà8ªæ¶ûcYsÛý)Ž¨¹íþ‡×Üv‡Äa5·Ý¡¨¹í‹Cjn»ÃãÏ5·Ýñ§šÛîÈøcÍmwT\sÛÕÜvÇÄ5·Ý±q@Ímw\ì_ó¡Û¹5·Ý ±_Ímv@ì[»¶;)ö©¹íNŽ½kn»Sb¯šÛîÔسæ¶;-ö¨¹íNÝkn»3b·šgÆ®5·ÝY±KÍmwvì\sÛ;ÕÜvçÆŽ5·Ýy±CÍmw~l_sÛ]ÛÕÜvƶ5·ÝE±MÍ‹cëšÛî’تæ6;1Õ®í.‹-kn»Ëc‹šÛîŠØ¼æ¶»26«¹í®ŠMkn»«c“šÛîšØ¸æ¶»66ª¹í®‹ kn»ëcƒšÛî†X¿æ¶»1Ö«¹ínŠukn»›cšÛî–X»æ¶»5Öª¹ín‹5kn»ÛcšÛîŽX½æ6»4V«]ÛÝ«ÖÜvwÇ*5·Ý=±rÍmwo¬TsÛÝ+ÖÜv÷Ç +5·Ý±|Ím÷`,WsÛ=ËÖÜvÇ25·Ý#±tÍm78–ª¹í%kn»Çb‰šÛîñX¼æ¶{"«¹ížŒEkn»§b‘šÛîéX¸æ—ƱPíÚîÙX°æ¶{.¨¹ížùkn»b¾šÛîŘ·æ¶{)橹í^Ž¹kn»Wb®šÛîÕ˜³æ¶{-樹í^Ùk>8ÞˆÙjn»7cÖšÛî­˜¥æ¶{;f®¹íÞ‰™jn»wcÆšÛ¡æ¶{?¦¯¹Íž‰éj×vÆ´5·ÝG1MÍm÷qL]sÛ}SÕÜvŸÆ”5·Ýg1EÍm÷yL^sÛ}“ÕÜv_Ƥ5·ÝW1IÍm÷uL\sÛ}ÕÜvßÆ„5·Ýw1AÍm÷}Œ_sÛýãÕÜv?Ƹ5·ÝO1NÍm÷—»æ6û ƪ]Ûý-Ƭ¹íþcÔÜvÿˆÑkþIü3F«¹íþ£ÖÜvÿŽ5·Ýb”šÛîç¹æ¶û%Fª¹íþ#ÖÜv¿Æ5·Ýo1 æ¶û_ _sÛýÃÕÜvCbØšÛnè?Zkn»a‡íïü>d·Ýpõï5·Ýðõÿjn³¿Æoµk»úó_kn»ëÿÖÜv#Õ¿ÔÜv#×?×Üv£Ôÿ©ùÐíê×Üv£Öÿª¹íF«ÿYsÛ^ÿ£æ¶£þ{Ím7fý·šÛn¬ú¯5·ÝØõ_jn»qêŸjn»qëkn»ñ⇚Ûnüø¾æ¶› ¾«¹í&Œokn³Ýoj×vÇ×5·Ý$ñUÍm7i|YsÛM_ÔÜv“Çç5SÄg5·Ý”ñiÍm7U|RsÛM×ÜvÓÄG5·Ý´ñaÍm7]|PsÛMï×Üv3Ä{5·ÝŒñnÍm7S¼SsÛÍo×Üv³Ä[5·Ý¬ñfÍm6Q¼Q»¶›=^¯¹íæˆ×jn»9ãÕšÛn®x¥æ¶›;^®¹í扗jn»yãÅšÛn¾x¡æ¶›?ž¯¹íˆçjn»ãÙšÛn¡x¦æ¶[8ž®¹í‰§jn»EãÉšÛn±x¢æ¶[<¯¹í–ˆÇjn»%ãÑšÛl¶\»¶[:©¹í–‰‡kn»eã¡šÛn¹x°æ¶[>¨¹íVˆûkn»㾚Ûn¥¸·æ¶[9íV‰»kn»U㮚Ûnµ¸³æ¶[=íÖˆÛkn»5㶚Ûn­¸µæ¶[;n©¹íÖ‰›kn»u㦚Ûl©¸±vm·~ÜPsÛm××ÜvÆu5·ÝFqmÍm·q\SsÛmW×Üv›ÆU5·ÝfqeÍm·y\QsÛm—×Üv[Æe5·Ý ¸´æ¶Û*.©¹í¶Ž‹kn»m⢚ÛnÛ¸°æ¶Û..¨¹í¶ókn»⼚Ûl½8·vm·SœSsÛíg×Üv»ÄY5·Ý®qfÍm·[œQsÛí§×Üv{Äi5·ÝžqjÍm·WœRsÛí'×ÜvûÄI5·Ý¾qbÍm·_œPsÛý!Ž¯¹íöãjn»âØšÛîÀ8¦æ¶;(Ž®¹íŽ£jn³ãȺ3ôçˆ|¸LóỚèj>BWó»šÔÕ|ä®æ£t5ØÕ|Ô®æ£u5½«ù]ÍÇìj>VW󱻚ÓÕ|Ü®æ¡ÿ‡ÌýÞÞÊá¹ëp×á®÷Á]oƒ»Þw½ îzÜõ¸ëp×à®ïÏ]ßž»¾;w}sîúÞÜõ­¹ë;s×7æ®ß“ÿpàc–Ê6  e Edgesi   X x ×q( üÀq¼s^ÞÑh46ÆF£ÑØh´S¼QÅ¢(ŠEQ‹¢(Eb¹vÖ)¶»uŠÆE;‹E£Nso§hw‹EcöùãS¿¿==Oý¾Â×ø:Ÿò ¾É·ø6ßå{|Ÿð#~ÌOø)?çü’ J8‘DK<‰$“J:™d“K>…SJTQC 4ÑBtÑC 1ÂL1Ã,ópÍ-÷<¨ŸP‰$šXâI$™TÒÉ$›\ò)¤˜Rʨ Šêh ‰Úè ‹ú`ˆƘ`Šf™ç)‹,±ÂKVYg“mvÙã€#N8å-ç\òkn¹ç  ý„N$ÑÄO"ɤ’N&Ùä’O!Å”RFUÔPGM´ÐF]ôÐÇ CŒ0ÆSÌ0ˇó†3ÞqÁ¸â†;>¨Ÿˆ ŠâH ‰ÒÈ ‹~FE”ð˜r*©¦–zi¦•v:馗~æ·Œ3É4O˜cgh ‚ !Œ¢ˆá;$D +idEyPD )§’jj©§‘f~M;tÓK?ƒ 3Ê8“Ló„9xÆs–yÁ+¾`ƒ-vxÍ>‡ó†3ÞqÁ{®¸áŽºSÁ„ðDC $‘Bd‘CQÂcÊ©¤š_QO#Í´ÒN'ÝôÒÏ ÃŒ2Î$Ó7   NameS o7   MappingInformationTypeS ByVerticeŸ7  ReferenceInformationTypeS Direct$D  q Normalsdz  d xmZmÌ]E\"Q©-ˆ)Dd)‚‰!vHbøi btcÑØ"4òa]*"–Ïñ‡„f£„b éÝ ”Á–¯¦S—–ÒJ TˆF|fwæzzyß?Û;wvfž=÷tÏÙ]çœ?ðüU³saã¼#kã),oíõ£Ç†x:ìˆÀÓ!G¬ îÈ/7î¾úÀràõ%ê˜.ð°çêY+ÐJÿÂ;žløœî#úÑÎ÷‡vO~¾¡ëW˃~ÂÓ‘çäC~øv×ÍÑG9OÜoæ‘o&s)ñ[nê+§÷¬“y"ùéº>.Ñêæ)–:a×gÃgÌ·z糺“ÇÝ™>¾néú¨wˆ×Ã;oòz…¹Ìoõ6ê‡Þ¾µÕû·3žžVµcd­OóF[n<åà‘¸Û<³]—òòÌ®#þͧ<~¼nþÃàK§˜.ð´`ÚðΙ÷Bã/í>Ò¯ä»Wº§~¾‰úlƒð­ÌÃ~cþÍÌOáqaÏ¡\‘:õ†žÛQÌ·¨'²îD~0^í^Ô!~^ßDZ,œv"êuäûyó^m îÄ7ýö=ñH}Ô \¾•yûqŽ{µz‡úå£ÜÆý+wþ½éÿä¤í#Ó‹eÙ£hýªo®ž„/~°_Gk‡ü`¼Æ|Ù£CÜ™nÃwžp(|uÜS~p·²ûäçË»'?Q?ôÔOl¥zÑ_ý„ûÇzþdõâ{áåØ=–!‡Û3lløÝ·mÙGàCO uWOÿÇO¯ß´xÝ~ÓZà^|ãO{è‰!ß6/Çn»túý®ë‡‹Ù<|œ>ÔÉä»ÝGúúnI÷qä'ËäG+~>¸ë&úÈ׿yò%íú*óxßsGúŒù–c6r²î±>ÇÅO‘üø‘ýÎo>ÔÏ–xµ\h3q»§OQ«³ù²-ðq?ŽC n”t>°èäG=¾ýÒ_edm>ý´§Ð¦5×´ë^ˆ»Õ[×ݺüL¼¸?ë´§€»+»N9òñÍÀã·^¿ ×W:ñíMÝgN÷‰ÔIä'úˆÐqÏô¶’_ŸîyÔOx´Oá~Ú[ç#G r&ËÜò?XàÑê…^ÔÛpúdá¦Ût¾qé÷1®‰8êîé'ø‘>âc<Á¯lÅGàW´™:º™>¸;ý–;‘Ãþƒß +~øíÏÛ8Æ—Z3Bÿ]û÷¼ÄÓI¿îÿ¯Z ~"îþ¹»ŽaËAk€GâùG«¶B'üþÚÔÆ•¸wû¼ +Üoí>c_òýÉÝGúȾ|„§/tž|„{Ë~}wïæS•sÖ/ç¶ô)Äsúxåg•>N:VïlÓG¿–‹x1݆ÏxpÆ5V/ðhõ¢ë“_è3©è3ÖQõûM¿^ʟ蓈{ý=È‘®:þ5øÖ÷ôùrÑ}mž-Ǿeˆç­kê|kgòÝgß<^|_›‚tL¸ßwÆ5WO¼¾uÛö¦sI÷©¯ÓWümݧÏ–£éÐ'GŽæË~N|ËÜíê>žx<à‘SÛ¸“ˆ;Ë1Ûè•>Y¸å .Ÿ"Ür G?øŒù¦Ûø<²>•|Ô <ÒGü@~áx¦I}úD♼È~Ò©wù8]—Í_»¯å8ï?Í?ÝuõsÈÞ¿öY´õлÚï±ÜÙñôÁW_jß[‹¼•¸ŸuW»Oó^kŸî©“L|ÿ¹5Kp}ñrâ•í9Ý}¨ûäúŒu,GÓ¡øž<ù(›Öu3}„—ýþC|Ç<Þø­úDâ™uÊgÌ·àËGãƒüÀËôi—c\3Ç9€Ëg’è#\ã>n©#ž|”Sº‰>ùë!{Üßr¬Ù·ù»…+þõ¿ÃV·:µ-ïòuŸiý72Fݱ²“¿¿ãÎtþü†¥Ðü½ܽÑ}ÂýÝ·ÎèüHêKß…~¤~a›ö©m~˳zOŸ"ËÑôÍ-pèèO>åÐù‹‘+îì¹åãG›¾Ü«Nù0OÖ¸X?útiŽc~çåËàWé[ß}·]ßDŸNÆï {5ýÙ« ¾ÒOôÁ8 ã +¾çõÒ¸ôðñß±Ów»½ýšÏÄý[ˆãw6²Îø=ƒWÅçï¾ðþuö{nßë~Ü¿À§ºwãÓ'ÙýÜQ÷Íý‰{òt?âþßó¾Þ¿MZö'¾êŠüýêÖ•Y'ê…od]È=ôŽû±éó¾Òý«qˆ÷¯Æ 9Ð/Ñ'iœ¥¯–x$o|ß Ÿ¸“Ý¿M—÷oÌ¿À5ÿοÕþÿo|Îwš„O5ÿ6>çSÇù×Û¼ \ó¢æ_áabþ•~æ¼8ÿ:êh^Lì'¾æEÌG#óÿÄß$_óê?)çÄüåËùýÀ/ŸÈqοªmÔ<¯ñ$?ÒGùÇóîÄøkÜå£<ºÃù~á¼Qûÿyøü ÜñùÏ“-Ÿ=µ–Ï«xžÄçH|ªçg|ïùœZßÜ8~~®ççÌçOׯ2×O +ñÊu­£`ý|¬·Œ{°~ÖÁ;ú(ã¸}˜³JŸm&ž˜Gý¤/Ýáú3üâ_þÛÖ'÷’í_ Sì5þûG?ÅþQãÿÿh_Ô¨ï'ö¼|É/ܯ?Nì ŸÜ?’Žö¥´ä¨ý£v}é#ÃÃgxø Ÿ÷øæ3™õgxÊ>œ<¼¯Ë{|j¯¡âWŸ˜OÌ'æ/íW~|âcïO\ýãó‰×ö‰ùħޟ˜OÌ'®ùeâZ +/UÇçàøÄúá}]ƒÙŸ<ÛŸa>õ»nû3q>Å—m&^ùögø¸wýíÏ0ŸÆ[·ý™øm;ïáÓvÞÃ|êÏ'®ùÅ'®õ+<¼y>U°}æsÄó¹x_W~|jç_Û'æ/íW~|b>qõOÌ'^Û'¾µOÌ'æó‰—ö‰«N±îòŸƒ÷WçvÄã×`¼ËUó)ŸOÌ'^¶óžqø?nç=q>ÅùÄëvޓϧøi;ï‰ó)Î'®ù½Þ¸þ™b|ŽO\ýò|Ç•Ÿ¸‹Oìsð¾.?ïžç£O¼´O\ùÙŸøØ>1ŸøÒÏw¼¶O|ëý‰Oíó‰¯ý|Ç5¿øĵ”ëºôþŸ˜O\ùñ‰k°øÄ|bŸ‹÷5ŸÚ—ö‰«ŽOÌ'æ_Ú'^Û'¾µOÌ'æ_Û'®ùÅ'®õßËî{Ÿu]ú{æW<>q Ÿ˜OÌ'~™G¾võâþìxåßïÏf>åW}¿?­§}Š¯îÏŽßÜŸÍ|Ê_úû'æ×üâ×úS–žwùyó|þgb>qåÇ'>´OÌ'æ—Ÿœwl^x_W~|jçWÿøÄ—ö‰×ö‰oíó‰—ö‰ùÄUÇ'>t1ÏËvÞ3ïbç=ÌçÈwÞïûf;ïò_=GøÔ¿êøÄ|bóÄûšOí|b>ñº÷Ìï¶÷0ŸòùÄ|⚟óný1j^—ö98>ñÚÏ#\ùñ‰k°œw\ùñ‰ùÄ5¯øÄ|âšo~obëÀûšOí|âµ}â[ûħ~a>1Ÿ¸æŸ¸Ö/}NÊOλyÇ'^Û'®x|â,>qåÇ'æ_Û'®:¿ßñ²ÝŸ9Ç•ß=ß—ul÷¦û35ŸÆ[·û3ñÛv†OíSþ²ÝŸ‰óùßîÏÄï2ë=Hß3å'>Ç'æW~|b>1Ÿøä}Èî¹+^ó¼¿ÙÝ{â|b>±uâ}ͧv>1Ÿ˜O|õ>d›_ö§8Ÿ/ŸÓ>Ç'æó‰½?1ŸøÔ>qùÉyÇ|â¥÷'æó‰ùÄÖ‰÷5ŸÚùÄ|b>ñÒûº÷Ò>Ç'æW~ö'®árÞ1Ÿ˜O|mŸ˜O¼´O\ù¯ž#|Šó‰ùÄkŸw¼¯ùÔÎ'æ×ü²?q­?Å8—ö98>ñê÷Qß3•Ÿâ5X|âÊÏý‰ùÄ×ö‰ùÄKûÄ•ÿê9|ôûhwïÉç¯íßúþÄûšOí|âš_|âZŠ~å'÷çàøÄkûÄ•Ÿ¸‹O\ùñ‰ùÄå'çúþÄKûÄ•ŸøØ>ñÁ÷OïÝsÍkû”kŸ˜¼¯ù|ioŸ82ë¼òŸƒãó‰+?>q Ÿ˜O|êû—Ÿøćö‰—ö‰+?>1Ÿ¸ú¿z_<÷ú9²¶Où·ö‰ùÄ<á}]óËþÔ^>Îý~®Tä=ɇ“«é:ùøøøÉäÛÓÓÓäïóÉÿrr÷õäòýÍäÿ»ÉÕ?ß?Ÿçö\*þÃŒWÓëï)çóÏ3^ãÿ:¹ÆËÿwd°ûxÌx5åÿ7Äk=Ïx÷ïäá/^+Î_¸Æá/<ü…‡¿ðð'Î_¸Æã/<ü…‡?ýùç/\ãñ®Ïç/<ü…‡¿p}á¿ððþÞð}v‹kmR  w UVIndexi  j x-Õs´ççEá;¶'ÖĶ=±mOlÛÛöÄ6ë©m·I;µÝ¤nzžæܵÎúìwÿ¹ßµîÀÀÀÀ lîl®òàÜyêðlÞ:<4›¯Ëæ¯ÃóêðˆlÁ:<2[¨Ê®Ã£³Eêð˜lZÆá±Ù¢Ù´ò¸ÜÅ2ÏÏ8–qX»gÖûdÆaí>•qX»OgÖî3‡uúlÆa>—qX§ÏgÖé ‡uúbÆa¾”qX§/gÖé+‡µûjÆi¦Ý׳¯•uúFž}3ã°NßÊ8¬Ó·3ëôŒÃ:}7ã°NßË8¬Ó÷3ëôfÆaÞÊ8¬Ó2ëôÃŒÃ:ÍÉ8¬Ó²9e~œqX§ŸdÖ駇uúYÆaí~žqši÷Ëìe~U‡uúuÖé7uX§ßÖa~W‡uú}ÖéuX§?ÖaþT‡uúsÖé/uX§¿Öá9ÙÛ‡uz'ã°NË8¬Óß3ëôŒÃ:ý3ã°vÿÊ8Í´ûOöï²vÿ­ÃÚ½[‡µôžÃÚ Ê›ÃÚ sX»!ak74Ìa톅9¬Ýð0‡µæ°v#ÃÖiT˜Ã:sX§1aë46ÌaÆ…9¬Óø0‡ušæ°vÃœfÚMOÊ°vSÂÖnj˜Ã:Í•qX§¹3ë4OÆaæÍ8¬Ó|‡uš?ã°N dÖiÁŒÃ:-”qX§…3ë´HÆa¦eÖiÑŒÃ:-–qX§Å3ë´DÆaí–Ì8ÍtZ:[ª¬Ó2uX§eë°NËÕa–¯Ã:­P‡uZ±ë´RÖiå:¬Ó*uX§Uë°N«ÕaV¯Ã:­Q‡uZ³ë´VÖií:¬Ó:uX§uë°vëÕi¦ÝÙúeí6¬ÃÚmT‡µÛ¸k7½k·IÖnÓ:¬ÝfuX»Íë°v[Ôaí¶¬ÃÚmU‡µÛºk·MÖnÛ:¬ÝvuX»íë°v;Ôaív¬ÃÚíT§™v»d;—µÛµk·[Ön÷:¬ÝuX»=ë°v{Õaíö®ÃÚíS‡µÛ·k·_Önÿ:¬ÝuX»ë°vÕaífÔaí®ÃÚR‡µ;´kwXfÚ‘^ÖîÈ:¬ÝQuX»£ë°vÇÔa펭ÃÚW‡µ;¾kwBÖîÄ:¬ÝIuX»“ë°v§ÔaíN­ÃÚV‡µ;½kwFÖîÌ:¬ÝYuX»³ë4ÓîÜ윲vçÕaíίÃÚ]P‡µ»°k7³kwQÖîâ:¬Ý%uX»Kë°v—Õaí.¯ÃÚ]Q‡µ»²kwUÖîê:¬Ý5uX»kë°v×Õaí®¯Ëùÿß Áïý;¸1<$ì}Sxh®÷Íáa¹Þ·„‡çzß‘ë}[xd®÷íáQ¹Þw„Gçzß“ë}Wxl®÷Ýáq¹Þ÷„Ççzßžë}_xb®÷ýáI¹Þ„'çzÏ +OÉõ~0<5×û¡°oÄ·òp¯ïä‘Ìõ<Úëûx,s}÷ú.žÈ\ßÄ“½¾‡§2×·ðt¯ïà™Ìõ <Ûë÷.sýöÏ÷úÝ_È\¿ù‹½~ï—2×oýr¯ßù•Ìõ¿Úë÷}-û§—] iS   LayerElementMaterialI ¹R   VersionIe ÏR   NameS þR  MappingInformationTypeS AllSame5S   ReferenceInformationTypeS IndexToDirect\S   Materialsi  âT   LayerI ™S   VersionId T LayerElementÚS   TypeS LayerElementNormalöS   +TypedIndexI oT LayerElementFT   TypeS LayerElementMaterialbT   +TypedIndexI ÕT LayerElement¬T   TypeS LayerElementUVÈT   +TypedIndexI S]  ! GeometryLÐÂ* S + GeometryS Mesh¿U  … Verticesd x àúœ> Éù¿ É À É À Éù¿ `§´’¾ `§´‚¾ Éù¿ É @ É @ Éù¿ Éù? +V  M PolygonVertexIndexi @   þÿÿÿ  ûÿÿÿ  ûÿÿÿ  ûÿÿÿ ûÿÿÿjV  - Edgesi       ‹V   GeometryVersionI| óX   LayerElementNormalI ÈV   VersionIe ÞV   NameS W   MappingInformationTypeS ByPolygonVertexEW  ReferenceInformationTypeS DirectæX   Normalsd0 € àÿÿï¿ @Ä.Y> àÿÿï¿ @Ä.Y> ð¿ Ä.Y> ð¿ Ä.Y> §yâ¿ @§yâ? `§yâ¿ §yâ¿ @§yâ? `§yâ¿ §yâ¿ @§yâ? `§yâ¿ @§yâ¿ @§yâ? §yâ? @§yâ¿ @§yâ? §yâ? @§yâ¿ @§yâ? §yâ? @§yâ? §yâ? @§yâ? @§yâ? §yâ? @§yâ? @§yâ? §yâ? @§yâ? @§yâ? `§yâ? §yâ¿ @§yâ? `§yâ? §yâ¿ @§yâ? €§yâ? §yâ¿ ÞZ   LayerElementUVI ,Y   VersionIe FY  NameS map1}Y   MappingInformationTypeS ByPolygonVertex´Y   ReferenceInformationTypeS IndexToDirectpZ  ­ UVd   à? Ð? àÿÿÏ? à? à? è? Ð? Ð? à? Ø? à? à? à? ä? à? è? à? à? ð?ÑZ  M UVIndexi @            Í[   LayerElementMaterialI [   VersionIe 3[   NameS b[  MappingInformationTypeS AllSame™[   ReferenceInformationTypeS IndexToDirectÀ[   Materialsi  F]   LayerI ý[   VersionId g\ LayerElement>\   TypeS LayerElementNormalZ\   +TypedIndexI Ó\ LayerElementª\   TypeS LayerElementMaterialÆ\   +TypedIndexI 9] LayerElement]   TypeS LayerElementUV,]   +TypedIndexI ^  & NodeAttributeL $ƒ S NodeAttributeS Nullè] Properties70Û]  ! PS LookS enumS S I ^  TypeFlagsS Null u`  $ ModelL0öq* S pCube1 ModelS Meshc^   VersionIè /` Properties70µ^  + PS RotationActiveS boolS S I ë^  ( PS InheritTypeS enumS S I @_  G PS + ScalingMaxS Vector3DS VectorS D D D †_  8 PS DefaultAttributeIndexS intS IntegerS I ã_  O PS Lcl TranslationS Lcl TranslationS S A+DF  e:׿D +t%ˆ±@D`ð¾d¯Mþ?"`  1 PS currentUVSetS KStringS S US map1 E`   ShadingCTh`   CullingS + CullingOff Ùb  ( ModelL@ÿq* S pCylinder1 ModelS MeshÈ`   VersionIè “b Properties70a  + PS RotationActiveS boolS S I Pa  ( PS InheritTypeS enumS S I ¥a  G PS + ScalingMaxS Vector3DS VectorS D D D ëa  8 PS DefaultAttributeIndexS intS IntegerS I Gb  N PS Lcl TranslationS Lcl TranslationS S ADÜÿ¨}@D m¥æ\& @DØE‘…¾@†b  1 PS currentUVSetS KStringS S US map1 ©b   ShadingCTÌb   CullingS + CullingOff äe  % ModelLPr* S pPlane1 ModelS Mesh)c   VersionIè že Properties70{c  + PS RotationActiveS boolS S I ±c  ( PS InheritTypeS enumS S I d  G PS + ScalingMaxS Vector3DS VectorS D D D Ld  8 PS DefaultAttributeIndexS intS IntegerS I ¨d  N PS Lcl TranslationS Lcl TranslationS S AD D DÓF¥û1!@þd  H PS Lcl RotationS Lcl RotationS S AD €V@D D Re  F PS Lcl ScalingS Lcl ScalingS S ADøôO^z @DøôO^z @DøôO^z @‘e  1 PS currentUVSetS KStringS S US map1 ´e   ShadingCT×e   CullingS + CullingOff ïh  % ModelL`r* S pPlane2 ModelS Mesh4f   VersionIè ©h Properties70†f  + PS RotationActiveS boolS S I ¼f  ( PS InheritTypeS enumS S I g  G PS + ScalingMaxS Vector3DS VectorS D D D Wg  8 PS DefaultAttributeIndexS intS IntegerS I ³g  N PS Lcl TranslationS Lcl TranslationS S AD D D3â؈©"@ h  H PS Lcl RotationS Lcl RotationS S AD €V@D D ]h  F PS Lcl ScalingS Lcl ScalingS S ADøôO^z @DøôO^z @DøôO^z @œh  1 PS currentUVSetS KStringS S US map1 ¿h   ShadingCTâh   CullingS + CullingOff úk  % ModelLpr* S pPlane3 ModelS Mesh?i   VersionIè ´k Properties70‘i  + PS RotationActiveS boolS S I Çi  ( PS InheritTypeS enumS S I j  G PS + ScalingMaxS Vector3DS VectorS D D D bj  8 PS DefaultAttributeIndexS intS IntegerS I ¾j  N PS Lcl TranslationS Lcl TranslationS S AD D D™ç` $@k  H PS Lcl RotationS Lcl RotationS S AD €V@D D hk  F PS Lcl ScalingS Lcl ScalingS S ADøôO^z @DøôO^z @DøôO^z @§k  1 PS currentUVSetS KStringS S US map1 Êk   ShadingCTík   CullingS + CullingOff o  % ModelL€#r* S pPlane4 ModelS MeshJl   VersionIè ¿n Properties70œl  + PS RotationActiveS boolS S I Òl  ( PS InheritTypeS enumS S I 'm  G PS + ScalingMaxS Vector3DS VectorS D D D mm  8 PS DefaultAttributeIndexS intS IntegerS I Ém  N PS Lcl TranslationS Lcl TranslationS S AD D D0«&öyP&@n  H PS Lcl RotationS Lcl RotationS S AD €V@D D sn  F PS Lcl ScalingS Lcl ScalingS S ADøôO^z @DøôO^z @DøôO^z @²n  1 PS currentUVSetS KStringS S US map1 Õn   ShadingCTøn   CullingS + CullingOff r  % ModelL,r* S pPlane5 ModelS MeshUo   VersionIè Êq Properties70§o  + PS RotationActiveS boolS S I Ýo  ( PS InheritTypeS enumS S I 2p  G PS + ScalingMaxS Vector3DS VectorS D D D xp  8 PS DefaultAttributeIndexS intS IntegerS I Ôp  N PS Lcl TranslationS Lcl TranslationS S AD D Dhܲ ™%@*q  H PS Lcl RotationS Lcl RotationS S AD €V@D D ~q  F PS Lcl ScalingS Lcl ScalingS S ADøôO^z @DøôO^z @DøôO^z @½q  1 PS currentUVSetS KStringS S US map1 àq   ShadingCTr   CullingS + CullingOff àt  & ModelL 5r* S persp1 ModelS Cameraar   VersionIè št Properties70Ñr  I PS PostRotationS Vector3DS VectorS D D €VÀD +s  + PS RotationActiveS boolS S I @s  ( PS InheritTypeS enumS S I •s  G PS + ScalingMaxS Vector3DS VectorS D D D Ûs  8 PS DefaultAttributeIndexS intS IntegerS I 7t  N PS Lcl TranslationS Lcl TranslationS S AD D @D O}hb*@t  H PS Lcl RotationS Lcl RotationS S AD D €f@D €f@ °t   ShadingCYÓt   CullingS + CullingOff kx  0 ModelL°>r* S directionalLight1 ModelS Light;u   VersionIè %x Properties70­u  K PS RotationOffsetS Vector3DS VectorS D’™h 3ÚÄZÀD»!ïR/@D ’_Jú?³‰  1 PS currentUVSetS KStringS S US map1 Ö‰   ShadingCTù‰   CullingS + CullingOff iŒ  ' ModelLpÜ* S pPyramid1 ModelS MeshXŠ   VersionIè #Œ Properties70ªŠ  + PS RotationActiveS boolS S I àŠ  ( PS InheritTypeS enumS S I 5‹  G PS + ScalingMaxS Vector3DS VectorS D D D {‹  8 PS DefaultAttributeIndexS intS IntegerS I ׋  N PS Lcl TranslationS Lcl TranslationS S AD4xªK‡Ã)ÀD?âfœú@DÌå"ó +@Œ  1 PS currentUVSetS KStringS S US map1 9Œ   ShadingCT\Œ   CullingS + CullingOff 2Ž  ( ModelL€"Ü* S transform1 ModelS Null¼Œ   VersionIè ì Properties70  + PS RotationActiveS boolS S I D  ( PS InheritTypeS enumS S I ™  G PS + ScalingMaxS Vector3DS VectorS D D D ß  8 PS DefaultAttributeIndexS intS IntegerS I Ž   ShadingCY%Ž   CullingS + CullingOff º’  * MaterialLH„ S normalMapTest MaterialS ŠŽ   VersionIf ­Ž  + ShadingModelS phongÉŽ   +MultiLayerI ­’ Properties701  A PS AmbientColorS ColorS S AD D D €  A PS DiffuseColorS ColorS S AD à?D à?D à?¿  1 PS DiffuseFactorS NumberS S AD  ™™é?  6 PS TransparencyFactorS NumberS S AD ð?S  B PS SpecularColorS ColorS S AD à?D à?D à?•  4 PS ReflectionFactorS NumberS S AD à?è  E PS EmissiveS Vector3DS VectorS D D D :‘  D PS AmbientS Vector3DS VectorS D D D Œ‘  D PS DiffuseS Vector3DS VectorS D  ™™Ù?D  ™™Ù?D  ™™Ù?ß‘  E PS SpecularS Vector3DS VectorS D à?D à?D à?’  2 PS ShininessS doubleS NumberS D 4@]’  0 PS OpacityS doubleS NumberS D ð? ’  5 PS ReflectivityS doubleS NumberS D ו  % MaterialLð{”ƒ S lambert1 MaterialS “   VersionIf 2“  ShadingModelS lambertN“   +MultiLayerI Ê• Properties70¶“  A PS AmbientColorS ColorS S AD D D ”  A PS DiffuseColorS ColorS S AD à?D à?D à?D”  1 PS DiffuseFactorS NumberS S AD  ™™é?ˆ”  6 PS TransparencyFactorS NumberS S AD ð?Û”  E PS EmissiveS Vector3DS VectorS D D D -•  D PS AmbientS Vector3DS VectorS D D D •  D PS DiffuseS Vector3DS VectorS D  ™™Ù?D  ™™Ù?D  ™™Ù?½•  0 PS OpacityS doubleS NumberS D ð? óš  ( MaterialLp„ S transparent MaterialS -–   VersionIf P–  + ShadingModelS phongl–   +MultiLayerI æš Properties70Ô–  A PS AmbientColorS ColorS S AD D D #—  A PS DiffuseColorS ColorS S AD à?D à?D à?b—  1 PS DiffuseFactorS NumberS S AD  ©?µ—  E PS TransparentColorS ColorS S AD ÷*è?D ÷*è?D ÷*è?ù—  6 PS TransparencyFactorS NumberS S AD ð?I˜  B PS SpecularColorS ColorS S AD à?D à?D à?Œ˜  5 PS ShininessExponentS NumberS S AD§|ªF?@Θ  4 PS ReflectionFactorS NumberS S AD à?!™  E PS EmissiveS Vector3DS VectorS D D D s™  D PS AmbientS Vector3DS VectorS D D D Å™  D PS DiffuseS Vector3DS VectorS D  ™?D  ™?D  ™?š  E PS SpecularS Vector3DS VectorS D à?D à?D à?Xš  2 PS ShininessS doubleS NumberS D§|ªF?@–š  0 PS OpacityS doubleS NumberS D $TÏ?Ùš  5 PS ReflectivityS doubleS NumberS D    ' MaterialLÐD„ S glasGreen1 MaterialS H›   VersionIf k›  + ShadingModelS phong‡›   +MultiLayerI   Properties70ï›  A PS AmbientColorS ColorS S AD D D >œ  A PS DiffuseColorS ColorS S AD D D }œ  1 PS DiffuseFactorS NumberS S AD  ™™é?Ðœ  E PS TransparentColorS ColorS S AD D ð?D   6 PS TransparencyFactorS NumberS S AD ð?d  B PS SpecularColorS ColorS S AD à?D à?D à?§  5 PS ShininessExponentS NumberS S AD§|ªF?@é  4 PS ReflectionFactorS NumberS S AD à?<ž  E PS EmissiveS Vector3DS VectorS D D D Žž  D PS AmbientS Vector3DS VectorS D D D àž  D PS DiffuseS Vector3DS VectorS D D D 3Ÿ  E PS SpecularS Vector3DS VectorS D à?D à?D à?sŸ  2 PS ShininessS doubleS NumberS D§|ªF?@±Ÿ  0 PS OpacityS doubleS NumberS DVUUUUUå?ôŸ  5 PS ReflectivityS doubleS NumberS D &¥  $ MaterialLPL„ S glasRed MaterialS `    VersionIf ƒ   + ShadingModelS phongŸ    +MultiLayerI ¥ Properties70¡  A PS AmbientColorS ColorS S AD D D V¡  A PS DiffuseColorS ColorS S AD D D •¡  1 PS DiffuseFactorS NumberS S AD  ™™é?è¡  E PS TransparentColorS ColorS S AD ð?D D ,¢  6 PS TransparencyFactorS NumberS S AD ð?|¢  B PS SpecularColorS ColorS S AD à?D à?D à?¿¢  5 PS ShininessExponentS NumberS S AD§|ªF?@£  4 PS ReflectionFactorS NumberS S AD à?T£  E PS EmissiveS Vector3DS VectorS D D D ¦£  D PS AmbientS Vector3DS VectorS D D D ø£  D PS DiffuseS Vector3DS VectorS D D D K¤  E PS SpecularS Vector3DS VectorS D à?D à?D à?‹¤  2 PS ShininessS doubleS NumberS D§|ªF?@ɤ  0 PS OpacityS doubleS NumberS DVUUUUUå? ¥  5 PS ReflectivityS doubleS NumberS D î©  ' MaterialL0N„ S glaseBlack MaterialS {¥   VersionIf ž¥  + ShadingModelS phongº¥   +MultiLayerI á© Properties70"¦  A PS AmbientColorS ColorS S AD D D q¦  A PS DiffuseColorS ColorS S AD D D °¦  1 PS DiffuseFactorS NumberS S AD  ™™é?ô¦  6 PS TransparencyFactorS NumberS S AD ð?D§  B PS SpecularColorS ColorS S AD à?D à?D à?‡§  5 PS ShininessExponentS NumberS S AD§|ªF?@ɧ  4 PS ReflectionFactorS NumberS S AD à?¨  E PS EmissiveS Vector3DS VectorS D D D n¨  D PS AmbientS Vector3DS VectorS D D D À¨  D PS DiffuseS Vector3DS VectorS D D D ©  E PS SpecularS Vector3DS VectorS D à?D à?D à?S©  2 PS ShininessS doubleS NumberS D§|ªF?@‘©  0 PS OpacityS doubleS NumberS D ð?Ô©  5 PS ReflectivityS doubleS NumberS D ¯  % MaterialLP„ S glasBlue MaterialS Aª   VersionIf dª  + ShadingModelS phong€ª   +MultiLayerI ú® Properties70èª  A PS AmbientColorS ColorS S AD D D 7«  A PS DiffuseColorS ColorS S AD D D v«  1 PS DiffuseFactorS NumberS S AD  ™™é?É«  E PS TransparentColorS ColorS S AD D D ð? ¬  6 PS TransparencyFactorS NumberS S AD ð?]¬  B PS SpecularColorS ColorS S AD à?D à?D à? ¬  5 PS ShininessExponentS NumberS S AD§|ªF?@⬠ 4 PS ReflectionFactorS NumberS S AD à?5­  E PS EmissiveS Vector3DS VectorS D D D ‡­  D PS AmbientS Vector3DS VectorS D D D Ù­  D PS DiffuseS Vector3DS VectorS D D D ,®  E PS SpecularS Vector3DS VectorS D à?D à?D à?l®  2 PS ShininessS doubleS NumberS D§|ªF?@ª®  0 PS OpacityS doubleS NumberS DVUUUUUå?í®  5 PS ReflectivityS doubleS NumberS D <°  ) MaterialL …` S emissiveTest MaterialS ^¯   VersionIf ƒ¯  ShadingModelS unknownŸ¯   +MultiLayerI /° Properties70æ¯  PS MayaS CompoundS S "°  . PS Maya|TypeIdS intS IntegerS IÀÊ µ  ) MaterialLðQ„ S specularTest MaterialS “°   VersionIf ¶°  + ShadingModelS phongÒ°   +MultiLayerI ù´ Properties70:±  A PS AmbientColorS ColorS S AD D D ‰±  A PS DiffuseColorS ColorS S AD D D ȱ  1 PS DiffuseFactorS NumberS S AD  ™™é? ²  6 PS TransparencyFactorS NumberS S AD ð?\²  B PS SpecularColorS ColorS S AD "Ãí?D "Ãí?D "Ãí?Ÿ²  5 PS ShininessExponentS NumberS S AD§|ªF?@á²  4 PS ReflectionFactorS NumberS S AD àÖøë?4³  E PS EmissiveS Vector3DS VectorS D D D †³  D PS AmbientS Vector3DS VectorS D D D س  D PS DiffuseS Vector3DS VectorS D D D +´  E PS SpecularS Vector3DS VectorS D "Ãí?D "Ãí?D "Ãí?k´  2 PS ShininessS doubleS NumberS D§|ªF?@©´  0 PS OpacityS doubleS NumberS D ð?ì´  5 PS ReflectivityS doubleS NumberS D ü¶  # VideoLÀ˜ƒ S file2 VideoS ClipUµ  TypeS Clip¶ Properties70¶  ‡ PS PathS KStringS XRefUrlS S\ C:/Users/Destranix/Documents/maya/projects/Test/images/Tardis_Displacement/Wood_007_ROUGH.tx +¶   UseMipMapI ¡¶  a FilenameS\ C:/Users/Destranix/Documents/maya/projects/Test/images/Tardis_Displacement/Wood_007_ROUGH.txï¶  1 RelativeFilenameS, resources\textures\Tardis_Displacement\Wood_007_ROUGH.tx º  ! TextureL#„ S file2 TextureS W·   TypeS TextureVideoClipp·   VersionIÊ ›·   TextureNameS file2 Texturep¸ Properties70ö·  4 PS CurrentTextureBlendModeS enumS S I -¸  ) PS UVSetS KStringS S S map1c¸  ( PS UseMaterialS boolS S I “¸   MediaS file2 Video ¹  a FileNameS\ C:/Users/Destranix/Documents/maya/projects/Test/images/Tardis_Displacement/Wood_007_ROUGH.txW¹  1 RelativeFilenameS, resources\textures\Tardis_Displacement\Wood_007_ROUGH.txˆ¹   ModelUVTranslationD D µ¹   ModelUVScalingD ð?D ð?ß¹  Texture_Alpha_SourceS Noneº   CroppingI I I I Î  > ImplementationL´v* S+ emissiveTest_Implementation ImplementationS ‡º   VersionId Î Properties70ߺ  1 PS ShaderLanguageS KStringS S S SFX$»  7 PS ShaderLanguageVersionS KStringS S S 28[»  ) PS RenderAPIS KStringS S S œ»  3 PS RootBindingNameS KStringS S S rootøÍ  ( PS ShaderGraphS BlobS S Iý ëÍ   +BinaryDataRý SFX_WIN +Version=28 +GroupVersion=-1.000000 +Advanced=0 +HelpID=0 +ParentMaterial=0 +NumberOfNodes=5 +#NT=10100 1 Hw Material Base-Hw Shader Nodes-Core + PC=35 + name=1 v=5000 _Material + version=1 v=2003 1.842000 + posx=1 v=2003 10.000000 + posy=1 v=2003 10.000000 + classname=1 v=5000 Hw Material Base + submenuname=1 v=5000 Core + bitmapnodeindex=1 v=2002 10 + isadvanced=1 v=2001 1 + advanceddelete=1 v=2001 1 + helpid=1 v=2002 73 + grpnodecolor=1 v=5012 4 + grpPosX=1 v=2003 -1129.380005 + grpPosY=1 v=2003 -143.923004 + disableconsolidation_HwShader=2 e=1 v=2001 0 + value_ClampDynamicLights=2 e=1 v=2002 99 + value_MaxNumberLights=2 e=1 v=2002 3 + value_Gamma=2 e=2 v=2001 0 + value_Wireframe=2 e=3 v=2001 0 + value_DepthTest=2 e=4 v=2001 1 + value_DepthWrite=2 e=4 v=2001 1 + value_CastShadow=2 e=5 v=2001 1 + value_SurfaceMaskCutoff=2 e=6 v=2003 0.000000 + value_SSAO=2 e=7 v=2001 1 + options_Tessellation=2 e=900 v=5012 0 + value_FlatTessellationBlend=2 e=901 v=2003 0.000000 + value_BoundingBoxMultiplier=2 e=902 v=2003 1.000000 + value_ClippingBiasAdd=2 e=902 v=2003 5.000000 + options_Displacement=2 e=1000 v=5012 1 + options_VDM_CoordSys=2 e=1001 v=5012 1 + value_DisplacementMultiplier=2 e=1002 v=2003 1.000000 + value_DisplacementOffset=2 e=1003 v=2003 0.000000 + cgfxprofile_HwShader=2 e=1999 v=5012 0 + config_HwShader=2 e=2000 v=5012 1 + shadername_HwShader=2 e=2001 v=5000 + saveshadertodisk_HwShader=2 e=2002 v=5015 + group=-1 + ISC=9 + SVT=2002 2002 0 0 0 _NumberOfLights + SVT=5001 3002 0 0 0 _ObjectVertexPosition + SVT=5001 2003 0 0 0 + SVT=5001 3002 0 0 0 _Displacement + SVT=5001 5018 0 0 0 _SurfaceShader + SVT=5001 2003 0 0 0 _SurfaceMask + SVT=5001 2003 0 0 0 _SurfaceMaskCutoff + SVT=2001 2001 0 0 0 _Gamma + SVT=1001 1002 0 0 0 + OSC=0 +#NT=10100 1 Traditional Game Surface Shader-Hw Shader Nodes-Surface Shaders + PC=26 + name=1 v=5000 TraditionalGameSurfaceShader + version=1 v=2003 1.481000 + posx=1 v=2003 -200.000000 + posy=1 v=2003 10.000000 + previewswatch=1 v=2002 2 + classname=1 v=5000 Traditional Game Surface Shader + submenuname=1 v=5000 Surface Shaders + bitmapnodeindex=1 v=2002 10 + isadvanced=1 v=2001 1 + advanceddelete=1 v=2001 1 + helpid=1 v=2002 74 + grpnodecolor=1 v=5012 4 + grpPosX=1 v=2003 -990.607971 + grpPosY=1 v=2003 169.649994 + options_Diffuse=2 e=1 v=5012 0 + options_Specular=2 e=1 v=5012 0 + value_FlipBackFaces=2 e=1 v=2001 1 + value_TranslucencyDistortion=2 e=1100 v=2003 0.200000 + value_TranslucencyPower=2 e=1101 v=2003 3.000000 + value_TranslucencyMinimum=2 e=1102 v=2003 0.000000 + color_TranslucencyOuter=2 e=1104 v=3003 1.000000,0.640000,0.250000,1.000000 + color_TranslucencyMedium=2 e=1105 v=3003 1.000000,0.210000,0.140000,1.000000 + color_TranslucencyInner=2 e=1106 v=3003 0.250000,0.050000,0.020000,1.000000 + value_UseStreamLightData=2 e=1500 v=2001 0 + value_BakedLightColorSet=2 e=1502 v=5000 BakedLightColorSet + value_BakedLightColorSetUnshared=2 e=1503 v=2001 1 + group=-1 + ISC=17 + SVT=5001 2003 0 0 0 _Opacity + SVT=5001 3002 0 0 0 _Emissive + SVT=5001 2003 0 0 0 _AmbientOcclusion + SVT=5001 3002 0 0 0 _DiffuseColor + SVT=5001 2003 0 0 0 _SpecularPower + SVT=5001 3002 0 0 0 _SpecularColor + SVT=5001 3002 0 0 0 _Reflection + SVT=5001 2003 0 0 0 _ReflectionIntensity + SVT=5001 3002 0 0 0 _Normal + SVT=5001 3002 0 0 0 _ObjectThickness + SVT=5001 2003 0 0 0 _BlendedNormal + SVT=5001 2003 0 0 0 _BlendedNormalMask + SVT=5001 3002 0 0 0 _AnisotropicDirection + SVT=5001 3001 0 0 0 _AnisotropicSpread + SVT=5001 3002 0 0 0 _IBL + SVT=5001 2003 0 0 0 _Weight + SVT=1001 1002 0 0 0 + OSC=2 + SVT=5001 5018 0 _SurfaceShader + CC=1 + C=1 0 0 0 4 0 0 + CPC=0 + SVT=1001 1002 0 + CC=0 +#NT=20011 0 + PC=3 + posx=1 v=2003 -567.500000 + posy=1 v=2003 135.000000 + color=2 e=0 v=3003 0.159091,0.159091,0.159091,1.000000 + group=-1 + ISC=0 + OSC=6 + SVT=5001 3003 1 + CC=0 + SVT=5001 3002 2 + CC=1 + C=2 1 2 1 3 0 0 + CPC=0 + SVT=5001 2003 3 + CC=0 + SVT=5001 2003 4 + CC=0 + SVT=5001 2003 5 + CC=0 + SVT=5001 2003 6 + CC=0 +#NT=20011 0 + PC=3 + posx=1 v=2003 -490.500000 + posy=1 v=2003 -45.000000 + color=2 e=0 v=3003 0.462700,0.000000,0.839200,1.000000 + group=-1 + ISC=0 + OSC=6 + SVT=5001 3003 1 + CC=0 + SVT=5001 3002 2 + CC=1 + C=3 1 2 1 1 0 0 + CPC=0 + SVT=5001 2003 3 + CC=0 + SVT=5001 2003 4 + CC=0 + SVT=5001 2003 5 + CC=0 + SVT=5001 2003 6 + CC=0 +#NT=20011 0 + PC=3 + posx=1 v=2003 -537.305542 + posy=1 v=2003 315.972229 + color=2 e=0 v=3003 0.164773,0.164773,0.164773,1.000000 + group=-1 + ISC=0 + OSC=6 + SVT=5001 3003 1 + CC=0 + SVT=5001 3002 2 + CC=1 + C=4 1 2 1 5 0 0 + CPC=0 + SVT=5001 2003 3 + CC=0 + SVT=5001 2003 4 + CC=0 + SVT=5001 2003 5 + CC=0 + SVT=5001 2003 6 + CC=0 + Ï  ' BindingTableL0»˜– S root 1 BindingTableS kÎ   VersionId Ï Properties70ÀÎ  . PS + TargetNameS KStringS S S rootþÎ  0 PS + TargetTypeS KStringS S S shader ŠÐ  & AnimationStackL°B† S Take 001 AnimStackS }Ð Properties70°Ï  0 PS + LocalStartS KTimeS TimeS LR^´r íÏ  / PS LocalStopS KTimeS TimeS Lp6ŒÄ5 /Ð  4 PS ReferenceStartS KTimeS TimeS LR^´r pÐ  3 PS ReferenceStopS KTimeS TimeS Lp6ŒÄ5 ÙÐ  ' AnimationLayerLp k* S BaseLayer AnimLayerS ™Ñ  , AnimationCurveNodeL0C† S Visibility AnimCurveNodeS ŒÑ Properties70Ñ  4 PS d|VisibilityS + VisibilityS S AD ð? ­Ò  # AnimationCurveNodeL úB† S T AnimCurveNodeS  Ò Properties70)Ò  ' PS d|XS NumberS S ADF  e:׿^Ò  ' PS d|YS NumberS S AD +t%ˆ±@“Ò  ' PS d|ZS NumberS S AD`ð¾d¯Mþ? ÁÓ  # AnimationCurveNodeL€ÌB† S S AnimCurveNodeS ´Ó Properties70=Ó  ' PS d|XS NumberS S AD ð?rÓ  ' PS d|YS NumberS S AD ð?§Ó  ' PS d|ZS NumberS S AD ð? ÕÔ  # AnimationCurveNodeL`ªB† S R AnimCurveNodeS ÈÔ Properties70QÔ  ' PS d|XS NumberS S AD †Ô  ' PS d|YS NumberS S AD »Ô  ' PS d|ZS NumberS S AD 5Ö   AnimationCurveLà` S AnimCurveS +Õ  DefaultD CÕ   KeyVerI© lÕ   KeyTimel  R^´r —Õ   KeyValueFloatf  €?ÁÕ   KeyAttrFlagsi   ûÕ   KeyAttrDataFloatf    (Ö   KeyAttrRefCounti   •×   AnimationCurveLà†` S AnimCurveS ‹Ö  DefaultD £Ö   KeyVerI© ÌÖ   KeyTimel  R^´r ÷Ö   KeyValueFloatf  -Ó¹¾!×   KeyAttrFlagsi  a [×   KeyAttrDataFloatf    ˆ×   KeyAttrRefCounti   õØ   AnimationCurveL Š` S AnimCurveS ë×  DefaultD Ø   KeyVerI© ,Ø   KeyTimel  R^´r WØ   KeyValueFloatf  Œ}@Ø   KeyAttrFlagsi  a »Ø   KeyAttrDataFloatf    èØ   KeyAttrRefCounti   UÚ   AnimationCurveLà‹` S AnimCurveS KÙ  DefaultD cÙ   KeyVerI© ŒÙ   KeyTimel  R^´r ·Ù   KeyValueFloatf  {mò?áÙ   KeyAttrFlagsi  a Ú   KeyAttrDataFloatf    HÚ   KeyAttrRefCounti   µÛ   AnimationCurveL€‘` S AnimCurveS «Ú  DefaultD ÃÚ   KeyVerI© ìÚ   KeyTimel  R^´r Û   KeyValueFloatf  €?AÛ   KeyAttrFlagsi  a {Û   KeyAttrDataFloatf    ¨Û   KeyAttrRefCounti   Ý   AnimationCurveL ƒ` S AnimCurveS Ü  DefaultD #Ü   KeyVerI© LÜ   KeyTimel  R^´r wÜ   KeyValueFloatf  €?¡Ü   KeyAttrFlagsi  a ÛÜ   KeyAttrDataFloatf    Ý   KeyAttrRefCounti   uÞ   AnimationCurveLÀ~` S AnimCurveS kÝ  DefaultD ƒÝ   KeyVerI© ¬Ý   KeyTimel  R^´r ×Ý   KeyValueFloatf  €?Þ   KeyAttrFlagsi  a ;Þ   KeyAttrDataFloatf    hÞ   KeyAttrRefCounti   Õß   AnimationCurveL€‡` S AnimCurveS ËÞ  DefaultD ãÞ   KeyVerI© ß   KeyTimel  R^´r 7ß   KeyValueFloatf  aß   KeyAttrFlagsi  a ›ß   KeyAttrDataFloatf    Èß   KeyAttrRefCounti   5á   AnimationCurveL€–` S AnimCurveS +à  DefaultD Cà   KeyVerI© là   KeyTimel  R^´r —à   KeyValueFloatf  Áà   KeyAttrFlagsi  a ûà   KeyAttrDataFloatf    (á   KeyAttrRefCounti   •â   AnimationCurveL`“` S AnimCurveS ‹á  DefaultD £á   KeyVerI© Ìá   KeyTimel  R^´r ÷á   KeyValueFloatf  !â   KeyAttrFlagsi  a [â   KeyAttrDataFloatf    ˆâ   KeyAttrRefCounti   Œð Connectionsáâ   CS OOL0öq* L ã   CS OOL@ÿq* L /ã   CS OOLPr* L Vã   CS OOL`r* L }ã   CS OOLpr* L ¤ã   CS OOL€#r* L Ëã   CS OOL,r* L òã   CS OOL 5r* L ä   CS OOL°>r* L @ä   CS OOLÀGr* L gä   CS OOL ìÛ* L Žä   CS OOL0õÛ* L µä   CS OOL@þÛ* L Üä   CS OOLPÜ* L å   CS OOL`Ü* L *å   CS OOLpÜ* L Qå   CS OOL€"Ü* L xå   CS OOLp k* L°B† Ÿå   CS OOL0C† Lp k* Æå   CS OOL úB† Lp k* íå   CS OOL€ÌB† Lp k* æ   CS OOL`ªB† Lp k* Iæ  ' CS OPL#„ LH„ S NormalMappæ   CS OOLÀ˜ƒ L#„ —æ   CS OOLÐü* L0öq* ¾æ   CS OOLH„ L0öq* ùæ  - CS OPL úB† L0öq* S Lcl Translation1ç  * CS OPL`ªB† L0öq* S Lcl Rotationhç  ) CS OPL€ÌB† L0öq* S Lcl Scalingžç  ( CS OPL0C† L0öq* S + VisibilityÅç   CS OOLÐÒ* L@ÿq* ìç   CS OOLð{”ƒ L@ÿq* è   CS OOLД* LPr* :è   CS OOLp„ LPr* aè   CS OOLЪ* L`r* ˆè   CS OOLp„ L`r* ¯è   CS OOLЬ* Lpr* Öè   CS OOLp„ Lpr* ýè   CS OOLИ* L€#r* $é   CS OOLp„ L€#r* Ké   CS OOLТ* L,r* ré   CS OOLp„ L,r* ™é   CS OOLpŒž_ L 5r* Àé   CS OOLðȱƒ L°>r* çé   CS OOLÐÞ* LÀGr* ê   CS OOLÐD„ LÀGr* 5ê   CS OOLPL„ LÀGr* \ê   CS OOL0N„ LÀGr* ƒê   CS OOLP„ LÀGr* ªê   CS OOLÐÄ* L ìÛ* Ñê   CS OOLÐD„ L ìÛ* øê   CS OOLPL„ L ìÛ* ë   CS OOL0N„ L ìÛ* Fë   CS OOLP„ L ìÛ* më   CS OOLÐœ* L0õÛ* ”ë   CS OOLÐD„ L0õÛ* »ë   CS OOLPL„ L0õÛ* âë   CS OOL0N„ L0õÛ* ì   CS OOLP„ L0õÛ* 0ì   CS OOLÐÐ* L@þÛ* Wì   CS OOLÐD„ L@þÛ* ~ì   CS OOLPL„ L@þÛ* ¥ì   CS OOL0N„ L@þÛ* Ìì   CS OOLP„ L@þÛ* óì   CS OOLм* LPÜ* í   CS OOLÐD„ LPÜ* Aí   CS OOLPL„ LPÜ* hí   CS OOL0N„ LPÜ* í   CS OOLP„ LPÜ* ¶í   CS OOL …` L´v* Ýí   CS OOL0»˜– L´v* î   CS OOLÐÎ* L`Ü* +î   CS OOL …` L`Ü* Rî   CS OOLÐÂ* LpÜ* yî   CS OOLðQ„ LpÜ*  î   CS OOL $ƒ L€"Ü* Øî  * CS OPLà` L0C† S d|Visibilityï  ! CS OPLà†` L úB† S d|X6ï  ! CS OPL Š` L úB† S d|Yeï  ! CS OPLà‹` L úB† S d|Z”ï  ! CS OPL€‘` L€ÌB† S d|XÃï  ! CS OPL ƒ` L€ÌB† S d|Yòï  ! CS OPLÀ~` L€ÌB† S d|Z!ð  ! CS OPL€‡` L`ªB† S d|XPð  ! CS OPL€–` L`ªB† S d|Yð  ! CS OPL`“` L`ªB† S d|Z qñ Takes¿ð  CurrentS Take 001dñ  TakeS Take 001ñ   FileNameS Take_001.tak+ñ   LocalTimeLR^´r Lp6ŒÄ5 Wñ   ReferenceTimeLR^´r Lp6ŒÄ5 ú¼« ÕÀÜe³ðô"s „ øZŒjÞõÙ~ìé ãu) \ No newline at end of file diff --git a/test/models/JT/conrod.jt b/test/models/JT/conrod.jt new file mode 100644 index 000000000..566507720 Binary files /dev/null and b/test/models/JT/conrod.jt differ diff --git a/test/models/PLY/points.ply b/test/models/PLY/points.ply new file mode 100644 index 000000000..91f4bb83b --- /dev/null +++ b/test/models/PLY/points.ply @@ -0,0 +1,17 @@ +ply +format ascii 1.0 +element vertex 4 +property float x +property float y +property float z +property uchar red +property uchar green +property uchar blue +property float nx +property float ny +property float nz +end_header +0.0 0.0 0.0 255 255 255 0.0 1.0 0.0 +0.0 0.0 1.0 255 0 255 0.0 0.0 1.0 +0.0 1.0 0.0 255 255 0 1.0 0.0 0.0 +0.0 1.0 1.0 0 255 255 1.0 1.0 0.0 diff --git a/test/models/glTF2/cameras/Cameras.gltf b/test/models/glTF2/cameras/Cameras.gltf new file mode 100644 index 000000000..25e9e24a3 --- /dev/null +++ b/test/models/glTF2/cameras/Cameras.gltf @@ -0,0 +1,98 @@ +{ + "scenes" : [ + { + "nodes" : [ 0, 1, 2 ] + } + ], + "nodes" : [ + { + "rotation" : [ -0.383, 0.0, 0.0, 0.92375 ], + "mesh" : 0 + }, + { + "translation" : [ 0.5, 0.5, 3.0 ], + "camera" : 0 + }, + { + "translation" : [ 0.5, 0.5, 3.0 ], + "camera" : 1 + } + ], + + "cameras" : [ + { + "type": "perspective", + "perspective": { + "aspectRatio": 1.0, + "yfov": 0.7, + "zfar": 100, + "znear": 0.01 + } + }, + { + "type": "orthographic", + "orthographic": { + "xmag": 1.0, + "ymag": 1.0, + "zfar": 100, + "znear": 0.01 + } + } + ], + + "meshes" : [ + { + "primitives" : [ { + "attributes" : { + "POSITION" : 1 + }, + "indices" : 0 + } ] + } + ], + + "buffers" : [ + { + "uri" : "simpleSquare.bin", + "byteLength" : 60 + } + ], + "bufferViews" : [ + { + "buffer" : 0, + "byteOffset" : 0, + "byteLength" : 12, + "target" : 34963 + }, + { + "buffer" : 0, + "byteOffset" : 12, + "byteLength" : 48, + "target" : 34962 + } + ], + "accessors" : [ + { + "bufferView" : 0, + "byteOffset" : 0, + "componentType" : 5123, + "count" : 6, + "type" : "SCALAR", + "max" : [ 3 ], + "min" : [ 0 ] + }, + { + "bufferView" : 1, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 4, + "type" : "VEC3", + "max" : [ 1.0, 1.0, 0.0 ], + "min" : [ 0.0, 0.0, 0.0 ] + } + ], + + "asset" : { + "version" : "2.0" + } +} diff --git a/test/models/glTF2/cameras/simpleSquare.bin b/test/models/glTF2/cameras/simpleSquare.bin new file mode 100644 index 000000000..a6edb3b0d Binary files /dev/null and b/test/models/glTF2/cameras/simpleSquare.bin differ diff --git a/test/models/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube.bin b/test/models/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube.bin new file mode 100644 index 000000000..7b14a1793 Binary files /dev/null and b/test/models/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube.bin differ diff --git a/test/models/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube.gltf b/test/models/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube.gltf new file mode 100644 index 000000000..b1b720147 --- /dev/null +++ b/test/models/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube.gltf @@ -0,0 +1,282 @@ +{ + "accessors": [ + { + "bufferView": 0, + "componentType": 5126, + "count": 24, + "type": "VEC3" + }, + { + "bufferView": 1, + "componentType": 5126, + "count": 24, + "type": "VEC4" + }, + { + "bufferView": 2, + "componentType": 5126, + "count": 24, + "type": "VEC3", + "max": [ + 0.0100000035, + 0.0100000035, + 0.01 + ], + "min": [ + -0.0100000044, + -0.0100000054, + -0.01 + ] + }, + { + "bufferView": 3, + "componentType": 5126, + "count": 24, + "type": "VEC3", + "name": "thin" + }, + { + "bufferView": 4, + "componentType": 5126, + "count": 24, + "type": "VEC3", + "max": [ + 0.0, + 0.01893253, + 0.0 + ], + "min": [ + 0.0, + 0.0, + 0.0 + ], + "name": "thin" + }, + { + "bufferView": 5, + "componentType": 5126, + "count": 24, + "type": "VEC3", + "name": "thin" + }, + { + "bufferView": 6, + "componentType": 5126, + "count": 24, + "type": "VEC3", + "name": "angle" + }, + { + "bufferView": 7, + "componentType": 5126, + "count": 24, + "type": "VEC3", + "max": [ + 0.0, + 0.0198908355, + 0.0 + ], + "min": [ + 0.0, + 0.0, + 0.0 + ], + "name": "angle" + }, + { + "bufferView": 8, + "componentType": 5126, + "count": 24, + "type": "VEC3", + "name": "angle" + }, + { + "bufferView": 9, + "componentType": 5123, + "count": 36, + "type": "SCALAR" + }, + { + "bufferView": 10, + "componentType": 5126, + "count": 127, + "type": "SCALAR", + "max": [ + 4.19999743 + ], + "min": [ + 0.0 + ] + }, + { + "bufferView": 11, + "componentType": 5126, + "count": 254, + "type": "SCALAR" + } + ], + "animations": [ + { + "channels": [ + { + "sampler": 0, + "target": { + "node": 0, + "path": "weights" + } + } + ], + "samplers": [ + { + "input": 10, + "interpolation": "LINEAR", + "output": 11 + } + ], + "name": "Square" + } + ], + "asset": { + "generator": "glTF Tools for Unity", + "version": "2.0" + }, + "bufferViews": [ + { + "buffer": 0, + "byteLength": 288 + }, + { + "buffer": 0, + "byteOffset": 288, + "byteLength": 384 + }, + { + "buffer": 0, + "byteOffset": 672, + "byteLength": 288 + }, + { + "buffer": 0, + "byteOffset": 960, + "byteLength": 288 + }, + { + "buffer": 0, + "byteOffset": 1248, + "byteLength": 288 + }, + { + "buffer": 0, + "byteOffset": 1536, + "byteLength": 288 + }, + { + "buffer": 0, + "byteOffset": 1824, + "byteLength": 288 + }, + { + "buffer": 0, + "byteOffset": 2112, + "byteLength": 288 + }, + { + "buffer": 0, + "byteOffset": 2400, + "byteLength": 288 + }, + { + "buffer": 0, + "byteOffset": 2688, + "byteLength": 72 + }, + { + "buffer": 0, + "byteOffset": 2760, + "byteLength": 508 + }, + { + "buffer": 0, + "byteOffset": 3268, + "byteLength": 1016 + } + ], + "buffers": [ + { + "uri": "AnimatedMorphCube.bin", + "byteLength": 4284 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 0, + "TANGENT": 1, + "POSITION": 2 + }, + "indices": 9, + "material": 0, + "targets": [ + { + "NORMAL": 3, + "POSITION": 4, + "TANGENT": 5 + }, + { + "NORMAL": 6, + "POSITION": 7, + "TANGENT": 8 + } + ] + } + ], + "weights": [ + 0.0, + 0.0 + ], + "name": "Cube" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorFactor": [ + 0.6038274, + 0.6038274, + 0.6038274, + 1.0 + ], + "metallicFactor": 0.0, + "roughnessFactor": 0.5 + }, + "name": "Material" + } + ], + "nodes": [ + { + "mesh": 0, + "rotation": [ + 0.0, + 0.7071067, + -0.7071068, + 0.0 + ], + "scale": [ + 100.0, + 100.0, + 100.0 + ], + "name": "AnimatedMorphCube" + } + ], + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ] +} \ No newline at end of file diff --git a/test/models/glTF2/simple_skin/simple_skin.gltf b/test/models/glTF2/simple_skin/simple_skin.gltf new file mode 100644 index 000000000..e075bb34c --- /dev/null +++ b/test/models/glTF2/simple_skin/simple_skin.gltf @@ -0,0 +1,148 @@ +{ + "scenes" : [ { + "nodes" : [ 0 ] + } ], + + "nodes" : [ { + "skin" : 0, + "mesh" : 0, + "children" : [ 1 ] + }, { + "children" : [ 2 ], + "translation" : [ 0.0, 1.0, 0.0 ] + }, { + "rotation" : [ 0.0, 0.0, 0.0, 1.0 ] + } ], + + "meshes" : [ { + "primitives" : [ { + "attributes" : { + "POSITION" : 1, + "JOINTS_0" : 2, + "WEIGHTS_0" : 3 + }, + "indices" : 0 + } ] + } ], + + "skins" : [ { + "inverseBindMatrices" : 4, + "joints" : [ 1, 2 ] + } ], + + "animations" : [ { + "channels" : [ { + "sampler" : 0, + "target" : { + "node" : 2, + "path" : "rotation" + } + } ], + "samplers" : [ { + "input" : 5, + "interpolation" : "LINEAR", + "output" : 6 + } ] + } ], + + "buffers" : [ { + "uri" : "data:application/gltf-buffer;base64,AAABAAMAAAADAAIAAgADAAUAAgAFAAQABAAFAAcABAAHAAYABgAHAAkABgAJAAgAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAD8AAAAAAACAPwAAAD8AAAAAAAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAAAAAAAAwD8AAAAAAACAPwAAwD8AAAAAAAAAAAAAAEAAAAAAAACAPwAAAEAAAAAA", + "byteLength" : 168 + }, { + "uri" : "data:application/gltf-buffer;base64,AAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAABAPwAAgD4AAAAAAAAAAAAAQD8AAIA+AAAAAAAAAAAAAAA/AAAAPwAAAAAAAAAAAAAAPwAAAD8AAAAAAAAAAAAAgD4AAEA/AAAAAAAAAAAAAIA+AABAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAA=", + "byteLength" : 320 + }, { + "uri" : "data:application/gltf-buffer;base64,AACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAvwAAgL8AAAAAAACAPwAAgD8AAAAAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAL8AAIC/AAAAAAAAgD8=", + "byteLength" : 128 + }, { + "uri" : "data:application/gltf-buffer;base64,AAAAAAAAAD8AAIA/AADAPwAAAEAAACBAAABAQAAAYEAAAIBAAACQQAAAoEAAALBAAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAkxjEPkSLbD8AAAAAAAAAAPT9ND/0/TQ/AAAAAAAAAAD0/TQ/9P00PwAAAAAAAAAAkxjEPkSLbD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAkxjEvkSLbD8AAAAAAAAAAPT9NL/0/TQ/AAAAAAAAAAD0/TS/9P00PwAAAAAAAAAAkxjEvkSLbD8AAAAAAAAAAAAAAAAAAIA/", + "byteLength" : 240 + } ], + + "bufferViews" : [ { + "buffer" : 0, + "byteOffset" : 0, + "byteLength" : 48, + "target" : 34963 + }, { + "buffer" : 0, + "byteOffset" : 48, + "byteLength" : 120, + "target" : 34962 + }, { + "buffer" : 1, + "byteOffset" : 0, + "byteLength" : 320, + "byteStride" : 16 + }, { + "buffer" : 2, + "byteOffset" : 0, + "byteLength" : 128 + }, { + "buffer" : 3, + "byteOffset" : 0, + "byteLength" : 240 + } ], + + "accessors" : [ { + "bufferView" : 0, + "byteOffset" : 0, + "componentType" : 5123, + "count" : 24, + "type" : "SCALAR", + "max" : [ 9 ], + "min" : [ 0 ] + }, { + "bufferView" : 1, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 10, + "type" : "VEC3", + "max" : [ 1.0, 2.0, 0.0 ], + "min" : [ 0.0, 0.0, 0.0 ] + }, { + "bufferView" : 2, + "byteOffset" : 0, + "componentType" : 5123, + "count" : 10, + "type" : "VEC4", + "max" : [ 0, 1, 0, 0 ], + "min" : [ 0, 1, 0, 0 ] + }, { + "bufferView" : 2, + "byteOffset" : 160, + "componentType" : 5126, + "count" : 10, + "type" : "VEC4", + "max" : [ 1.0, 1.0, 0.0, 0.0 ], + "min" : [ 0.0, 0.0, 0.0, 0.0 ] + }, { + "bufferView" : 3, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 2, + "type" : "MAT4", + "max" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.5, -1.0, 0.0, 1.0 ], + "min" : [ 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.5, -1.0, 0.0, 1.0 ] + }, { + "bufferView" : 4, + "byteOffset" : 0, + "componentType" : 5126, + "count" : 12, + "type" : "SCALAR", + "max" : [ 5.5 ], + "min" : [ 0.0 ] + }, { + "bufferView" : 4, + "byteOffset" : 48, + "componentType" : 5126, + "count" : 12, + "type" : "VEC4", + "max" : [ 0.0, 0.0, 0.707, 1.0 ], + "min" : [ 0.0, 0.0, -0.707, 0.707 ] + } ], + + "asset" : { + "version" : "2.0" + } +} \ No newline at end of file diff --git a/test/unit/AbstractImportExportBase.cpp b/test/unit/AbstractImportExportBase.cpp index c09ec0fd7..bf89fa5d4 100644 --- a/test/unit/AbstractImportExportBase.cpp +++ b/test/unit/AbstractImportExportBase.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/AbstractImportExportBase.h b/test/unit/AbstractImportExportBase.h index 529b9cf7d..d6ae37d60 100644 --- a/test/unit/AbstractImportExportBase.h +++ b/test/unit/AbstractImportExportBase.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -39,17 +39,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ #pragma once +#ifndef AI_ABSTRACTIMPORTEXPORTBASE_H_INC +#define AI_ABSTRACTIMPORTEXPORTBASE_H_INC #include "UnitTestPCH.h" +// --------------------------------------------------------------------------- +/** Abstract base class to test import and export + */ + // --------------------------------------------------------------------------- class AbstractImportExportBase : public ::testing::Test { public: + /// @brief The class destructor. virtual ~AbstractImportExportBase(); - virtual bool importerTest() = 0; + + /// @brief The importer-test, will return true for successful import. + /// @return true for success, false for failure. + virtual bool importerTest(); + + /// @brief The exporter-test, will return true for successful import. + /// @return true for success, false for failure. virtual bool exporterTest(); }; +inline +bool AbstractImportExportBase::importerTest() { + return true; +} + inline bool AbstractImportExportBase::exporterTest() { return true; } + +#endif // AI_ABSTRACTIMPORTEXPORTBASE_H_INC diff --git a/test/unit/AssimpAPITest.cpp b/test/unit/AssimpAPITest.cpp index faf551f7c..3e1d97314 100644 --- a/test/unit/AssimpAPITest.cpp +++ b/test/unit/AssimpAPITest.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/Common/utLineSplitter.cpp b/test/unit/Common/utLineSplitter.cpp index ad050ea73..2aa581add 100644 --- a/test/unit/Common/utLineSplitter.cpp +++ b/test/unit/Common/utLineSplitter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/ImportExport/utAssjsonImportExport.cpp b/test/unit/ImportExport/utAssjsonImportExport.cpp new file mode 100644 index 000000000..82dbf8b57 --- /dev/null +++ b/test/unit/ImportExport/utAssjsonImportExport.cpp @@ -0,0 +1,69 @@ +/* +--------------------------------------------------------------------------- +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 "UnitTestPCH.h" +#include "AbstractImportExportBase.h" + +#include +#include +#include +#include + +using namespace Assimp; + +#ifndef ASSIMP_BUILD_NO_EXPORT + +class utAssjsonImportExport : public AbstractImportExportBase { +public: + bool exporterTest() override { + Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure); + + Exporter exporter; + aiReturn res = exporter.Export(scene, "assjson", "./spider_test.json"); + return aiReturn_SUCCESS == res; + } +}; + +TEST_F(utAssjsonImportExport, exportTest) { + EXPECT_TRUE(exporterTest()); +} + +#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/test/unit/ImportExport/utCOBImportExport.cpp b/test/unit/ImportExport/utCOBImportExport.cpp index 854f27cbb..d80757e53 100644 --- a/test/unit/ImportExport/utCOBImportExport.cpp +++ b/test/unit/ImportExport/utCOBImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/ImportExport/utExporter.cpp b/test/unit/ImportExport/utExporter.cpp index 9ce4bfdd7..43e711cb3 100644 --- a/test/unit/ImportExport/utExporter.cpp +++ b/test/unit/ImportExport/utExporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -71,3 +71,32 @@ TEST_F(ExporterTest, ProgressHandlerTest) { TestProgressHandler *ph(new TestProgressHandler); exporter.SetProgressHandler(ph); } + +// Make sure all the registered exporters have useful descriptions +TEST_F(ExporterTest, ExporterIdTest) { + Exporter exporter; + size_t exportFormatCount = exporter.GetExportFormatCount(); + EXPECT_NE(0u, exportFormatCount) << "No registered exporters"; + typedef std::map ExportIdMap; + ExportIdMap exporterMap; + for (size_t i = 0; i < exportFormatCount; ++i) + { + // Check that the exporter description exists and makes sense + const aiExportFormatDesc* desc = exporter.GetExportFormatDescription(i); + ASSERT_NE(nullptr, desc) << "Missing aiExportFormatDesc at index " << i; + EXPECT_NE(nullptr, desc->id) << "Null exporter ID at index " << i; + EXPECT_STRNE("", desc->id) << "Empty exporter ID at index " << i; + EXPECT_NE(nullptr, desc->description) << "Null exporter description at index " << i; + EXPECT_STRNE("", desc->description) << "Empty exporter description at index " << i; + EXPECT_NE(nullptr, desc->fileExtension) << "Null exporter file extension at index " << i; + EXPECT_STRNE("", desc->fileExtension) << "Empty exporter file extension at index " << i; + + // Check the ID is unique + std::string key(desc->id); + std::pair result = exporterMap.emplace(key, desc); + EXPECT_TRUE(result.second) << "Duplicate exported id: '" << key << "' " << desc->description << " *." << desc->fileExtension << " at index " << i; + } + + const aiExportFormatDesc* desc = exporter.GetExportFormatDescription(exportFormatCount); + EXPECT_EQ(nullptr, desc) << "More exporters than claimed"; +} diff --git a/tools/assimp_qt_viewer/loggerview.hpp b/test/unit/ImportExport/utNFFImportExport.cpp similarity index 69% rename from tools/assimp_qt_viewer/loggerview.hpp rename to test/unit/ImportExport/utNFFImportExport.cpp index 9011f671f..d2fc1df5f 100644 --- a/tools/assimp_qt_viewer/loggerview.hpp +++ b/test/unit/ImportExport/utNFFImportExport.cpp @@ -1,9 +1,9 @@ -/* +/* --------------------------------------------------------------------------- Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -40,28 +40,24 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -#pragma once -// Header files, Assimp. -#include +#include "UnitTestPCH.h" +#include "AbstractImportExportBase.h" +#include +#include -class QTextBrowser; +using namespace Assimp; -/// @class CLoggerView -/// @brief GUI-stream for Assimp logging sub-sytem. Get data for logging and write it to output widget. -class CLoggerView final : public ::Assimp::LogStream { +class utNFFImportExport : public AbstractImportExportBase { public: - /// @brief The class constructor. - /// @param [in] pOutputWidget - pointer to output widget. - explicit CLoggerView( QTextBrowser* pOutputWidget ); - - /// @brief The class destructor. - virtual ~CLoggerView(); - - /// Write message to output widget. Used by Assimp. - /// \param [in] pMessage - message for displaying. - virtual void write(const char *pMessage); - -private: - QTextBrowser * mOutputWidget; ///< Widget for displaying messages. + virtual bool importerTest() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/NFF/NFF/ManyEarthsNotJustOne.nff", 0); + return true; + return nullptr != scene; + } }; + +TEST_F(utNFFImportExport, importNFFFromFileTest) { + EXPECT_TRUE(importerTest()); +} diff --git a/test/unit/ImportExport/utOFFImportExport.cpp b/test/unit/ImportExport/utOFFImportExport.cpp index a355beab6..eadd48b12 100644 --- a/test/unit/ImportExport/utOFFImportExport.cpp +++ b/test/unit/ImportExport/utOFFImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/ImportExport/utOgreImportExport.cpp b/test/unit/ImportExport/utOgreImportExport.cpp index 1950fc90a..608d0b068 100644 --- a/test/unit/ImportExport/utOgreImportExport.cpp +++ b/test/unit/ImportExport/utOgreImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/ImportExport/utQ3BSPFileImportExport.cpp b/test/unit/ImportExport/utQ3BSPFileImportExport.cpp index ba12652b4..70d89f1d2 100644 --- a/test/unit/ImportExport/utQ3BSPFileImportExport.cpp +++ b/test/unit/ImportExport/utQ3BSPFileImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/tools/assimp_qt_viewer/main.cpp b/test/unit/ImportExport/utXGLImportExport.cpp similarity index 75% rename from tools/assimp_qt_viewer/main.cpp rename to test/unit/ImportExport/utXGLImportExport.cpp index 6dfdd4981..89e780e20 100644 --- a/tools/assimp_qt_viewer/main.cpp +++ b/test/unit/ImportExport/utXGLImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -41,18 +41,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ -// Thanks to acorn89 for support. +#include "UnitTestPCH.h" +#include "AbstractImportExportBase.h" +#include +#include -// Header files, project. -#include "mainwindow.hpp" +using namespace Assimp; -// Header files, Qt. -#include +class utXGLImportExport : public AbstractImportExportBase { +public: + virtual bool importerTest() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/XGL/sample_official.xgl", 0); + return true; + return nullptr != scene; + } +}; -int main(int argc, char *argv[]) { - QApplication app(argc, argv); - MainWindow win; - win.show(); - - return app.exec(); +TEST_F(utXGLImportExport, importXGLFromFileTest) { + EXPECT_TRUE(importerTest()); } diff --git a/test/unit/SceneDiffer.cpp b/test/unit/SceneDiffer.cpp index 30b6e9086..684d9fee6 100644 --- a/test/unit/SceneDiffer.cpp +++ b/test/unit/SceneDiffer.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -123,7 +123,7 @@ void SceneDiffer::showReport() { return; } - for ( std::vector::iterator it = m_diffs.begin(); it != m_diffs.end(); it++ ) { + for ( std::vector::iterator it = m_diffs.begin(); it != m_diffs.end(); ++it ) { std::cout << *it << "\n"; } diff --git a/test/unit/SceneDiffer.h b/test/unit/SceneDiffer.h index 5c9ce2c3b..2a8bdae33 100644 --- a/test/unit/SceneDiffer.h +++ b/test/unit/SceneDiffer.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/TestIOSystem.h b/test/unit/TestIOSystem.h index f984baa13..5749df45b 100644 --- a/test/unit/TestIOSystem.h +++ b/test/unit/TestIOSystem.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/test/unit/TestModelFactory.h b/test/unit/TestModelFactory.h index 6afbe5685..0e48fb744 100644 --- a/test/unit/TestModelFactory.h +++ b/test/unit/TestModelFactory.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -89,7 +89,7 @@ public: scene->mMeshes[ 0 ]->mFaces[ 0 ].mIndices[ 1 ] = 1; scene->mMeshes[ 0 ]->mFaces[ 0 ].mIndices[ 2 ] = 2; - scene->mRootNode = new aiNode; + scene->mRootNode = new aiNode(); scene->mRootNode->mNumMeshes = 1; scene->mRootNode->mMeshes = new unsigned int[1]{ 0 }; diff --git a/test/unit/UTLogStream.h b/test/unit/UTLogStream.h index 6e24fc5ed..e679249df 100644 --- a/test/unit/UTLogStream.h +++ b/test/unit/UTLogStream.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/test/unit/ut3DImportExport.cpp b/test/unit/ut3DImportExport.cpp index 1268fa360..a3a3197cc 100644 --- a/test/unit/ut3DImportExport.cpp +++ b/test/unit/ut3DImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/ut3DSImportExport.cpp b/test/unit/ut3DSImportExport.cpp index b40694132..edec1d793 100644 --- a/test/unit/ut3DSImportExport.cpp +++ b/test/unit/ut3DSImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -66,3 +66,11 @@ public: TEST_F( ut3DSImportExport, import3DSFromFileTest ) { EXPECT_TRUE( importerTest() ); } + +TEST_F( ut3DSImportExport, import3DSformatdetection) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/3DS/testFormatDetection", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} + diff --git a/test/unit/utACImportExport.cpp b/test/unit/utACImportExport.cpp index 937c0afb4..192de16a0 100644 --- a/test/unit/utACImportExport.cpp +++ b/test/unit/utACImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utAMFImportExport.cpp b/test/unit/utAMFImportExport.cpp index 332d5b929..6eb0b4418 100644 --- a/test/unit/utAMFImportExport.cpp +++ b/test/unit/utAMFImportExport.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/test/unit/utASEImportExport.cpp b/test/unit/utASEImportExport.cpp index 28c498dca..313f0f83a 100644 --- a/test/unit/utASEImportExport.cpp +++ b/test/unit/utASEImportExport.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/test/unit/utAnim.cpp b/test/unit/utAnim.cpp index 40c840d7e..7d4cff7d1 100644 --- a/test/unit/utAnim.cpp +++ b/test/unit/utAnim.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/test/unit/utAssbinImportExport.cpp b/test/unit/utAssbinImportExport.cpp index bbfb9421b..42504df56 100644 --- a/test/unit/utAssbinImportExport.cpp +++ b/test/unit/utAssbinImportExport.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -53,20 +51,20 @@ using namespace Assimp; class utAssbinImportExport : public AbstractImportExportBase { public: - virtual bool importerTest() { - Assimp::Importer importer; + bool importerTest() override { + Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure ); Exporter exporter; - EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "assbin", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_test.assbin" ) ); - const aiScene *newScene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider_test.assbin", aiProcess_ValidateDataStructure ); + EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "assbin", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_out.assbin" ) ); + const aiScene *newScene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider_out.assbin", aiProcess_ValidateDataStructure ); return newScene != nullptr; } }; TEST_F( utAssbinImportExport, exportAssbin3DFromFileTest ) { - Assimp::Importer importer; + Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure ); EXPECT_NE( nullptr, scene ); } diff --git a/test/unit/utB3DImportExport.cpp b/test/unit/utB3DImportExport.cpp index 6795f8cba..ea75b1939 100644 --- a/test/unit/utB3DImportExport.cpp +++ b/test/unit/utB3DImportExport.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/test/unit/utBVHImportExport.cpp b/test/unit/utBVHImportExport.cpp index eebfe1439..c4ed43cf8 100644 --- a/test/unit/utBVHImportExport.cpp +++ b/test/unit/utBVHImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utBatchLoader.cpp b/test/unit/utBatchLoader.cpp index ce95727ee..36dcbf288 100644 --- a/test/unit/utBatchLoader.cpp +++ b/test/unit/utBatchLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -41,7 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ #include "UnitTestPCH.h" -#include "Importer.h" +#include "Common/Importer.h" #include "TestIOSystem.h" using namespace ::Assimp; diff --git a/test/unit/utBlendImportAreaLight.cpp b/test/unit/utBlendImportAreaLight.cpp index c2f6c0be3..a259294aa 100644 --- a/test/unit/utBlendImportAreaLight.cpp +++ b/test/unit/utBlendImportAreaLight.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utBlendImportMaterials.cpp b/test/unit/utBlendImportMaterials.cpp index f36ffdb18..151c614c0 100644 --- a/test/unit/utBlendImportMaterials.cpp +++ b/test/unit/utBlendImportMaterials.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -133,10 +133,10 @@ TEST_F(BlendImportMaterials, testImportMaterialwith2texturesAnd2TexCoordMappings // material has 2 diffuse textures ASSERT_TRUE(pTest->HasMaterials()); - EXPECT_EQ(1, pTest->mNumMaterials); + EXPECT_EQ(1u, pTest->mNumMaterials); const aiMaterial *pMat = pTest->mMaterials[0]; ASSERT_TRUE(nullptr != pMat); - ASSERT_EQ(2, pMat->GetTextureCount(aiTextureType_DIFFUSE)); + ASSERT_EQ(2u, pMat->GetTextureCount(aiTextureType_DIFFUSE)); aiString aPath; aiTextureMapping tm = aiTextureMapping::aiTextureMapping_OTHER; aiReturn result = pMat->GetTexture(aiTextureType_DIFFUSE, 0, &aPath, &tm); @@ -146,7 +146,7 @@ TEST_F(BlendImportMaterials, testImportMaterialwith2texturesAnd2TexCoordMappings // mesh has 2 texturecoord sets ASSERT_TRUE(pTest->HasMeshes()); - EXPECT_EQ(1, pTest->mNumMeshes); + EXPECT_EQ(1u, pTest->mNumMeshes); const aiMesh *pMesh = pTest->mMeshes[0]; ASSERT_TRUE(nullptr != pMesh); ASSERT_TRUE(pMesh->HasTextureCoords(0)); diff --git a/test/unit/utBlenderImportExport.cpp b/test/unit/utBlenderImportExport.cpp index 5634b33a8..b2d268497 100644 --- a/test/unit/utBlenderImportExport.cpp +++ b/test/unit/utBlenderImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utBlenderIntermediate.cpp b/test/unit/utBlenderIntermediate.cpp index 55490e613..30f29017d 100644 --- a/test/unit/utBlenderIntermediate.cpp +++ b/test/unit/utBlenderIntermediate.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -41,11 +41,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ #include "UnitTestPCH.h" -#include "BlenderIntermediate.h" -#include "./../include/assimp/camera.h" -#include "./../include/assimp/light.h" -#include "./../include/assimp/mesh.h" -#include "./../include/assimp/texture.h" +#include "Blender/BlenderIntermediate.h" +#include +#include +#include +#include using namespace ::Assimp; using namespace ::Assimp::Blender; diff --git a/test/unit/utBlenderWork.cpp b/test/unit/utBlenderWork.cpp index a17764673..c0e3347ab 100644 --- a/test/unit/utBlenderWork.cpp +++ b/test/unit/utBlenderWork.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -73,11 +71,6 @@ TEST_F(BlenderWorkTest,work_279) { ASSERT_TRUE(pTest->HasMaterials()); ASSERT_TRUE(pTest->HasMeshes()); ASSERT_TRUE(pTest->mMeshes[0]->mNumVertices > 0); - ASSERT_EQ(44, pTest->mMeshes[0]->mNumFaces); - EXPECT_EQ(1, pTest->mNumMaterials); + ASSERT_EQ(44u, pTest->mMeshes[0]->mNumFaces); + EXPECT_EQ(1u, pTest->mNumMaterials); } - - - - - diff --git a/test/unit/utCSMImportExport.cpp b/test/unit/utCSMImportExport.cpp index 4da51f089..7f6ae0f4e 100644 --- a/test/unit/utCSMImportExport.cpp +++ b/test/unit/utCSMImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utColladaExportCamera.cpp b/test/unit/utColladaExportCamera.cpp index 3219dbf0c..ff84422e5 100644 --- a/test/unit/utColladaExportCamera.cpp +++ b/test/unit/utColladaExportCamera.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -52,18 +52,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. class ColladaExportCamera : public ::testing::Test { public: - - virtual void SetUp() - { + void SetUp() override{ ex = new Assimp::Exporter(); im = new Assimp::Importer(); } - virtual void TearDown() - { + void TearDown() override { delete ex; + ex = nullptr; delete im; + im = nullptr; } protected: @@ -71,16 +70,15 @@ protected: Assimp::Importer* im; }; -TEST_F(ColladaExportCamera, testExportCamera) -{ +TEST_F(ColladaExportCamera, testExportCamera) { const char* file = "cameraExp.dae"; const aiScene* pTest = im->ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/cameras.dae", aiProcess_ValidateDataStructure); - ASSERT_TRUE(pTest!=NULL); + ASSERT_NE( nullptr, pTest ); ASSERT_TRUE(pTest->HasCameras()); - EXPECT_EQ(AI_SUCCESS,ex->Export(pTest,"collada",file)); + EXPECT_EQ( AI_SUCCESS, ex->Export(pTest,"collada",file)); const unsigned int origNumCams( pTest->mNumCameras ); std::unique_ptr origFOV( new float[ origNumCams ] ); std::unique_ptr orifClipPlaneNear( new float[ origNumCams ] ); @@ -89,7 +87,7 @@ TEST_F(ColladaExportCamera, testExportCamera) std::unique_ptr pos( new aiVector3D[ origNumCams ] ); for (size_t i = 0; i < origNumCams; i++) { const aiCamera *orig = pTest->mCameras[ i ]; - ASSERT_TRUE( orig != nullptr ); + ASSERT_NE(nullptr, orig ); origFOV[ i ] = orig->mHorizontalFOV; orifClipPlaneNear[ i ] = orig->mClipPlaneNear; @@ -99,7 +97,7 @@ TEST_F(ColladaExportCamera, testExportCamera) } const aiScene* imported = im->ReadFile(file, aiProcess_ValidateDataStructure); - ASSERT_TRUE(imported!=NULL); + ASSERT_NE(nullptr, imported ); EXPECT_TRUE( imported->HasCameras() ); EXPECT_EQ( origNumCams, imported->mNumCameras ); @@ -119,5 +117,3 @@ TEST_F(ColladaExportCamera, testExportCamera) } #endif // ASSIMP_BUILD_NO_EXPORT - - diff --git a/test/unit/utColladaExportLight.cpp b/test/unit/utColladaExportLight.cpp index 71f404c29..502cecf3a 100644 --- a/test/unit/utColladaExportLight.cpp +++ b/test/unit/utColladaExportLight.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utColladaImportExport.cpp b/test/unit/utColladaImportExport.cpp index c7ad6f906..1a2a6bc9d 100644 --- a/test/unit/utColladaImportExport.cpp +++ b/test/unit/utColladaImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -57,6 +57,19 @@ public: } }; -TEST_F( utColladaImportExport, importBlenFromFileTest ) { - EXPECT_TRUE( importerTest() ); +TEST_F(utColladaImportExport, importBlenFromFileTest) { + EXPECT_TRUE(importerTest()); +} + +class utColladaZaeImportExport : public AbstractImportExportBase { +public: + virtual bool importerTest() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/Collada/duck.zae", aiProcess_ValidateDataStructure); + return nullptr != scene; + } +}; + +TEST_F(utColladaZaeImportExport, importBlenFromFileTest) { + EXPECT_TRUE(importerTest()); } diff --git a/test/unit/utD3MFImportExport.cpp b/test/unit/utD3MFImportExport.cpp index c5fdd003b..c9b17d898 100644 --- a/test/unit/utD3MFImportExport.cpp +++ b/test/unit/utD3MFImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -48,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#include "D3MFExporter.h" +#include "3MF/D3MFExporter.h" class utD3MFImporterExporter : public AbstractImportExportBase { public: diff --git a/test/unit/utDXFImporterExporter.cpp b/test/unit/utDXFImporterExporter.cpp index e0e764ea6..af57ffc79 100644 --- a/test/unit/utDXFImporterExporter.cpp +++ b/test/unit/utDXFImporterExporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utDefaultIOStream.cpp b/test/unit/utDefaultIOStream.cpp index cf51ed56a..bfc82a620 100644 --- a/test/unit/utDefaultIOStream.cpp +++ b/test/unit/utDefaultIOStream.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utFBXImporterExporter.cpp b/test/unit/utFBXImporterExporter.cpp index 1d6cdf883..1445e3c3e 100644 --- a/test/unit/utFBXImporterExporter.cpp +++ b/test/unit/utFBXImporterExporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -70,29 +70,151 @@ TEST_F( utFBXImporterExporter, importBareBoxWithoutColorsAndTextureCoords ) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/FBX/box.fbx", aiProcess_ValidateDataStructure ); EXPECT_NE( nullptr, scene ); - EXPECT_EQ(scene->mNumMeshes, 1); + EXPECT_EQ(scene->mNumMeshes, 1u); aiMesh* mesh = scene->mMeshes[0]; - EXPECT_EQ(mesh->mNumFaces, 12); - EXPECT_EQ(mesh->mNumVertices, 36); + EXPECT_EQ(mesh->mNumFaces, 12u); + EXPECT_EQ(mesh->mNumVertices, 36u); +} + +TEST_F(utFBXImporterExporter, importCubesWithNoNames) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/cubes_nonames.fbx", aiProcess_ValidateDataStructure); + ASSERT_TRUE(scene); + + ASSERT_TRUE(scene->mRootNode); + const auto root = scene->mRootNode; + ASSERT_STREQ(root->mName.C_Str(), "RootNode"); + ASSERT_TRUE(root->mChildren); + ASSERT_EQ(root->mNumChildren, 2u); + + const auto child0 = root->mChildren[0]; + ASSERT_TRUE(child0); + ASSERT_STREQ(child0->mName.C_Str(), "RootNode001"); + ASSERT_TRUE(child0->mChildren); + ASSERT_EQ(child0->mNumChildren, 1u); + + const auto child00 = child0->mChildren[0]; + ASSERT_TRUE(child00); + ASSERT_STREQ(child00->mName.C_Str(), "RootNode001001"); + + const auto child1 = root->mChildren[1]; + ASSERT_TRUE(child1); + ASSERT_STREQ(child1->mName.C_Str(), "RootNode002"); + ASSERT_TRUE(child1->mChildren); + ASSERT_EQ(child1->mNumChildren, 1u); + + const auto child10 = child1->mChildren[0]; + ASSERT_TRUE(child10); + ASSERT_STREQ(child10->mName.C_Str(), "RootNode002001"); +} + +TEST_F(utFBXImporterExporter, importCubesWithUnicodeDuplicatedNames) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/cubes_with_names.fbx", aiProcess_ValidateDataStructure); + ASSERT_TRUE(scene); + + ASSERT_TRUE(scene->mRootNode); + const auto root = scene->mRootNode; + ASSERT_STREQ(root->mName.C_Str(), "RootNode"); + ASSERT_TRUE(root->mChildren); + ASSERT_EQ(root->mNumChildren, 2u); + + const auto child0 = root->mChildren[0]; + ASSERT_TRUE(child0); + ASSERT_STREQ(child0->mName.C_Str(), "Cube2"); + ASSERT_TRUE(child0->mChildren); + ASSERT_EQ(child0->mNumChildren, 1u); + + const auto child00 = child0->mChildren[0]; + ASSERT_TRUE(child00); + ASSERT_STREQ(child00->mName.C_Str(), "\xd0\x9a\xd1\x83\xd0\xb1\x31"); + + const auto child1 = root->mChildren[1]; + ASSERT_TRUE(child1); + ASSERT_STREQ(child1->mName.C_Str(), "Cube3"); + ASSERT_TRUE(child1->mChildren); + ASSERT_EQ(child1->mNumChildren, 1u); + + const auto child10 = child1->mChildren[0]; + ASSERT_TRUE(child10); + ASSERT_STREQ(child10->mName.C_Str(), "\xd0\x9a\xd1\x83\xd0\xb1\x31""001"); +} + +TEST_F(utFBXImporterExporter, importCubesComplexTransform) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/cubes_with_mirroring_and_pivot.fbx", aiProcess_ValidateDataStructure); + ASSERT_TRUE(scene); + + ASSERT_TRUE(scene->mRootNode); + const auto root = scene->mRootNode; + ASSERT_STREQ(root->mName.C_Str(), "RootNode"); + ASSERT_TRUE(root->mChildren); + ASSERT_EQ(root->mNumChildren, 2u); + + const auto child0 = root->mChildren[0]; + ASSERT_TRUE(child0); + ASSERT_STREQ(child0->mName.C_Str(), "Cube2"); + ASSERT_TRUE(child0->mChildren); + ASSERT_EQ(child0->mNumChildren, 1u); + + const auto child00 = child0->mChildren[0]; + ASSERT_TRUE(child00); + ASSERT_STREQ(child00->mName.C_Str(), "Cube1"); + + const auto child1 = root->mChildren[1]; + ASSERT_TRUE(child1); + ASSERT_STREQ(child1->mName.C_Str(), "Cube3"); + + auto parent = child1; + const size_t chain_length = 8u; + const char* chainStr[chain_length] = { + "Cube1001_$AssimpFbx$_Translation", + "Cube1001_$AssimpFbx$_RotationPivot", + "Cube1001_$AssimpFbx$_RotationPivotInverse", + "Cube1001_$AssimpFbx$_ScalingOffset", + "Cube1001_$AssimpFbx$_ScalingPivot", + "Cube1001_$AssimpFbx$_Scaling", + "Cube1001_$AssimpFbx$_ScalingPivotInverse", + "Cube1001" + }; + for (size_t i = 0; i < chain_length; ++i) { + ASSERT_TRUE(parent->mChildren); + ASSERT_EQ(parent->mNumChildren, 1u); + auto node = parent->mChildren[0]; + ASSERT_TRUE(node); + ASSERT_STREQ(node->mName.C_Str(), chainStr[i]); + parent = node; + } + ASSERT_EQ(0u, parent->mNumChildren) << "Leaf node"; +} + +TEST_F(utFBXImporterExporter, importCloseToIdentityTransforms) { + Assimp::Importer importer; + // This was asserting in FBXConverter.cpp because the transforms appeared to be the identity by one test, but not by another. + // This asset should now load successfully. + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/close_to_identity_transforms.fbx", aiProcess_ValidateDataStructure); + ASSERT_TRUE(scene); } TEST_F( utFBXImporterExporter, importPhongMaterial ) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/FBX/phong_cube.fbx", aiProcess_ValidateDataStructure ); EXPECT_NE( nullptr, scene ); - EXPECT_EQ( (unsigned int)1, scene->mNumMaterials ); + EXPECT_EQ( 1u, scene->mNumMaterials ); const aiMaterial *mat = scene->mMaterials[0]; EXPECT_NE( nullptr, mat ); - float f; aiColor3D c; + float f; + aiColor3D c; + // phong_cube.fbx has all properties defined EXPECT_EQ( mat->Get(AI_MATKEY_COLOR_DIFFUSE, c), aiReturn_SUCCESS ); EXPECT_EQ( c, aiColor3D(0.5, 0.25, 0.25) ); EXPECT_EQ( mat->Get(AI_MATKEY_COLOR_SPECULAR, c), aiReturn_SUCCESS ); EXPECT_EQ( c, aiColor3D(0.25, 0.25, 0.5) ); EXPECT_EQ( mat->Get(AI_MATKEY_SHININESS_STRENGTH, f), aiReturn_SUCCESS ); - EXPECT_EQ( f, 0.5 ); + EXPECT_EQ( f, 0.5f ); EXPECT_EQ( mat->Get(AI_MATKEY_SHININESS, f), aiReturn_SUCCESS ); - EXPECT_EQ( f, 10.0 ); + EXPECT_EQ( f, 10.0f ); EXPECT_EQ( mat->Get(AI_MATKEY_COLOR_AMBIENT, c), aiReturn_SUCCESS ); EXPECT_EQ( c, aiColor3D(0.125, 0.25, 0.25) ); EXPECT_EQ( mat->Get(AI_MATKEY_COLOR_EMISSIVE, c), aiReturn_SUCCESS ); @@ -100,7 +222,7 @@ TEST_F( utFBXImporterExporter, importPhongMaterial ) { EXPECT_EQ( mat->Get(AI_MATKEY_COLOR_TRANSPARENT, c), aiReturn_SUCCESS ); EXPECT_EQ( c, aiColor3D(0.75, 0.5, 0.25) ); EXPECT_EQ( mat->Get(AI_MATKEY_OPACITY, f), aiReturn_SUCCESS ); - EXPECT_EQ( f, 0.5 ); + EXPECT_EQ( f, 0.5f ); } TEST_F(utFBXImporterExporter, importUnitScaleFactor) { @@ -114,3 +236,49 @@ TEST_F(utFBXImporterExporter, importUnitScaleFactor) { scene->mMetaData->Get("UnitScaleFactor", factor); EXPECT_DOUBLE_EQ(500.0, factor); } + +TEST_F(utFBXImporterExporter, importEmbeddedAsciiTest) { + // see https://github.com/assimp/assimp/issues/1957 + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/embedded_ascii/box.FBX", aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + + EXPECT_EQ(1u, scene->mNumMaterials); + aiMaterial *mat = scene->mMaterials[0]; + ASSERT_NE(nullptr, mat); + + aiString path; + aiTextureMapMode modes[2]; + EXPECT_EQ(aiReturn_SUCCESS, mat->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes)); + ASSERT_STREQ(path.C_Str(), "..\\..\\..\\Desktop\\uv_test.png"); + + ASSERT_EQ(1u, scene->mNumTextures); + ASSERT_TRUE(scene->mTextures[0]->pcData); + ASSERT_EQ(439176u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression splits data by 512Kb, it should be two parts for this texture"; +} + +TEST_F(utFBXImporterExporter, importEmbeddedFragmentedAsciiTest) { + // see https://github.com/assimp/assimp/issues/1957 + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/embedded_ascii/box_embedded_texture_fragmented.fbx", aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); + + EXPECT_EQ(1u, scene->mNumMaterials); + aiMaterial *mat = scene->mMaterials[0]; + ASSERT_NE(nullptr, mat); + + aiString path; + aiTextureMapMode modes[2]; + ASSERT_EQ(aiReturn_SUCCESS, mat->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes)); + ASSERT_STREQ(path.C_Str(), "paper.png"); + + ASSERT_EQ(1u, scene->mNumTextures); + ASSERT_TRUE(scene->mTextures[0]->pcData); + ASSERT_EQ(968029u, scene->mTextures[0]->mWidth) << "FBX ASCII base64 compression splits data by 512Kb, it should be two parts for this texture"; +} + +TEST_F(utFBXImporterExporter, fbxTokenizeTestTest) { + //Assimp::Importer importer; + //const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/FBX/transparentTest2.fbx", aiProcess_ValidateDataStructure); + //EXPECT_NE(nullptr, scene); +} diff --git a/test/unit/utFastAtof.cpp b/test/unit/utFastAtof.cpp index 10284a1de..ef1e72202 100644 --- a/test/unit/utFastAtof.cpp +++ b/test/unit/utFastAtof.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utFindDegenerates.cpp b/test/unit/utFindDegenerates.cpp index 5fd016b2c..064031f34 100644 --- a/test/unit/utFindDegenerates.cpp +++ b/test/unit/utFindDegenerates.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -42,43 +40,49 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "UnitTestPCH.h" -#include - +#include "PostProcessing/FindDegenerates.h" using namespace std; using namespace Assimp; class FindDegeneratesProcessTest : public ::testing::Test { public: + FindDegeneratesProcessTest() + : Test() + , mMesh( nullptr ) + , mProcess( nullptr ) { + // empty + } + +protected: virtual void SetUp(); virtual void TearDown(); protected: - aiMesh* mesh; - FindDegeneratesProcess* process; + aiMesh* mMesh; + FindDegeneratesProcess* mProcess; }; -// ------------------------------------------------------------------------------------------------ void FindDegeneratesProcessTest::SetUp() { - mesh = new aiMesh(); - process = new FindDegeneratesProcess(); + mMesh = new aiMesh(); + mProcess = new FindDegeneratesProcess(); - mesh->mNumFaces = 1000; - mesh->mFaces = new aiFace[1000]; + mMesh->mNumFaces = 1000; + mMesh->mFaces = new aiFace[1000]; - mesh->mNumVertices = 5000*2; - mesh->mVertices = new aiVector3D[5000*2]; + mMesh->mNumVertices = 5000*2; + mMesh->mVertices = new aiVector3D[5000*2]; for (unsigned int i = 0; i < 5000; ++i) { - mesh->mVertices[i] = mesh->mVertices[i+5000] = aiVector3D((float)i); + mMesh->mVertices[i] = mMesh->mVertices[i+5000] = aiVector3D((float)i); } - mesh->mPrimitiveTypes = aiPrimitiveType_LINE | aiPrimitiveType_POINT | + mMesh->mPrimitiveTypes = aiPrimitiveType_LINE | aiPrimitiveType_POINT | aiPrimitiveType_POLYGON | aiPrimitiveType_TRIANGLE; unsigned int numOut = 0, numFaces = 0; for (unsigned int i = 0; i < 1000; ++i) { - aiFace& f = mesh->mFaces[i]; + aiFace& f = mMesh->mFaces[i]; f.mNumIndices = (i % 5)+1; // between 1 and 5 f.mIndices = new unsigned int[f.mNumIndices]; bool had = false; @@ -103,46 +107,46 @@ void FindDegeneratesProcessTest::SetUp() { if (!had) ++numFaces; } - mesh->mNumUVComponents[0] = numOut; - mesh->mNumUVComponents[1] = numFaces; + mMesh->mNumUVComponents[0] = numOut; + mMesh->mNumUVComponents[1] = numFaces; } void FindDegeneratesProcessTest::TearDown() { - delete mesh; - delete process; + delete mMesh; + delete mProcess; } TEST_F(FindDegeneratesProcessTest, testDegeneratesDetection) { - process->EnableInstantRemoval(false); - process->ExecuteOnMesh(mesh); + mProcess->EnableInstantRemoval(false); + mProcess->ExecuteOnMesh(mMesh); unsigned int out = 0; for (unsigned int i = 0; i < 1000; ++i) { - aiFace& f = mesh->mFaces[i]; + aiFace& f = mMesh->mFaces[i]; out += f.mNumIndices; } - EXPECT_EQ(1000U, mesh->mNumFaces); - EXPECT_EQ(10000U, mesh->mNumVertices); - EXPECT_EQ(out, mesh->mNumUVComponents[0]); + EXPECT_EQ(1000U, mMesh->mNumFaces); + EXPECT_EQ(10000U, mMesh->mNumVertices); + EXPECT_EQ(out, mMesh->mNumUVComponents[0]); EXPECT_EQ(static_cast( aiPrimitiveType_LINE | aiPrimitiveType_POINT | aiPrimitiveType_POLYGON | aiPrimitiveType_TRIANGLE), - mesh->mPrimitiveTypes); + mMesh->mPrimitiveTypes); } TEST_F(FindDegeneratesProcessTest, testDegeneratesRemoval) { - process->EnableAreaCheck(false); - process->EnableInstantRemoval(true); - process->ExecuteOnMesh(mesh); + mProcess->EnableAreaCheck(false); + mProcess->EnableInstantRemoval(true); + mProcess->ExecuteOnMesh(mMesh); - EXPECT_EQ(mesh->mNumUVComponents[1], mesh->mNumFaces); + EXPECT_EQ(mMesh->mNumUVComponents[1], mMesh->mNumFaces); } TEST_F(FindDegeneratesProcessTest, testDegeneratesRemovalWithAreaCheck) { - process->EnableAreaCheck(true); - process->EnableInstantRemoval(true); - process->ExecuteOnMesh(mesh); + mProcess->EnableAreaCheck(true); + mProcess->EnableInstantRemoval(true); + mProcess->ExecuteOnMesh(mMesh); - EXPECT_EQ(mesh->mNumUVComponents[1]-100, mesh->mNumFaces); + EXPECT_EQ(mMesh->mNumUVComponents[1]-100, mMesh->mNumFaces); } diff --git a/test/unit/utFindInvalidData.cpp b/test/unit/utFindInvalidData.cpp index 2313555b8..7c70a71a9 100644 --- a/test/unit/utFindInvalidData.cpp +++ b/test/unit/utFindInvalidData.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -42,97 +40,106 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "UnitTestPCH.h" -#include -#include "../../include/assimp/mesh.h" - +#include "PostProcessing/FindInvalidDataProcess.h" +#include using namespace std; using namespace Assimp; -class FindInvalidDataProcessTest : public ::testing::Test -{ +class utFindInvalidDataProcess : public ::testing::Test { public: + utFindInvalidDataProcess() + : Test() + , mMesh(nullptr) + , mProcess(nullptr) { + // empty + } + +protected: virtual void SetUp(); virtual void TearDown(); protected: - aiMesh* pcMesh; - FindInvalidDataProcess* piProcess; + aiMesh* mMesh; + FindInvalidDataProcess* mProcess; }; // ------------------------------------------------------------------------------------------------ -void FindInvalidDataProcessTest::SetUp() -{ +void utFindInvalidDataProcess::SetUp() { ASSERT_TRUE( AI_MAX_NUMBER_OF_TEXTURECOORDS >= 3); - piProcess = new FindInvalidDataProcess(); - pcMesh = new aiMesh(); + mProcess = new FindInvalidDataProcess(); + mMesh = new aiMesh(); - pcMesh->mNumVertices = 1000; - pcMesh->mVertices = new aiVector3D[1000]; - for (unsigned int i = 0; i < 1000;++i) - pcMesh->mVertices[i] = aiVector3D((float)i); + mMesh->mNumVertices = 1000; + mMesh->mVertices = new aiVector3D[1000]; + for (unsigned int i = 0; i < 1000; ++i) { + mMesh->mVertices[i] = aiVector3D((float)i); + } - pcMesh->mNormals = new aiVector3D[1000]; - for (unsigned int i = 0; i < 1000;++i) - pcMesh->mNormals[i] = aiVector3D((float)i+1); + mMesh->mNormals = new aiVector3D[1000]; + for (unsigned int i = 0; i < 1000; ++i) { + mMesh->mNormals[i] = aiVector3D((float)i + 1); + } - pcMesh->mTangents = new aiVector3D[1000]; - for (unsigned int i = 0; i < 1000;++i) - pcMesh->mTangents[i] = aiVector3D((float)i); + mMesh->mTangents = new aiVector3D[1000]; + for (unsigned int i = 0; i < 1000; ++i) { + mMesh->mTangents[i] = aiVector3D((float)i); + } - pcMesh->mBitangents = new aiVector3D[1000]; - for (unsigned int i = 0; i < 1000;++i) - pcMesh->mBitangents[i] = aiVector3D((float)i); + mMesh->mBitangents = new aiVector3D[1000]; + for (unsigned int i = 0; i < 1000; ++i) { + mMesh->mBitangents[i] = aiVector3D((float)i); + } - for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) - { - pcMesh->mTextureCoords[a] = new aiVector3D[1000]; - for (unsigned int i = 0; i < 1000;++i) - pcMesh->mTextureCoords[a][i] = aiVector3D((float)i); + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) { + mMesh->mTextureCoords[a] = new aiVector3D[1000]; + for (unsigned int i = 0; i < 1000; ++i) { + mMesh->mTextureCoords[a][i] = aiVector3D((float)i); + } } } // ------------------------------------------------------------------------------------------------ -void FindInvalidDataProcessTest::TearDown() -{ - delete piProcess; - delete pcMesh; +void utFindInvalidDataProcess::TearDown() { + delete mProcess; + delete mMesh; } // ------------------------------------------------------------------------------------------------ -TEST_F(FindInvalidDataProcessTest, testStepNegativeResult) -{ - ::memset(pcMesh->mNormals,0,pcMesh->mNumVertices*sizeof(aiVector3D)); - ::memset(pcMesh->mBitangents,0,pcMesh->mNumVertices*sizeof(aiVector3D)); +TEST_F(utFindInvalidDataProcess, testStepNegativeResult) { + ::memset(mMesh->mNormals, 0, mMesh->mNumVertices*sizeof(aiVector3D) ); + ::memset(mMesh->mBitangents, 0, mMesh->mNumVertices*sizeof(aiVector3D) ); - pcMesh->mTextureCoords[2][455] = aiVector3D( std::numeric_limits::quiet_NaN() ); + mMesh->mTextureCoords[2][455] = aiVector3D( std::numeric_limits::quiet_NaN() ); - piProcess->ProcessMesh(pcMesh); + mProcess->ProcessMesh(mMesh); - EXPECT_TRUE(NULL != pcMesh->mVertices); - EXPECT_TRUE(NULL == pcMesh->mNormals); - EXPECT_TRUE(NULL == pcMesh->mTangents); - EXPECT_TRUE(NULL == pcMesh->mBitangents); + EXPECT_TRUE(NULL != mMesh->mVertices); + EXPECT_EQ(NULL, mMesh->mNormals); + EXPECT_EQ(NULL, mMesh->mTangents); + EXPECT_EQ(NULL, mMesh->mBitangents); - for (unsigned int i = 0; i < 2;++i) - EXPECT_TRUE(NULL != pcMesh->mTextureCoords[i]); + for (unsigned int i = 0; i < 2; ++i) { + EXPECT_TRUE(NULL != mMesh->mTextureCoords[i]); + } - for (unsigned int i = 2; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) - EXPECT_TRUE(NULL == pcMesh->mTextureCoords[i]); + for (unsigned int i = 2; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + EXPECT_EQ(NULL, mMesh->mTextureCoords[i]); + } } // ------------------------------------------------------------------------------------------------ -TEST_F(FindInvalidDataProcessTest, testStepPositiveResult) -{ - piProcess->ProcessMesh(pcMesh); +TEST_F(utFindInvalidDataProcess, testStepPositiveResult) { + mProcess->ProcessMesh(mMesh); - EXPECT_TRUE(NULL != pcMesh->mVertices); + EXPECT_NE(nullptr, mMesh->mVertices); - EXPECT_TRUE(NULL != pcMesh->mNormals); - EXPECT_TRUE(NULL != pcMesh->mTangents); - EXPECT_TRUE(NULL != pcMesh->mBitangents); + EXPECT_NE(nullptr, mMesh->mNormals); + EXPECT_NE(nullptr, mMesh->mTangents); + EXPECT_NE(nullptr, mMesh->mBitangents); - for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) - EXPECT_TRUE(NULL != pcMesh->mTextureCoords[i]); + for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + EXPECT_NE(nullptr, mMesh->mTextureCoords[i]); + } } diff --git a/test/unit/utFixInfacingNormals.cpp b/test/unit/utFixInfacingNormals.cpp index 742b12013..40b962dcb 100644 --- a/test/unit/utFixInfacingNormals.cpp +++ b/test/unit/utFixInfacingNormals.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utGenBoundingBoxesProcess.cpp b/test/unit/utGenBoundingBoxesProcess.cpp new file mode 100644 index 000000000..2c2f831bc --- /dev/null +++ b/test/unit/utGenBoundingBoxesProcess.cpp @@ -0,0 +1,96 @@ +/* +--------------------------------------------------------------------------- +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 "UnitTestPCH.h" + +#include "PostProcessing/GenBoundingBoxesProcess.h" +#include +#include + +using namespace Assimp; + +class utGenBoundingBoxesProcess : public ::testing::Test { +public: + utGenBoundingBoxesProcess() + : Test() + , mProcess(nullptr) + , mMesh(nullptr) + , mScene(nullptr) { + // empty + } + + void SetUp() override { + mProcess = new GenBoundingBoxesProcess; + mMesh = new aiMesh(); + mMesh->mNumVertices = 100; + mMesh->mVertices = new aiVector3D[100]; + for (unsigned int i = 0; i < 100; ++i) { + mMesh->mVertices[i] = aiVector3D((ai_real)i, (ai_real)i, (ai_real)i); + } + mScene = new aiScene(); + mScene->mNumMeshes = 1; + mScene->mMeshes = new aiMesh*[1]; + mScene->mMeshes[0] = mMesh; + } + + void TearDown() override { + delete mProcess; + delete mScene; + } + +protected: + GenBoundingBoxesProcess *mProcess; + aiMesh *mMesh; + aiScene* mScene; +}; + +TEST_F(utGenBoundingBoxesProcess, executeTest) { + mProcess->Execute(mScene); + + aiMesh* mesh = mScene->mMeshes[0]; + EXPECT_NE(nullptr, mesh); + EXPECT_EQ(0, mesh->mAABB.mMin.x); + EXPECT_EQ(0, mesh->mAABB.mMin.y); + EXPECT_EQ(0, mesh->mAABB.mMin.z); + + EXPECT_EQ(99, mesh->mAABB.mMax.x); + EXPECT_EQ(99, mesh->mAABB.mMax.y); + EXPECT_EQ(99, mesh->mAABB.mMax.z); +} diff --git a/test/unit/utGenNormals.cpp b/test/unit/utGenNormals.cpp index 253d76742..36f0b18bc 100644 --- a/test/unit/utGenNormals.cpp +++ b/test/unit/utGenNormals.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -41,7 +41,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ #include "UnitTestPCH.h" -#include + +#include "PostProcessing/GenVertexNormalsProcess.h" using namespace ::std; using namespace ::Assimp; diff --git a/test/unit/utHMPImportExport.cpp b/test/unit/utHMPImportExport.cpp index 1e1a4bcd2..35f4583aa 100644 --- a/test/unit/utHMPImportExport.cpp +++ b/test/unit/utHMPImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utIFCImportExport.cpp b/test/unit/utIFCImportExport.cpp index 01132435b..3f7cf7c8c 100644 --- a/test/unit/utIFCImportExport.cpp +++ b/test/unit/utIFCImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utIOStreamBuffer.cpp b/test/unit/utIOStreamBuffer.cpp index 41575fa59..6c6153135 100644 --- a/test/unit/utIOStreamBuffer.cpp +++ b/test/unit/utIOStreamBuffer.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utIOSystem.cpp b/test/unit/utIOSystem.cpp index c5c02bd45..80165fe79 100644 --- a/test/unit/utIOSystem.cpp +++ b/test/unit/utIOSystem.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utImporter.cpp b/test/unit/utImporter.cpp index b76c96d2a..3e88e3ff4 100644 --- a/test/unit/utImporter.cpp +++ b/test/unit/utImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utImproveCacheLocality.cpp b/test/unit/utImproveCacheLocality.cpp index 01f99ebb9..8564bb01d 100644 --- a/test/unit/utImproveCacheLocality.cpp +++ b/test/unit/utImproveCacheLocality.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utIssues.cpp b/test/unit/utIssues.cpp index e526c2b82..0e30fa182 100644 --- a/test/unit/utIssues.cpp +++ b/test/unit/utIssues.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -74,7 +74,7 @@ TEST_F( utIssues, OpacityBugWhenExporting_727 ) { if ( newScene->mNumMaterials > 0 ) { std::cout << "Desc = " << desc->description << "\n"; EXPECT_EQ( AI_SUCCESS, newScene->mMaterials[ 0 ]->Get( AI_MATKEY_OPACITY, newOpacity ) ); - EXPECT_EQ( opacity, newOpacity ); + EXPECT_FLOAT_EQ( opacity, newOpacity ); } delete scene; } diff --git a/test/unit/utJoinVertices.cpp b/test/unit/utJoinVertices.cpp index 522cec4af..215b0dd90 100644 --- a/test/unit/utJoinVertices.cpp +++ b/test/unit/utJoinVertices.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -43,15 +41,22 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitTestPCH.h" #include -#include +#include "PostProcessing/JoinVerticesProcess.h" using namespace std; using namespace Assimp; -class JoinVerticesTest : public ::testing::Test -{ +class utJoinVertices : public ::testing::Test { public: + utJoinVertices() + : Test() + , piProcess(nullptr) + , pcMesh(nullptr) { + // empty + } + +protected: virtual void SetUp(); virtual void TearDown(); @@ -61,8 +66,7 @@ protected: }; // ------------------------------------------------------------------------------------------------ -void JoinVerticesTest::SetUp() -{ +void utJoinVertices::SetUp() { // construct the process piProcess = new JoinVerticesProcess(); @@ -72,11 +76,9 @@ void JoinVerticesTest::SetUp() pcMesh->mNumVertices = 900; aiVector3D*& pv = pcMesh->mVertices = new aiVector3D[900]; - for (unsigned int i = 0; i < 3;++i) - { + for (unsigned int i = 0; i < 3;++i) { const unsigned int base = i*300; - for (unsigned int a = 0; a < 300;++a) - { + for (unsigned int a = 0; a < 300;++a) { pv[base+a].x = pv[base+a].y = pv[base+a].z = (float)a; } } @@ -84,38 +86,37 @@ void JoinVerticesTest::SetUp() // generate faces - each vertex is referenced once pcMesh->mNumFaces = 300; pcMesh->mFaces = new aiFace[300]; - for (unsigned int i = 0,p = 0; i < 300;++i) - { + for (unsigned int i = 0,p = 0; i < 300;++i) { aiFace& face = pcMesh->mFaces[i]; face.mIndices = new unsigned int[ face.mNumIndices = 3 ]; - for (unsigned int a = 0; a < 3;++a) + for (unsigned int a = 0; a < 3; ++a) { face.mIndices[a] = p++; + } } // generate extra members - set them to zero to make sure they're identical pcMesh->mTextureCoords[0] = new aiVector3D[900]; - for (unsigned int i = 0; i < 900;++i)pcMesh->mTextureCoords[0][i] = aiVector3D( 0.f ); - - pcMesh->mNormals = new aiVector3D[900]; - for (unsigned int i = 0; i < 900;++i)pcMesh->mNormals[i] = aiVector3D( 0.f ); - - pcMesh->mTangents = new aiVector3D[900]; - for (unsigned int i = 0; i < 900;++i)pcMesh->mTangents[i] = aiVector3D( 0.f ); - pcMesh->mBitangents = new aiVector3D[900]; - for (unsigned int i = 0; i < 900;++i)pcMesh->mBitangents[i] = aiVector3D( 0.f ); + pcMesh->mNormals = new aiVector3D[900]; + pcMesh->mTangents = new aiVector3D[900]; + for (unsigned int i = 0; i < 900; ++i) { + pcMesh->mTextureCoords[0][i] = aiVector3D(0.f); + pcMesh->mNormals[i] = aiVector3D(0.f); + pcMesh->mTangents[i] = aiVector3D(0.f); + pcMesh->mBitangents[i] = aiVector3D(0.f); + } } // ------------------------------------------------------------------------------------------------ -void JoinVerticesTest::TearDown() -{ +void utJoinVertices::TearDown() { delete this->pcMesh; + pcMesh = nullptr; delete this->piProcess; + piProcess = nullptr; } // ------------------------------------------------------------------------------------------------ -TEST_F(JoinVerticesTest, testProcess) -{ +TEST_F(utJoinVertices, testProcess) { // execute the step on the given data piProcess->ProcessMesh(pcMesh,0); @@ -123,15 +124,14 @@ TEST_F(JoinVerticesTest, testProcess) ASSERT_EQ(300U, pcMesh->mNumFaces); ASSERT_EQ(300U, pcMesh->mNumVertices); - ASSERT_TRUE(NULL != pcMesh->mNormals); - ASSERT_TRUE(NULL != pcMesh->mTangents); - ASSERT_TRUE(NULL != pcMesh->mBitangents); - ASSERT_TRUE(NULL != pcMesh->mTextureCoords[0]); + ASSERT_TRUE( nullptr != pcMesh->mNormals); + ASSERT_TRUE( nullptr != pcMesh->mTangents); + ASSERT_TRUE( nullptr != pcMesh->mBitangents); + ASSERT_TRUE( nullptr != pcMesh->mTextureCoords[0]); // the order doesn't care float fSum = 0.f; - for (unsigned int i = 0; i < 300;++i) - { + for (unsigned int i = 0; i < 300; ++i) { aiVector3D& v = pcMesh->mVertices[i]; fSum += v.x + v.y + v.z; @@ -142,4 +142,3 @@ TEST_F(JoinVerticesTest, testProcess) } EXPECT_EQ(150.f*299.f*3.f, fSum); // gaussian sum equation } - diff --git a/code/ScaleProcess.cpp b/test/unit/utLWOImportExport.cpp similarity index 52% rename from code/ScaleProcess.cpp rename to test/unit/utLWOImportExport.cpp index facc39d7d..c8655b664 100644 --- a/code/ScaleProcess.cpp +++ b/test/unit/utLWOImportExport.cpp @@ -1,15 +1,17 @@ /* +--------------------------------------------------------------------------- Open Asset Import Library (assimp) ----------------------------------------------------------------------- +--------------------------------------------------------------------------- + +Copyright (c) 2006-2019, assimp team -Copyright (c) 2006-2018, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the -following conditions are met: +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 @@ -36,68 +38,44 @@ 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_GLOBALSCALE_PROCESS - -#include "ScaleProcess.h" - -#include +#include "UnitTestPCH.h" +#include "AbstractImportExportBase.h" #include +#include +#include -namespace Assimp { +using namespace Assimp; -ScaleProcess::ScaleProcess() -: BaseProcess() -, mScale( AI_CONFIG_GLOBAL_SCALE_FACTOR_DEFAULT ) { - // empty -} -ScaleProcess::~ScaleProcess() { - // empty -} +class utLWOImportExport : public AbstractImportExportBase { +public: + virtual bool importerTest() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/boxuv.lwo", aiProcess_ValidateDataStructure); -void ScaleProcess::setScale( ai_real scale ) { - mScale = scale; -} + EXPECT_EQ(1u, scene->mNumMeshes); + EXPECT_NE(nullptr, scene->mMeshes[0]); + EXPECT_EQ(24u, scene->mMeshes[0]->mNumVertices); -ai_real ScaleProcess::getScale() const { - return mScale; -} + //This test model is using n-gons, so 6 faces instead of 12 tris + EXPECT_EQ(6u, scene->mMeshes[0]->mNumFaces); + EXPECT_EQ(aiPrimitiveType_POLYGON, scene->mMeshes[0]->mPrimitiveTypes); + EXPECT_EQ(true, scene->mMeshes[0]->HasTextureCoords(0)); -bool ScaleProcess::IsActive( unsigned int pFlags ) const { - return ( pFlags & aiProcess_GlobalScale ) != 0; -} - -void ScaleProcess::SetupProperties( const Importer* pImp ) { - mScale = pImp->GetPropertyFloat( AI_CONFIG_GLOBAL_SCALE_FACTOR_KEY, 0 ); -} - -void ScaleProcess::Execute( aiScene* pScene ) { - if ( nullptr == pScene ) { - return; + return nullptr != scene; } +}; - if ( nullptr == pScene->mRootNode ) { - return; - } - - traverseNodes( pScene->mRootNode ); +TEST_F( utLWOImportExport, importLWObox_uv ) { + EXPECT_TRUE( importerTest() ); } -void ScaleProcess::traverseNodes( aiNode *node ) { - applyScaling( node ); +TEST_F(utLWOImportExport, importLWOformatdetection) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/LWO/LWO2/formatDetection", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); } -void ScaleProcess::applyScaling( aiNode *currentNode ) { - if ( nullptr != currentNode ) { - currentNode->mTransformation.a1 = currentNode->mTransformation.a1 * mScale; - currentNode->mTransformation.b2 = currentNode->mTransformation.b2 * mScale; - currentNode->mTransformation.c3 = currentNode->mTransformation.c3 * mScale; - } -} - -} // Namespace Assimp - -#endif // !! ASSIMP_BUILD_NO_GLOBALSCALE_PROCESS diff --git a/test/unit/utLWSImportExport.cpp b/test/unit/utLWSImportExport.cpp index e34cfc90e..b04424b48 100644 --- a/test/unit/utLWSImportExport.cpp +++ b/test/unit/utLWSImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utLimitBoneWeights.cpp b/test/unit/utLimitBoneWeights.cpp index 1ce1cff1b..927a9e37c 100644 --- a/test/unit/utLimitBoneWeights.cpp +++ b/test/unit/utLimitBoneWeights.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -43,90 +41,90 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitTestPCH.h" #include -#include +#include "PostProcessing/LimitBoneWeightsProcess.h" using namespace std; using namespace Assimp; class LimitBoneWeightsTest : public ::testing::Test { public: + LimitBoneWeightsTest() + : Test() + , mProcess(nullptr) + , mMesh(nullptr) { + // empty + } + +protected: virtual void SetUp(); virtual void TearDown(); protected: - LimitBoneWeightsProcess* piProcess; - aiMesh* pcMesh; + LimitBoneWeightsProcess *mProcess; + aiMesh *mMesh; }; // ------------------------------------------------------------------------------------------------ -void LimitBoneWeightsTest::SetUp() -{ +void LimitBoneWeightsTest::SetUp() { // construct the process - this->piProcess = new LimitBoneWeightsProcess(); + this->mProcess = new LimitBoneWeightsProcess(); // now need to create a nice mesh for testing purposes - this->pcMesh = new aiMesh(); + this->mMesh = new aiMesh(); - pcMesh->mNumVertices = 500; - pcMesh->mVertices = new aiVector3D[500]; // uninit. - pcMesh->mNumBones = 30; - pcMesh->mBones = new aiBone*[30]; + mMesh->mNumVertices = 500; + mMesh->mVertices = new aiVector3D[500]; // uninit. + mMesh->mNumBones = 30; + mMesh->mBones = new aiBone*[30]; unsigned int iCur = 0; - for (unsigned int i = 0; i < 30;++i) - { - aiBone* pc = pcMesh->mBones[i] = new aiBone(); + for (unsigned int i = 0; i < 30;++i) { + aiBone* pc = mMesh->mBones[i] = new aiBone(); pc->mNumWeights = 250; pc->mWeights = new aiVertexWeight[pc->mNumWeights]; - for (unsigned int qq = 0; qq < pc->mNumWeights;++qq) - { + for (unsigned int qq = 0; qq < pc->mNumWeights;++qq) { aiVertexWeight& v = pc->mWeights[qq]; v.mVertexId = iCur++; - if (500 == iCur)iCur = 0; + if (500 == iCur) { + iCur = 0; + } v.mWeight = 1.0f / 15; // each vertex should occur once in two bones } } } // ------------------------------------------------------------------------------------------------ -void LimitBoneWeightsTest::TearDown() -{ - delete pcMesh; - delete piProcess; +void LimitBoneWeightsTest::TearDown() { + delete mMesh; + delete mProcess; } // ------------------------------------------------------------------------------------------------ -TEST_F(LimitBoneWeightsTest, testProcess) -{ +TEST_F(LimitBoneWeightsTest, testProcess) { // execute the step on the given data - piProcess->ProcessMesh(pcMesh); + mProcess->ProcessMesh(mMesh); // check whether everything is ok ... typedef std::vector VertexWeightList; - VertexWeightList* asWeights = new VertexWeightList[pcMesh->mNumVertices]; + VertexWeightList* asWeights = new VertexWeightList[mMesh->mNumVertices]; - for (unsigned int i = 0; i < pcMesh->mNumVertices;++i) + for (unsigned int i = 0; i < mMesh->mNumVertices; ++i) { asWeights[i].reserve(4); + } // sort back as per-vertex lists - for (unsigned int i = 0; i < pcMesh->mNumBones;++i) - { - aiBone& pcBone = **(pcMesh->mBones+i); - for (unsigned int q = 0; q < pcBone.mNumWeights;++q) - { + for (unsigned int i = 0; i < mMesh->mNumBones;++i) { + aiBone& pcBone = **(mMesh->mBones+i); + for (unsigned int q = 0; q < pcBone.mNumWeights;++q) { aiVertexWeight weight = pcBone.mWeights[q]; asWeights[weight.mVertexId].push_back(LimitBoneWeightsProcess::Weight (i,weight.mWeight)); } } // now validate the size of the lists and check whether all weights sum to 1.0f - for (unsigned int i = 0; i < pcMesh->mNumVertices;++i) - { + for (unsigned int i = 0; i < mMesh->mNumVertices;++i) { EXPECT_LE(asWeights[i].size(), 4U); float fSum = 0.0f; - for (VertexWeightList::const_iterator - iter = asWeights[i].begin(); - iter != asWeights[i].end();++iter) - { + for (VertexWeightList::const_iterator iter = asWeights[i].begin(); iter != asWeights[i].end();++iter) { fSum += (*iter).mWeight; } EXPECT_GE(fSum, 0.95F); diff --git a/test/unit/utMDCImportExport.cpp b/test/unit/utMDCImportExport.cpp index 19b8e68d2..30a4cfad1 100644 --- a/test/unit/utMDCImportExport.cpp +++ b/test/unit/utMDCImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utMaterialSystem.cpp b/test/unit/utMaterialSystem.cpp index 55ee6e2a0..701b933e7 100644 --- a/test/unit/utMaterialSystem.cpp +++ b/test/unit/utMaterialSystem.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -43,13 +43,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitTestPCH.h" #include -#include +#include "Material/MaterialSystem.h" using namespace ::std; using namespace ::Assimp; -class MaterialSystemTest : public ::testing::Test -{ +class MaterialSystemTest : public ::testing::Test { public: virtual void SetUp() { this->pcMat = new aiMaterial(); } virtual void TearDown() { delete this->pcMat; } diff --git a/test/unit/utMatrix3x3.cpp b/test/unit/utMatrix3x3.cpp index bc15f780d..bff8ca1cd 100644 --- a/test/unit/utMatrix3x3.cpp +++ b/test/unit/utMatrix3x3.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utMatrix4x4.cpp b/test/unit/utMatrix4x4.cpp index b11f0b43d..e94bf500c 100644 --- a/test/unit/utMatrix4x4.cpp +++ b/test/unit/utMatrix4x4.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utMetadata.cpp b/test/unit/utMetadata.cpp index c2cd6e1ef..64b7dfe4c 100644 --- a/test/unit/utMetadata.cpp +++ b/test/unit/utMetadata.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utObjImportExport.cpp b/test/unit/utObjImportExport.cpp index f0b20fb7f..b6cb72623 100644 --- a/test/unit/utObjImportExport.cpp +++ b/test/unit/utObjImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -78,7 +78,7 @@ static const float VertComponents[ 24 * 3 ] = { 0.500000, -0.500000, 0.500000f }; -static const std::string ObjModel = +static const char *ObjModel = "o 1\n" "\n" "# Vertex list\n" @@ -105,7 +105,7 @@ static const std::string ObjModel = "\n" "# End of file\n"; -static const std::string ObjModel_Issue1111 = +static const char *ObjModel_Issue1111 = "o 1\n" "\n" "# Vertex list\n" @@ -205,8 +205,8 @@ protected: ::Assimp::Exporter exporter; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure ); EXPECT_NE( nullptr, scene ); - EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "obj", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_test.obj" ) ); - EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "objnomtl", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_nomtl_test.obj" ) ); + EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "obj", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_out.obj" ) ); + EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "objnomtl", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_nomtl_out.obj" ) ); return true; } @@ -231,7 +231,7 @@ TEST_F( utObjImportExport, exportObjFromFileTest ) { #endif // ASSIMP_BUILD_NO_EXPORT TEST_F( utObjImportExport, obj_import_test ) { - const aiScene *scene = m_im->ReadFileFromMemory( (void*) ObjModel.c_str(), ObjModel.size(), 0 ); + const aiScene *scene = m_im->ReadFileFromMemory( (void*) ObjModel, strlen(ObjModel), 0 ); aiScene *expected = createScene(); EXPECT_NE( nullptr, scene ); @@ -252,7 +252,7 @@ TEST_F( utObjImportExport, obj_import_test ) { } TEST_F( utObjImportExport, issue1111_no_mat_name_Test ) { - const aiScene *scene = m_im->ReadFileFromMemory( ( void* ) ObjModel_Issue1111.c_str(), ObjModel_Issue1111.size(), 0 ); + const aiScene *scene = m_im->ReadFileFromMemory( ( void* ) ObjModel_Issue1111, strlen(ObjModel_Issue1111), 0 ); EXPECT_NE( nullptr, scene ); } @@ -263,7 +263,7 @@ TEST_F( utObjImportExport, issue809_vertex_color_Test ) { #ifndef ASSIMP_BUILD_NO_EXPORT ::Assimp::Exporter exporter; - EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "obj", ASSIMP_TEST_MODELS_DIR "/OBJ/test.obj" ) ); + EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "obj", ASSIMP_TEST_MODELS_DIR "/OBJ/test_out.obj" ) ); #endif // ASSIMP_BUILD_NO_EXPORT } @@ -290,7 +290,7 @@ TEST_F( utObjImportExport, issue1923_vertex_color_Test ) { } TEST_F( utObjImportExport, issue1453_segfault ) { - static const std::string ObjModel = + static const char *ObjModel = "v 0.0 0.0 0.0\n" "v 0.0 0.0 1.0\n" "v 0.0 1.0 0.0\n" @@ -301,12 +301,12 @@ TEST_F( utObjImportExport, issue1453_segfault ) { "v 1.0 1.0 1.0\nB"; Assimp::Importer myimporter; - const aiScene *scene = myimporter.ReadFileFromMemory( ObjModel.c_str(), ObjModel.size(), aiProcess_ValidateDataStructure ); + const aiScene *scene = myimporter.ReadFileFromMemory( ObjModel, strlen(ObjModel), aiProcess_ValidateDataStructure ); EXPECT_EQ( nullptr, scene ); } TEST_F(utObjImportExport, relative_indices_Test) { - static const std::string ObjModel = + static const char *ObjModel = "v -0.500000 0.000000 0.400000\n" "v -0.500000 0.000000 -0.800000\n" "v -0.500000 1.000000 -0.800000\n" @@ -314,7 +314,7 @@ TEST_F(utObjImportExport, relative_indices_Test) { "f -4 -3 -2 -1\nB"; Assimp::Importer myimporter; - const aiScene *scene = myimporter.ReadFileFromMemory(ObjModel.c_str(), ObjModel.size(), aiProcess_ValidateDataStructure); + const aiScene *scene = myimporter.ReadFileFromMemory(ObjModel, strlen(ObjModel), aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); EXPECT_EQ(scene->mNumMeshes, 1U); @@ -331,14 +331,14 @@ TEST_F(utObjImportExport, relative_indices_Test) { } TEST_F(utObjImportExport, homogeneous_coordinates_Test) { - static const std::string ObjModel = + static const char *ObjModel = "v -0.500000 0.000000 0.400000 0.50000\n" "v -0.500000 0.000000 -0.800000 1.00000\n" "v 0.500000 1.000000 -0.800000 0.5000\n" "f 1 2 3\nB"; Assimp::Importer myimporter; - const aiScene *scene = myimporter.ReadFileFromMemory(ObjModel.c_str(), ObjModel.size(), aiProcess_ValidateDataStructure); + const aiScene *scene = myimporter.ReadFileFromMemory(ObjModel, strlen(ObjModel), aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); EXPECT_EQ(scene->mNumMeshes, 1U); @@ -354,29 +354,76 @@ TEST_F(utObjImportExport, homogeneous_coordinates_Test) { } TEST_F(utObjImportExport, homogeneous_coordinates_divide_by_zero_Test) { - static const std::string ObjModel = + static const char *ObjModel = "v -0.500000 0.000000 0.400000 0.\n" "v -0.500000 0.000000 -0.800000 1.00000\n" "v 0.500000 1.000000 -0.800000 0.5000\n" "f 1 2 3\nB"; Assimp::Importer myimporter; - const aiScene *scene = myimporter.ReadFileFromMemory(ObjModel.c_str(), ObjModel.size(), aiProcess_ValidateDataStructure); + const aiScene *scene = myimporter.ReadFileFromMemory(ObjModel, strlen(ObjModel), aiProcess_ValidateDataStructure); EXPECT_EQ(nullptr, scene); } TEST_F(utObjImportExport, 0based_array_Test) { - static const std::string ObjModel = + static const char *ObjModel = "v -0.500000 0.000000 0.400000\n" "v -0.500000 0.000000 -0.800000\n" "v -0.500000 1.000000 -0.800000\n" "f 0 1 2\nB"; - Assimp::Importer myimporter; - const aiScene *scene = myimporter.ReadFileFromMemory(ObjModel.c_str(), ObjModel.size(), 0); + Assimp::Importer myImporter; + const aiScene *scene = myImporter.ReadFileFromMemory(ObjModel, strlen(ObjModel), 0); EXPECT_EQ(nullptr, scene); } +TEST_F(utObjImportExport, invalid_normals_uvs) { + static const char *ObjModel = + "v -0.500000 0.000000 0.400000\n" + "v -0.500000 0.000000 -0.800000\n" + "v -0.500000 1.000000 -0.800000\n" + "vt 0 0\n" + "vn 0 1 0\n" + "f 1/1/1 1/1/1 2/2/2\nB"; + + Assimp::Importer myImporter; + const aiScene *scene = myImporter.ReadFileFromMemory(ObjModel, strlen(ObjModel), 0); + EXPECT_NE(nullptr, scene); +} + +TEST_F(utObjImportExport, no_vt_just_vns) { + static const char *ObjModel = + "v 0 0 0\n" + "v 0 0 0\n" + "v 0 0 0\n" + "v 0 0 0\n" + "v 0 0 0\n" + "v 0 0 0\n" + "v 0 0 0\n" + "v 0 0 0\n" + "v 0 0 0\n" + "v 0 0 0\n" + "v 10 0 0\n" + "v 0 10 0\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "vn 0 0 1\n" + "f 10/10 11/11 12/12\n"; + + Assimp::Importer myImporter; + const aiScene *scene = myImporter.ReadFileFromMemory(ObjModel, strlen(ObjModel), 0); + EXPECT_NE(nullptr, scene); +} + TEST_F( utObjImportExport, mtllib_after_g ) { ::Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/cube_mtllib_after_g.obj", aiProcess_ValidateDataStructure ); @@ -396,3 +443,42 @@ TEST_F(utObjImportExport, import_point_cloud) { ASSERT_NE(nullptr, scene); } +TEST_F(utObjImportExport, import_without_linend) { + Assimp::Importer myImporter; + const aiScene *scene = myImporter.ReadFile(ASSIMP_TEST_MODELS_DIR "/OBJ/box_without_lineending.obj", 0); + ASSERT_NE(nullptr, scene); +} + +TEST_F(utObjImportExport, import_with_line_continuations) { + static const char *ObjModel = + "v -0.5 -0.5 0.5\n" + "v -0.5 \\\n" + " -0.5 -0.5\n" + "v -0.5 \\\n" + " 0.5 \\\n" + " -0.5\n" + "f 1 2 3\n"; + + Assimp::Importer myImporter; + const aiScene *scene = myImporter.ReadFileFromMemory(ObjModel, strlen(ObjModel), 0); + EXPECT_NE(nullptr, scene); + + EXPECT_EQ(scene->mNumMeshes, 1U); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 3U); + EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 1U); + + auto vertices = scene->mMeshes[0]->mVertices; + const float threshold = 0.0001f; + + EXPECT_NEAR(vertices[0].x, -0.5f, threshold); + EXPECT_NEAR(vertices[0].y, -0.5f, threshold); + EXPECT_NEAR(vertices[0].z, 0.5f, threshold); + + EXPECT_NEAR(vertices[1].x, -0.5f, threshold); + EXPECT_NEAR(vertices[1].y, -0.5f, threshold); + EXPECT_NEAR(vertices[1].z, -0.5f, threshold); + + EXPECT_NEAR(vertices[2].x, -0.5f, threshold); + EXPECT_NEAR(vertices[2].y, 0.5f, threshold); + EXPECT_NEAR(vertices[2].z, -0.5f, threshold); +} diff --git a/test/unit/utObjTools.cpp b/test/unit/utObjTools.cpp index 6604dfd59..2de45d962 100644 --- a/test/unit/utObjTools.cpp +++ b/test/unit/utObjTools.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -41,8 +41,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ #include "UnitTestPCH.h" -#include "ObjTools.h" -#include "ObjFileParser.h" +#include "Obj/ObjTools.h" +#include "Obj/ObjFileParser.h" using namespace ::Assimp; diff --git a/test/unit/utOpenGEXImportExport.cpp b/test/unit/utOpenGEXImportExport.cpp index 313a7210e..4e154f50f 100644 --- a/test/unit/utOpenGEXImportExport.cpp +++ b/test/unit/utOpenGEXImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utPLYImportExport.cpp b/test/unit/utPLYImportExport.cpp index 5aabe0805..17d1b28de 100644 --- a/test/unit/utPLYImportExport.cpp +++ b/test/unit/utPLYImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -56,6 +56,9 @@ public: const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", aiProcess_ValidateDataStructure); EXPECT_EQ( 1u, scene->mNumMeshes ); EXPECT_NE( nullptr, scene->mMeshes[0] ); + if (nullptr == scene->mMeshes[0]) { + return false; + } EXPECT_EQ( 8u, scene->mMeshes[0]->mNumVertices ); EXPECT_EQ( 6u, scene->mMeshes[0]->mNumFaces ); @@ -68,7 +71,7 @@ public: Exporter exporter; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "ply", ASSIMP_TEST_MODELS_DIR "/PLY/cube_test.ply")); + EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "ply", ASSIMP_TEST_MODELS_DIR "/PLY/cube_out.ply")); return true; } diff --git a/test/unit/utPMXImporter.cpp b/test/unit/utPMXImporter.cpp index 3a1ce1f6a..62d3b0707 100644 --- a/test/unit/utPMXImporter.cpp +++ b/test/unit/utPMXImporter.cpp @@ -42,7 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitTestPCH.h" #include "SceneDiffer.h" #include "AbstractImportExportBase.h" -#include "MMDImporter.h" +#include "MMD/MMDImporter.h" #include diff --git a/test/unit/utPretransformVertices.cpp b/test/unit/utPretransformVertices.cpp index d8f7de165..0839740ac 100644 --- a/test/unit/utPretransformVertices.cpp +++ b/test/unit/utPretransformVertices.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -43,7 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitTestPCH.h" #include -#include +#include "PostProcessing/PretransformVertices.h" using namespace std; @@ -51,18 +51,24 @@ using namespace Assimp; class PretransformVerticesTest : public ::testing::Test { public: + PretransformVerticesTest() + : Test() + , mScene(nullptr) + , mProcess(nullptr) { + // empty + } + +protected: virtual void SetUp(); virtual void TearDown(); protected: - - aiScene* scene; - PretransformVertices* process; + aiScene *mScene; + PretransformVertices *mProcess; }; // ------------------------------------------------------------------------------------------------ -void AddNodes(unsigned int num, aiNode* father, unsigned int depth) -{ +void AddNodes(unsigned int num, aiNode* father, unsigned int depth) { father->mChildren = new aiNode*[father->mNumChildren = 5]; for (unsigned int i = 0; i < 5; ++i) { aiNode* nd = father->mChildren[i] = new aiNode(); @@ -79,26 +85,26 @@ void AddNodes(unsigned int num, aiNode* father, unsigned int depth) } if (depth > 1) { - for (unsigned int i = 0; i < 5; ++i) - AddNodes(i, father->mChildren[i],depth-1); + for (unsigned int i = 0; i < 5; ++i) { + AddNodes(i, father->mChildren[i], depth - 1); + } } } // ------------------------------------------------------------------------------------------------ -void PretransformVerticesTest::SetUp() -{ - scene = new aiScene(); +void PretransformVerticesTest::SetUp() { + mScene = new aiScene(); // add 5 empty materials - scene->mMaterials = new aiMaterial*[scene->mNumMaterials = 5]; + mScene->mMaterials = new aiMaterial*[mScene->mNumMaterials = 5]; for (unsigned int i = 0; i < 5;++i) { - scene->mMaterials[i] = new aiMaterial(); + mScene->mMaterials[i] = new aiMaterial(); } // add 25 test meshes - scene->mMeshes = new aiMesh*[scene->mNumMeshes = 25]; - for ( unsigned int i = 0; i < 25; ++i) { - aiMesh* mesh = scene->mMeshes[ i ] = new aiMesh(); + mScene->mMeshes = new aiMesh*[mScene->mNumMeshes = 25]; + for ( unsigned int i = 0; i < 25; ++i) { + aiMesh* mesh = mScene->mMeshes[ i ] = new aiMesh(); mesh->mPrimitiveTypes = aiPrimitiveType_POINT; mesh->mFaces = new aiFace[ mesh->mNumFaces = 10+i ]; @@ -124,36 +130,33 @@ void PretransformVerticesTest::SetUp() } // construct some nodes (1+25) - scene->mRootNode = new aiNode(); - scene->mRootNode->mName.Set("Root"); - AddNodes(0,scene->mRootNode,2); + mScene->mRootNode = new aiNode(); + mScene->mRootNode->mName.Set("Root"); + AddNodes(0, mScene->mRootNode, 2); - process = new PretransformVertices(); + mProcess = new PretransformVertices(); } // ------------------------------------------------------------------------------------------------ -void PretransformVerticesTest::TearDown() -{ - delete scene; - delete process; +void PretransformVerticesTest::TearDown() { + delete mScene; + delete mProcess; } // ------------------------------------------------------------------------------------------------ -TEST_F(PretransformVerticesTest, testProcessCollapseHierarchy) -{ - process->KeepHierarchy(false); - process->Execute(scene); +TEST_F(PretransformVerticesTest, testProcessCollapseHierarchy) { + mProcess->KeepHierarchy(false); + mProcess->Execute(mScene); - EXPECT_EQ(5U, scene->mNumMaterials); - EXPECT_EQ(10U, scene->mNumMeshes); // every second mesh has normals + EXPECT_EQ(5U, mScene->mNumMaterials); + EXPECT_EQ(10U, mScene->mNumMeshes); // every second mesh has normals } // ------------------------------------------------------------------------------------------------ -TEST_F(PretransformVerticesTest, testProcessKeepHierarchy) -{ - process->KeepHierarchy(true); - process->Execute(scene); +TEST_F(PretransformVerticesTest, testProcessKeepHierarchy) { + mProcess->KeepHierarchy(true); + mProcess->Execute(mScene); - EXPECT_EQ(5U, scene->mNumMaterials); - EXPECT_EQ(49U, scene->mNumMeshes); // see note on mesh 12 above + EXPECT_EQ(5U, mScene->mNumMaterials); + EXPECT_EQ(49U, mScene->mNumMeshes); // see note on mesh 12 above } diff --git a/test/unit/utProfiler.cpp b/test/unit/utProfiler.cpp index 49c9a855c..b86f1952c 100644 --- a/test/unit/utProfiler.cpp +++ b/test/unit/utProfiler.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utQ3DImportExport.cpp b/test/unit/utQ3DImportExport.cpp index 6f840cfc9..51fa4b70a 100644 --- a/test/unit/utQ3DImportExport.cpp +++ b/test/unit/utQ3DImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utRemoveComments.cpp b/test/unit/utRemoveComments.cpp index e236b1d30..cd3175f5a 100644 --- a/test/unit/utRemoveComments.cpp +++ b/test/unit/utRemoveComments.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utRemoveComponent.cpp b/test/unit/utRemoveComponent.cpp index 5fb9656d1..a1ae7ef47 100644 --- a/test/unit/utRemoveComponent.cpp +++ b/test/unit/utRemoveComponent.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -43,22 +43,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitTestPCH.h" #include -#include -#include - +#include "PostProcessing/RemoveVCProcess.h" +#include "Material/MaterialSystem.h" using namespace std; using namespace Assimp; -class RemoveVCProcessTest : public ::testing::Test -{ +class RemoveVCProcessTest : public ::testing::Test { public: - virtual void SetUp(); virtual void TearDown(); protected: - RemoveVCProcess* piProcess; aiScene* pScene; }; diff --git a/test/unit/utRemoveRedundantMaterials.cpp b/test/unit/utRemoveRedundantMaterials.cpp index 312302846..7810afbef 100644 --- a/test/unit/utRemoveRedundantMaterials.cpp +++ b/test/unit/utRemoveRedundantMaterials.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -43,24 +43,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitTestPCH.h" #include -#include -#include - +#include "PostProcessing/RemoveRedundantMaterials.h" +#include "Material/MaterialSystem.h" using namespace std; using namespace Assimp; -class RemoveRedundantMatsTest : public ::testing::Test -{ +class RemoveRedundantMatsTest : public ::testing::Test { public: - virtual void SetUp(); virtual void TearDown(); protected: - RemoveRedundantMatsProcess* piProcess; - aiScene* pcScene1; }; diff --git a/test/unit/utRemoveVCProcess.cpp b/test/unit/utRemoveVCProcess.cpp index 8c726de4a..8db5941d0 100644 --- a/test/unit/utRemoveVCProcess.cpp +++ b/test/unit/utRemoveVCProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -41,7 +41,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ #include "UnitTestPCH.h" -#include "code/RemoveVCProcess.h" +#include "PostProcessing/RemoveVCProcess.h" + #include #include diff --git a/test/unit/utSIBImporter.cpp b/test/unit/utSIBImporter.cpp index da51b14af..582baef64 100644 --- a/test/unit/utSIBImporter.cpp +++ b/test/unit/utSIBImporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -42,9 +42,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "UnitTestPCH.h" -#include "SIBImporter.h" +#include "SIB/SIBImporter.h" + #include #include + #include "AbstractImportExportBase.h" using namespace ::Assimp; diff --git a/test/unit/utSMDImportExport.cpp b/test/unit/utSMDImportExport.cpp index ea315db83..dae490508 100644 --- a/test/unit/utSMDImportExport.cpp +++ b/test/unit/utSMDImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -42,7 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "UnitTestPCH.h" -#include "SMDLoader.h" +#include "SMD/SMDLoader.h" #include #include #include "AbstractImportExportBase.h" diff --git a/test/unit/utSTLImportExport.cpp b/test/unit/utSTLImportExport.cpp index ee62253fd..0f90aacf9 100644 --- a/test/unit/utSTLImportExport.cpp +++ b/test/unit/utSTLImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -80,6 +80,12 @@ TEST_F(utSTLImporterExporter, test_multiple) { EXPECT_NE(nullptr, scene2); } +TEST_F(utSTLImporterExporter, importSTLformatdetection) { + ::Assimp::Importer importer; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/STL/formatDetection", aiProcess_ValidateDataStructure); + + EXPECT_NE(nullptr, scene); +} TEST_F( utSTLImporterExporter, test_with_two_solids ) { Assimp::Importer importer; @@ -146,10 +152,10 @@ TEST_F(utSTLImporterExporter, test_export_pointclouds) { auto pMesh = scene.mMeshes[0]; - long numValidPoints = points.size(); + size_t numValidPoints = points.size(); pMesh->mVertices = new aiVector3D[numValidPoints]; - pMesh->mNumVertices = numValidPoints; + pMesh->mNumVertices = static_cast( numValidPoints ); int i = 0; for (XYZ &p : points) { diff --git a/test/unit/utScaleProcess.cpp b/test/unit/utScaleProcess.cpp index e01f822b9..fd2773c24 100644 --- a/test/unit/utScaleProcess.cpp +++ b/test/unit/utScaleProcess.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -41,7 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ #include "UnitTestPCH.h" -#include "ScaleProcess.h" +#include "PostProcessing/ScaleProcess.h" #include "TestModelFactory.h" namespace Assimp { @@ -69,18 +69,5 @@ TEST_F( utScaleProcess, accessScaleTest ) { EXPECT_FLOAT_EQ( 2.0f, process.getScale() ); } -TEST_F( utScaleProcess, rescaleModelTest ) { - float opacity; - aiScene *testScene = TestModelFacttory::createDefaultTestModel( opacity ); - ai_real v1 = testScene->mRootNode->mTransformation.a1; - ScaleProcess process; - process.setScale( 10.0f ); - process.Execute( testScene ); - ai_real v2 = testScene->mRootNode->mTransformation.a1; - const ai_real scale = v2 / v1; - EXPECT_FLOAT_EQ( scale, 10.0f ); - TestModelFacttory::releaseDefaultTestModel( &testScene ); -} - } // Namespace UnitTest } // Namespace Assimp diff --git a/test/unit/utSceneCombiner.cpp b/test/unit/utSceneCombiner.cpp index 3e7ba0146..e9be598e1 100644 --- a/test/unit/utSceneCombiner.cpp +++ b/test/unit/utSceneCombiner.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utScenePreprocessor.cpp b/test/unit/utScenePreprocessor.cpp index 788ee1d34..7233e1379 100644 --- a/test/unit/utScenePreprocessor.cpp +++ b/test/unit/utScenePreprocessor.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -45,72 +45,72 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include +#include "Common/ScenePreprocessor.h" using namespace std; using namespace Assimp; - -class ScenePreprocessorTest : public ::testing::Test -{ +class ScenePreprocessorTest : public ::testing::Test { public: + ScenePreprocessorTest() + : Test() + , mScenePreprocessor(nullptr) + , mScene(nullptr) { + // empty + } +protected: virtual void SetUp(); virtual void TearDown(); protected: - void CheckIfOnly(aiMesh* p, unsigned int num, unsigned flag); + void ProcessAnimation(aiAnimation* anim) { mScenePreprocessor->ProcessAnimation(anim); } + void ProcessMesh(aiMesh* mesh) { mScenePreprocessor->ProcessMesh(mesh); } - void ProcessAnimation(aiAnimation* anim) { pp->ProcessAnimation(anim); } - void ProcessMesh(aiMesh* mesh) { pp->ProcessMesh(mesh); } - - ScenePreprocessor* pp; - aiScene* scene; +private: + ScenePreprocessor *mScenePreprocessor; + aiScene *mScene; }; // ------------------------------------------------------------------------------------------------ -void ScenePreprocessorTest::SetUp() -{ +void ScenePreprocessorTest::SetUp() { // setup a dummy scene with a single node - scene = new aiScene(); - scene->mRootNode = new aiNode(); - scene->mRootNode->mName.Set(""); + mScene = new aiScene(); + mScene->mRootNode = new aiNode(); + mScene->mRootNode->mName.Set(""); // add some translation - scene->mRootNode->mTransformation.a4 = 1.f; - scene->mRootNode->mTransformation.b4 = 2.f; - scene->mRootNode->mTransformation.c4 = 3.f; + mScene->mRootNode->mTransformation.a4 = 1.f; + mScene->mRootNode->mTransformation.b4 = 2.f; + mScene->mRootNode->mTransformation.c4 = 3.f; // and allocate a ScenePreprocessor to operate on the scene - pp = new ScenePreprocessor(scene); + mScenePreprocessor = new ScenePreprocessor(mScene); } // ------------------------------------------------------------------------------------------------ -void ScenePreprocessorTest::TearDown() -{ - delete pp; - delete scene; +void ScenePreprocessorTest::TearDown() { + delete mScenePreprocessor; + delete mScene; } // ------------------------------------------------------------------------------------------------ // Check whether ProcessMesh() returns flag for a mesh that consist of primitives with num indices -void ScenePreprocessorTest::CheckIfOnly(aiMesh* p, unsigned int num, unsigned int flag) -{ +void ScenePreprocessorTest::CheckIfOnly(aiMesh* p, unsigned int num, unsigned int flag) { // Triangles only for (unsigned i = 0; i < p->mNumFaces;++i) { p->mFaces[i].mNumIndices = num; } - pp->ProcessMesh(p); + mScenePreprocessor->ProcessMesh(p); EXPECT_EQ(flag, p->mPrimitiveTypes); p->mPrimitiveTypes = 0; } // ------------------------------------------------------------------------------------------------ // Check whether a mesh is preprocessed correctly. Case 1: The mesh needs preprocessing -TEST_F(ScenePreprocessorTest, testMeshPreprocessingPos) -{ - aiMesh* p = new aiMesh(); +TEST_F(ScenePreprocessorTest, testMeshPreprocessingPos) { + aiMesh* p = new aiMesh; p->mNumFaces = 100; p->mFaces = new aiFace[p->mNumFaces]; @@ -145,9 +145,8 @@ TEST_F(ScenePreprocessorTest, testMeshPreprocessingPos) // ------------------------------------------------------------------------------------------------ // Check whether a mesh is preprocessed correctly. Case 1: The mesh doesn't need preprocessing -TEST_F(ScenePreprocessorTest, testMeshPreprocessingNeg) -{ - aiMesh* p = new aiMesh(); +TEST_F(ScenePreprocessorTest, testMeshPreprocessingNeg) { + aiMesh* p = new aiMesh; p->mPrimitiveTypes = aiPrimitiveType_TRIANGLE|aiPrimitiveType_POLYGON; ProcessMesh(p); @@ -160,8 +159,7 @@ TEST_F(ScenePreprocessorTest, testMeshPreprocessingNeg) // ------------------------------------------------------------------------------------------------ // Make a dummy animation with a single channel, '' -aiAnimation* MakeDummyAnimation() -{ +aiAnimation* MakeDummyAnimation() { aiAnimation* p = new aiAnimation(); p->mNumChannels = 1; p->mChannels = new aiNodeAnim*[1]; @@ -172,8 +170,7 @@ aiAnimation* MakeDummyAnimation() // ------------------------------------------------------------------------------------------------ // Check whether an anim is preprocessed correctly. Case 1: The anim needs preprocessing -TEST_F(ScenePreprocessorTest, testAnimationPreprocessingPos) -{ +TEST_F(ScenePreprocessorTest, testAnimationPreprocessingPos) { aiAnimation* p = MakeDummyAnimation(); aiNodeAnim* anim = p->mChannels[0]; diff --git a/test/unit/utSharedPPData.cpp b/test/unit/utSharedPPData.cpp index 94f2a5678..53008a27a 100644 --- a/test/unit/utSharedPPData.cpp +++ b/test/unit/utSharedPPData.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -43,21 +43,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitTestPCH.h" #include -#include +#include "Common/BaseProcess.h" using namespace std; using namespace Assimp; -class SharedPPDataTest : public ::testing::Test -{ +class SharedPPDataTest : public ::testing::Test { public: - virtual void SetUp(); virtual void TearDown(); protected: - SharedPostProcessInfo* shared; }; diff --git a/test/unit/utSimd.cpp b/test/unit/utSimd.cpp index 33358c0da..d6bd9fe90 100644 --- a/test/unit/utSimd.cpp +++ b/test/unit/utSimd.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -41,7 +41,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitTestPCH.h" -#include "simd.h" +#include "Common/simd.h" using namespace ::Assimp; diff --git a/test/unit/utSortByPType.cpp b/test/unit/utSortByPType.cpp index 7affd56f1..fb637b004 100644 --- a/test/unit/utSortByPType.cpp +++ b/test/unit/utSortByPType.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -43,29 +43,33 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitTestPCH.h" #include -#include -#include +#include "Common/ScenePreprocessor.h" +#include "PostProcessing/SortByPTypeProcess.h" using namespace std; using namespace Assimp; -class SortByPTypeProcessTest : public ::testing::Test -{ +class SortByPTypeProcessTest : public ::testing::Test { public: + SortByPTypeProcessTest() + : Test() + , mProcess1(nullptr) + , mScene(nullptr) { + // empty + } +protected: virtual void SetUp(); virtual void TearDown(); protected: - - SortByPTypeProcess* process1; - aiScene* scene; + SortByPTypeProcess* mProcess1; + aiScene* mScene; }; // ------------------------------------------------------------------------------------------------ -static unsigned int num[10][4] = - { +static unsigned int num[10][4] = { {0,0,0,1000}, {0,0,1000,0}, {0,1000,0,0}, @@ -79,8 +83,7 @@ static unsigned int num[10][4] = }; // ------------------------------------------------------------------------------------------------ -static unsigned int result[10] = -{ +static unsigned int result[10] = { aiPrimitiveType_POLYGON, aiPrimitiveType_TRIANGLE, aiPrimitiveType_LINE, @@ -94,19 +97,16 @@ static unsigned int result[10] = }; // ------------------------------------------------------------------------------------------------ -void SortByPTypeProcessTest::SetUp() -{ -// process0 = new DeterminePTypeHelperProcess(); - process1 = new SortByPTypeProcess(); - scene = new aiScene(); +void SortByPTypeProcessTest::SetUp() { + mProcess1 = new SortByPTypeProcess(); + mScene = new aiScene(); - scene->mNumMeshes = 10; - scene->mMeshes = new aiMesh*[10]; + mScene->mNumMeshes = 10; + mScene->mMeshes = new aiMesh*[10]; bool five = false; - for (unsigned int i = 0; i < 10; ++i) - { - aiMesh* mesh = scene->mMeshes[i] = new aiMesh(); + for (unsigned int i = 0; i < 10; ++i) { + aiMesh* mesh = mScene->mMeshes[i] = new aiMesh(); mesh->mNumFaces = 1000; aiFace* faces = mesh->mFaces = new aiFace[1000]; aiVector3D* pv = mesh->mVertices = new aiVector3D[mesh->mNumFaces*5]; @@ -119,27 +119,24 @@ void SortByPTypeProcessTest::SetUp() unsigned int remaining[4] = {num[i][0],num[i][1],num[i][2],num[i][3]}; unsigned int n = 0; - for (unsigned int m = 0; m < 1000; ++m) - { + for (unsigned int m = 0; m < 1000; ++m) { unsigned int idx = m % 4; - while (true) - { - if (!remaining[idx]) - { - if (4 == ++idx)idx = 0; + while (true) { + if (!remaining[idx]) { + if (4 == ++idx) { + idx = 0; + } continue; } break; } faces->mNumIndices = idx+1; - if (4 == faces->mNumIndices) - { + if (4 == faces->mNumIndices) { if(five)++faces->mNumIndices; five = !five; } faces->mIndices = new unsigned int[faces->mNumIndices]; - for (unsigned int q = 0; q mNumIndices;++q,++n) - { + for (unsigned int q = 0; q mNumIndices;++q,++n) { faces->mIndices[q] = n; float f = (float)remaining[idx]; @@ -156,12 +153,11 @@ void SortByPTypeProcessTest::SetUp() mesh->mNumVertices = n; } - scene->mRootNode = new aiNode(); - scene->mRootNode->mNumChildren = 5; - scene->mRootNode->mChildren = new aiNode*[5]; - for (unsigned int i = 0; i< 5;++i ) - { - aiNode* node = scene->mRootNode->mChildren[i] = new aiNode(); + mScene->mRootNode = new aiNode(); + mScene->mRootNode->mNumChildren = 5; + mScene->mRootNode->mChildren = new aiNode*[5]; + for (unsigned int i = 0; i< 5;++i ) { + aiNode* node = mScene->mRootNode->mChildren[i] = new aiNode(); node->mNumMeshes = 2; node->mMeshes = new unsigned int[2]; node->mMeshes[0] = (i<<1u); @@ -170,48 +166,27 @@ void SortByPTypeProcessTest::SetUp() } // ------------------------------------------------------------------------------------------------ -void SortByPTypeProcessTest::TearDown() -{ - //delete process0; - delete process1; - delete scene; +void SortByPTypeProcessTest::TearDown() { + delete mProcess1; + delete mScene; } // ------------------------------------------------------------------------------------------------ -//TEST_F(SortByPTypeProcessTest, DeterminePTypeStep() -//{ -// process0->Execute(scene); -// -// for (unsigned int i = 0; i < 10; ++i) -// { -// aiMesh* mesh = scene->mMeshes[i]; -// EXPECT_TRUE(mesh->mPrimitiveTypes == result[i]); -// } -//} - -// ------------------------------------------------------------------------------------------------ -TEST_F(SortByPTypeProcessTest, SortByPTypeStep) -{ - // process0->Execute(scene); - - // and another small test for ScenePreprocessor - ScenePreprocessor s(scene); +TEST_F(SortByPTypeProcessTest, SortByPTypeStep) { + ScenePreprocessor s(mScene); s.ProcessScene(); for (unsigned int m = 0; m< 10;++m) - EXPECT_EQ(result[m], scene->mMeshes[m]->mPrimitiveTypes); + EXPECT_EQ(result[m], mScene->mMeshes[m]->mPrimitiveTypes); - process1->Execute(scene); + mProcess1->Execute(mScene); unsigned int idx = 0; - for (unsigned int m = 0,real = 0; m< 10;++m) - { - for (unsigned int n = 0; n < 4;++n) - { - if ((idx = num[m][n])) - { - EXPECT_TRUE(real < scene->mNumMeshes); + for (unsigned int m = 0,real = 0; m< 10;++m) { + for (unsigned int n = 0; n < 4;++n) { + if ((idx = num[m][n])) { + EXPECT_TRUE(real < mScene->mNumMeshes); - aiMesh* mesh = scene->mMeshes[real]; + aiMesh* mesh = mScene->mMeshes[real]; EXPECT_TRUE(NULL != mesh); EXPECT_EQ(AI_PRIMITIVE_TYPE_FOR_N_INDICES(n+1), mesh->mPrimitiveTypes); @@ -222,8 +197,7 @@ TEST_F(SortByPTypeProcessTest, SortByPTypeStep) EXPECT_TRUE(NULL != mesh->mTextureCoords[0]); EXPECT_TRUE(mesh->mNumFaces == idx); - for (unsigned int f = 0; f < mesh->mNumFaces;++f) - { + for (unsigned int f = 0; f < mesh->mNumFaces;++f) { aiFace& face = mesh->mFaces[f]; EXPECT_TRUE(face.mNumIndices == (n+1) || (3 == n && face.mNumIndices > 3)); } @@ -232,4 +206,3 @@ TEST_F(SortByPTypeProcessTest, SortByPTypeStep) } } } - diff --git a/test/unit/utSplitLargeMeshes.cpp b/test/unit/utSplitLargeMeshes.cpp index 496049d65..fb3f2a037 100644 --- a/test/unit/utSplitLargeMeshes.cpp +++ b/test/unit/utSplitLargeMeshes.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -43,16 +43,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitTestPCH.h" #include -#include - +#include "PostProcessing/SplitLargeMeshes.h" using namespace std; using namespace Assimp; -class SplitLargeMeshesTest : public ::testing::Test -{ +class SplitLargeMeshesTest : public ::testing::Test { public: - virtual void SetUp(); virtual void TearDown(); diff --git a/test/unit/utStringUtils.cpp b/test/unit/utStringUtils.cpp index ab053fd6f..3791e8622 100644 --- a/test/unit/utStringUtils.cpp +++ b/test/unit/utStringUtils.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utTargetAnimation.cpp b/test/unit/utTargetAnimation.cpp index 6bbc1f418..bbcacd2cb 100644 --- a/test/unit/utTargetAnimation.cpp +++ b/test/unit/utTargetAnimation.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utTextureTransform.cpp b/test/unit/utTextureTransform.cpp index 6bbc1f418..bbcacd2cb 100644 --- a/test/unit/utTextureTransform.cpp +++ b/test/unit/utTextureTransform.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utTriangulate.cpp b/test/unit/utTriangulate.cpp index e421d40b1..c65e24a95 100644 --- a/test/unit/utTriangulate.cpp +++ b/test/unit/utTriangulate.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -43,7 +43,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitTestPCH.h" #include -#include + +#include "PostProcessing/TriangulateProcess.h" using namespace std; diff --git a/test/unit/utTypes.cpp b/test/unit/utTypes.cpp index a67154f7c..6289c75e7 100644 --- a/test/unit/utTypes.cpp +++ b/test/unit/utTypes.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utValidateDataStructure.cpp b/test/unit/utValidateDataStructure.cpp new file mode 100644 index 000000000..61fc93dd7 --- /dev/null +++ b/test/unit/utValidateDataStructure.cpp @@ -0,0 +1,199 @@ +/* +--------------------------------------------------------------------------- +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 "UnitTestPCH.h" + +#include +#include +#include + +using namespace std; +using namespace Assimp; + + +class ValidateDataStructureTest : public ::testing::Test +{ +public: + + virtual void SetUp(); + virtual void TearDown(); + +protected: + + + ValidateDSProcess* vds; + aiScene* scene; +}; + +// ------------------------------------------------------------------------------------------------ +void ValidateDataStructureTest::SetUp() +{ + // setup a dummy scene with a single node + scene = new aiScene(); + scene->mRootNode = new aiNode(); + scene->mRootNode->mName.Set(""); + + // add some translation + scene->mRootNode->mTransformation.a4 = 1.f; + scene->mRootNode->mTransformation.b4 = 2.f; + scene->mRootNode->mTransformation.c4 = 3.f; + + // and allocate a ScenePreprocessor to operate on the scene + vds = new ValidateDSProcess(); +} + +// ------------------------------------------------------------------------------------------------ +void ValidateDataStructureTest::TearDown() +{ + delete vds; + delete scene; +} + + + +// ------------------------------------------------------------------------------------------------ +//Template +//TEST_F(ScenePreprocessorTest, test) +//{ +//} +// TODO Conditions not yet checked: +//132: ReportError("aiScene::%s is NULL (aiScene::%s is %i)", +//139: ReportError("aiScene::%s[%i] is NULL (aiScene::%s is %i)", +//156: ReportError("aiScene::%s is NULL (aiScene::%s is %i)", +//163: ReportError("aiScene::%s[%i] is NULL (aiScene::%s is %i)", +//173: ReportError("aiScene::%s[%i] has the same name as " +//192: ReportError("aiScene::%s[%i] has no corresponding node in the scene graph (%s)", +//196: ReportError("aiScene::%s[%i]: there are more than one nodes with %s as name", +//217: ReportError("aiScene::mNumMeshes is 0. At least one mesh must be there"); +//220: ReportError("aiScene::mMeshes is non-null although there are no meshes"); +//229: ReportError("aiScene::mAnimations is non-null although there are no animations"); +//238: ReportError("aiScene::mCameras is non-null although there are no cameras"); +//247: ReportError("aiScene::mLights is non-null although there are no lights"); +//256: ReportError("aiScene::mTextures is non-null although there are no textures"); +//266: ReportError("aiScene::mNumMaterials is 0. At least one material must be there"); +//270: ReportError("aiScene::mMaterials is non-null although there are no materials"); +//281: ReportWarning("aiLight::mType is aiLightSource_UNDEFINED"); +//286: ReportWarning("aiLight::mAttenuationXXX - all are zero"); +//290: ReportError("aiLight::mAngleInnerCone is larger than aiLight::mAngleOuterCone"); +//295: ReportWarning("aiLight::mColorXXX - all are black and won't have any influence"); +//303: ReportError("aiCamera::mClipPlaneFar must be >= aiCamera::mClipPlaneNear"); +//308: ReportWarning("%f is not a valid value for aiCamera::mHorizontalFOV",pCamera->mHorizontalFOV); +//317: ReportError("aiMesh::mMaterialIndex is invalid (value: %i maximum: %i)", +//332: ReportError("aiMesh::mFaces[%i].mNumIndices is 0",i); +//336: ReportError("aiMesh::mFaces[%i] is a POINT but aiMesh::mPrimitiveTypes " +//337: "does not report the POINT flag",i); +//343: ReportError("aiMesh::mFaces[%i] is a LINE but aiMesh::mPrimitiveTypes " +//344: "does not report the LINE flag",i); +//350: ReportError("aiMesh::mFaces[%i] is a TRIANGLE but aiMesh::mPrimitiveTypes " +//351: "does not report the TRIANGLE flag",i); +//357: this->ReportError("aiMesh::mFaces[%i] is a POLYGON but aiMesh::mPrimitiveTypes " +//358: "does not report the POLYGON flag",i); +//365: ReportError("aiMesh::mFaces[%i].mIndices is NULL",i); +//370: ReportError("The mesh %s contains no vertices", pMesh->mName.C_Str()); +//374: ReportError("Mesh has too many vertices: %u, but the limit is %u",pMesh->mNumVertices,AI_MAX_VERTICES); +//377: ReportError("Mesh has too many faces: %u, but the limit is %u",pMesh->mNumFaces,AI_MAX_FACES); +//382: ReportError("If there are tangents, bitangent vectors must be present as well"); +//387: ReportError("Mesh %s contains no faces", pMesh->mName.C_Str()); +//398: ReportError("Face %u has too many faces: %u, but the limit is %u",i,face.mNumIndices,AI_MAX_FACE_INDICES); +//404: ReportError("aiMesh::mFaces[%i]::mIndices[%i] is out of range",i,a); +//412: ReportError("aiMesh::mVertices[%i] is referenced twice - second " +//426: ReportWarning("There are unreferenced vertices"); +//439: ReportError("Texture coordinate channel %i exists " +//453: ReportError("Vertex color channel %i is exists " +//464: ReportError("aiMesh::mBones is NULL (aiMesh::mNumBones is %i)", +//480: ReportError("Bone %u has too many weights: %u, but the limit is %u",i,bone->mNumWeights,AI_MAX_BONE_WEIGHTS); +//485: ReportError("aiMesh::mBones[%i] is NULL (aiMesh::mNumBones is %i)", +//498: ReportError("aiMesh::mBones[%i], name = \"%s\" has the same name as " +//507: ReportWarning("aiMesh::mVertices[%i]: bone weight sum != 1.0 (sum is %f)",i,afSum[i]); +//513: ReportError("aiMesh::mBones is non-null although there are no bones"); +//524: ReportError("aiBone::mNumWeights is zero"); +//531: ReportError("aiBone::mWeights[%i].mVertexId is out of range",i); +//534: ReportWarning("aiBone::mWeights[%i].mWeight has an invalid value",i); +//549: ReportError("aiAnimation::mChannels is NULL (aiAnimation::mNumChannels is %i)", +//556: ReportError("aiAnimation::mChannels[%i] is NULL (aiAnimation::mNumChannels is %i)", +//563: ReportError("aiAnimation::mNumChannels is 0. At least one node animation channel must be there."); +//567: // if (!pAnimation->mDuration)this->ReportError("aiAnimation::mDuration is zero"); +//592: ReportError("Material property %s is expected to be a string",prop->mKey.data); +//596: ReportError("%s #%i is set, but there are only %i %s textures", +//611: ReportError("Found texture property with index %i, although there " +//619: ReportError("Material property %s%i is expected to be an integer (size is %i)", +//627: ReportError("Material property %s%i is expected to be 5 floats large (size is %i)", +//635: ReportError("Material property %s%i is expected to be an integer (size is %i)", +//656: ReportWarning("Invalid UV index: %i (key %s). Mesh %i has only %i UV channels", +//676: ReportWarning("UV-mapped texture, but there are no UV coords"); +//690: ReportError("aiMaterial::mProperties[%i] is NULL (aiMaterial::mNumProperties is %i)", +//694: ReportError("aiMaterial::mProperties[%i].mDataLength or " +//702: ReportError("aiMaterial::mProperties[%i].mDataLength is " +//707: ReportError("Missing null-terminator in string material property"); +//713: ReportError("aiMaterial::mProperties[%i].mDataLength is " +//720: ReportError("aiMaterial::mProperties[%i].mDataLength is " +//739: ReportWarning("A specular shading model is specified but there is no " +//743: ReportWarning("A specular shading model is specified but the value of the " +//752: ReportWarning("Invalid opacity value (must be 0 < opacity < 1.0)"); +//776: ReportError("aiTexture::pcData is NULL"); +//781: ReportError("aiTexture::mWidth is zero (aiTexture::mHeight is %i, uncompressed texture)", +//788: ReportError("aiTexture::mWidth is zero (compressed texture)"); +//791: ReportWarning("aiTexture::achFormatHint must be zero-terminated"); +//794: ReportWarning("aiTexture::achFormatHint should contain a file extension " +//804: ReportError("aiTexture::achFormatHint contains non-lowercase letters"); +//815: ReportError("Empty node animation channel"); +//822: ReportError("aiNodeAnim::mPositionKeys is NULL (aiNodeAnim::mNumPositionKeys is %i)", +//833: ReportError("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is larger " +//840: ReportWarning("aiNodeAnim::mPositionKeys[%i].mTime (%.5f) is smaller " +//853: ReportError("aiNodeAnim::mRotationKeys is NULL (aiNodeAnim::mNumRotationKeys is %i)", +//861: ReportError("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is larger " +//868: ReportWarning("aiNodeAnim::mRotationKeys[%i].mTime (%.5f) is smaller " +//880: ReportError("aiNodeAnim::mScalingKeys is NULL (aiNodeAnim::mNumScalingKeys is %i)", +//888: ReportError("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is larger " +//895: ReportWarning("aiNodeAnim::mScalingKeys[%i].mTime (%.5f) is smaller " +//907: ReportError("A node animation channel must have at least one subtrack"); +//915: ReportError("A node of the scenegraph is NULL"); +//920: ReportError("Non-root node %s lacks a valid parent (aiNode::mParent is NULL) ",pNode->mName); +//928: ReportError("aiNode::mMeshes is NULL for node %s (aiNode::mNumMeshes is %i)", +//937: ReportError("aiNode::mMeshes[%i] is out of range for node %s (maximum is %i)", +//942: ReportError("aiNode::mMeshes[%i] is already referenced by this node %s (value: %i)", +//951: ReportError("aiNode::mChildren is NULL for node %s (aiNode::mNumChildren is %i)", +//965: ReportError("aiString::length is too large (%i, maximum is %lu)", +//974: ReportError("aiString::data is invalid: the terminal zero is at a wrong offset"); +//979: ReportError("aiString::data is invalid. There is no terminal character"); +} + diff --git a/test/unit/utVector3.cpp b/test/unit/utVector3.cpp index 387b4614d..adeb70615 100644 --- a/test/unit/utVector3.cpp +++ b/test/unit/utVector3.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/test/unit/utVersion.cpp b/test/unit/utVersion.cpp index 4886377f8..233b2fb0b 100644 --- a/test/unit/utVersion.cpp +++ b/test/unit/utVersion.cpp @@ -2,9 +2,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -55,11 +53,11 @@ TEST_F( utVersion, aiGetLegalStringTest ) { } TEST_F( utVersion, aiGetVersionMinorTest ) { - EXPECT_EQ( aiGetVersionMinor(), 1U ); + EXPECT_EQ( aiGetVersionMinor(), 0U ); } TEST_F( utVersion, aiGetVersionMajorTest ) { - EXPECT_EQ( aiGetVersionMajor(), 4U ); + EXPECT_EQ( aiGetVersionMajor(), 5U ); } TEST_F( utVersion, aiGetCompileFlagsTest ) { diff --git a/test/unit/utVertexTriangleAdjacency.cpp b/test/unit/utVertexTriangleAdjacency.cpp index dc109f519..e48d3521e 100644 --- a/test/unit/utVertexTriangleAdjacency.cpp +++ b/test/unit/utVertexTriangleAdjacency.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -42,19 +42,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "UnitTestPCH.h" -#include "assimp/types.h" -#include "assimp/mesh.h" - -#include +#include +#include +#include "Common/VertexTriangleAdjacency.h" using namespace std; using namespace Assimp; -class VTAdjacencyTest : public ::testing::Test -{ +class VTAdjacencyTest : public ::testing::Test { protected: - void checkMesh(const aiMesh& mesh); }; diff --git a/test/unit/utX3DImportExport.cpp b/test/unit/utX3DImportExport.cpp index aeee72318..2aa0ae3cc 100644 --- a/test/unit/utX3DImportExport.cpp +++ b/test/unit/utX3DImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utXImporterExporter.cpp b/test/unit/utXImporterExporter.cpp index d4c742e6f..53e156bcc 100644 --- a/test/unit/utXImporterExporter.cpp +++ b/test/unit/utXImporterExporter.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp index 264580aad..829d31451 100644 --- a/test/unit/utglTF2ImportExport.cpp +++ b/test/unit/utglTF2ImportExport.cpp @@ -3,9 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team - - +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -55,17 +53,23 @@ class utglTF2ImportExport : public AbstractImportExportBase { public: virtual bool importerTest() { Assimp::Importer importer; - const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure); + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", + aiProcess_ValidateDataStructure); EXPECT_NE( scene, nullptr ); - if ( !scene ) return false; + if (!scene) { + return false; + } EXPECT_TRUE( scene->HasMaterials() ); - if ( !scene->HasMaterials() ) return false; + if (!scene->HasMaterials()) { + return false; + } const aiMaterial *material = scene->mMaterials[0]; aiString path; aiTextureMapMode modes[2]; - EXPECT_EQ( aiReturn_SUCCESS, material->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, nullptr, nullptr, modes) ); + EXPECT_EQ( aiReturn_SUCCESS, material->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr, + nullptr, nullptr, modes) ); EXPECT_STREQ( path.C_Str(), "CesiumLogoFlat.png" ); EXPECT_EQ( modes[0], aiTextureMapMode_Mirror ); EXPECT_EQ( modes[1], aiTextureMapMode_Clamp ); @@ -75,7 +79,8 @@ public: virtual bool binaryImporterTest() { Assimp::Importer importer; - const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/2CylinderEngine-glTF-Binary/2CylinderEngine.glb", aiProcess_ValidateDataStructure); + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/2CylinderEngine-glTF-Binary/2CylinderEngine.glb", + aiProcess_ValidateDataStructure); return nullptr != scene; } @@ -83,7 +88,8 @@ public: virtual bool exporterTest() { Assimp::Importer importer; Assimp::Exporter exporter; - const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure ); + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", + aiProcess_ValidateDataStructure ); EXPECT_NE( nullptr, scene ); EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "gltf2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured_out.gltf" ) ); @@ -105,7 +111,8 @@ TEST_F( utglTF2ImportExport, importBinaryglTF2FromFileTest ) { TEST_F(utglTF2ImportExport, importglTF2AndExportToOBJ) { Assimp::Importer importer; Assimp::Exporter exporter; - const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure); + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", + aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "obj", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured_out.obj")); } @@ -113,7 +120,8 @@ TEST_F(utglTF2ImportExport, importglTF2AndExportToOBJ) { TEST_F(utglTF2ImportExport, importglTF2EmbeddedAndExportToOBJ) { Assimp::Importer importer; Assimp::Exporter exporter; - const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-Embedded/BoxTextured.gltf", aiProcess_ValidateDataStructure); + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-Embedded/BoxTextured.gltf", + aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "obj", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-Embedded/BoxTextured_out.obj")); } @@ -124,10 +132,9 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModePointsWithoutIndices) { //Points without indices const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_00.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 1024); - for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) - { - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 1); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 1024u); + for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) { + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 1u); EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i); } } @@ -137,12 +144,11 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLinesWithoutIndices) { //Lines without indices const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_01.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 8); - for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) - { - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2); - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i*2); - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], i*2 + 1); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 8u); + for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) { + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2u); + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i*2u); + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], i*2u + 1u); } } @@ -151,15 +157,14 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLinesLoopWithoutIndices) { //Lines loop without indices const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_02.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u); - std::array l1 = {{ 0, 1, 2, 3, 0 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2); - for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) - { - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2); + std::array l1 = {{ 0u, 1u, 2u, 3u, 0u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u); + for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) { + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2u); EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], l1[i]); - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], l1[i + 1]); + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], l1[i + 1u]); } } @@ -168,14 +173,13 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLinesStripWithoutIndices) { //Lines strip without indices const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_03.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 5); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 5u); - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2); - for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) - { - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2); + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u); + for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) { + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2u); EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i); - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], i + 1); + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], i + 1u); } } @@ -184,19 +188,17 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesStripWithoutIndices //Triangles strip without indices const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_04.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4); - std::array f1 = {{ 0, 1, 2 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u); + std::array f1 = {{ 0u, 1u, 2u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u); + for (unsigned int i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]); } - std::array f2 = {{ 2, 1, 3 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + std::array f2 = {{ 2u, 1u, 3u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]); } } @@ -206,19 +208,17 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesFanWithoutIndices) //Triangles fan without indices const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_05.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4); - std::array f1 = {{ 0, 1, 2 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u); + std::array f1 = {{ 0u, 1u, 2u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]); } - std::array f2 = {{ 0, 2, 3 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + std::array f2 = {{ 0u, 2u, 3u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]); } } @@ -228,19 +228,17 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesWithoutIndices) { //Triangles without indices const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_06.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 6); - std::array f1 = {{ 0, 1, 2 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 6u); + std::array f1 = {{ 0u, 1u, 2u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]); } - std::array f2 = {{ 3, 4, 5 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + std::array f2 = {{ 3u, 4u, 5u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]); } } @@ -250,10 +248,9 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModePoints) { //Line loop const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_07.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 1024); - for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) - { - EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 1); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 1024u); + for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) { + EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 1u); EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i); } } @@ -263,9 +260,9 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLines) { //Lines const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_08.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4); - std::array l1 = {{ 0, 3, 2, 1, 0 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u); + std::array l1 = {{ 0u, 3u, 2u, 1u, 0u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u); for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], l1[i]); @@ -278,9 +275,9 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLineLoop) { //Line loop const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_09.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4); - std::array l1 = {{ 0, 3, 2, 1, 0 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u); + std::array l1 = {{ 0, 3u, 2u, 1u, 0u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u); for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], l1[i]); @@ -293,11 +290,10 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLineStrip) { //Lines Strip const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_10.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4); - std::array l1 = {{ 0, 3, 2, 1, 0 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2); - for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) - { + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u); + std::array l1 = {{ 0u, 3u, 2u, 1u, 0u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u); + for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], l1[i]); EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], l1[i + 1]); } @@ -308,19 +304,17 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesStrip) { //Triangles strip const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_11.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4); - std::array f1 = {{ 0, 3, 1 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u); + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u); + std::array f1 = {{ 0u, 3u, 1u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]); } - std::array f2 = {{ 1, 3, 2 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + std::array f2 = {{ 1u, 3u, 2u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]); } } @@ -330,19 +324,17 @@ TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesFan) { //Triangles fan const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_12.gltf", aiProcess_ValidateDataStructure); EXPECT_NE(nullptr, scene); - EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4); - EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2); - std::array f1 = {{ 0, 3, 2 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u); + EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u); + std::array f1 = {{ 0u, 3u, 2u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u ); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]); } - std::array f2 = {{ 0, 2, 1 }}; - EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3); - for (int i = 0; i < 3; ++i) - { + std::array f2 = {{ 0u, 2u, 1u }}; + EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u ); + for (size_t i = 0; i < 3; ++i) { EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]); } } @@ -356,11 +348,12 @@ std::vector ReadFile(const char* name) { } ::fseek(p, 0, SEEK_END); - const auto size = ::ftell(p); + const size_t size = ::ftell(p); ::fseek(p, 0, SEEK_SET); ret.resize(size); - ::fread(&ret[0], 1, size, p); + const size_t readSize = ::fread(&ret[0], 1, size, p); + EXPECT_EQ(readSize, size); ::fclose(p); return ret; @@ -375,9 +368,32 @@ TEST_F(utglTF2ImportExport, importglTF2FromMemory) { EXPECT_EQ( nullptr, Scene );*/ } +TEST_F( utglTF2ImportExport, bug_import_simple_skin ) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/simple_skin/simple_skin.gltf", + aiProcess_ValidateDataStructure ); + EXPECT_NE( nullptr, scene ); +} + +TEST_F(utglTF2ImportExport, import_cameras) { + Assimp::Importer importer; + const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/cameras/Cameras.gltf", + aiProcess_ValidateDataStructure); + EXPECT_NE(nullptr, scene); +} + #ifndef ASSIMP_BUILD_NO_EXPORT TEST_F( utglTF2ImportExport, exportglTF2FromFileTest ) { EXPECT_TRUE( exporterTest() ); } +TEST_F( utglTF2ImportExport, crash_in_anim_mesh_destructor ) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube.gltf", + aiProcess_ValidateDataStructure); + ASSERT_NE( nullptr, scene ); + Assimp::Exporter exporter; + ASSERT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube_out.glTF")); +} + #endif // ASSIMP_BUILD_NO_EXPORT diff --git a/test/unit/utglTFImportExport.cpp b/test/unit/utglTFImportExport.cpp index 17aa94d31..562cb05b9 100644 --- a/test/unit/utglTFImportExport.cpp +++ b/test/unit/utglTFImportExport.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/tools/assimp_cmd/CMakeLists.txt b/tools/assimp_cmd/CMakeLists.txt index ae38b5f11..5ea4e1a24 100644 --- a/tools/assimp_cmd/CMakeLists.txt +++ b/tools/assimp_cmd/CMakeLists.txt @@ -1,7 +1,7 @@ # Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # -# Copyright (c) 2006-2018, assimp team +# Copyright (c) 2006-2019, assimp team # All rights reserved. diff --git a/tools/assimp_cmd/CompareDump.cpp b/tools/assimp_cmd/CompareDump.cpp index d8304f020..db7e3aada 100644 --- a/tools/assimp_cmd/CompareDump.cpp +++ b/tools/assimp_cmd/CompareDump.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -53,7 +53,7 @@ const char* AICMD_MSG_CMPDUMP_HELP = "\tCompare two short dumps produced with \'assimp dump <..> -s\' for equality.\n" ; -#include "../../code/assbin_chunks.h" +#include "Common/assbin_chunks.h" //////////////////////////////////////////////////////////////////////////////////////////////////// #include "generic_inserter.hpp" @@ -62,7 +62,7 @@ const char* AICMD_MSG_CMPDUMP_HELP = #include #include #include -#include "../../include/assimp/ai_assert.h" +#include // get << for aiString template diff --git a/tools/assimp_cmd/Export.cpp b/tools/assimp_cmd/Export.cpp index 03f896822..e29936e38 100644 --- a/tools/assimp_cmd/Export.cpp +++ b/tools/assimp_cmd/Export.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team diff --git a/tools/assimp_cmd/ImageExtractor.cpp b/tools/assimp_cmd/ImageExtractor.cpp index ce472dcb3..a587ab434 100644 --- a/tools/assimp_cmd/ImageExtractor.cpp +++ b/tools/assimp_cmd/ImageExtractor.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -228,7 +228,8 @@ int DoExport(const aiTexture* tx, FILE* p, const std::string& extension, // Implementation of the assimp extract utility int Assimp_Extract (const char* const* params, unsigned int num) { - const char* const invalid = "assimp extract: Invalid number of arguments. See \'assimp extract --help\'\n"; + const char* const invalid = "assimp extract: Invalid number of arguments. See \'assimp extract --help\'\n"; + // assimp extract in out [options] if (num < 1) { printf(invalid); return 1; @@ -240,11 +241,7 @@ int Assimp_Extract (const char* const* params, unsigned int num) return 0; } - // asssimp extract in out [options] - if (num < 1) { - printf(invalid); - return 1; - } + std::string in = std::string(params[0]); std::string out = (num > 1 ? std::string(params[1]) : "-"); diff --git a/tools/assimp_cmd/Info.cpp b/tools/assimp_cmd/Info.cpp index ae858bfe8..d730b9308 100644 --- a/tools/assimp_cmd/Info.cpp +++ b/tools/assimp_cmd/Info.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -51,26 +51,26 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include const char* AICMD_MSG_INFO_HELP_E = -"assimp info [-r] [-v]\n" -"\tPrint basic structure of a 3D model\n" -"\t-r,--raw: No postprocessing, do a raw import\n" -"\t-v,--verbose: Print verbose info such as node transform data\n"; + "assimp info [-r] [-v]\n" + "\tPrint basic structure of a 3D model\n" + "\t-r,--raw: No postprocessing, do a raw import\n" + "\t-v,--verbose: Print verbose info such as node transform data\n" + "\t-s, --silent: Print only minimal info\n"; -const std::string TREE_BRANCH_ASCII = "|-"; -const std::string TREE_BRANCH_UTF8 = "\xe2\x94\x9c\xe2\x95\xb4"; -const std::string TREE_STOP_ASCII = "'-"; -const std::string TREE_STOP_UTF8 = "\xe2\x94\x94\xe2\x95\xb4"; -const std::string TREE_CONTINUE_ASCII = "| "; -const std::string TREE_CONTINUE_UTF8 = "\xe2\x94\x82 "; +const char *TREE_BRANCH_ASCII = "|-"; +const char *TREE_BRANCH_UTF8 = "\xe2\x94\x9c\xe2\x95\xb4"; +const char *TREE_STOP_ASCII = "'-"; +const char *TREE_STOP_UTF8 = "\xe2\x94\x94\xe2\x95\xb4"; +const char *TREE_CONTINUE_ASCII = "| "; +const char *TREE_CONTINUE_UTF8 = "\xe2\x94\x82 "; -// note: by default this is outputing utf-8 text. +// note: by default this is using utf-8 text. // this is well supported on pretty much any linux terminal. // if this causes problems on some platform, // put an #ifdef to use the ascii version for that platform. -const std::string TREE_BRANCH = TREE_BRANCH_UTF8; -const std::string TREE_STOP = TREE_STOP_UTF8; -const std::string TREE_CONTINUE = TREE_CONTINUE_UTF8; - +const char *TREE_BRANCH = TREE_BRANCH_UTF8; +const char *TREE_STOP = TREE_STOP_UTF8; +const char *TREE_CONTINUE = TREE_CONTINUE_UTF8; // ----------------------------------------------------------------------------------- unsigned int CountNodes(const aiNode* root) @@ -279,14 +279,7 @@ void PrintHierarchy( // ----------------------------------------------------------------------------------- // Implementation of the assimp info utility to print basic file info -int Assimp_Info (const char* const* params, unsigned int num) -{ - if (num < 1) { - printf("assimp info: Invalid number of arguments. " - "See \'assimp info --help\'\n"); - return 1; - } - +int Assimp_Info (const char* const* params, unsigned int num) { // --help if (!strcmp( params[0],"-h")||!strcmp( params[0],"--help")||!strcmp( params[0],"-?") ) { printf("%s",AICMD_MSG_INFO_HELP_E); @@ -305,6 +298,7 @@ int Assimp_Info (const char* const* params, unsigned int num) // get -r and -v arguments bool raw = false; bool verbose = false; + bool silent = false; for(unsigned int i = 1; i < num; ++i) { if (!strcmp(params[i],"--raw")||!strcmp(params[i],"-r")) { raw = true; @@ -312,12 +306,26 @@ int Assimp_Info (const char* const* params, unsigned int num) if (!strcmp(params[i],"--verbose")||!strcmp(params[i],"-v")) { verbose = true; } + if (!strcmp(params[i], "--silent") || !strcmp(params[i], "-s")) { + silent = true; + } } - // do maximum post-processing unless -r was specified + // Verbose and silent at the same time are not allowed + if ( verbose && silent ) { + printf("assimp info: Invalid arguments, verbose and silent at the same time are forbitten. "); + return 1; + } + + // Parse post-processing flags unless -r was specified ImportData import; if (!raw) { - import.ppFlags = aiProcessPreset_TargetRealtime_MaxQuality; + // get import flags + ProcessStandardArguments(import, params + 1, num - 1); + + //No custom post process flags defined, we set all the post process flags active + if(import.ppFlags == 0) + import.ppFlags |= aiProcessPreset_TargetRealtime_MaxQuality; } // import the main model @@ -380,6 +388,12 @@ int Assimp_Info (const char* const* params, unsigned int num) ) ; + if (silent) + { + printf("\n"); + return 0; + } + // meshes if (scene->mNumMeshes) { printf("\nMeshes: (name) [vertices / bones / faces | primitive_types]\n"); diff --git a/tools/assimp_cmd/Main.cpp b/tools/assimp_cmd/Main.cpp index 2a18bf33a..9173a756b 100644 --- a/tools/assimp_cmd/Main.cpp +++ b/tools/assimp_cmd/Main.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -384,6 +384,7 @@ int ProcessStandardArguments( // -om --optimize-meshes // -db --debone // -sbc --split-by-bone-count + // -gs --global-scale // // -c --config-file= @@ -472,6 +473,9 @@ int ProcessStandardArguments( else if (!strcmp(param, "-embtex") || ! strcmp(param, "--embed-textures")) { fill.ppFlags |= aiProcess_EmbedTextures; } + else if (!strcmp(param, "-gs") || ! strcmp(param, "--global-scale")) { + fill.ppFlags |= aiProcess_GlobalScale; + } else if (! strncmp( param, "-c",2) || ! strncmp( param, "--config=",9)) { const unsigned int ofs = (params[i][1] == '-' ? 9 : 2); diff --git a/tools/assimp_cmd/Main.h b/tools/assimp_cmd/Main.h index 56b06d57e..5dc4f7d28 100644 --- a/tools/assimp_cmd/Main.h +++ b/tools/assimp_cmd/Main.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -89,9 +89,8 @@ extern Assimp::Exporter* globalExporter; #endif // ------------------------------------------------------------------------------ -/** Defines common import parameters */ -struct ImportData -{ +/// Defines common import parameters +struct ImportData { ImportData() : ppFlags (0) , showLog (false) @@ -99,11 +98,9 @@ struct ImportData , log (false) {} - /** Postprocessing flags - */ + /// Post-processing flags unsigned int ppFlags; - // Log to std::err? bool showLog; diff --git a/tools/assimp_cmd/WriteDumb.cpp b/tools/assimp_cmd/WriteDumb.cpp index b05adf249..559bf08c6 100644 --- a/tools/assimp_cmd/WriteDumb.cpp +++ b/tools/assimp_cmd/WriteDumb.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -46,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "Main.h" -#include "../code/ProcessHelper.h" +#include "PostProcessing/ProcessHelper.h" const char* AICMD_MSG_DUMP_HELP = "assimp dump [] [-b] [-s] [-z] [common parameters]\n" @@ -59,7 +59,7 @@ const char* AICMD_MSG_DUMP_HELP = "\t -cfull Fires almost all post processing steps \n" ; -#include "../../code/assbin_chunks.h" +#include "Common/assbin_chunks.h" FILE* out = NULL; bool shortened = false; @@ -276,9 +276,12 @@ inline uint32_t WriteBounds(const T* in, unsigned int size) void ChangeInteger(uint32_t ofs,uint32_t n) { const uint32_t cur = ftell(out); - fseek(out,ofs,SEEK_SET); - fwrite(&n,4,1,out); - fseek(out,cur,SEEK_SET); + int retCode; + retCode = fseek(out, ofs, SEEK_SET); + ai_assert(0 == retCode); + fwrite(&n, 4, 1, out); + retCode = fseek(out, cur, SEEK_SET); + ai_assert(0 == retCode); } // ----------------------------------------------------------------------------------- @@ -679,7 +682,13 @@ void WriteBinaryDump(const aiScene* scene, FILE* _out, const char* src, const ch shortened = _shortened; time_t tt = time(NULL); - tm* p = gmtime(&tt); +#if _WIN32 + tm* p = gmtime(&tt); +#else + struct tm now; + tm* p = gmtime_r(&tt, &now); +#endif + ai_assert(nullptr != p); // header fprintf(out,"ASSIMP.binary-dump.%s",asctime(p)); @@ -861,7 +870,13 @@ static std::string encodeXML(const std::string& data) { void WriteDump(const aiScene* scene, FILE* out, const char* src, const char* cmd, bool shortened) { time_t tt = ::time(NULL); - tm* p = ::gmtime(&tt); +#if _WIN32 + tm* p = gmtime(&tt); +#else + struct tm now; + tm* p = gmtime_r(&tt, &now); +#endif + ai_assert(nullptr != p); std::string c = cmd; std::string::size_type s; @@ -1321,10 +1336,6 @@ int Assimp_Dump (const char* const* params, unsigned int num) { const char* fail = "assimp dump: Invalid number of arguments. " "See \'assimp dump --help\'\r\n"; - if (num < 1) { - printf("%s", fail); - return 1; - } // --help if (!strcmp( params[0], "-h") || !strcmp( params[0], "--help") || !strcmp( params[0], "-?") ) { diff --git a/tools/assimp_qt_viewer/CMakeLists.txt b/tools/assimp_qt_viewer/CMakeLists.txt deleted file mode 100644 index f559041d3..000000000 --- a/tools/assimp_qt_viewer/CMakeLists.txt +++ /dev/null @@ -1,76 +0,0 @@ -set(PROJECT_VERSION "") -project(assimp_qt_viewer) - -cmake_minimum_required(VERSION 2.6) - -FIND_PACKAGE(OpenGL QUIET) - -# Qt5 version -FIND_PACKAGE(Qt5 COMPONENTS Gui Widgets OpenGL QUIET) - -SET(VIEWER_BUILD:BOOL FALSE) - -IF( Qt5Widgets_FOUND AND OPENGL_FOUND) - SET(VIEWER_BUILD TRUE) -ELSE( Qt5Widgets_FOUND AND OPENGL_FOUND) - SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "") - - IF (NOT Qt5_FOUND) - SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} Qt5") - ENDIF (NOT Qt5_FOUND) - - IF (NOT OPENGL_FOUND) - SET ( ASSIMP_QT_VIEWER_DEPENDENCIES "${ASSIMP_QT_VIEWER_DEPENDENCIES} OpengGL") - ENDIF (NOT OPENGL_FOUND) - - MESSAGE (WARNING "Build of assimp_qt_viewer is disabled. Unsatisfied dendencies: ${ASSIMP_QT_VIEWER_DEPENDENCIES}") -ENDIF( Qt5Widgets_FOUND AND OPENGL_FOUND) - -IF(VIEWER_BUILD) - INCLUDE_DIRECTORIES( - ${Assimp_SOURCE_DIR}/include - ${Assimp_SOURCE_DIR}/code - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_SOURCE_DIR} - ${OPENGL_INCLUDE_DIR} - ${IL_INCLUDE_DIR} - ) - - LINK_DIRECTORIES(${Assimp_BINARY_DIR}) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -pedantic -Wall") - - SET(assimp_qt_viewer_SRCS - main.cpp - loggerview.hpp - loggerview.cpp - glview.hpp - glview.cpp - mainwindow.hpp - mainwindow.cpp - ) - - MESSAGE("assimp_qt_viewer use Qt5") - INCLUDE_DIRECTORIES(${Qt5Widgets_INCLUDES}) - qt5_wrap_ui(UISrcs mainwindow.ui) - qt5_wrap_cpp(MOCrcs mainwindow.hpp glview.hpp) - - add_executable(${PROJECT_NAME} ${assimp_qt_viewer_SRCS} ${UISrcs} ${MOCrcs}) - target_link_libraries(${PROJECT_NAME} Qt5::Gui Qt5::Widgets Qt5::OpenGL ${IL_LIBRARIES} ${OPENGL_LIBRARIES} assimp) - - IF(WIN32) # Check if we are on Windows - IF(MSVC) # Check if we are using the Visual Studio compiler - #set_target_properties(TestProject PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS") - ELSEIF(CMAKE_COMPILER_IS_GNUCXX) - # SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mwindows") # Not tested - ELSE() - MESSAGE(SEND_ERROR "You are using an unsupported Windows compiler! (Not MSVC or GCC)") - ENDIF() - ELSEIF(UNIX) - # Nothing special required - ELSE() - MESSAGE(SEND_ERROR "You are on an unsupported platform! (Not Win32 or Unix)") - ENDIF() - - SET_PROPERTY(TARGET ${PROJECT_NAME} PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) - INSTALL(TARGETS assimp_qt_viewer DESTINATION "${ASSIMP_BIN_INSTALL_DIR}") -ENDIF(VIEWER_BUILD) diff --git a/tools/assimp_qt_viewer/doc/Assimp_qt_viewer. Manual (en).odt b/tools/assimp_qt_viewer/doc/Assimp_qt_viewer. Manual (en).odt deleted file mode 100644 index 6e4e8c193..000000000 Binary files a/tools/assimp_qt_viewer/doc/Assimp_qt_viewer. Manual (en).odt and /dev/null differ diff --git a/tools/assimp_qt_viewer/doc/Assimp_qt_viewer. Manual (ru).odt b/tools/assimp_qt_viewer/doc/Assimp_qt_viewer. Manual (ru).odt deleted file mode 100644 index 6bd8f8dbb..000000000 Binary files a/tools/assimp_qt_viewer/doc/Assimp_qt_viewer. Manual (ru).odt and /dev/null differ diff --git a/tools/assimp_qt_viewer/glview.cpp b/tools/assimp_qt_viewer/glview.cpp deleted file mode 100644 index 409e323cc..000000000 --- a/tools/assimp_qt_viewer/glview.cpp +++ /dev/null @@ -1,1161 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2018, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ -#include "glview.hpp" - -// Header files, Qt. -#include - -// Header files, OpenGL. -#if defined(__APPLE__) -# include -#else -# include -#endif - -// Header files, DevIL. - -// Header files, Assimp. -#include - -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -CGLView::SHelper_Mesh::SHelper_Mesh(const size_t pQuantity_Point, const size_t pQuantity_Line, const size_t pQuantity_Triangle, const SBBox& pBBox) -: Quantity_Point(pQuantity_Point) -, Quantity_Line(pQuantity_Line) -, Quantity_Triangle(pQuantity_Triangle) -, BBox(pBBox) { - Index_Point = pQuantity_Point ? new GLuint[pQuantity_Point * 1] : nullptr; - Index_Line = pQuantity_Line ? new GLuint[pQuantity_Line * 2] : nullptr; - Index_Triangle = pQuantity_Triangle ? new GLuint[pQuantity_Triangle * 3] : nullptr; -} - -CGLView::SHelper_Mesh::~SHelper_Mesh() { - delete [] Index_Point; - delete [] Index_Line; - delete [] Index_Triangle; -} - -void CGLView::SHelper_Camera::SetDefault() { - Position.Set(0, 0, 0); - Target.Set(0, 0, -1); - Rotation_AroundCamera = aiMatrix4x4(); - Rotation_Scene = aiMatrix4x4(); - Translation_ToScene.Set(0, 0, 2); -} - -static void set_float4(float f[4], float a, float b, float c, float d) { - f[0] = a; - f[1] = b; - f[2] = c; - f[3] = d; -} - -static void color4_to_float4(const aiColor4D *c, float f[4]) { - f[0] = c->r; - f[1] = c->g; - f[2] = c->b; - f[3] = c->a; -} - -void CGLView::Material_Apply(const aiMaterial* pMaterial) { - GLfloat tcol[4]; - aiColor4D taicol; - unsigned int max; - int ret1, ret2; - int texture_index = 0; - aiString texture_path; - - ///TODO: cache materials - // Disable color material because glMaterial is used. - glDisable(GL_COLOR_MATERIAL);///TODO: cache - - // Set texture. If assigned. - if(AI_SUCCESS == pMaterial->GetTexture(aiTextureType_DIFFUSE, texture_index, &texture_path)) { - //bind texture - unsigned int texture_ID = mTexture_IDMap.value(texture_path.data, 0); - - glBindTexture(GL_TEXTURE_2D, texture_ID); - } - // - // Set material parameters from scene or default values. - // - // Diffuse - set_float4(tcol, 0.8f, 0.8f, 0.8f, 1.0f); - if ( AI_SUCCESS == aiGetMaterialColor( pMaterial, AI_MATKEY_COLOR_DIFFUSE, &taicol )) { - color4_to_float4( &taicol, tcol ); - } - - glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, tcol); - - // Specular - set_float4(tcol, 0.0f, 0.0f, 0.0f, 1.0f); - if ( AI_SUCCESS == aiGetMaterialColor( pMaterial, AI_MATKEY_COLOR_SPECULAR, &taicol )) { - color4_to_float4( &taicol, tcol ); - } - - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, tcol); - // Ambient - set_float4(tcol, 0.2f, 0.2f, 0.2f, 1.0f); - if ( AI_SUCCESS == aiGetMaterialColor( pMaterial, AI_MATKEY_COLOR_AMBIENT, &taicol )) { - color4_to_float4( &taicol, tcol ); - } - glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, tcol); - - // Emission - set_float4(tcol, 0.0f, 0.0f, 0.0f, 1.0f); - if(AI_SUCCESS == aiGetMaterialColor(pMaterial, AI_MATKEY_COLOR_EMISSIVE, &taicol)) color4_to_float4(&taicol, tcol); - - glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, tcol); - // Shininess - ai_real shininess, strength; - - max = 1; - ret1 = aiGetMaterialFloatArray(pMaterial, AI_MATKEY_SHININESS, &shininess, &max); - // Shininess strength - max = 1; - ret2 = aiGetMaterialFloatArray(pMaterial, AI_MATKEY_SHININESS_STRENGTH, &strength, &max); - if((ret1 == AI_SUCCESS) && (ret2 == AI_SUCCESS)) { - glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess * strength);///TODO: cache - } else { - glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f);///TODO: cache - set_float4(tcol, 0.0f, 0.0f, 0.0f, 0.0f); - glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, tcol); - } - - // Fill mode - GLenum fill_mode; - int wireframe; - - max = 1; - if(AI_SUCCESS == aiGetMaterialIntegerArray(pMaterial, AI_MATKEY_ENABLE_WIREFRAME, &wireframe, &max)) - fill_mode = wireframe ? GL_LINE : GL_FILL; - else - fill_mode = GL_FILL; - - glPolygonMode(GL_FRONT_AND_BACK, fill_mode);///TODO: cache - // Fill side - int two_sided; - - max = 1; - if((AI_SUCCESS == aiGetMaterialIntegerArray(pMaterial, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided)///TODO: cache - glDisable(GL_CULL_FACE); - else - glEnable(GL_CULL_FACE); -} - -void CGLView::Matrix_NodeToRoot(const aiNode* pNode, aiMatrix4x4& pOutMatrix) -{ - const aiNode* node_cur; - std::list mat_list; - - pOutMatrix = aiMatrix4x4(); - // starting walk from current element to root - node_cur = pNode; - if(node_cur != nullptr) - { - do - { - // if cur_node is group then store group transformation matrix in list. - mat_list.push_back(node_cur->mTransformation); - node_cur = node_cur->mParent; - } while(node_cur != nullptr); - } - - // multiply all matrices in reverse order - for ( std::list::reverse_iterator rit = mat_list.rbegin(); rit != mat_list.rend(); rit++) - { - pOutMatrix = pOutMatrix * (*rit); - } -} - -void CGLView::ImportTextures(const QString& scenePath) { - auto LoadTexture = [&](const QString& pFileName) -> bool ///TODO: IME texture mode, operation. - { - GLuint id_ogl_texture;// OpenGL texture ID. - - if(!pFileName.startsWith(AI_EMBEDDED_TEXNAME_PREFIX)) - { - QString basepath = scenePath.left(scenePath.lastIndexOf('/') + 1);// path with '/' at the end. - QString fileloc = (basepath + pFileName); - - fileloc.replace('\\', "/"); - int x, y, n; - unsigned char *data = stbi_load(fileloc.toLocal8Bit(), &x, &y, &n, STBI_rgb_alpha ); - if ( nullptr == data ) { - LogError(QString("Couldn't load Image: %1").arg(fileloc)); - - return false; - } - - // Convert every colour component into unsigned byte. If your image contains alpha channel you can replace IL_RGB with IL_RGBA. - - glGenTextures(1, &id_ogl_texture);// Texture ID generation. - mTexture_IDMap[pFileName] = id_ogl_texture;// save texture ID for filename in map - glBindTexture(GL_TEXTURE_2D, id_ogl_texture);// Binding of texture ID. - // Redefine standard texture values - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// We will use linear interpolation for magnification filter. - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);// We will use linear interpolation for minifying filter. - glTexImage2D(GL_TEXTURE_2D, 0, n, x, y, 0, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, data );// Texture specification. - - // Cleanup - } - else - { - struct SPixel_Description - { - const char* FormatHint; - const GLint Image_InternalFormat; - const GLint Pixel_Format; - }; - - constexpr SPixel_Description Pixel_Description[] = { - {"rgba8880", GL_RGB, GL_RGB}, - {"rgba8888", GL_RGBA, GL_RGBA} - }; - - constexpr size_t Pixel_Description_Count = sizeof(Pixel_Description) / sizeof(SPixel_Description); - - size_t idx_description; - // Get texture index. - bool ok; - size_t idx_texture = pFileName.right(strlen(AI_EMBEDDED_TEXNAME_PREFIX)).toULong(&ok); - - if(!ok) - { - LogError("Can not get index of the embedded texture from path in material."); - - return false; - } - - // Create alias for conveniance. - const aiTexture& als = *mScene->mTextures[idx_texture]; - - if(als.mHeight == 0)// Compressed texture. - { - LogError("IME: compressed embedded textures are not implemented."); - } - else - { - ok = false; - for(size_t idx = 0; idx < Pixel_Description_Count; idx++) - { - if(als.CheckFormat(Pixel_Description[idx].FormatHint)) - { - idx_description = idx; - ok = true; - break; - } - } - - if(!ok) - { - LogError(QString("Unsupported format hint for embedded texture: [%1]").arg(als.achFormatHint)); - - return false; - } - - glGenTextures(1, &id_ogl_texture);// Texture ID generation. - mTexture_IDMap[pFileName] = id_ogl_texture;// save texture ID for filename in map - glBindTexture(GL_TEXTURE_2D, id_ogl_texture);// Binding of texture ID. - // Redefine standard texture values - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// We will use linear interpolation for magnification filter. - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);// We will use linear interpolation for minifying filter. - // Texture specification. - glTexImage2D(GL_TEXTURE_2D, 0, Pixel_Description[idx_description].Image_InternalFormat, als.mWidth, als.mHeight, 0, - Pixel_Description[idx_description].Pixel_Format, GL_UNSIGNED_BYTE, (uint8_t*)als.pcData); - }// if(als.mHeight == 0) else - }// if(!filename.startsWith(AI_EMBEDDED_TEXNAME_PREFIX)) else - - return true; - };// auto LoadTexture = [&](const aiString& pPath) - - if(mScene == nullptr) - { - LogError("Trying to load textures for empty scene."); - - return; - } - - // - // Load textures. - // - // Get textures file names and number of textures. - for(size_t idx_material = 0; idx_material < mScene->mNumMaterials; idx_material++) { - int idx_texture = 0; - aiString path; - - do { - if (mScene->mMaterials[ idx_material ]->GetTexture( aiTextureType_DIFFUSE, idx_texture, &path ) != AI_SUCCESS) { - break; - } - - LoadTexture(QString(path.C_Str())); - idx_texture++; - } while(true); - }// for(size_t idx_material = 0; idx_material < mScene->mNumMaterials; idx_material++) - - // Textures list is empty, exit. - if(mTexture_IDMap.empty()) { - LogInfo("No textures for import."); - } -} - -void CGLView::BBox_GetForNode(const aiNode& pNode, const aiMatrix4x4& pParent_TransformationMatrix, SBBox& pNodeBBox, bool& pFirstAssign) -{ - aiMatrix4x4 mat_trans = pParent_TransformationMatrix * pNode.mTransformation; - - // Check if node has meshes - for(size_t idx_idx_mesh = 0; idx_idx_mesh < pNode.mNumMeshes; idx_idx_mesh++) - { - size_t idx_mesh; - SBBox bbox_local; - aiVector3D bbox_vertices[8]; - - idx_mesh = pNode.mMeshes[idx_idx_mesh]; - // Get vertices of mesh BBox - BBox_GetVertices(mHelper_Mesh[idx_mesh]->BBox, bbox_vertices); - // Transform vertices - for(size_t idx_vert = 0; idx_vert < 8; idx_vert++) bbox_vertices[idx_vert] *= mat_trans; - - // And create BBox for transformed mesh - BBox_GetFromVertices(bbox_vertices, 8, bbox_local); - - if(!pFirstAssign) - { - BBox_Extend(bbox_local, pNodeBBox); - } - else - { - pFirstAssign = false; - pNodeBBox = bbox_local; - } - }// for(size_t idx_idx_mesh = 0; idx_idx_mesh < pNode.mNumMeshes; idx_idx_mesh++) - - for(size_t idx_node = 0; idx_node < pNode.mNumChildren; idx_node++) - { - BBox_GetForNode(*pNode.mChildren[idx_node], mat_trans, pNodeBBox, pFirstAssign); - } -} - -void CGLView::BBox_Extend(const SBBox& pChild, SBBox& pParent) -{ - // search minimal... - AssignIfLesser(&pParent.Minimum.x, pChild.Minimum.x); - AssignIfLesser(&pParent.Minimum.y, pChild.Minimum.y); - AssignIfLesser(&pParent.Minimum.z, pChild.Minimum.z); - // and maximal values - AssignIfGreater(&pParent.Maximum.x, pChild.Maximum.x); - AssignIfGreater(&pParent.Maximum.y, pChild.Maximum.y); - AssignIfGreater(&pParent.Maximum.z, pChild.Maximum.z); -} - -void CGLView::BBox_GetVertices(const SBBox& pBBox, aiVector3D pVertex[8]) -{ - pVertex[0] = pBBox.Minimum; - pVertex[1].Set(pBBox.Minimum.x, pBBox.Minimum.y, pBBox.Maximum.z); - pVertex[2].Set(pBBox.Minimum.x, pBBox.Maximum.y, pBBox.Maximum.z); - pVertex[3].Set(pBBox.Minimum.x, pBBox.Maximum.y, pBBox.Minimum.z); - - pVertex[4].Set(pBBox.Maximum.x, pBBox.Minimum.y, pBBox.Minimum.z); - pVertex[5].Set(pBBox.Maximum.x, pBBox.Minimum.y, pBBox.Maximum.z); - pVertex[6] = pBBox.Maximum; - pVertex[7].Set(pBBox.Maximum.x, pBBox.Maximum.y, pBBox.Minimum.z); - -} - -void CGLView::BBox_GetFromVertices(const aiVector3D* pVertices, const size_t pVerticesQuantity, SBBox& pBBox) -{ - if(pVerticesQuantity == 0) - { - pBBox.Maximum.Set(0, 0, 0); - pBBox.Minimum.Set(0, 0, 0); - - return; - } - - // Assign first values. - pBBox.Minimum = pVertices[0]; - pBBox.Maximum = pVertices[0]; - - for(size_t idx_vert = 1; idx_vert < pVerticesQuantity; idx_vert++) - { - const ai_real x = pVertices[idx_vert].x; - const ai_real y = pVertices[idx_vert].y; - const ai_real z = pVertices[idx_vert].z; - - // search minimal... - AssignIfLesser(&pBBox.Minimum.x, x); - AssignIfLesser(&pBBox.Minimum.y, y); - AssignIfLesser(&pBBox.Minimum.z, z); - // and maximal values - AssignIfGreater(&pBBox.Maximum.x, x); - AssignIfGreater(&pBBox.Maximum.y, y); - AssignIfGreater(&pBBox.Maximum.z, z); - } -} - -void CGLView::LogInfo(const QString& pMessage) { - Assimp::DefaultLogger::get()->info(pMessage.toStdString()); -} - -void CGLView::LogError(const QString& pMessage) { - Assimp::DefaultLogger::get()->error(pMessage.toStdString()); -} - -void CGLView::Draw_Node(const aiNode* pNode) { - aiMatrix4x4 mat_node = pNode->mTransformation; - - // Apply node transformation matrix. - mat_node.Transpose(); - glPushMatrix(); -#ifdef ASSIMP_DOUBLE_PRECISION - glMultMatrixd((GLdouble*)mat_node[0]); -#else - glMultMatrixf((GLfloat*)&mat_node); -#endif // ASSIMP_DOUBLE_PRECISION - - // Draw all meshes assigned to this node - for(size_t idx_mesh_arr = 0; idx_mesh_arr < pNode->mNumMeshes; idx_mesh_arr++) Draw_Mesh(pNode->mMeshes[idx_mesh_arr]); - - // Draw all children nodes - for(size_t idx_node = 0; idx_node < pNode->mNumChildren; idx_node++) Draw_Node(pNode->mChildren[idx_node]); - - // Restore transformation matrix. - glPopMatrix(); -} - -void CGLView::Draw_Mesh(const size_t pMesh_Index) -{ - // Check argument - if(pMesh_Index >= mHelper_Mesh_Quantity) return; - - aiMesh& mesh_cur = *mScene->mMeshes[pMesh_Index]; - - if(!mesh_cur.HasPositions()) return;// Nothing to draw. - - // If mesh use material then apply it - if(mScene->HasMaterials()) Material_Apply(mScene->mMaterials[mesh_cur.mMaterialIndex]); - - // - // Vertices array - // - glEnableClientState(GL_VERTEX_ARRAY); -#if ASSIMP_DOUBLE_PRECISION - glVertexPointer(3, GL_DOUBLE, 0, mesh_cur.mVertices); -#else - glVertexPointer(3, GL_FLOAT, 0, mesh_cur.mVertices); -#endif // ASSIMP_DOUBLE_PRECISION - - if(mesh_cur.HasVertexColors(0)) - { - glEnable(GL_COLOR_MATERIAL);///TODO: cache - glEnableClientState(GL_COLOR_ARRAY); -#ifdef ASSIMP_DOUBLE_PRECISION - glColorPointer(4, GL_DOUBLE, 0, mesh_cur.mColors[0]); -#else - glColorPointer(4, GL_FLOAT, 0, mesh_cur.mColors[0]); -#endif // ASSIMP_DOUBLE_PRECISION - } - - // - // Texture coordinates array - // - if(mesh_cur.HasTextureCoords(0)) - { - glEnableClientState(GL_TEXTURE_COORD_ARRAY); -#ifdef ASSIMP_DOUBLE_PRECISION - glTexCoordPointer(2, GL_DOUBLE, sizeof(aiVector3D), mesh_cur.mTextureCoords[0]); -#else - glTexCoordPointer(2, GL_FLOAT, sizeof(aiVector3D), mesh_cur.mTextureCoords[0]); -#endif // ASSIMP_DOUBLE_PRECISION - } - - // - // Normals array - // - if(mesh_cur.HasNormals()) - { - glEnableClientState(GL_NORMAL_ARRAY); -#ifdef ASSIMP_DOUBLE_PRECISION - glNormalPointer(GL_DOUBLE, 0, mesh_cur.mNormals); -#else - glNormalPointer(GL_FLOAT, 0, mesh_cur.mNormals); -#endif // ASSIMP_DOUBLE_PRECISION - } - - // - // Draw arrays - // - SHelper_Mesh& helper_cur = *mHelper_Mesh[pMesh_Index]; - - if(helper_cur.Quantity_Triangle > 0) glDrawElements(GL_TRIANGLES, helper_cur.Quantity_Triangle * 3, GL_UNSIGNED_INT, helper_cur.Index_Triangle); - if(helper_cur.Quantity_Line > 0) glDrawElements(GL_LINES,helper_cur.Quantity_Line * 2, GL_UNSIGNED_INT, helper_cur.Index_Line); - if(helper_cur.Quantity_Point > 0) glDrawElements(GL_POINTS, helper_cur.Quantity_Point, GL_UNSIGNED_INT, helper_cur.Index_Point); - - // - // Clean up - // - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); -} - -void CGLView::Draw_BBox(const SBBox& pBBox) -{ - aiVector3D vertex[8]; - - BBox_GetVertices(pBBox, vertex); - // Draw - if(mLightingEnabled) glDisable(GL_LIGHTING);///TODO: display list - - glEnable(GL_COLOR_MATERIAL); - glBindTexture(GL_TEXTURE_1D, 0); - glBindTexture(GL_TEXTURE_2D, 0); - glBindTexture(GL_TEXTURE_3D, 0); - const QColor c_w(Qt::white); - - glColor3f(c_w.redF(), c_w.greenF(), c_w.blueF()); - - glBegin(GL_LINE_STRIP); -# ifdef ASSIMP_DOUBLE_PRECISION - glVertex3dv(&vertex[0][0]), glVertex3dv(&vertex[1][0]), glVertex3dv(&vertex[2][0]), glVertex3dv(&vertex[3][0]), glVertex3dv(&vertex[0][0]);// "Minimum" side. - glVertex3dv(&vertex[4][0]), glVertex3dv(&vertex[5][0]), glVertex3dv(&vertex[6][0]), glVertex3dv(&vertex[7][0]), glVertex3dv(&vertex[4][0]);// Edge and "maximum" side. -# else - glVertex3fv(&vertex[0][0]), glVertex3fv(&vertex[1][0]), glVertex3fv(&vertex[2][0]), glVertex3fv(&vertex[3][0]), glVertex3fv(&vertex[0][0]);// "Minimum" side. - glVertex3fv(&vertex[4][0]), glVertex3fv(&vertex[5][0]), glVertex3fv(&vertex[6][0]), glVertex3fv(&vertex[7][0]), glVertex3fv(&vertex[4][0]);// Edge and "maximum" side. -# endif // ASSIMP_DOUBLE_PRECISION - glEnd(); - - glBegin(GL_LINES); -# ifdef ASSIMP_DOUBLE_PRECISION - glVertex3dv(&vertex[1][0]), glVertex3dv(&vertex[5][0]); - glVertex3dv(&vertex[2][0]), glVertex3dv(&vertex[6][0]); - glVertex3dv(&vertex[3][0]), glVertex3dv(&vertex[7][0]); -# else - glVertex3fv(&vertex[1][0]), glVertex3fv(&vertex[5][0]); - glVertex3fv(&vertex[2][0]), glVertex3fv(&vertex[6][0]); - glVertex3fv(&vertex[3][0]), glVertex3fv(&vertex[7][0]); -# endif // ASSIMP_DOUBLE_PRECISION - glEnd(); - glDisable(GL_COLOR_MATERIAL); - if(mLightingEnabled) glEnable(GL_LIGHTING); - -} - -void CGLView::Enable_Textures(const bool pEnable) { - if(pEnable) { - glEnable(GL_TEXTURE_1D); - glEnable(GL_TEXTURE_2D); - glEnable(GL_TEXTURE_3D); - } else { - glDisable(GL_TEXTURE_1D); - glDisable(GL_TEXTURE_2D); - glDisable(GL_TEXTURE_3D); - } -} - -void CGLView::initializeGL() { - mGLContext_Current = true; - initializeOpenGLFunctions(); - glClearColor(0.5f, 0.5f, 0.5f, 1.0f); - glShadeModel(GL_SMOOTH); - - glEnable(GL_DEPTH_TEST); - glEnable(GL_NORMALIZE); - glEnable(GL_TEXTURE_2D); - glEnable( GL_MULTISAMPLE ); - - glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT); - glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); - glDisable(GL_COLOR_MATERIAL); - - glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); - - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - - glFrontFace(GL_CCW); -} - -void CGLView::resizeGL(int width, int height) { - mCamera_Viewport_AspectRatio = (GLdouble)width / height; - glViewport(0, 0, width, height); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(mCamera_FOVY, mCamera_Viewport_AspectRatio, 1.0, 100000.0);///TODO: znear/zfar depend on scene size. -} - -void CGLView::drawCoordSystem() { - // Disable lighting. Colors must be bright and colorful) - if ( mLightingEnabled ) glDisable( GL_LIGHTING );///TODO: display list - - // For same reason - disable textures. - glBindTexture(GL_TEXTURE_1D, 0); - glBindTexture(GL_TEXTURE_2D, 0); - glBindTexture(GL_TEXTURE_3D, 0); - glEnable(GL_COLOR_MATERIAL); - glBegin(GL_LINES); - - // X, -X - glColor3f(1.0f, 0.0f, 0.0f), glVertex3f(0.0, 0.0, 0.0), glVertex3f(100000.0, 0.0, 0.0); - glColor3f(0.5f, 0.5f, 1.0f), glVertex3f(0.0, 0.0, 0.0), glVertex3f(-100000.0, 0.0, 0.0); - // Y, -Y - glColor3f(0.0f, 1.0f, 0.0f), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 100000.0, 0.0); - glColor3f(1.0f, 0.0f, 1.0f), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, -100000.0, 0.0); - // Z, -Z - glColor3f(0.0f, 0.0f, 1.0f), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 0.0, 100000.0); - glColor3f(1.0f, 1.0f, 0.0f), glVertex3f(0.0, 0.0, 0.0), glVertex3f(0.0, 0.0, -100000.0); - glColor3f(1.0f, 1.0f, 1.0f); - - glEnd(); - // Restore previous state of lighting. - if (mLightingEnabled) { - glEnable( GL_LIGHTING ); - } -} - -void CGLView::paintGL() { - QTime time_paintbegin; - - time_paintbegin = QTime::currentTime(); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - // Apply current camera transformations. -#if ASSIMP_DOUBLE_PRECISION - glMultMatrixd((GLdouble*)&mHelper_Camera.Rotation_AroundCamera); - glTranslated(-mHelper_Camera.Translation_ToScene.x, -mHelper_Camera.Translation_ToScene.y, -mHelper_Camera.Translation_ToScene.z); - glMultMatrixd((GLdouble*)&mHelper_Camera.Rotation_Scene); -#else - glMultMatrixf((GLfloat*)&mHelper_Camera.Rotation_AroundCamera); - glTranslatef(-mHelper_Camera.Translation_ToScene.x, -mHelper_Camera.Translation_ToScene.y, -mHelper_Camera.Translation_ToScene.z); - glMultMatrixf((GLfloat*)&mHelper_Camera.Rotation_Scene); -#endif // ASSIMP_DOUBLE_PRECISION - - // Coordinate system - if ( mScene_AxesEnabled ) { - drawCoordSystem(); - } - - glDisable(GL_COLOR_MATERIAL); - - // Scene - if(mScene != nullptr) { - Draw_Node(mScene->mRootNode); - // Scene BBox - if (mScene_DrawBBox) { - Draw_BBox( mScene_BBox ); - } - } - - emit Paint_Finished((size_t) time_paintbegin.msecsTo(QTime::currentTime()), mHelper_Camera.Translation_ToScene.Length()); -} - - -CGLView::CGLView( QWidget *pParent ) -: QOpenGLWidget( pParent ) -, mGLContext_Current( false ) { - // set initial view - mHelper_CameraDefault.SetDefault(); - Camera_Set( 0 ); -} - -CGLView::~CGLView() { - FreeScene(); -} - -void CGLView::FreeScene() { - // Set scene to null and after that \ref paintGL will not try to render it. - mScene = nullptr; - // Clean helper objects. - if(mHelper_Mesh != nullptr) - { - for(size_t idx_mesh = 0; idx_mesh < mHelper_Mesh_Quantity; idx_mesh++) delete mHelper_Mesh[idx_mesh]; - - delete [] mHelper_Mesh; - mHelper_Mesh = nullptr; - } - - mHelper_Mesh_Quantity = 0; - // Delete textures - const int id_tex_size = mTexture_IDMap.size(); - - if(id_tex_size) - { - GLuint* id_tex = new GLuint[id_tex_size]; - QMap::iterator it = mTexture_IDMap.begin(); - - for(int idx = 0; idx < id_tex_size; idx++, it++) - { - id_tex[idx] = it.value(); - } - - glDeleteTextures(id_tex_size, id_tex); - mTexture_IDMap.clear(); - delete [] id_tex; - } -} - -void CGLView::SetScene(const aiScene *pScene, const QString& pScenePath) { - FreeScene();// Clear old data - // Why checking here, not at begin of function. Because old scene may not exist at know. So, need cleanup. - if (pScene == nullptr) { - return; - } - - mScene = pScene;// Copy pointer of new scene. - - // - // Meshes - // - // Create helper objects for meshes. This allow to render meshes as OpenGL arrays. - if(mScene->HasMeshes()) - { - // Create mesh helpers array. - mHelper_Mesh_Quantity = mScene->mNumMeshes; - mHelper_Mesh = new SHelper_Mesh*[mScene->mNumMeshes]; - - // Walk through the meshes and extract needed data and, also calculate BBox. - for(size_t idx_mesh = 0; idx_mesh < mScene->mNumMeshes; idx_mesh++) - { - aiMesh& mesh_cur = *mScene->mMeshes[idx_mesh]; - - // - // Calculate BBox - // - SBBox mesh_bbox; - - BBox_GetFromVertices(mesh_cur.mVertices, mesh_cur.mNumVertices, mesh_bbox); - // - // Create vertices indices arrays splitted by primitive type. - // - size_t indcnt_p = 0;// points quantity - size_t indcnt_l = 0;// lines quantity - size_t indcnt_t = 0;// triangles quantity - - if(mesh_cur.HasFaces()) - { - // Usual way: all faces are triangles - if(mesh_cur.mPrimitiveTypes == aiPrimitiveType_TRIANGLE) - { - indcnt_t = mesh_cur.mNumFaces; - } - else - { - // Calculate count of primitives by types. - for(size_t idx_face = 0; idx_face < mesh_cur.mNumFaces; idx_face++) - { - if(mesh_cur.mFaces[idx_face].mNumIndices == 3) - indcnt_t++; - else if(mesh_cur.mFaces[idx_face].mNumIndices == 2) - indcnt_l++; - else if(mesh_cur.mFaces[idx_face].mNumIndices == 1) - indcnt_p++; - } - }// if(mesh_cur.mPrimitiveTypes == aiPrimitiveType_TRIANGLE) else - - // Create helper - mHelper_Mesh[idx_mesh] = new SHelper_Mesh(indcnt_p, indcnt_l, indcnt_t, mesh_bbox); - // Fill indices arrays - indcnt_p = 0, indcnt_l = 0, indcnt_t = 0;// Reuse variables as indices - for(size_t idx_face = 0; idx_face < mesh_cur.mNumFaces; idx_face++) - { - if(mesh_cur.mFaces[idx_face].mNumIndices == 3) - { - mHelper_Mesh[idx_mesh]->Index_Triangle[indcnt_t++] = mesh_cur.mFaces[idx_face].mIndices[0]; - mHelper_Mesh[idx_mesh]->Index_Triangle[indcnt_t++] = mesh_cur.mFaces[idx_face].mIndices[1]; - mHelper_Mesh[idx_mesh]->Index_Triangle[indcnt_t++] = mesh_cur.mFaces[idx_face].mIndices[2]; - } - else if(mesh_cur.mFaces[idx_face].mNumIndices == 2) - { - mHelper_Mesh[idx_mesh]->Index_Line[indcnt_l++] = mesh_cur.mFaces[idx_face].mIndices[0]; - mHelper_Mesh[idx_mesh]->Index_Line[indcnt_l++] = mesh_cur.mFaces[idx_face].mIndices[1]; - } - else if(mesh_cur.mFaces[idx_face].mNumIndices == 1) - { - mHelper_Mesh[idx_mesh]->Index_Point[indcnt_p++] = mesh_cur.mFaces[idx_face].mIndices[0]; - } - }// for(size_t idx_face = 0; idx_face < mesh_cur.mNumFaces; idx_face++) - }// if(mesh_cur.HasFaces()) - else - { - // If mesh has no faces then vertices can be just points set. - indcnt_p = mesh_cur.mNumVertices; - // Create helper - mHelper_Mesh[idx_mesh] = new SHelper_Mesh(indcnt_p, 0, 0, mesh_bbox); - // Fill indices arrays - for(size_t idx = 0; idx < indcnt_p; idx++) mHelper_Mesh[idx_mesh]->Index_Point[idx] = idx; - - }// if(mesh_cur.HasFaces()) else - }// for(size_t idx_mesh = 0; idx_mesh < mScene->mNumMeshes; idx_mesh++) - }// if(mScene->HasMeshes()) - - // - // Scene BBox - // - // For calculating right BBox we must walk through all nodes and apply transformation to meshes BBoxes - if(mHelper_Mesh_Quantity > 0) - { - bool first_assign = true; - aiMatrix4x4 mat_root; - - BBox_GetForNode(*mScene->mRootNode, mat_root, mScene_BBox, first_assign); - mScene_Center = mScene_BBox.Maximum + mScene_BBox.Minimum; - mScene_Center /= 2; - } - else - { - mScene_BBox = {{0, 0, 0}, {0, 0, 0}}; - mScene_Center = {0, 0, 0}; - }// if(mHelper_Mesh_Count > 0) else - - // - // Textures - // - ImportTextures(pScenePath); - - // - // Light sources - // - Lighting_Enable(); - // If scene has no lights then enable default - if(!mScene->HasLights()) - { - const GLfloat col_amb[4] = { 0.2, 0.2, 0.2, 1.0 }; - SLightParameters lp; - - lp.Type = aiLightSource_POINT; - lp.Ambient.r = col_amb[0], lp.Ambient.g = col_amb[1], lp.Ambient.b = col_amb[2], lp.Ambient.a = col_amb[3]; - lp.Diffuse = { 1.0, 1.0, 1.0, 1.0 }; - lp.Specular = lp.Diffuse; - lp.For.Point.Position = mScene_Center; - lp.For.Point.Attenuation_Constant = 1; - lp.For.Point.Attenuation_Linear = 0; - lp.For.Point.Attenuation_Quadratic = 0; - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, col_amb); - Lighting_EditSource(0, lp); - emit SceneObject_LightSource("_default");// Light source will be enabled in signal handler. - } - else - { - for(size_t idx_light = 0; idx_light < mScene->mNumLights; idx_light++) - { - SLightParameters lp; - QString name; - const aiLight& light_cur = *mScene->mLights[idx_light]; - - auto col3_to_col4 = [](const aiColor3D& pCol3) -> aiColor4D { return aiColor4D(pCol3.r, pCol3.g, pCol3.b, 1.0); }; - - ///TODO: find light source node and apply all transformations - // General properties - name = light_cur.mName.C_Str(); - lp.Ambient = col3_to_col4(light_cur.mColorAmbient); - lp.Diffuse = col3_to_col4(light_cur.mColorDiffuse); - lp.Specular = col3_to_col4(light_cur.mColorSpecular); - lp.Type = light_cur.mType; - // Depend on type properties - switch(light_cur.mType) - { - case aiLightSource_DIRECTIONAL: - lp.For.Directional.Direction = light_cur.mDirection; - break; - case aiLightSource_POINT: - lp.For.Point.Position = light_cur.mPosition; - lp.For.Point.Attenuation_Constant = light_cur.mAttenuationConstant; - lp.For.Point.Attenuation_Linear = light_cur.mAttenuationLinear; - lp.For.Point.Attenuation_Quadratic = light_cur.mAttenuationQuadratic; - break; - case aiLightSource_SPOT: - lp.For.Spot.Position = light_cur.mPosition; - lp.For.Spot.Direction = light_cur.mDirection; - lp.For.Spot.Attenuation_Constant = light_cur.mAttenuationConstant; - lp.For.Spot.Attenuation_Linear = light_cur.mAttenuationLinear; - lp.For.Spot.Attenuation_Quadratic = light_cur.mAttenuationQuadratic; - lp.For.Spot.CutOff = light_cur.mAngleOuterCone; - break; - case aiLightSource_AMBIENT: - lp.For.Point.Position = light_cur.mPosition, lp.For.Point.Attenuation_Constant = 1, lp.For.Point.Attenuation_Linear = 0, lp.For.Point.Attenuation_Quadratic = 0; - name.append("_unsup_ambient"); - break; - case aiLightSource_AREA: - lp.For.Point.Position = light_cur.mPosition, lp.For.Point.Attenuation_Constant = 1, lp.For.Point.Attenuation_Linear = 0, lp.For.Point.Attenuation_Quadratic = 0; - name.append("_unsup_area"); - break; - case aiLightSource_UNDEFINED: - lp.For.Point.Position = light_cur.mPosition, lp.For.Point.Attenuation_Constant = 1, lp.For.Point.Attenuation_Linear = 0, lp.For.Point.Attenuation_Quadratic = 0; - name.append("_unsup_undefined"); - break; - default: - lp.For.Point.Position = light_cur.mPosition, lp.For.Point.Attenuation_Constant = 1, lp.For.Point.Attenuation_Linear = 0, lp.For.Point.Attenuation_Quadratic = 0; - name.append("_unsupported_invalid"); - break; - }// switch(light_cur.mType) - - // Add light source - // Use index if name is empty. - if (name.isEmpty()) { - name += QString( "%1" ).arg( idx_light ); - } - - Lighting_EditSource(idx_light, lp); - emit SceneObject_LightSource(name);// Light source will be enabled in signal handler. - }// for(size_t idx_light = 0; idx_light < mScene->mNumLights; idx_light++) - }// if(!mScene->HasLights()) else - - // - // Cameras - // - if(!mScene->HasCameras()) - { - mCamera_DefaultAdded = true; - mHelper_CameraDefault.SetDefault(); - // Calculate distance from camera to scene. Distance must be enoguh for that viewport contain whole scene. - const GLfloat tg_angle = tan(mCamera_FOVY / 2); - - GLfloat val_x = ((mScene_BBox.Maximum.x - mScene_BBox.Minimum.x) / 2) / (mCamera_Viewport_AspectRatio * tg_angle); - GLfloat val_y = ((mScene_BBox.Maximum.y - mScene_BBox.Minimum.y) / 2) / tg_angle; - GLfloat val_step = val_x; - - AssignIfGreater(val_step, val_y); - mHelper_CameraDefault.Translation_ToScene.Set(mScene_Center.x, mScene_Center.y, val_step + mScene_BBox.Maximum.z); - emit SceneObject_Camera("_default"); - } - else - { - mCamera_DefaultAdded = false; - for(size_t idx_cam = 0; idx_cam < mScene->mNumCameras; idx_cam++) - { - emit SceneObject_Camera(mScene->mCameras[idx_cam]->mName.C_Str()); - } - }// if(!mScene->HasCameras()) else -} - -void CGLView::Lighting_Enable() { - mLightingEnabled = true; - glEnable(GL_LIGHTING); -} - -void CGLView::Lighting_Disable() { - glDisable( GL_LIGHTING ); - mLightingEnabled = false; -} - -void CGLView::Lighting_EditSource(const size_t pLightNumber, const SLightParameters& pLightParameters) -{ - const size_t light_num = GL_LIGHT0 + pLightNumber; - - GLfloat farr[4]; - - if(pLightNumber >= GL_MAX_LIGHTS) return;///TODO: return value; - - // Ambient color - farr[0] = pLightParameters.Ambient.r; - farr[1] = pLightParameters.Ambient.g; - farr[2] = pLightParameters.Ambient.b; - farr[3] = pLightParameters.Ambient.a; - glLightfv(light_num, GL_AMBIENT, farr); - - // Diffuse color - farr[0] = pLightParameters.Diffuse.r; - farr[1] = pLightParameters.Diffuse.g; - farr[2] = pLightParameters.Diffuse.b; - farr[3] = pLightParameters.Diffuse.a; - glLightfv(light_num, GL_DIFFUSE, farr); - - // Specular color - farr[0] = pLightParameters.Specular.r; - farr[1] = pLightParameters.Specular.g; - farr[2] = pLightParameters.Specular.b; - farr[3] = pLightParameters.Specular.a; - glLightfv(light_num, GL_SPECULAR, farr); - - // Other parameters - switch(pLightParameters.Type) - { - case aiLightSource_DIRECTIONAL: - // Direction - farr[0] = pLightParameters.For.Directional.Direction.x, farr[1] = pLightParameters.For.Directional.Direction.y; - farr[2] = pLightParameters.For.Directional.Direction.z; farr[3] = 0; - glLightfv(light_num, GL_POSITION, farr); - break; - case aiLightSource_POINT: - // Position - farr[0] = pLightParameters.For.Point.Position.x, farr[1] = pLightParameters.For.Point.Position.y; - farr[2] = pLightParameters.For.Point.Position.z; farr[3] = 1; - glLightfv(light_num, GL_POSITION, farr); - // Attenuation - glLightf(light_num, GL_CONSTANT_ATTENUATION, pLightParameters.For.Point.Attenuation_Constant); - glLightf(light_num, GL_LINEAR_ATTENUATION, pLightParameters.For.Point.Attenuation_Linear); - glLightf(light_num, GL_QUADRATIC_ATTENUATION, pLightParameters.For.Point.Attenuation_Quadratic); - glLightf(light_num, GL_SPOT_CUTOFF, 180.0); - break; - case aiLightSource_SPOT: - // Position - farr[0] = pLightParameters.For.Spot.Position.x, farr[1] = pLightParameters.For.Spot.Position.y, farr[2] = pLightParameters.For.Spot.Position.z; farr[3] = 1; - glLightfv(light_num, GL_POSITION, farr); - // Attenuation - glLightf(light_num, GL_CONSTANT_ATTENUATION, pLightParameters.For.Spot.Attenuation_Constant); - glLightf(light_num, GL_LINEAR_ATTENUATION, pLightParameters.For.Spot.Attenuation_Linear); - glLightf(light_num, GL_QUADRATIC_ATTENUATION, pLightParameters.For.Spot.Attenuation_Quadratic); - // Spot specific - farr[0] = pLightParameters.For.Spot.Direction.x, farr[1] = pLightParameters.For.Spot.Direction.y, farr[2] = pLightParameters.For.Spot.Direction.z; farr[3] = 0; - glLightfv(light_num, GL_SPOT_DIRECTION, farr); - glLightf(light_num, GL_SPOT_CUTOFF, pLightParameters.For.Spot.CutOff); - break; - default:// For unknown light source types use point source. - // Position - farr[0] = pLightParameters.For.Point.Position.x, farr[1] = pLightParameters.For.Point.Position.y; - farr[2] = pLightParameters.For.Point.Position.z; farr[3] = 1; - glLightfv(light_num, GL_POSITION, farr); - // Attenuation - glLightf(light_num, GL_CONSTANT_ATTENUATION, 1); - glLightf(light_num, GL_LINEAR_ATTENUATION, 0); - glLightf(light_num, GL_QUADRATIC_ATTENUATION, 0); - glLightf(light_num, GL_SPOT_CUTOFF, 180.0); - break; - }// switch(pLightParameters.Type) -} - -void CGLView::Lighting_EnableSource(const size_t pLightNumber) { - if(pLightNumber >= GL_MAX_LIGHTS) return;///TODO: return value; - - glEnable(GL_LIGHT0 + pLightNumber); -} - -void CGLView::Lighting_DisableSource(const size_t pLightNumber) -{ - if(pLightNumber >= GL_MAX_LIGHTS) return;///TODO: return value; - - glDisable(GL_LIGHT0 + pLightNumber); -} - -void CGLView::Camera_Set(const size_t pCameraNumber) -{ - SHelper_Camera& hcam = mHelper_Camera;// reference with short name for conveniance. - aiVector3D up; - - if(mCamera_DefaultAdded || (pCameraNumber >= mScene->mNumCameras))// If default camera used then 'pCameraNumber' doesn't matter. - { - // Transformation parameters - hcam = mHelper_CameraDefault; - up.Set(0, 1, 0); - } - else - { - const aiCamera& camera_cur = *mScene->mCameras[pCameraNumber]; - const aiNode* camera_node; - - aiMatrix4x4 camera_mat; - aiQuaternion camera_quat_rot; - aiVector3D camera_tr; - - up = camera_cur.mUp; - // - // Try to get real coordinates of the camera. - // - // Find node - camera_node = mScene->mRootNode->FindNode(camera_cur.mName); - if(camera_node != nullptr) Matrix_NodeToRoot(camera_node, camera_mat); - - hcam.Position = camera_cur.mLookAt; - hcam.Target = camera_cur.mPosition; - hcam.Rotation_AroundCamera = aiMatrix4x4(camera_quat_rot.GetMatrix()); - hcam.Rotation_AroundCamera.Transpose(); - // get components of transformation matrix. - camera_mat.DecomposeNoScaling(camera_quat_rot, camera_tr); - hcam.Rotation_Scene = aiMatrix4x4(); - hcam.Translation_ToScene = camera_tr; - } - - // Load identity matrix - travel to world begin. - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - // Set camera and update picture - gluLookAt(hcam.Position.x, hcam.Position.y, hcam.Position.z, hcam.Target.x, hcam.Target.y, hcam.Target.z, up.x, up.y, up.z); -} - -void CGLView::Camera_RotateScene(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z, const aiMatrix4x4* pMatrix_Rotation_Initial) { - auto deg2rad = [](const GLfloat pDegree) -> GLfloat { - return pDegree * AI_MATH_PI / 180.0f; - }; - - aiMatrix4x4 mat_rot; - - mat_rot.FromEulerAnglesXYZ(deg2rad(pAngle_X), deg2rad(pAngle_Y), deg2rad(pAngle_Z)); - if(pMatrix_Rotation_Initial != nullptr) - mHelper_Camera.Rotation_Scene = *pMatrix_Rotation_Initial * mat_rot; - else - mHelper_Camera.Rotation_Scene *= mat_rot; -} - -void CGLView::Camera_Rotate(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z, const aiMatrix4x4* pMatrix_Rotation_Initial) -{ - auto deg2rad = [](const GLfloat pDegree) -> GLfloat { return pDegree * AI_MATH_PI / 180.0; }; - - aiMatrix4x4 mat_rot; - - mat_rot.FromEulerAnglesXYZ(deg2rad(pAngle_X), deg2rad(pAngle_Y), deg2rad(pAngle_Z)); - if(pMatrix_Rotation_Initial != nullptr) - mHelper_Camera.Rotation_AroundCamera = *pMatrix_Rotation_Initial * mat_rot; - else - mHelper_Camera.Rotation_AroundCamera *= mat_rot; -} - -void CGLView::Camera_Translate(const GLfloat pTranslate_X, const GLfloat pTranslate_Y, const GLfloat pTranslate_Z) -{ - aiVector3D vect_tr(pTranslate_X, pTranslate_Y, pTranslate_Z); - - vect_tr *= mHelper_Camera.Rotation_AroundCamera; - mHelper_Camera.Translation_ToScene += vect_tr; -} - -void CGLView::Camera_Matrix(aiMatrix4x4& pRotation_Camera, aiMatrix4x4& pRotation_Scene, aiVector3D& pTranslation_Camera) -{ - pRotation_Camera = mHelper_Camera.Rotation_AroundCamera; - pRotation_Scene = mHelper_Camera.Rotation_Scene; - pTranslation_Camera = mHelper_Camera.Translation_ToScene; -} diff --git a/tools/assimp_qt_viewer/glview.hpp b/tools/assimp_qt_viewer/glview.hpp deleted file mode 100644 index 3cdb1fd11..000000000 --- a/tools/assimp_qt_viewer/glview.hpp +++ /dev/null @@ -1,456 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2018, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -#pragma once - -// Header files, Qt. -#include -#if ASSIMP_QT4_VIEWER -# include -#else -# include -# include -#endif // ASSIMP_QT4_VIEWER - -// Header files Assimp -#include - -/// \class CGLView -/// Class which hold and render scene. -#if ASSIMP_QT4_VIEWER -class CGLView : public QGLWidget -#else -class CGLView : public QOpenGLWidget, protected QOpenGLFunctions -#endif // ASSIMP_QT4_VIEWER -{ - Q_OBJECT - - /**********************************/ - /************* Types **************/ - /**********************************/ - -private: - - /// \struct SBBox - /// Bounding box for object. - struct SBBox - { - aiVector3D Minimum;///< Minimum values of coordinates. - aiVector3D Maximum;///< Maximum values of coordinates. - }; - - /// \struct SHelper_Mesh - /// Helper object for fast rendering of mesh (\ref aiMesh). - struct SHelper_Mesh - { - const size_t Quantity_Point;///< Quantity of points. - const size_t Quantity_Line;///< Quantity of lines. - const size_t Quantity_Triangle;///< Quantity of triangles. - GLuint* Index_Point;///< Array of indices for drawing points. - GLuint* Index_Line;///< Array of indices for drawing lines. - GLuint* Index_Triangle;///< Array of indices for drawing triangles. - - const SBBox BBox;///< BBox of mesh. - - /// \fn explicit SHelper_Mesh(const size_t pQuantity_Point, const size_t pQuantity_Line, const size_t pQuantity_Triangle, const SBBox& pBBox = {{0, 0, 0}, {0, 0, 0}}) - /// Constructor. - /// \param [in] pQuantity_Point - quantity of points. - /// \param [in] pQuantity_Line - quantity of lines. - /// \param [in] pQuantity_Triangle - quantity of triangles. - /// \param [in] pBBox - BBox of mesh. - explicit SHelper_Mesh(const size_t pQuantity_Point, const size_t pQuantity_Line, const size_t pQuantity_Triangle, const SBBox& pBBox = {{0, 0, 0}, {0, 0, 0}}); - - /// \fn ~SHelper_Mesh() - /// Destructor. - ~SHelper_Mesh(); - }; - - /// \struct SHelper_Camera - /// Information about position of the camera in space. - struct SHelper_Camera - { - aiVector3D Position;///< Coordinates of the camera. - aiVector3D Target;///< Target point of the camera. - // Transformation path: - // set Camera -> Rotation_AroundCamera -> Translation_ToScene -> Rotation_Scene -> draw Scene - aiMatrix4x4 Rotation_AroundCamera;///< Rotation matrix which set rotation angles of the scene around camera. - aiMatrix4x4 Rotation_Scene;///< Rotation matrix which set rotation angles of the scene around own center. - aiVector3D Translation_ToScene;///< Translation vector from camera to the scene. - - /// \fn void SetDefault() - /// Set default parameters of camera. - void SetDefault(); - }; - -public: - - /// \enum ELightType - /// Type of light source. - enum class ELightType { Directional, Point, Spot }; - - /// \struct SLightParameters - /// Parameters of light source. - struct SLightParameters - { - aiLightSourceType Type;///< Type of light source. - - aiColor4D Ambient;///< Ambient RGBA intensity of the light. - aiColor4D Diffuse;///< Diffuse RGBA intensity of the light. - aiColor4D Specular;///< Specular RGBA intensity of the light. - - union UFor - { - /// \struct SDirectional - /// Parameters of directional light source. - struct SDirectional - { - aiVector3D Direction; - - SDirectional() {} - } Directional; - - /// \struct SPoint - /// Parameters of point light source. - struct SPoint - { - aiVector3D Position; - GLfloat Attenuation_Constant; - GLfloat Attenuation_Linear; - GLfloat Attenuation_Quadratic; - - SPoint() {} - } Point; - - /// \struct SSpot - /// Parameters of spot light source. - struct SSpot - { - aiVector3D Position; - GLfloat Attenuation_Constant; - GLfloat Attenuation_Linear; - GLfloat Attenuation_Quadratic; - aiVector3D Direction; - GLfloat CutOff; - - SSpot() {} - } Spot; - - UFor() {} - } For; - - SLightParameters() {} - }; - - /**********************************/ - /************ Variables ***********/ - /**********************************/ - -private: - -#if !ASSIMP_QT4_VIEWER - // Qt5 widget has another behavior, so you must to know that you already made context are current. Yes, its a dirty hack. Better decision are welcome. - bool mGLContext_Current;///< Widget's GL-context made current. -#endif // ASSIMP_QT4_VIEWER - // Scene - const aiScene* mScene = nullptr;///< Copy of pointer to scene (\ref aiScene). - SBBox mScene_BBox;///< Bounding box of scene. - aiVector3D mScene_Center;///< Coordinates of center of the scene. - bool mScene_DrawBBox = false;///< Flag which control drawing scene BBox. - bool mScene_AxesEnabled = true;///< Flag which control drawing axes of the coordinate system. - // Meshes - size_t mHelper_Mesh_Quantity = 0;///< Quantity of meshes in scene. - SHelper_Mesh** mHelper_Mesh = nullptr;///< Array of pointers to helper objects for drawing mesh. Sequence of meshes are equivalent to \ref aiScene::mMeshes. - // Cameras - SHelper_Camera mHelper_Camera;///< Information about current camera placing in space. - SHelper_Camera mHelper_CameraDefault;///< Information about default camera initial placing in space. - bool mCamera_DefaultAdded = true;///< If true then scene has no defined cameras and default was added, if false - scene has defined cameras. - GLdouble mCamera_FOVY = 45.0;///< Specifies the field of view angle, in degrees, in the y direction. - GLdouble mCamera_Viewport_AspectRatio;///< Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height). - // Lighting - bool mLightingEnabled = false;///< If true then OpenGL lighting is enabled (glEnable(GL_LIGHTING)), if false - disabled. - ///TODO: map is goooood, but not for case when one image can be used in different materials with difference in: texture transformation, targeting of the - /// texture (ambient or emission, or even height map), texture properties. - QMap mTexture_IDMap;///< Map image filenames to textures ID's. - - /**********************************/ - /************ Functions ***********/ - /**********************************/ - -private: - - // Why in some cases pointers are used? Because: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36566 - template void AssignIfLesser(TArg* pBaseValue, const TArg pTestValue) { if(pTestValue < *pBaseValue) *pBaseValue = pTestValue; } - template void AssignIfGreater(TArg* pBaseValue, const TArg pTestValue) { if(pTestValue > *pBaseValue) *pBaseValue = pTestValue; } - - template void AssignIfLesser(TArg& pBaseValue, const TArg pTestValue) { if(pTestValue < pBaseValue) pBaseValue = pTestValue; } - template void AssignIfGreater(TArg& pBaseValue, const TArg pTestValue) { if(pTestValue > pBaseValue) pBaseValue = pTestValue; } - - /// \fn void Material_Apply(const aiMaterial* pMaterial) - /// Enable pointed material. - /// \param [in] pMaterial - pointer to material which must be used. - void Material_Apply(const aiMaterial* pMaterial); - - /// \fn void Matrix_NodeToRoot(const aiNode* pNode, aiMatrix4x4& pOutMatrix) - /// Calculate matrix for transforming coordinates from pointed node to root node (read as "global coordinate system"). - /// \param [in] pNode - pointer initial node from which relative coordintaes will be taken, - /// \param [out] pOutMatrix - matrix for transform relative coordinates in \ref pNode to coordinates in root node (\ref aiScene::mRootNode). - void Matrix_NodeToRoot(const aiNode* pNode, aiMatrix4x4& pOutMatrix); - - /// \fn void ImportTextures() - /// Import textures. - /// \param [in] pScenePath - path to the file of the scene. - void ImportTextures(const QString& pScenePath); - - /// \fn void BBox_GetForNode(const aiNode& pNode, const aiMatrix4x4& pParentNode_TransformationMatrix, SBBox& pNodeBBox, bool& pFirstAssign) - /// Calculate BBox for pointed node. Function walk thru child nodes and apply all transformations. - /// \param [in] pNode - reference to node for which needed BBox. - /// \param [in] pParent_TransformationMatrix - reference to parent (parent for pNode) transformation matrix. - /// \param [in,out] pNodeBBox - reference to where pNode BBox will be placed. It will expanded by child nodes BBoxes. - /// \param [in] pFirstAssign - means that pNodeBBox not contain valid BBox at now and assign ('=') will used for setting new value, If - /// false then \ref BBox_Extend will be used for setting new BBox. - void BBox_GetForNode(const aiNode& pNode, const aiMatrix4x4& pParent_TransformationMatrix, SBBox& pNodeBBox, bool& pFirstAssign); - - /// \fn void BBox_Extend(const SBBox& pChild, SBBox& pParent) - /// Check and if need - extend current node BBox with BBox of child node. - /// \param [in] pChild - reference to BBox which used for extend parent BBox. - /// \param [in.out] pParent - BBox which will be extended using child BBox. - void BBox_Extend(const SBBox& pChild, SBBox& pParent); - - /// \fn void BBox_GetVertices(const SBBox& pBBox, aiVector3D pVertices[8]) - /// Get vertices of a parallelepiped which is described by BBox. - /// \param [in] pBBox - input BBox. - /// \param [out] pVertices - array of vertices. - void BBox_GetVertices(const SBBox& pBBox, aiVector3D pVertices[8]); - - /// \fn void BBox_GetFromVertices(const aiVector3D* pVertices, const size_t pVerticesQuantity, SBBox& pBBox) - /// Calculate BBox for vertices array. - /// \param [in] pVertices - vertices array. - /// \param [in] pVerticesQuantity - quantity of vertices in array. If 0 then pBBox will be assigned with {{0, 0, 0}, {0, 0, 0}}. - /// \param [out] pBBox - calculated BBox. - void BBox_GetFromVertices(const aiVector3D* pVertices, const size_t pVerticesQuantity, SBBox& pBBox); - - /********************************************************************/ - /************************ Logging functions *************************/ - /********************************************************************/ - - /// \fn void LogInfo(const QString& pMessage) - /// Add message with severity "Warning" to log. - void LogInfo(const QString& pMessage); - - /// \fn void LogError(const QString& pMessage) - /// Add message with severity "Error" to log. - void LogError(const QString& pMessage); - - /********************************************************************/ - /************************** Draw functions **************************/ - /********************************************************************/ - - /// \fn void Draw_Node(const aiNode* pNode) - /// Apply node transformation and draw meshes assigned to this node. - /// \param [in] pNode - pointer to node for drawing (\ref aiNode). - void Draw_Node(const aiNode* pNode); - - /// \fn void Draw_Mesh(const size_t pMesh_Index) - /// Draw mesh. - /// \param [in] pMesh_Index - index of mesh which must be drawn. Index point to mesh in \ref mHelper_Mesh. - void Draw_Mesh(const size_t pMesh_Index); - - /// \fn void Draw_BBox(const SBBox& pBBox) - /// Draw bounding box using lines. - /// \param [in] pBBox - bounding box for drawing. - void Draw_BBox(const SBBox& pBBox); - - /********************************************************************/ - /*********************** Override functions ************************/ - /********************************************************************/ - -protected: - - /// \fn void drawCoordSystem() - /// Draw axes of the coordinate system. - void drawCoordSystem(); - - /// \fn void initializeGL() override - /// Override function to initialise OpenGL. - void initializeGL() override; - - /// \fn void resizeGL(int pWidth, int pHeight) override - /// \param [in] pWidth - new width of viewport. - /// \param [in] pHeight - new height of viewport. - void resizeGL(int pWidth, int pHeight) override; - - /// \fn void paintGL() override - /// Override function for rendering. - void paintGL() override; - -public: - - /********************************************************************/ - /********************** Constructor/Destructor **********************/ - /********************************************************************/ - - /// \fn explicit CGLView(QWidget* pParent) - /// Constructor. - /// \param [in] pParent - parent widget. - explicit CGLView(QWidget* pParent); - - /// \fn virtual ~CGLView() - /// Destructor. - virtual ~CGLView(); - - /********************************************************************/ - /********************* Scene control functions **********************/ - /********************************************************************/ - - /// \fn void FreeScene() - /// Free all helper objects data. - void FreeScene(); - - /// \fn void SetScene(const aiScene* pScene) - /// Set scene for rendering. - /// \param [in] pScene - pointer to scene. - /// \param [in] pScenePath - path to the file of the scene. - void SetScene(const aiScene* pScene, const QString& pScenePath); - - /// \fn void Enable_SceneBBox(const bool pEnable) - /// Enable drawing scene bounding box. - /// \param [in] pEnable - if true then bbox will be drawing, if false - will not be drawing. - void Enable_SceneBBox(const bool pEnable) { mScene_DrawBBox = pEnable; } - - /// \fn void Enable_Textures(const bool pEnable) - /// Control textures drawing. - /// \param [in] pEnable - if true then enable textures, false - disable textures. - void Enable_Textures(const bool pEnable); - - /// \fn void Enable_Axes(const bool pEnable) - /// Control axes drawing. - /// \param [in] pEnable - if true then enable axes, false - disable axes. - void Enable_Axes(const bool pEnable) { this->mScene_AxesEnabled = pEnable; } - - /********************************************************************/ - /******************** Lighting control functions ********************/ - /********************************************************************/ - - /// \fn void Lighting_Enable() - /// Enable OpenGL lighting. - void Lighting_Enable(); - - /// \fn void Lighting_Disable() - /// Disable OpenGL lighting. - void Lighting_Disable(); - - /// \fn void Lighting_EditSource(const size_t pLightNumber, const SLightParameters& pLightParameters) - /// Edit light source properties. - /// \param [in] pLightNumber - light source number. \ref aiScene::mLights. - /// \param [in] pLightParameters - light source parameters. - void Lighting_EditSource(const size_t pLightNumber, const SLightParameters& pLightParameters);///TODO: function set - - /// \fn void Lighting_EnableSource(const size_t pLightNumber) - /// Enable light source. - /// \param [in] pLightNumber - light source number. \ref aiScene::mLights. - void Lighting_EnableSource(const size_t pLightNumber); - - ///void Lighting_DisableSource(const size_t pLightNumber) - /// Disable light source, - /// \param [in] pLightNumber - light source number. \ref aiScene::mLights. - void Lighting_DisableSource(const size_t pLightNumber); - - /********************************************************************/ - /******************** Cameras control functions *********************/ - /********************************************************************/ - - /// \fn void Camera_Set(const size_t pCameraNumber) - /// Set view from pointed camera. - /// \param [in] pCamera_Index - index of the camera (\ref aiScene::mCameras). - void Camera_Set(const size_t pCameraNumber); - - /// \fn void Camera_RotateScene(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z, const aiMatrix4x4* pMatrix_Rotation_Initial) - /// Rotate scene around axisees. - /// \param [in] pAngle_X - specifies the angle of rotation around axis oX, in degrees. - /// \param [in] pAngle_Y - specifies the angle of rotation around axis oY, in degrees. - /// \param [in] pAngle_Z - specifies the angle of rotation around axis oZ, in degrees. - /// \param [in] pMatrix_Rotation_Initial - matrix from which calculates new transformation matrix. If not set (equal to nullptr) then current transformation matrix - /// will be used. - void Camera_RotateScene(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z, const aiMatrix4x4* pMatrix_Rotation_Initial = nullptr); - - /// \fn void Camera_Rotate(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z, const aiMatrix4x4* pMatrix_Rotation_Initial = nullptr) - /// Rotate camera around axisees. - /// \param [in] pAngle_X - specifies the angle of rotation around axis oX, in degrees. - /// \param [in] pAngle_Y - specifies the angle of rotation around axis oY, in degrees. - /// \param [in] pAngle_Z - specifies the angle of rotation around axis oZ, in degrees. - /// \param [in] pMatrix_Rotation_Initial - matrix from which calculates new transformation matrix. If not set (equal to nullptr) then current transformation matrix - /// will be used. - void Camera_Rotate(const GLfloat pAngle_X, const GLfloat pAngle_Y, const GLfloat pAngle_Z, const aiMatrix4x4* pMatrix_Rotation_Initial = nullptr); - - /// \fn void Camera_Translate(const size_t pTranslate_X, const size_t pTranslate_Y, const size_t pTranslate_Z) - /// Translate camera along axises. In local coordinates. - /// \param [in] pTranslate_X - specifies the X coordinate of translation vector. - /// \param [in] pTranslate_Y - specifies the Y coordinate of translation vector. - /// \param [in] pTranslate_Z - specifies the Z coordinate of translation vector. - void Camera_Translate(const GLfloat pTranslate_X, const GLfloat pTranslate_Y, const GLfloat pTranslate_Z); - - /// \fn void Camera_Matrix(aiMatrix4x4& pRotation_Camera, aiMatrix4x4& pRotation_Scene, aiVector3D& pTranslation_Camera) - /// Return data about camera position in world. - /// \param [out] pRotation_Camera - rotation matrix which set rotation angles of the scene around camera. - /// \param [out] pRotation_Scene - rotation matrix which set rotation angles of the scene around own center. - /// \param [out] pTranslation_Camera - translation vector from camera to the scene. - void Camera_Matrix(aiMatrix4x4& pRotation_Camera, aiMatrix4x4& pRotation_Scene, aiVector3D& pTranslation_Camera); - -signals: - - /// \fn void Paint_Finished(const size_t pPaintTime, const GLfloat pDistance) - ///< Signal. Emits when execution of \ref paintGL is end. - /// \param [out] pPaintTime_ms - time spent for rendering, in milliseconds. - /// \param [out] pDistance - distance between current camera and center of the scene. \sa SHelper_Camera::Translation_ToScene. - void Paint_Finished(const size_t pPaintTime_ms, const GLfloat pDistance); - - /// \fn void SceneObject_Camera(const QString& pName) - /// Signal. Emit for every camera found in scene. Also for default camera. - /// \param [out] pName - name of the camera. - void SceneObject_Camera(const QString& pName); - - /// \fn void SceneObject_LightSource(const QString& pName) - /// Signal. Emit for every light source found in scene. Also for default light source. - /// \param [out] pName - name of the light source. - void SceneObject_LightSource(const QString& pName); -};// class CGLView diff --git a/tools/assimp_qt_viewer/mainwindow.cpp b/tools/assimp_qt_viewer/mainwindow.cpp deleted file mode 100644 index 82c2fcbe3..000000000 --- a/tools/assimp_qt_viewer/mainwindow.cpp +++ /dev/null @@ -1,466 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2018, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -#include "mainwindow.hpp" -#include "ui_mainwindow.h" - -// Header files, Assimp. -#include -#include - -#ifndef __unused - #define __unused __attribute__((unused)) -#endif // __unused - -using namespace Assimp; - - -void MainWindow::ImportFile(const QString &pFileName) { - QTime time_begin = QTime::currentTime(); - - if ( mScene != nullptr ) { - mImporter.FreeScene(); - mGLView->FreeScene(); - } - - // Try to import scene. - mScene = mImporter.ReadFile(pFileName.toStdString(), aiProcess_Triangulate | aiProcess_GenNormals | aiProcess_ValidateDataStructure | \ - aiProcess_GenUVCoords | aiProcess_TransformUVCoords | aiProcess_FlipUVs); - if ( mScene != nullptr ) { - ui->lblLoadTime->setText(QString::number(time_begin.secsTo(QTime::currentTime()))); - LogInfo("Import done: " + pFileName); - // Prepare widgets for new scene. - ui->leFileName->setText(pFileName.right(pFileName.length() - pFileName.lastIndexOf('/') - 1)); - ui->lstLight->clear(); - ui->lstCamera->clear(); - ui->cbxLighting->setChecked(true); mGLView->Lighting_Enable(); - ui->cbxBBox->setChecked(false); mGLView->Enable_SceneBBox(false); - ui->cbxTextures->setChecked(true); mGLView->Enable_Textures(true); - - // - // Fill info labels - // - // Cameras - ui->lblCameraCount->setText(QString::number(mScene->mNumCameras)); - // Lights - ui->lblLightCount->setText(QString::number(mScene->mNumLights)); - // Meshes, faces, vertices. - size_t qty_face = 0; - size_t qty_vert = 0; - - for(size_t idx_mesh = 0; idx_mesh < mScene->mNumMeshes; idx_mesh++) { - qty_face += mScene->mMeshes[idx_mesh]->mNumFaces; - qty_vert += mScene->mMeshes[idx_mesh]->mNumVertices; - } - - ui->lblMeshCount->setText(QString::number(mScene->mNumMeshes)); - ui->lblFaceCount->setText(QString::number(qty_face)); - ui->lblVertexCount->setText(QString::number(qty_vert)); - // Animation - if(mScene->mNumAnimations) - ui->lblHasAnimation->setText("yes"); - else - ui->lblHasAnimation->setText("no"); - - // - // Set scene for GL viewer. - // - mGLView->SetScene(mScene, pFileName); - // Select first camera - ui->lstCamera->setCurrentRow(0); - mGLView->Camera_Set(0); - // Scene is loaded, do first rendering. - LogInfo("Scene is ready for rendering."); -#if ASSIMP_QT4_VIEWER - mGLView->updateGL(); -#else - mGLView->update(); -#endif // ASSIMP_QT4_VIEWER - } - else - { - ResetSceneInfos(); - - QString errorMessage = QString("Error parsing \'%1\' : \'%2\'").arg(pFileName).arg(mImporter.GetErrorString()); - QMessageBox::critical(this, "Import error", errorMessage); - LogError(errorMessage); - }// if(mScene != nullptr) -} - -void MainWindow::ResetSceneInfos() -{ - ui->lblLoadTime->clear(); - ui->leFileName->clear(); - ui->lblMeshCount->setText("0"); - ui->lblFaceCount->setText("0"); - ui->lblVertexCount->setText("0"); - ui->lblCameraCount->setText("0"); - ui->lblLightCount->setText("0"); - ui->lblHasAnimation->setText("no"); -} - -/********************************************************************/ -/************************ Logging functions *************************/ -/********************************************************************/ - -void MainWindow::LogInfo(const QString& pMessage) -{ - Assimp::DefaultLogger::get()->info(pMessage.toStdString()); -} - -void MainWindow::LogError(const QString& pMessage) -{ - Assimp::DefaultLogger::get()->error(pMessage.toStdString()); -} - -/********************************************************************/ -/*********************** Override functions ************************/ -/********************************************************************/ - -void MainWindow::mousePressEvent(QMouseEvent* pEvent) -{ - const QPoint ms_pt = pEvent->pos(); - aiVector3D temp_v3; - - // Check if GLView is pointed. - if(childAt(ms_pt) == mGLView) - { - if(!mMouse_Transformation.Position_Pressed_Valid) - { - mMouse_Transformation.Position_Pressed_Valid = true;// set flag - // Store current transformation matrices. - mGLView->Camera_Matrix(mMouse_Transformation.Rotation_AroundCamera, mMouse_Transformation.Rotation_Scene, temp_v3); - } - - if(pEvent->button() & Qt::LeftButton) - mMouse_Transformation.Position_Pressed_LMB = ms_pt; - else if(pEvent->button() & Qt::RightButton) - mMouse_Transformation.Position_Pressed_RMB = ms_pt; - } - else - { - mMouse_Transformation.Position_Pressed_Valid = false; - } -} - -void MainWindow::mouseReleaseEvent(QMouseEvent *pEvent) -{ - if(pEvent->buttons() == 0) mMouse_Transformation.Position_Pressed_Valid = false; - -} - -void MainWindow::mouseMoveEvent(QMouseEvent* pEvent) -{ - if(mMouse_Transformation.Position_Pressed_Valid) - { - if(pEvent->buttons() & Qt::LeftButton) - { - GLfloat dx = 180 * GLfloat(pEvent->x() - mMouse_Transformation.Position_Pressed_LMB.x()) / mGLView->width(); - GLfloat dy = 180 * GLfloat(pEvent->y() - mMouse_Transformation.Position_Pressed_LMB.y()) / mGLView->height(); - - if(pEvent->modifiers() & Qt::ShiftModifier) - mGLView->Camera_RotateScene(dy, 0, dx, &mMouse_Transformation.Rotation_Scene);// Rotate around oX and oZ axises. - else - mGLView->Camera_RotateScene(dy, dx, 0, &mMouse_Transformation.Rotation_Scene);// Rotate around oX and oY axises. - - #if ASSIMP_QT4_VIEWER - mGLView->updateGL(); - #else - mGLView->update(); - #endif // ASSIMP_QT4_VIEWER - } - - if(pEvent->buttons() & Qt::RightButton) - { - GLfloat dx = 180 * GLfloat(pEvent->x() - mMouse_Transformation.Position_Pressed_RMB.x()) / mGLView->width(); - GLfloat dy = 180 * GLfloat(pEvent->y() - mMouse_Transformation.Position_Pressed_RMB.y()) / mGLView->height(); - - if(pEvent->modifiers() & Qt::ShiftModifier) - mGLView->Camera_Rotate(dy, 0, dx, &mMouse_Transformation.Rotation_AroundCamera);// Rotate around oX and oZ axises. - else - mGLView->Camera_Rotate(dy, dx, 0, &mMouse_Transformation.Rotation_AroundCamera);// Rotate around oX and oY axises. - - #if ASSIMP_QT4_VIEWER - mGLView->updateGL(); - #else - mGLView->update(); - #endif // ASSIMP_QT4_VIEWER - } - } -} - -void MainWindow::keyPressEvent(QKeyEvent* pEvent) -{ -GLfloat step; - - if(pEvent->modifiers() & Qt::ControlModifier) - step = 10; - else if(pEvent->modifiers() & Qt::AltModifier) - step = 100; - else - step = 1; - - if(pEvent->key() == Qt::Key_A) - mGLView->Camera_Translate(-step, 0, 0); - else if(pEvent->key() == Qt::Key_D) - mGLView->Camera_Translate(step, 0, 0); - else if(pEvent->key() == Qt::Key_W) - mGLView->Camera_Translate(0, step, 0); - else if(pEvent->key() == Qt::Key_S) - mGLView->Camera_Translate(0, -step, 0); - else if(pEvent->key() == Qt::Key_Up) - mGLView->Camera_Translate(0, 0, -step); - else if(pEvent->key() == Qt::Key_Down) - mGLView->Camera_Translate(0, 0, step); - -#if ASSIMP_QT4_VIEWER - mGLView->updateGL(); -#else - mGLView->update(); -#endif // ASSIMP_QT4_VIEWER -} - -/********************************************************************/ -/********************** Constructor/Destructor **********************/ -/********************************************************************/ - -MainWindow::MainWindow(QWidget *parent) - : QMainWindow(parent), ui(new Ui::MainWindow), - mScene(nullptr) -{ - - // other variables - mMouse_Transformation.Position_Pressed_Valid = false; - - ui->setupUi(this); - // Create OpenGL widget - mGLView = new CGLView(this); - mGLView->setMinimumSize(800, 600); - mGLView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding); - mGLView->setFocusPolicy(Qt::StrongFocus); - // Connect to GLView signals. - connect(mGLView, SIGNAL(Paint_Finished(size_t, GLfloat)), SLOT(Paint_Finished(size_t, GLfloat))); - connect(mGLView, SIGNAL(SceneObject_Camera(QString)), SLOT(SceneObject_Camera(QString))); - connect(mGLView, SIGNAL(SceneObject_LightSource(QString)), SLOT(SceneObject_LightSource(QString))); - // and add it to layout - ui->hlMainView->insertWidget(0, mGLView, 4); - // Create logger - mLoggerView = new CLoggerView(ui->tbLog); - DefaultLogger::create("", Logger::VERBOSE); - DefaultLogger::get()->attachStream(mLoggerView, DefaultLogger::Debugging | DefaultLogger::Info | DefaultLogger::Err | DefaultLogger::Warn); - - ResetSceneInfos(); -} - -MainWindow::~MainWindow() -{ -using namespace Assimp; - - DefaultLogger::get()->detatchStream(mLoggerView, DefaultLogger::Debugging | DefaultLogger::Info | DefaultLogger::Err | DefaultLogger::Warn); - DefaultLogger::kill(); - - if(mScene != nullptr) mImporter.FreeScene(); - if(mLoggerView != nullptr) delete mLoggerView; - if(mGLView != nullptr) delete mGLView; - delete ui; -} - -/********************************************************************/ -/****************************** Slots *******************************/ -/********************************************************************/ - -void MainWindow::Paint_Finished(const size_t pPaintTime_ms, const GLfloat pDistance) -{ - ui->lblRenderTime->setText(QString::number(pPaintTime_ms)); - ui->lblDistance->setText(QString::number(pDistance)); -} - -void MainWindow::SceneObject_Camera(const QString& pName) -{ - ui->lstCamera->addItem(pName); -} - -void MainWindow::SceneObject_LightSource(const QString& pName) -{ - ui->lstLight->addItem(pName); - // After item added "currentRow" is still contain old value (even '-1' if first item added). Because "currentRow"/"currentItem" is changed by user interaction, - // not by "addItem". So, "currentRow" must be set manually. - ui->lstLight->setCurrentRow(ui->lstLight->count() - 1); - // And after "selectAll" handler of "signal itemSelectionChanged" will get right "currentItem" and "currentRow" values. - ui->lstLight->selectAll(); -} - -void MainWindow::on_butOpenFile_clicked() { - aiString filter_temp; - mImporter.GetExtensionList( filter_temp ); - - QString filename, filter; - filter = filter_temp.C_Str(); - filter.replace(';', ' '); - filter.append(" ;; All (*.*)"); - filename = QFileDialog::getOpenFileName(this, "Choose the file", "", filter); - - if (!filename.isEmpty()) { - ImportFile( filename ); - } -} - -void MainWindow::on_butExport_clicked() -{ - using namespace Assimp; - -#ifndef ASSIMP_BUILD_NO_EXPORT - QString filename, filter, format_id; - Exporter exporter; - QTime time_begin; - aiReturn rv; - QStringList exportersList; - QMap exportersMap; - - - if(mScene == nullptr) - { - QMessageBox::critical(this, "Export error", "Scene is empty"); - - return; - } - - for (size_t i = 0; i < exporter.GetExportFormatCount(); ++i) - { - const aiExportFormatDesc* desc = exporter.GetExportFormatDescription(i); - exportersList.push_back(desc->id + QString(": ") + desc->description); - exportersMap.insert(desc->id, desc); - } - - // get an exporter - bool dialogSelectExporterOk; - QString selectedExporter = QInputDialog::getItem(this, "Export format", "Select the exporter : ", exportersList, 0, false, &dialogSelectExporterOk); - if (!dialogSelectExporterOk) - return; - - // build the filter - QString selectedId = selectedExporter.left(selectedExporter.indexOf(':')); - filter = QString("*.") + exportersMap[selectedId]->fileExtension; - - // get file path - filename = QFileDialog::getSaveFileName(this, "Set file name", "", filter); - // if it's canceled - if (filename == "") - return; - - // begin export - time_begin = QTime::currentTime(); - rv = exporter.Export(mScene, selectedId.toLocal8Bit(), filename.toLocal8Bit(), aiProcess_FlipUVs); - ui->lblExportTime->setText(QString::number(time_begin.secsTo(QTime::currentTime()))); - if(rv == aiReturn_SUCCESS) - LogInfo("Export done: " + filename); - else - { - QString errorMessage = QString("Export failed: ") + filename; - LogError(errorMessage); - QMessageBox::critical(this, "Export error", errorMessage); - } -#endif -} - -void MainWindow::on_cbxLighting_clicked(bool pChecked) -{ - if(pChecked) - mGLView->Lighting_Enable(); - else - mGLView->Lighting_Disable(); - - mGLView->update(); -} - -void MainWindow::on_lstLight_itemSelectionChanged() -{ -bool selected = ui->lstLight->isItemSelected(ui->lstLight->currentItem()); - - if(selected) - mGLView->Lighting_EnableSource(ui->lstLight->currentRow()); - else - mGLView->Lighting_DisableSource(ui->lstLight->currentRow()); - -#if ASSIMP_QT4_VIEWER - mGLView->updateGL(); -#else - mGLView->update(); -#endif // ASSIMP_QT4_VIEWER -} - -void MainWindow::on_lstCamera_clicked( const QModelIndex &) -{ - mGLView->Camera_Set(ui->lstLight->currentRow()); -#if ASSIMP_QT4_VIEWER - mGLView->updateGL(); -#else - mGLView->update(); -#endif // ASSIMP_QT4_VIEWER -} - -void MainWindow::on_cbxBBox_clicked(bool checked) -{ - mGLView->Enable_SceneBBox(checked); -#if ASSIMP_QT4_VIEWER - mGLView->updateGL(); -#else - mGLView->update(); -#endif // ASSIMP_QT4_VIEWER -} - -void MainWindow::on_cbxDrawAxes_clicked(bool checked) -{ - mGLView->Enable_Axes(checked); -#if ASSIMP_QT4_VIEWER - mGLView->updateGL(); -#else - mGLView->update(); -#endif // ASSIMP_QT4_VIEWER -} - -void MainWindow::on_cbxTextures_clicked(bool checked) -{ - mGLView->Enable_Textures(checked); - mGLView->update(); -} diff --git a/tools/assimp_qt_viewer/mainwindow.hpp b/tools/assimp_qt_viewer/mainwindow.hpp deleted file mode 100644 index 1ebd19996..000000000 --- a/tools/assimp_qt_viewer/mainwindow.hpp +++ /dev/null @@ -1,148 +0,0 @@ -/* ---------------------------------------------------------------------------- -Open Asset Import Library (assimp) ---------------------------------------------------------------------------- - -Copyright (c) 2006-2018, assimp team - - - -All rights reserved. - -Redistribution and use of this software in source and binary forms, -with or without modification, are permitted provided that the following -conditions are met: - -* Redistributions of source code must retain the above -copyright notice, this list of conditions and the -following disclaimer. - -* Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the -following disclaimer in the documentation and/or other -materials provided with the distribution. - -* Neither the name of the assimp team, nor the names of its -contributors may be used to endorse or promote products -derived from this software without specific prior -written permission of the assimp team. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------------- -*/ - -#pragma once - -// Header files, Qt. -#if defined ASSIMP_QT4_VIEWER -# include -#else -# include -#endif - -// Header files, project. -#include "glview.hpp" -#include "loggerview.hpp" - -// Header files, Assimp. -#include -#include - -namespace Ui { - class MainWindow; -} - -/// \class MainWindow -/// Main window and algorithms. -class MainWindow : public QMainWindow { - Q_OBJECT - - struct SMouse_Transformation; - -public: - /// @brief The class constructor. - /// \param [in] pParent - pointer to parent widget. - explicit MainWindow( QWidget* pParent = 0 ); - - /// @brief The class destructor. - ~MainWindow(); - - /// Import scene from file. - /// \param [in] pFileName - path and name of the file. - void ImportFile(const QString& pFileName); - - /// Reset informations about the scene - void ResetSceneInfos(); - - /// Add message with severity "Warning" to log. - void LogInfo(const QString& pMessage); - - /// Add message with severity "Error" to log. - void LogError(const QString& pMessage); - -protected: - /// Override function which handles mouse event "button pressed". - /// \param [in] pEvent - pointer to event data. - void mousePressEvent(QMouseEvent* pEvent) override; - - /// Override function which handles mouse event "button released". - /// \param [in] pEvent - pointer to event data. - void mouseReleaseEvent(QMouseEvent *pEvent) override; - - /// Override function which handles mouse event "move". - /// \param [in] pEvent - pointer to event data. - void mouseMoveEvent(QMouseEvent* pEvent) override; - - /// Override function which handles key event "key pressed". - /// \param [in] pEvent - pointer to event data. - void keyPressEvent(QKeyEvent* pEvent) override; - -private slots: - /// Show paint/render time and distance between camera and center of the scene. - /// \param [in] pPaintTime_ms - paint time in milliseconds. - void Paint_Finished(const size_t pPaintTime_ms, const GLfloat pDistance); - - /// Add camera name to list. - /// \param [in] pName - name of the camera. - void SceneObject_Camera(const QString& pName); - - /// Add lighting source name to list. - /// \param [in] pName - name of the light source, - void SceneObject_LightSource(const QString& pName); - - void on_butOpenFile_clicked(); - void on_butExport_clicked(); - void on_cbxLighting_clicked(bool pChecked); - void on_lstLight_itemSelectionChanged(); - void on_lstCamera_clicked(const QModelIndex &index); - void on_cbxBBox_clicked(bool checked); - void on_cbxTextures_clicked(bool checked); - void on_cbxDrawAxes_clicked(bool checked); - -private: - Ui::MainWindow *ui; - CGLView *mGLView;///< Pointer to OpenGL render. - CLoggerView *mLoggerView;///< Pointer to logging object. - Assimp::Importer mImporter;///< Assimp importer. - const aiScene* mScene;///< Pointer to loaded scene (\ref aiScene). - - /// \struct SMouse_Transformation - /// Holds data about transformation of the scene/camera when mouse us used. - struct SMouse_Transformation { - bool Position_Pressed_Valid;///< Mouse button pressed on GLView. - QPoint Position_Pressed_LMB;///< Position where was pressed left mouse button. - QPoint Position_Pressed_RMB;///< Position where was pressed right mouse button. - aiMatrix4x4 Rotation_AroundCamera;///< Rotation matrix which set rotation angles of the scene around camera. - aiMatrix4x4 Rotation_Scene;///< Rotation matrix which set rotation angles of the scene around own center. - } mMouse_Transformation; -}; diff --git a/tools/assimp_qt_viewer/mainwindow.ui b/tools/assimp_qt_viewer/mainwindow.ui deleted file mode 100644 index 04208f585..000000000 --- a/tools/assimp_qt_viewer/mainwindow.ui +++ /dev/null @@ -1,544 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 641 - 778 - - - - MainWindow - - - - - - - - - QLayout::SetDefaultConstraint - - - - - - - - 0 - 0 - - - - Qt::NoFocus - - - File - - - - - - Qt::NoFocus - - - Open file - - - - - - - Qt::NoFocus - - - File name - - - - - - - - 160 - 16777215 - - - - Qt::NoFocus - - - false - - - true - - - - - - - Qt::NoFocus - - - Load time, s - - - - - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - Qt::NoFocus - - - Qt::Horizontal - - - - - - - Qt::NoFocus - - - Export - - - - - - - Qt::NoFocus - - - Export time, s - - - - - - - Qt::NoFocus - - - - - - - - - - - - - - 0 - 0 - - - - Qt::NoFocus - - - Info - - - - - - Qt::NoFocus - - - Render time, ms - - - - - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - Qt::NoFocus - - - Meshes - - - - - - - Qt::NoFocus - - - Faces - - - - - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - Qt::NoFocus - - - Vertices - - - - - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - Qt::NoFocus - - - Lights - - - - - - - Qt::NoFocus - - - Cameras - - - - - - - Qt::NoFocus - - - Animation - - - - - - - false - - - Qt::NoFocus - - - Shaders - - - - - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - false - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - Qt::NoFocus - - - - - - Qt::AlignCenter - - - - - - - Distance - - - - - - - - - - Qt::AlignCenter - - - - - - - - - - false - - - Qt::NoFocus - - - Dynamics - - - - - - Qt::NoFocus - - - Animation start - - - - - - - Qt::NoFocus - - - Animation stop - - - - - - - - - - - - - - Qt::NoFocus - - - 2 - - - - Log - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - Qt::NoFocus - - - - - - - - Lights and cameras - - - - - - Qt::NoFocus - - - Light sources of the scene - - - QAbstractItemView::SelectedClicked - - - false - - - QAbstractItemView::MultiSelection - - - - - - - Qt::NoFocus - - - Cameras of the scene - - - QAbstractItemView::NoEditTriggers - - - false - - - - - - - - Control - - - - - - Enable/Disable OpenGL lighting - - - Lighting - - - true - - - - - - - Scene BBox - - - - - - - Textures - - - - - - - Show Axes - - - true - - - - - - - - - - - - - - - - - installEventFilter() - - diff --git a/tools/assimp_view/AnimEvaluator.cpp b/tools/assimp_view/AnimEvaluator.cpp index 94c581df4..9d9481a77 100644 --- a/tools/assimp_view/AnimEvaluator.cpp +++ b/tools/assimp_view/AnimEvaluator.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -47,17 +47,21 @@ using namespace AssimpView; // ------------------------------------------------------------------------------------------------ // Constructor on a given animation. -AnimEvaluator::AnimEvaluator( const aiAnimation* pAnim) -{ - mAnim = pAnim; - mLastTime = 0.0; +AnimEvaluator::AnimEvaluator( const aiAnimation *pAnim ) +: mAnim(pAnim) +, mLastTime(0.0) { mLastPositions.resize( pAnim->mNumChannels, std::make_tuple( 0, 0, 0)); } +// ------------------------------------------------------------------------------------------------ +// Destructor. +AnimEvaluator::~AnimEvaluator() { + // empty +} + // ------------------------------------------------------------------------------------------------ // Evaluates the animation tracks for a given time stamp. -void AnimEvaluator::Evaluate( double pTime) -{ +void AnimEvaluator::Evaluate( double pTime ) { // extract ticks per second. Assume default value if not given double ticksPerSecond = mAnim->mTicksPerSecond != 0.0 ? mAnim->mTicksPerSecond : 25.0; // every following time calculation happens in ticks @@ -65,29 +69,29 @@ void AnimEvaluator::Evaluate( double pTime) // map into anim's duration double time = 0.0f; - if( mAnim->mDuration > 0.0) - time = fmod( pTime, mAnim->mDuration); + if (mAnim->mDuration > 0.0) { + time = fmod(pTime, mAnim->mDuration); + } - if( mTransforms.size() != mAnim->mNumChannels) - mTransforms.resize( mAnim->mNumChannels); + if (mTransforms.size() != mAnim->mNumChannels) { + mTransforms.resize(mAnim->mNumChannels); + } // calculate the transformations for each animation channel - for( unsigned int a = 0; a < mAnim->mNumChannels; a++) - { + for( unsigned int a = 0; a < mAnim->mNumChannels; ++a ) { const aiNodeAnim* channel = mAnim->mChannels[a]; // ******** Position ***** aiVector3D presentPosition( 0, 0, 0); - if( channel->mNumPositionKeys > 0) - { + if( channel->mNumPositionKeys > 0) { // Look for present frame number. Search from last position if time is after the last time, else from beginning // Should be much quicker than always looking from start for the average use case. unsigned int frame = (time >= mLastTime) ? std::get<0>(mLastPositions[a]) : 0; - while( frame < channel->mNumPositionKeys - 1) - { - if( time < channel->mPositionKeys[frame+1].mTime) + while( frame < channel->mNumPositionKeys - 1) { + if (time < channel->mPositionKeys[frame + 1].mTime) { break; - frame++; + } + ++frame; } // interpolate between this frame's value and next frame's value @@ -95,14 +99,13 @@ void AnimEvaluator::Evaluate( double pTime) const aiVectorKey& key = channel->mPositionKeys[frame]; const aiVectorKey& nextKey = channel->mPositionKeys[nextFrame]; double diffTime = nextKey.mTime - key.mTime; - if( diffTime < 0.0) + if (diffTime < 0.0) { diffTime += mAnim->mDuration; - if( diffTime > 0) - { + } + if( diffTime > 0) { float factor = float( (time - key.mTime) / diffTime); presentPosition = key.mValue + (nextKey.mValue - key.mValue) * factor; - } else - { + } else { presentPosition = key.mValue; } @@ -111,14 +114,13 @@ void AnimEvaluator::Evaluate( double pTime) // ******** Rotation ********* aiQuaternion presentRotation( 1, 0, 0, 0); - if( channel->mNumRotationKeys > 0) - { + if( channel->mNumRotationKeys > 0) { unsigned int frame = (time >= mLastTime) ? std::get<1>(mLastPositions[a]) : 0; - while( frame < channel->mNumRotationKeys - 1) - { - if( time < channel->mRotationKeys[frame+1].mTime) + while( frame < channel->mNumRotationKeys - 1) { + if (time < channel->mRotationKeys[frame + 1].mTime) { break; - frame++; + } + ++frame; } // interpolate between this frame's value and next frame's value @@ -126,14 +128,13 @@ void AnimEvaluator::Evaluate( double pTime) const aiQuatKey& key = channel->mRotationKeys[frame]; const aiQuatKey& nextKey = channel->mRotationKeys[nextFrame]; double diffTime = nextKey.mTime - key.mTime; - if( diffTime < 0.0) + if (diffTime < 0.0) { diffTime += mAnim->mDuration; - if( diffTime > 0) - { + } + if( diffTime > 0) { float factor = float( (time - key.mTime) / diffTime); aiQuaternion::Interpolate( presentRotation, key.mValue, nextKey.mValue, factor); - } else - { + } else { presentRotation = key.mValue; } @@ -142,14 +143,13 @@ void AnimEvaluator::Evaluate( double pTime) // ******** Scaling ********** aiVector3D presentScaling( 1, 1, 1); - if( channel->mNumScalingKeys > 0) - { + if( channel->mNumScalingKeys > 0) { unsigned int frame = (time >= mLastTime) ? std::get<2>(mLastPositions[a]) : 0; - while( frame < channel->mNumScalingKeys - 1) - { - if( time < channel->mScalingKeys[frame+1].mTime) + while( frame < channel->mNumScalingKeys - 1) { + if (time < channel->mScalingKeys[frame + 1].mTime) { break; - frame++; + } + ++frame; } // TODO: (thom) interpolation maybe? This time maybe even logarithmic, not linear @@ -164,7 +164,6 @@ void AnimEvaluator::Evaluate( double pTime) mat.a2 *= presentScaling.y; mat.b2 *= presentScaling.y; mat.c2 *= presentScaling.y; mat.a3 *= presentScaling.z; mat.b3 *= presentScaling.z; mat.c3 *= presentScaling.z; mat.a4 = presentPosition.x; mat.b4 = presentPosition.y; mat.c4 = presentPosition.z; - //mat.Transpose(); } mLastTime = time; diff --git a/tools/assimp_view/AnimEvaluator.h b/tools/assimp_view/AnimEvaluator.h index 417a02935..1b4d54186 100644 --- a/tools/assimp_view/AnimEvaluator.h +++ b/tools/assimp_view/AnimEvaluator.h @@ -4,7 +4,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -46,22 +46,23 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -namespace AssimpView -{ +namespace AssimpView { -/** Calculates transformations for a given timestamp from a set of animation tracks. Not directly useful, - * better use the AnimPlayer class. +/** + * @brief Calculates transformations for a given timestamp from a set of animation tracks. Not directly useful, + * better use the AnimPlayer class. */ -class AnimEvaluator -{ +class AnimEvaluator { public: - /** Constructor on a given animation. The animation is fixed throughout the lifetime of - * the object. - * @param pAnim The animation to calculate poses for. Ownership of the animation object stays - * at the caller, the evaluator just keeps a reference to it as long as it persists. - */ + /// @brief Constructor on a given animation. The animation is fixed throughout the lifetime of + /// the object. + /// @param pAnim The animation to calculate poses for. Ownership of the animation object stays + /// at the caller, the evaluator just keeps a reference to it as long as it persists. AnimEvaluator( const aiAnimation* pAnim); + /// @brief The class destructor. + ~AnimEvaluator(); + /** Evaluates the animation tracks for a given time stamp. The calculated pose can be retrieved as a * array of transformation matrices afterwards by calling GetTransformations(). * @param pTime The time for which you want to evaluate the animation, in seconds. Will be mapped into the animation cycle, so @@ -74,16 +75,9 @@ public: const std::vector& GetTransformations() const { return mTransforms; } protected: - /** The animation we're working on */ const aiAnimation* mAnim; - - /** At which frame the last evaluation happened for each channel. - * Useful to quickly find the corresponding frame for slightly increased time stamps - */ double mLastTime; std::vector > mLastPositions; - - /** The array to store the transformations results of the evaluation */ std::vector mTransforms; }; diff --git a/tools/assimp_view/Background.cpp b/tools/assimp_view/Background.cpp index 14bf5b90d..b356a245b 100644 --- a/tools/assimp_view/Background.cpp +++ b/tools/assimp_view/Background.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/tools/assimp_view/CMakeLists.txt b/tools/assimp_view/CMakeLists.txt index f75937eff..8112c19e8 100644 --- a/tools/assimp_view/CMakeLists.txt +++ b/tools/assimp_view/CMakeLists.txt @@ -1,7 +1,7 @@ # Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # -# Copyright (c) 2006-2018, assimp team +# Copyright (c) 2006-2019, assimp team # All rights reserved. @@ -88,6 +88,8 @@ SET_PROPERTY(TARGET assimp_viewer PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) IF ( MSVC ) ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS ) ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) + # assimp_viewer is ANSI (MBCS) throughout + REMOVE_DEFINITIONS( -DUNICODE -D_UNICODE ) ENDIF ( MSVC ) diff --git a/tools/assimp_view/Display.cpp b/tools/assimp_view/Display.cpp index 041ab34c5..ab29c1d3e 100644 --- a/tools/assimp_view/Display.cpp +++ b/tools/assimp_view/Display.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -102,17 +102,16 @@ void GetNodeCount(aiNode* pcNode, unsigned int* piCnt) } //------------------------------------------------------------------------------- -int CDisplay::EnableAnimTools(BOOL hm) -{ +int CDisplay::EnableAnimTools(BOOL hm) { EnableWindow(GetDlgItem(g_hDlg,IDC_PLAY),hm); EnableWindow(GetDlgItem(g_hDlg,IDC_SLIDERANIM),hm); + return 1; } //------------------------------------------------------------------------------- // Fill animation combo box -int CDisplay::FillAnimList(void) -{ +int CDisplay::FillAnimList(void) { if (0 != g_pcAsset->pcScene->mNumAnimations) { // now fill in all animation names diff --git a/tools/assimp_view/HelpDialog.cpp b/tools/assimp_view/HelpDialog.cpp index 7b2ebf7b6..1a9f08f5f 100644 --- a/tools/assimp_view/HelpDialog.cpp +++ b/tools/assimp_view/HelpDialog.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -48,14 +48,10 @@ namespace AssimpView { //------------------------------------------------------------------------------- // Message procedure for the help dialog //------------------------------------------------------------------------------- -INT_PTR CALLBACK HelpDialogProc(HWND hwndDlg,UINT uMsg, - WPARAM wParam,LPARAM lParam) - { - (void)lParam; - switch (uMsg) - { +INT_PTR CALLBACK HelpDialogProc(HWND hwndDlg,UINT uMsg, WPARAM wParam,LPARAM ) { + switch (uMsg) { case WM_INITDIALOG: - { + { // load the help file ... HRSRC res = FindResource(NULL,MAKEINTRESOURCE(IDR_TEXT1),"TEXT"); HGLOBAL hg = LoadResource(NULL,res); @@ -70,39 +66,38 @@ INT_PTR CALLBACK HelpDialogProc(HWND hwndDlg,UINT uMsg, FreeResource(hg); return TRUE; - } + } case WM_CLOSE: EndDialog(hwndDlg,0); return TRUE; case WM_COMMAND: - - if (IDOK == LOWORD(wParam)) - { + if (IDOK == LOWORD(wParam)) { EndDialog(hwndDlg,0); return TRUE; - } + } case WM_PAINT: { - PAINTSTRUCT sPaint; - HDC hdc = BeginPaint(hwndDlg,&sPaint); + PAINTSTRUCT sPaint; + HDC hdc = BeginPaint(hwndDlg,&sPaint); - HBRUSH hBrush = CreateSolidBrush(RGB(0xFF,0xFF,0xFF)); + HBRUSH hBrush = CreateSolidBrush(RGB(0xFF,0xFF,0xFF)); - RECT sRect; - sRect.left = 0; - sRect.top = 26; - sRect.right = 1000; - sRect.bottom = 507; - FillRect(hdc, &sRect, hBrush); + RECT sRect; + sRect.left = 0; + sRect.top = 26; + sRect.right = 1000; + sRect.bottom = 507; + FillRect(hdc, &sRect, hBrush); - EndPaint(hwndDlg,&sPaint); - return TRUE; + EndPaint(hwndDlg,&sPaint); + return TRUE; } - }; - return FALSE; } -}; \ No newline at end of file + return FALSE; +} + +} diff --git a/tools/assimp_view/Input.cpp b/tools/assimp_view/Input.cpp index 7a9582fb2..88e04b437 100644 --- a/tools/assimp_view/Input.cpp +++ b/tools/assimp_view/Input.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -194,7 +194,7 @@ void HandleMouseInputSkyBox( void ) //------------------------------------------------------------------------------- //------------------------------------------------------------------------------- -void HandleMouseInputLightIntensityAndColor( void ) +void HandleMouseInputLightIntensityAndColor() { POINT mousePos; GetCursorPos( &mousePos ); diff --git a/tools/assimp_view/LogDisplay.cpp b/tools/assimp_view/LogDisplay.cpp index bf0c190b6..d24b9bf20 100644 --- a/tools/assimp_view/LogDisplay.cpp +++ b/tools/assimp_view/LogDisplay.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -46,32 +46,26 @@ namespace AssimpView { CLogDisplay CLogDisplay::s_cInstance; //------------------------------------------------------------------------------- -void CLogDisplay::AddEntry(const std::string& szText, - const D3DCOLOR clrColor) - { +void CLogDisplay::AddEntry(const std::string& szText, const D3DCOLOR clrColor) { SEntry sNew; sNew.clrColor = clrColor; sNew.szText = szText; sNew.dwStartTicks = (DWORD)GetTickCount(); this->asEntries.push_back(sNew); - } +} //------------------------------------------------------------------------------- -void CLogDisplay::ReleaseNativeResource() - { - if (this->piFont) - { +void CLogDisplay::ReleaseNativeResource() { + if (this->piFont) { this->piFont->Release(); - this->piFont = NULL; - } + this->piFont = nullptr; } +} //------------------------------------------------------------------------------- -void CLogDisplay::RecreateNativeResource() - { - if (!this->piFont) - { +void CLogDisplay::RecreateNativeResource() { + if (!this->piFont) { if (FAILED(D3DXCreateFont(g_piDevice, 16, //Font height 0, //Font width @@ -84,20 +78,17 @@ void CLogDisplay::RecreateNativeResource() 5, //Quality DEFAULT_PITCH|FF_DONTCARE, //PitchAndFamily "Verdana", //pFacename, - &this->piFont))) - { + &this->piFont))) { CLogDisplay::Instance().AddEntry("Unable to load font",D3DCOLOR_ARGB(0xFF,0xFF,0,0)); - this->piFont = NULL; + this->piFont = nullptr; return; - } } - return; } +} //------------------------------------------------------------------------------- -void CLogDisplay::OnRender() - { +void CLogDisplay::OnRender() { DWORD dwTick = (DWORD) GetTickCount(); DWORD dwLimit = dwTick - 8000; DWORD dwLimit2 = dwLimit + 3000; @@ -117,9 +108,8 @@ void CLogDisplay::OnRender() sRect.bottom = sWndRect.bottom; // if no asset is loaded draw a "no asset loaded" text in the center - if (!g_pcAsset) - { - const char* szText = "Nothing to display ... \r\nTry [Viewer | Open asset] to load an asset"; + if (!g_pcAsset) { + const char* szText = "Nothing to display ... \r\nTry [Viewer | Open asset] to load an asset"; // shadow RECT sCopy; @@ -151,38 +141,34 @@ void CLogDisplay::OnRender() // text this->piFont->DrawText(NULL,szText , -1,&sWndRect,DT_CENTER | DT_VCENTER,D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0xFF)); - } + } // update all elements in the queue and render them for (std::list::iterator - i = this->asEntries.begin(); - i != this->asEntries.end();++i,++iCnt) - { - if ((*i).dwStartTicks < dwLimit) - { + i = this->asEntries.begin(); + i != this->asEntries.end();++i,++iCnt) { + if ((*i).dwStartTicks < dwLimit) { i = this->asEntries.erase(i); - if(i == this->asEntries.end())break; + if (i == this->asEntries.end()) { + break; } - else if (NULL != this->piFont) - { + } else if (nullptr != this->piFont) { float fAlpha = 1.0f; - if ((*i).dwStartTicks <= dwLimit2) - { + if ((*i).dwStartTicks <= dwLimit2) { // linearly interpolate to create the fade out effect fAlpha = 1.0f - (float)(dwLimit2 - (*i).dwStartTicks) / 3000.0f; - } + } D3DCOLOR& clrColor = (*i).clrColor; clrColor &= ~(0xFFu << 24); clrColor |= (((unsigned char)(fAlpha * 255.0f)) & 0xFFu) << 24; const char* szText = (*i).szText.c_str(); - if (sRect.top + 30 > sWndRect.bottom) - { + if (sRect.top + 30 > sWndRect.bottom) { // end of window. send a special message szText = "... too many errors"; clrColor = D3DCOLOR_ARGB(0xFF,0xFF,100,0x0); - } + } // draw the black shadow RECT sCopy; @@ -225,9 +211,11 @@ void CLogDisplay::OnRender() sRect.top += iPX; sRect.bottom += iPX; - if (szText != (*i).szText.c_str())break; + if (szText != (*i).szText.c_str()) { + break; } } - return; } -}; \ No newline at end of file +} + +} diff --git a/tools/assimp_view/LogWindow.cpp b/tools/assimp_view/LogWindow.cpp index dba70ee71..ca9b88f95 100644 --- a/tools/assimp_view/LogWindow.cpp +++ b/tools/assimp_view/LogWindow.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -101,13 +101,11 @@ INT_PTR CALLBACK LogDialogProc(HWND hwndDlg,UINT uMsg, } //------------------------------------------------------------------------------- -void CLogWindow::Init () -{ +void CLogWindow::Init () { this->hwnd = ::CreateDialog(g_hInstance,MAKEINTRESOURCE(IDD_LOGVIEW), NULL,&LogDialogProc); - if (!this->hwnd) - { + if (!this->hwnd) { CLogDisplay::Instance().AddEntry("[ERROR] Unable to create logger window", D3DCOLOR_ARGB(0xFF,0,0xFF,0)); } @@ -116,11 +114,10 @@ void CLogWindow::Init () this->szText = AI_VIEW_RTF_LOG_HEADER;; this->szPlainText = ""; } + //------------------------------------------------------------------------------- -void CLogWindow::Show() -{ - if (this->hwnd) - { +void CLogWindow::Show() { + if (this->hwnd) { ShowWindow(this->hwnd,SW_SHOW); this->bIsVisible = true; @@ -128,24 +125,23 @@ void CLogWindow::Show() this->Update(); } } + //------------------------------------------------------------------------------- -void CMyLogStream::write(const char* message) -{ +void CMyLogStream::write(const char* message) { CLogWindow::Instance().WriteLine(message); } + //------------------------------------------------------------------------------- -void CLogWindow::Clear() -{ +void CLogWindow::Clear() { this->szText = AI_VIEW_RTF_LOG_HEADER;; this->szPlainText = ""; this->Update(); } + //------------------------------------------------------------------------------- -void CLogWindow::Update() -{ - if (this->bIsVisible) - { +void CLogWindow::Update() { + if (this->bIsVisible) { SETTEXTEX sInfo; sInfo.flags = ST_DEFAULT; sInfo.codepage = CP_ACP; @@ -154,20 +150,16 @@ void CLogWindow::Update() EM_SETTEXTEX,(WPARAM)&sInfo,( LPARAM)this->szText.c_str()); } } + //------------------------------------------------------------------------------- -void CLogWindow::Save() -{ +void CLogWindow::Save() { char szFileName[MAX_PATH]; DWORD dwTemp = MAX_PATH; - if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"LogDestination",NULL,NULL, - (BYTE*)szFileName,&dwTemp)) - { + if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"LogDestination",NULL,NULL,(BYTE*)szFileName,&dwTemp)) { // Key was not found. Use C: strcpy(szFileName,""); - } - else - { + } else { // need to remove the file name char* sz = strrchr(szFileName,'\\'); if (!sz) @@ -196,14 +188,13 @@ void CLogWindow::Save() CLogDisplay::Instance().AddEntry("[INFO] The log file has been saved", D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0)); } + //------------------------------------------------------------------------------- -void CLogWindow::WriteLine(const char* message) -{ +void CLogWindow::WriteLine(const char* message) { this->szPlainText.append(message); this->szPlainText.append("\r\n"); - if (0 != this->szText.length()) - { + if (0 != this->szText.length()) { this->szText.resize(this->szText.length()-1); } @@ -231,12 +222,10 @@ void CLogWindow::WriteLine(const char* message) } std::string _message = message; - for (unsigned int i = 0; i < _message.length();++i) - { + for (unsigned int i = 0; i < _message.length();++i) { if ('\\' == _message[i] || '}' == _message[i] || - '{' == _message[i]) - { + '{' == _message[i]) { _message.insert(i++,"\\"); } } @@ -244,8 +233,7 @@ void CLogWindow::WriteLine(const char* message) this->szText.append(_message); this->szText.append("\\par}}"); - if (this->bIsVisible && this->bUpdate) - { + if (this->bIsVisible && this->bUpdate) { SETTEXTEX sInfo; sInfo.flags = ST_DEFAULT; sInfo.codepage = CP_ACP; @@ -253,7 +241,6 @@ void CLogWindow::WriteLine(const char* message) SendDlgItemMessage(this->hwnd,IDC_EDIT1, EM_SETTEXTEX,(WPARAM)&sInfo,( LPARAM)this->szText.c_str()); } - return; } -}; //! AssimpView \ No newline at end of file +} //! AssimpView diff --git a/tools/assimp_view/Material.cpp b/tools/assimp_view/Material.cpp index 1fb13f5a8..2c5316d81 100644 --- a/tools/assimp_view/Material.cpp +++ b/tools/assimp_view/Material.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -136,7 +136,6 @@ extern float g_smoothAngle /*= 80.f*/; extern unsigned int ppsteps, ppstepsdefault; extern bool nopointslines; - CMaterialManager CMaterialManager::s_cInstance; //------------------------------------------------------------------------------- diff --git a/tools/assimp_view/MeshRenderer.cpp b/tools/assimp_view/MeshRenderer.cpp index 834c5a9e2..dfa249735 100644 --- a/tools/assimp_view/MeshRenderer.cpp +++ b/tools/assimp_view/MeshRenderer.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -49,8 +49,7 @@ namespace AssimpView { CMeshRenderer CMeshRenderer::s_cInstance; //------------------------------------------------------------------------------- -int CMeshRenderer::DrawUnsorted(unsigned int iIndex) -{ +int CMeshRenderer::DrawUnsorted(unsigned int iIndex) { ai_assert(iIndex < g_pcAsset->pcScene->mNumMeshes); // set vertex and index buffer @@ -77,8 +76,7 @@ int CMeshRenderer::DrawUnsorted(unsigned int iIndex) return 1; } //------------------------------------------------------------------------------- -int CMeshRenderer::DrawSorted(unsigned int iIndex,const aiMatrix4x4& mWorld) -{ +int CMeshRenderer::DrawSorted(unsigned int iIndex,const aiMatrix4x4& mWorld) { ai_assert(iIndex < g_pcAsset->pcScene->mNumMeshes); AssetHelper::MeshHelper* pcHelper = g_pcAsset->apcMeshes[iIndex]; diff --git a/tools/assimp_view/MessageProc.cpp b/tools/assimp_view/MessageProc.cpp index 5a9cfd0ed..cbd8b2f1a 100644 --- a/tools/assimp_view/MessageProc.cpp +++ b/tools/assimp_view/MessageProc.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -47,9 +47,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #ifdef __MINGW32__ -#include +# include #else -#include +# include #endif namespace AssimpView { @@ -92,31 +92,29 @@ void MakeFileAssociations() { GetModuleFileName(NULL,szTemp2,MAX_PATH); sprintf(szTemp,"%s %%1",szTemp2); - HKEY g_hRegistry; + HKEY hRegistry = NULL; aiString list, tmp; aiGetExtensionList(&list); tmp = list; const char* sz = strtok(list.data,";"); - do - { + do { char buf[256]; ai_assert(sz[0] == '*'); sprintf(buf,"Software\\Classes\\%s",sz+1); - RegCreateKeyEx(HKEY_CURRENT_USER,buf,0,NULL,0,KEY_ALL_ACCESS, NULL, &g_hRegistry,NULL); - RegSetValueEx(g_hRegistry,"",0,REG_SZ,(const BYTE*)"ASSIMPVIEW_CLASS",(DWORD)strlen("ASSIMPVIEW_CLASS")+1); - RegCloseKey(g_hRegistry); - } - while ((sz = strtok(NULL,";"))); + RegCreateKeyEx(HKEY_CURRENT_USER,buf,0,NULL,0,KEY_ALL_ACCESS, NULL, &hRegistry,NULL); + RegSetValueEx(hRegistry,"",0,REG_SZ,(const BYTE*)"ASSIMPVIEW_CLASS",(DWORD)strlen("ASSIMPVIEW_CLASS")+1); + RegCloseKey(hRegistry); + } while ((sz = strtok(NULL,";"))); - RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\Classes\\ASSIMPVIEW_CLASS",0,NULL,0,KEY_ALL_ACCESS, NULL, &g_hRegistry,NULL); - RegCloseKey(g_hRegistry); + RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\Classes\\ASSIMPVIEW_CLASS",0,NULL,0,KEY_ALL_ACCESS, NULL, &hRegistry,NULL); + RegCloseKey(hRegistry); - RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\Classes\\ASSIMPVIEW_CLASS\\shell\\open\\command",0,NULL,0,KEY_ALL_ACCESS, NULL, &g_hRegistry,NULL); - RegSetValueEx(g_hRegistry,"",0,REG_SZ,(const BYTE*)szTemp,(DWORD)strlen(szTemp)+1); - RegCloseKey(g_hRegistry); + RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\Classes\\ASSIMPVIEW_CLASS\\shell\\open\\command",0,NULL,0,KEY_ALL_ACCESS, NULL, &hRegistry,NULL); + RegSetValueEx(hRegistry,"",0,REG_SZ,(const BYTE*)szTemp,(DWORD)strlen(szTemp)+1); + RegCloseKey(hRegistry); CLogDisplay::Instance().AddEntry("[OK] File assocations have been registered", D3DCOLOR_ARGB(0xFF,0,0xFF,0)); @@ -124,19 +122,19 @@ void MakeFileAssociations() { CLogDisplay::Instance().AddEntry(tmp.data,D3DCOLOR_ARGB(0xFF,0,0xFF,0)); } - //------------------------------------------------------------------------------- // Handle command line parameters // // The function loads an asset specified on the command line as first argument // Other command line parameters are not handled //------------------------------------------------------------------------------- -void HandleCommandLine(char* p_szCommand) -{ +void HandleCommandLine(char* p_szCommand) { char* sz = p_szCommand; //bool bQuak = false; - if (strlen(sz) < 2)return; + if (strlen(sz) < 2) { + return; + } if (*sz == '\"') { char* sz2 = strrchr(sz,'\"'); @@ -157,8 +155,7 @@ void HandleCommandLine(char* p_szCommand) //------------------------------------------------------------------------------- // Load the light colors from the registry //------------------------------------------------------------------------------- -void LoadLightColors() -{ +void LoadLightColors() { DWORD dwTemp = 4; RegQueryValueEx(g_hRegistry,"LightColor0",NULL,NULL, (BYTE*)&g_avLightColors[0],&dwTemp); RegQueryValueEx(g_hRegistry,"LightColor1",NULL,NULL, (BYTE*)&g_avLightColors[1],&dwTemp); @@ -168,8 +165,7 @@ void LoadLightColors() //------------------------------------------------------------------------------- // Save the light colors to the registry //------------------------------------------------------------------------------- -void SaveLightColors() -{ +void SaveLightColors() { RegSetValueExA(g_hRegistry,"LightColor0",0,REG_DWORD,(const BYTE*)&g_avLightColors[0],4); RegSetValueExA(g_hRegistry,"LightColor1",0,REG_DWORD,(const BYTE*)&g_avLightColors[1],4); RegSetValueExA(g_hRegistry,"LightColor2",0,REG_DWORD,(const BYTE*)&g_avLightColors[2],4); @@ -178,8 +174,7 @@ void SaveLightColors() //------------------------------------------------------------------------------- // Save the checker pattern colors to the registry //------------------------------------------------------------------------------- -void SaveCheckerPatternColors() -{ +void SaveCheckerPatternColors() { // we have it as float4. save it as binary value --. RegSetValueExA(g_hRegistry,"CheckerPattern0",0,REG_BINARY, (const BYTE*)CDisplay::Instance().GetFirstCheckerColor(), @@ -193,8 +188,7 @@ void SaveCheckerPatternColors() //------------------------------------------------------------------------------- // Load the checker pattern colors from the registry //------------------------------------------------------------------------------- -void LoadCheckerPatternColors() -{ +void LoadCheckerPatternColors() { DWORD dwTemp = sizeof(D3DXVECTOR3); RegQueryValueEx(g_hRegistry,"CheckerPattern0",NULL,NULL, (BYTE*) /* jep, this is evil */ CDisplay::Instance().GetFirstCheckerColor(),&dwTemp); @@ -206,8 +200,7 @@ void LoadCheckerPatternColors() //------------------------------------------------------------------------------- // Changed pp setup //------------------------------------------------------------------------------- -void UpdatePPSettings() -{ +void UpdatePPSettings() { DWORD dwValue = ppsteps; RegSetValueExA(g_hRegistry,"PostProcessing",0,REG_DWORD,(const BYTE*)&dwValue,4); UpdateWindow(g_hDlg); @@ -216,8 +209,7 @@ void UpdatePPSettings() //------------------------------------------------------------------------------- // Toggle the "Display Normals" state //------------------------------------------------------------------------------- -void ToggleNormals() -{ +void ToggleNormals() { g_sOptions.bRenderNormals = !g_sOptions.bRenderNormals; // store this in the registry, too @@ -226,97 +218,72 @@ void ToggleNormals() RegSetValueExA(g_hRegistry,"RenderNormals",0,REG_DWORD,(const BYTE*)&dwValue,4); } +static void storeRegKey(bool option, LPCSTR name) { + // store this in the registry, too + DWORD dwValue = 0; + if (option) { + dwValue = 1; + } + RegSetValueExA(g_hRegistry, name, 0, REG_DWORD, (const BYTE*)&dwValue, 4); + +} //------------------------------------------------------------------------------- // Toggle the "AutoRotate" state //------------------------------------------------------------------------------- -void ToggleAutoRotate() -{ +void ToggleAutoRotate() { g_sOptions.bRotate = !g_sOptions.bRotate; - - // store this in the registry, too - DWORD dwValue = 0; - if (g_sOptions.bRotate)dwValue = 1; - RegSetValueExA(g_hRegistry,"AutoRotate",0,REG_DWORD,(const BYTE*)&dwValue,4); + storeRegKey(g_sOptions.bRotate, "AutoRotate"); UpdateWindow(g_hDlg); } //------------------------------------------------------------------------------- // Toggle the "FPS" state //------------------------------------------------------------------------------- -void ToggleFPSView() -{ +void ToggleFPSView() { g_bFPSView = !g_bFPSView; SetupFPSView(); - - // store this in the registry, too - DWORD dwValue = 0; - if (g_bFPSView)dwValue = 1; - RegSetValueExA(g_hRegistry,"FPSView",0,REG_DWORD,(const BYTE*)&dwValue,4); + storeRegKey(g_bFPSView, "FPSView"); } //------------------------------------------------------------------------------- // Toggle the "2 Light sources" state //------------------------------------------------------------------------------- -void ToggleMultipleLights() -{ +void ToggleMultipleLights() { g_sOptions.b3Lights = !g_sOptions.b3Lights; - - // store this in the registry, too - DWORD dwValue = 0; - if (g_sOptions.b3Lights)dwValue = 1; - RegSetValueExA(g_hRegistry,"MultipleLights",0,REG_DWORD,(const BYTE*)&dwValue,4); + storeRegKey(g_sOptions.b3Lights, "MultipleLights"); } //------------------------------------------------------------------------------- // Toggle the "LightRotate" state //------------------------------------------------------------------------------- -void ToggleLightRotate() -{ +void ToggleLightRotate() { g_sOptions.bLightRotate = !g_sOptions.bLightRotate; - - // store this in the registry, too - DWORD dwValue = 0; - if (g_sOptions.bLightRotate)dwValue = 1; - RegSetValueExA(g_hRegistry,"LightRotate",0,REG_DWORD,(const BYTE*)&dwValue,4); + storeRegKey(g_sOptions.bLightRotate, "LightRotate"); } //------------------------------------------------------------------------------- // Toggle the "NoTransparency" state //------------------------------------------------------------------------------- -void ToggleTransparency() -{ +void ToggleTransparency() { g_sOptions.bNoAlphaBlending = !g_sOptions.bNoAlphaBlending; - - // store this in the registry, too - DWORD dwValue = 0; - if (g_sOptions.bNoAlphaBlending)dwValue = 1; - RegSetValueExA(g_hRegistry,"NoTransparency",0,REG_DWORD,(const BYTE*)&dwValue,4); + storeRegKey(g_sOptions.bNoAlphaBlending, "NoTransparency"); } //------------------------------------------------------------------------------- // Toggle the "LowQuality" state //------------------------------------------------------------------------------- -void ToggleLowQuality() -{ +void ToggleLowQuality() { g_sOptions.bLowQuality = !g_sOptions.bLowQuality; - - // store this in the registry, too - DWORD dwValue = 0; - if (g_sOptions.bLowQuality)dwValue = 1; - RegSetValueExA(g_hRegistry,"LowQuality",0,REG_DWORD,(const BYTE*)&dwValue,4); + storeRegKey(g_sOptions.bLowQuality, "LowQuality"); } //------------------------------------------------------------------------------- // Toggle the "Specular" state //------------------------------------------------------------------------------- -void ToggleSpecular() -{ +void ToggleSpecular() { g_sOptions.bNoSpecular = !g_sOptions.bNoSpecular; - // store this in the registry, too - DWORD dwValue = 0; - if (g_sOptions.bNoSpecular)dwValue = 1; - RegSetValueExA(g_hRegistry,"NoSpecular",0,REG_DWORD,(const BYTE*)&dwValue,4); + storeRegKey(g_sOptions.bNoSpecular, "NoSpecular"); // update all specular materials CMaterialManager::Instance().UpdateSpecularMaterials(); @@ -325,14 +292,10 @@ void ToggleSpecular() //------------------------------------------------------------------------------- // Toggle the "RenderMats" state //------------------------------------------------------------------------------- -void ToggleMats() -{ +void ToggleMats() { g_sOptions.bRenderMats = !g_sOptions.bRenderMats; - // store this in the registry, too - DWORD dwValue = 0; - if (g_sOptions.bRenderMats)dwValue = 1; - RegSetValueExA(g_hRegistry,"RenderMats",0,REG_DWORD,(const BYTE*)&dwValue,4); + storeRegKey(g_sOptions.bRenderMats, "RenderMats"); // update all specular materials CMaterialManager::Instance().UpdateSpecularMaterials(); @@ -341,55 +304,40 @@ void ToggleMats() //------------------------------------------------------------------------------- // Toggle the "Culling" state //------------------------------------------------------------------------------- -void ToggleCulling() -{ +void ToggleCulling() { g_sOptions.bCulling = !g_sOptions.bCulling; - - // store this in the registry, too - DWORD dwValue = 0; - if (g_sOptions.bCulling)dwValue = 1; - RegSetValueExA(g_hRegistry,"Culling",0,REG_DWORD,(const BYTE*)&dwValue,4); + storeRegKey(g_sOptions.bCulling, "Culling"); } //------------------------------------------------------------------------------- // Toggle the "Skeleton" state //------------------------------------------------------------------------------- -void ToggleSkeleton() -{ +void ToggleSkeleton() { g_sOptions.bSkeleton = !g_sOptions.bSkeleton; - - // store this in the registry, too - DWORD dwValue = 0; - if (g_sOptions.bCulling)dwValue = 1; - RegSetValueExA(g_hRegistry,"Skeleton",0,REG_DWORD,(const BYTE*)&dwValue,4); + storeRegKey(g_sOptions.bSkeleton, "Skeleton"); } //------------------------------------------------------------------------------- // Toggle the "WireFrame" state //------------------------------------------------------------------------------- -void ToggleWireFrame() -{ - if (g_sOptions.eDrawMode == RenderOptions::WIREFRAME) +void ToggleWireFrame() { + if (g_sOptions.eDrawMode == RenderOptions::WIREFRAME) { g_sOptions.eDrawMode = RenderOptions::NORMAL; - else g_sOptions.eDrawMode = RenderOptions::WIREFRAME; + } else { + g_sOptions.eDrawMode = RenderOptions::WIREFRAME; + } - // store this in the registry, too - DWORD dwValue = 0; - if (RenderOptions::WIREFRAME == g_sOptions.eDrawMode)dwValue = 1; - RegSetValueExA(g_hRegistry,"Wireframe",0,REG_DWORD,(const BYTE*)&dwValue,4); + storeRegKey(RenderOptions::WIREFRAME == g_sOptions.eDrawMode, "Wireframe"); } - //------------------------------------------------------------------------------- // Toggle the "MultiSample" state //------------------------------------------------------------------------------- -void ToggleMS() -{ +void ToggleMS() { g_sOptions.bMultiSample = !g_sOptions.bMultiSample; DeleteAssetData(); ShutdownDevice(); - if (0 == CreateDevice()) - { + if (0 == CreateDevice()) { CLogDisplay::Instance().AddEntry( "[ERROR] Failed to toggle MultiSampling mode"); g_sOptions.bMultiSample = !g_sOptions.bMultiSample; @@ -397,28 +345,21 @@ void ToggleMS() } CreateAssetData(); - if (g_sOptions.bMultiSample) - { + if (g_sOptions.bMultiSample) { CLogDisplay::Instance().AddEntry( "[OK] Changed MultiSampling mode to the maximum value for this device"); - } - else - { + } else { CLogDisplay::Instance().AddEntry( "[OK] MultiSampling has been disabled"); } - // store this in the registry, too - DWORD dwValue = 0; - if (g_sOptions.bMultiSample)dwValue = 1; - RegSetValueExA(g_hRegistry,"MultiSampling",0,REG_DWORD,(const BYTE*)&dwValue,4); + storeRegKey(g_sOptions.bMultiSample, "MultiSampling"); } //------------------------------------------------------------------------------- // Expand or collapse the UI //------------------------------------------------------------------------------- -void ToggleUIState() -{ +void ToggleUIState() { // adjust the size RECT sRect; GetWindowRect(g_hDlg,&sRect); @@ -430,46 +371,33 @@ void ToggleUIState() sRect2.left -= sRect.left; sRect2.top -= sRect.top; - DWORD dwValue; - if (BST_UNCHECKED == IsDlgButtonChecked(g_hDlg,IDC_BLUBB)) - { + if (BST_UNCHECKED == IsDlgButtonChecked(g_hDlg,IDC_BLUBB)) { SetWindowPos(g_hDlg,NULL,0,0,sRect.right-214,sRect.bottom, SWP_NOMOVE | SWP_NOZORDER); - dwValue = 0; SetWindowText(GetDlgItem(g_hDlg,IDC_BLUBB),">>"); - RegSetValueExA(g_hRegistry,"LastUIState",0,REG_DWORD,(const BYTE*)&dwValue,4); - } - else - { + storeRegKey(false, "MultiSampling"); + } else { SetWindowPos(g_hDlg,NULL,0,0,sRect.right+214,sRect.bottom, SWP_NOMOVE | SWP_NOZORDER); - dwValue = 1; + storeRegKey(true, "LastUIState"); SetWindowText(GetDlgItem(g_hDlg,IDC_BLUBB),"<<"); - RegSetValueExA(g_hRegistry,"LastUIState",0,REG_DWORD,(const BYTE*)&dwValue,4); } UpdateWindow(g_hDlg); - return; } - //------------------------------------------------------------------------------- -// Load the background texture for the cviewer +// Load the background texture for the viewer //------------------------------------------------------------------------------- -void LoadBGTexture() -{ +void LoadBGTexture() { char szFileName[MAX_PATH]; DWORD dwTemp = MAX_PATH; - if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"TextureSrc",NULL,NULL, - (BYTE*)szFileName,&dwTemp)) - { + if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"TextureSrc",NULL,NULL, (BYTE*)szFileName,&dwTemp)) { // Key was not found. Use C: strcpy(szFileName,""); - } - else - { + } else { // need to remove the file name char* sz = strrchr(szFileName,'\\'); if (!sz) @@ -495,14 +423,12 @@ void LoadBGTexture() RegSetValueExA(g_hRegistry,"LastSkyBoxSrc",0,REG_SZ,(const BYTE*)"",MAX_PATH); CBackgroundPainter::Instance().SetTextureBG(szFileName); - return; } //------------------------------------------------------------------------------- // Reset the background color to a smart and nice grey //------------------------------------------------------------------------------- -void ClearBG() -{ +void ClearBG() { D3DCOLOR clrColor = D3DCOLOR_ARGB(0xFF,100,100,100); CBackgroundPainter::Instance().SetColor(clrColor); @@ -510,14 +436,12 @@ void ClearBG() RegSetValueExA(g_hRegistry,"LastTextureSrc",0,REG_SZ,(const BYTE*)"",MAX_PATH); RegSetValueExA(g_hRegistry,"Color",0,REG_DWORD,(const BYTE*)&clrColor,4); - return; } //------------------------------------------------------------------------------- // Let the user choose a color in a windows standard color dialog //------------------------------------------------------------------------------- -void DisplayColorDialog(D3DCOLOR* pclrResult) -{ +void DisplayColorDialog(D3DCOLOR* pclrResult) { CHOOSECOLOR clr; clr.lStructSize = sizeof(CHOOSECOLOR); clr.hwndOwner = g_hDlg; @@ -534,15 +458,12 @@ void DisplayColorDialog(D3DCOLOR* pclrResult) GetRValue(clr.rgbResult), GetGValue(clr.rgbResult), GetBValue(clr.rgbResult)); - return; } - //------------------------------------------------------------------------------- // Let the user choose a color in a windows standard color dialog //------------------------------------------------------------------------------- -void DisplayColorDialog(D3DXVECTOR4* pclrResult) -{ +void DisplayColorDialog(D3DXVECTOR4* pclrResult) { CHOOSECOLOR clr; clr.lStructSize = sizeof(CHOOSECOLOR); clr.hwndOwner = g_hDlg; @@ -560,14 +481,12 @@ void DisplayColorDialog(D3DXVECTOR4* pclrResult) pclrResult->x = GetRValue(clr.rgbResult) / 255.0f; pclrResult->y = GetGValue(clr.rgbResult) / 255.0f; pclrResult->z = GetBValue(clr.rgbResult) / 255.0f; - return; } //------------------------------------------------------------------------------- -// Let the user choose the baclground color for the viewer +// Let the user choose the background color for the viewer //------------------------------------------------------------------------------- -void ChooseBGColor() -{ +void ChooseBGColor() { RegSetValueExA(g_hRegistry,"LastSkyBoxSrc",0,REG_SZ,(const BYTE*)"",MAX_PATH); RegSetValueExA(g_hRegistry,"LastTextureSrc",0,REG_SZ,(const BYTE*)"",MAX_PATH); @@ -576,14 +495,12 @@ void ChooseBGColor() CBackgroundPainter::Instance().SetColor(clrColor); RegSetValueExA(g_hRegistry,"Color",0,REG_DWORD,(const BYTE*)&clrColor,4); - return; } //------------------------------------------------------------------------------- // Display the OpenFile dialog and let the user choose a new slybox as bg //------------------------------------------------------------------------------- -void LoadSkybox() -{ +void LoadSkybox() { char szFileName[MAX_PATH]; DWORD dwTemp = MAX_PATH; @@ -622,23 +539,26 @@ void LoadSkybox() return; } +template +inline +void SaveRelease(T **iface ) { + if (nullptr != iface) { + (*iface)->Release(); + *iface = nullptr; + } +} //------------------------------------------------------------------------------- -// Sace a screenshot to an user-defined file +// Save a screenshot to an user-defined file //------------------------------------------------------------------------------- -void SaveScreenshot() -{ +void SaveScreenshot() { char szFileName[MAX_PATH]; DWORD dwTemp = MAX_PATH; - if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"ScreenShot",NULL,NULL, - (BYTE*)szFileName,&dwTemp)) - { + if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"ScreenShot",NULL,NULL, (BYTE*)szFileName,&dwTemp)) { // Key was not found. Use C: strcpy(szFileName,""); - } - else - { + } else { // need to remove the file name char* sz = strrchr(szFileName,'\\'); if (!sz) @@ -662,49 +582,42 @@ void SaveScreenshot() IDirect3DSurface9* pi = NULL; g_piDevice->GetRenderTarget(0,&pi); - if(!pi || FAILED(D3DXSaveSurfaceToFile(szFileName,D3DXIFF_PNG,pi,NULL,NULL))) - { + if(!pi || FAILED(D3DXSaveSurfaceToFile(szFileName,D3DXIFF_PNG,pi,NULL,NULL))) { CLogDisplay::Instance().AddEntry("[ERROR] Unable to save screenshot", D3DCOLOR_ARGB(0xFF,0xFF,0,0)); - } - else - { + } else { CLogDisplay::Instance().AddEntry("[INFO] The screenshot has been saved", D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0)); } - if(pi)pi->Release(); - return; + SaveRelease(&pi); } //------------------------------------------------------------------------------- // Get the amount of memory required for textures //------------------------------------------------------------------------------- -void AddTextureMem(IDirect3DTexture9* pcTex, unsigned int& out) -{ - if (!pcTex)return; +void AddTextureMem(IDirect3DTexture9* pcTex, unsigned int& out) { + if (!pcTex) { + return; + } D3DSURFACE_DESC sDesc; pcTex->GetLevelDesc(0,&sDesc); out += (sDesc.Width * sDesc.Height) << 2; - return; } //------------------------------------------------------------------------------- // Display memory statistics //------------------------------------------------------------------------------- -void DisplayMemoryConsumption() -{ +void DisplayMemoryConsumption() { // first get the memory consumption for the aiScene - if (! g_pcAsset ||!g_pcAsset->pcScene) - { + if (! g_pcAsset ||!g_pcAsset->pcScene) { MessageBox(g_hDlg,"No asset is loaded. Can you guess how much memory I need to store nothing?", "Memory consumption",MB_OK); return; } unsigned int iScene = sizeof(aiScene); - for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) - { + for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) { iScene += sizeof(aiMesh); if (g_pcAsset->pcScene->mMeshes[i]->HasPositions()) iScene += sizeof(aiVector3D) * g_pcAsset->pcScene->mMeshes[i]->mNumVertices; @@ -715,22 +628,20 @@ void DisplayMemoryConsumption() if (g_pcAsset->pcScene->mMeshes[i]->HasTangentsAndBitangents()) iScene += sizeof(aiVector3D) * g_pcAsset->pcScene->mMeshes[i]->mNumVertices * 2; - for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) - { - if (g_pcAsset->pcScene->mMeshes[i]->HasVertexColors(a)) + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS;++a) { + if (g_pcAsset->pcScene->mMeshes[i]->HasVertexColors(a)) { iScene += sizeof(aiColor4D) * g_pcAsset->pcScene->mMeshes[i]->mNumVertices; - else break; + } else { + break; + } } - for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) - { + for (unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS;++a) { if (g_pcAsset->pcScene->mMeshes[i]->HasTextureCoords(a)) iScene += sizeof(aiVector3D) * g_pcAsset->pcScene->mMeshes[i]->mNumVertices; else break; } - if (g_pcAsset->pcScene->mMeshes[i]->HasBones()) - { - for (unsigned int p = 0; p < g_pcAsset->pcScene->mMeshes[i]->mNumBones;++p) - { + if (g_pcAsset->pcScene->mMeshes[i]->HasBones()) { + for (unsigned int p = 0; p < g_pcAsset->pcScene->mMeshes[i]->mNumBones;++p) { iScene += sizeof(aiBone); iScene += g_pcAsset->pcScene->mMeshes[i]->mBones[p]->mNumWeights * sizeof(aiVertexWeight); } @@ -738,22 +649,20 @@ void DisplayMemoryConsumption() iScene += (sizeof(aiFace) + 3 * sizeof(unsigned int))*g_pcAsset->pcScene->mMeshes[i]->mNumFaces; } // add all embedded textures - for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumTextures;++i) - { + for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumTextures;++i) { const aiTexture* pc = g_pcAsset->pcScene->mTextures[i]; - if (0 != pc->mHeight) - { + if (0 != pc->mHeight) { iScene += 4 * pc->mHeight * pc->mWidth; + } else { + iScene += pc->mWidth; } - else iScene += pc->mWidth; } // add 30k for each material ... a string has 4k for example iScene += g_pcAsset->pcScene->mNumMaterials * 30 * 1024; // now get the memory consumption required by D3D, first all textures unsigned int iTexture = 0; - for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) - { + for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) { AssetHelper::MeshHelper* pc = g_pcAsset->apcMeshes[i]; AddTextureMem(pc->piDiffuseTexture,iTexture); @@ -767,15 +676,13 @@ void DisplayMemoryConsumption() unsigned int iVRAM = iTexture; // now get the memory consumption of all vertex/index buffers - unsigned int iVB = 0; - unsigned int iIB = 0; - for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) - { + unsigned int iVB( 0 ), iIB(0); + for (unsigned int i = 0; i < g_pcAsset->pcScene->mNumMeshes;++i) { AssetHelper:: MeshHelper* pc = g_pcAsset->apcMeshes[i]; union{ - D3DVERTEXBUFFER_DESC sDesc; - D3DINDEXBUFFER_DESC sDesc2; + D3DVERTEXBUFFER_DESC sDesc; + D3DINDEXBUFFER_DESC sDesc2; }; if (pc->piVB) @@ -814,36 +721,30 @@ void DisplayMemoryConsumption() iScene / 1024,iTexture / 1024,iVB / 1024,iIB / 1024,iVRAM / 1024, (iScene + iTexture + iVB + iIB + iVRAM) / 1024); MessageBox(g_hDlg,szOut,"Memory consumption",MB_OK); - return; } //------------------------------------------------------------------------------- // Save the list of recent files to the registry //------------------------------------------------------------------------------- -void SaveHistory() -{ - for (unsigned int i = 0; i < AI_VIEW_NUM_RECENT_FILES;++i) - { +void SaveHistory() { + for (unsigned int i = 0; i < AI_VIEW_NUM_RECENT_FILES;++i) { char szName[66]; sprintf(szName,"Recent%i",i+1); RegSetValueEx(g_hRegistry,szName,0,REG_SZ, (const BYTE*)g_aPreviousFiles[i].c_str(),(DWORD)g_aPreviousFiles[i].length()); } - return; } //------------------------------------------------------------------------------- // Recover the file history //------------------------------------------------------------------------------- -void LoadHistory() -{ +void LoadHistory() { g_aPreviousFiles.resize(AI_VIEW_NUM_RECENT_FILES); char szFileName[MAX_PATH]; - for (unsigned int i = 0; i < AI_VIEW_NUM_RECENT_FILES;++i) - { + for (unsigned int i = 0; i < AI_VIEW_NUM_RECENT_FILES;++i) { char szName[66]; sprintf(szName,"Recent%i",i+1); @@ -851,20 +752,17 @@ void LoadHistory() szFileName[0] ='\0'; if(ERROR_SUCCESS == RegQueryValueEx(g_hRegistry,szName,NULL,NULL, - (BYTE*)szFileName,&dwTemp)) - { + (BYTE*)szFileName,&dwTemp)) { g_aPreviousFiles[i] = std::string(szFileName); } } // add sub items for all recent files g_hHistoryMenu = CreateMenu(); - for (int i = AI_VIEW_NUM_RECENT_FILES-1; i >= 0;--i) - { + for (int i = AI_VIEW_NUM_RECENT_FILES-1; i >= 0;--i) { const char* szText = g_aPreviousFiles[i].c_str(); UINT iFlags = 0; - if ('\0' == *szText) - { + if ('\0' == *szText) { szText = ""; iFlags = MF_GRAYED | MF_DISABLED; } @@ -873,19 +771,17 @@ void LoadHistory() ModifyMenu(GetMenu(g_hDlg),ID_VIEWER_RECENTFILES,MF_BYCOMMAND | MF_POPUP, (UINT_PTR)g_hHistoryMenu,"Recent files"); - return; } //------------------------------------------------------------------------------- // Clear the file history //------------------------------------------------------------------------------- -void ClearHistory() -{ - for(unsigned int i = 0; i < AI_VIEW_NUM_RECENT_FILES;++i) +void ClearHistory() { + for (unsigned int i = 0; i < AI_VIEW_NUM_RECENT_FILES; ++i) { g_aPreviousFiles[i] = std::string(""); + } - for (int i = AI_VIEW_NUM_RECENT_FILES-1; i >= 0;--i) - { + for (int i = AI_VIEW_NUM_RECENT_FILES-1; i >= 0;--i) { ModifyMenu(g_hHistoryMenu,AI_VIEW_RECENT_FILE_ID(i), MF_STRING | MF_BYCOMMAND | MF_GRAYED | MF_DISABLED,AI_VIEW_RECENT_FILE_ID(i),""); } @@ -896,50 +792,44 @@ void ClearHistory() //------------------------------------------------------------------------------- // Update the file history //------------------------------------------------------------------------------- -void UpdateHistory() -{ - if(!g_hHistoryMenu)return; +void UpdateHistory() { + if (!g_hHistoryMenu) { + return; + } std::string sz = std::string(g_szFileName); - if (g_aPreviousFiles[AI_VIEW_NUM_RECENT_FILES-1] == sz)return; + if (g_aPreviousFiles[AI_VIEW_NUM_RECENT_FILES - 1] == sz) { + return; + } // add the new asset to the list of recent files - for (unsigned int i = 0; i < AI_VIEW_NUM_RECENT_FILES-1;++i) - { + for (unsigned int i = 0; i < AI_VIEW_NUM_RECENT_FILES-1;++i) { g_aPreviousFiles[i] = g_aPreviousFiles[i+1]; } g_aPreviousFiles[AI_VIEW_NUM_RECENT_FILES-1] = sz; - for (int i = AI_VIEW_NUM_RECENT_FILES-1; i >= 0;--i) - { + for (int i = AI_VIEW_NUM_RECENT_FILES-1; i >= 0;--i) { const char* szText = g_aPreviousFiles[i].c_str(); UINT iFlags = 0; - if ('\0' == *szText) - { + if ('\0' == *szText) { szText = ""; iFlags = MF_GRAYED | MF_DISABLED; } ModifyMenu(g_hHistoryMenu,AI_VIEW_RECENT_FILE_ID(i), MF_STRING | MF_BYCOMMAND | iFlags,AI_VIEW_RECENT_FILE_ID(i),szText); } - return; } //------------------------------------------------------------------------------- // Open a new asset //------------------------------------------------------------------------------- -void OpenAsset() -{ +void OpenAsset() { char szFileName[MAX_PATH]; DWORD dwTemp = MAX_PATH; - if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"CurrentApp",NULL,NULL, - (BYTE*)szFileName,&dwTemp)) - { + if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"CurrentApp",NULL,NULL, (BYTE*)szFileName,&dwTemp)) { // Key was not found. Use C: strcpy(szFileName,""); - } - else - { + } else { // need to remove the file name char* sz = strrchr(szFileName,'\\'); if (!sz) @@ -962,21 +852,28 @@ void OpenAsset() strcpy(szCur,"*.*"); szCur[4] = 0; - OPENFILENAME sFilename1 = { - sizeof(OPENFILENAME), - g_hDlg,GetModuleHandle(NULL), szList, NULL, 0, 1, - szFileName, MAX_PATH, NULL, 0, NULL, - "Import Asset into ASSIMP", - OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_NOCHANGEDIR, - 0, 1, ".x", 0, NULL, NULL - }; - if(GetOpenFileName(&sFilename1) == 0) return; + OPENFILENAME sFilename1; + ZeroMemory(&sFilename1, sizeof(sFilename1)); + sFilename1.lStructSize = sizeof(sFilename1); + sFilename1.hwndOwner = g_hDlg; + sFilename1.hInstance = GetModuleHandle(NULL); + sFilename1.lpstrFile = szFileName; + sFilename1.lpstrFile[0] = '\0'; + sFilename1.nMaxFile = sizeof(szList); + sFilename1.lpstrFilter = szList; + sFilename1.nFilterIndex = 1; + sFilename1.lpstrFileTitle = NULL; + sFilename1.nMaxFileTitle = 0; + sFilename1.lpstrInitialDir = NULL; + sFilename1.Flags = OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_NOCHANGEDIR; + if (GetOpenFileName(&sFilename1) == 0) { + return; + } // Now store the file in the registry RegSetValueExA(g_hRegistry,"CurrentApp",0,REG_SZ,(const BYTE*)szFileName,MAX_PATH); - if (0 != strcmp(g_szFileName,szFileName)) - { + if (0 != strcmp(g_szFileName,szFileName)) { strcpy(g_szFileName, szFileName); DeleteAssetData(); DeleteAsset(); @@ -988,13 +885,10 @@ void OpenAsset() // Save the list of previous files to the registry SaveHistory(); } - return; } //------------------------------------------------------------------------------- -void SetupPPUIState() -{ - +void SetupPPUIState() { // that's ugly. anyone willing to rewrite me from scratch? HMENU hMenu = GetMenu(g_hDlg); CheckMenuItem(hMenu,ID_VIEWER_PP_JIV,ppsteps & aiProcess_JoinIdenticalVertices ? MF_CHECKED : MF_UNCHECKED); @@ -1018,13 +912,11 @@ void SetupPPUIState() //------------------------------------------------------------------------------- // Fill the 'export' top level menu with a list of all supported export formats //------------------------------------------------------------------------------- -void PopulateExportMenu() -{ +void PopulateExportMenu() { // add sub items for all recent files Exporter exp; HMENU hm = ::CreateMenu(); - for(size_t i = 0; i < exp.GetExportFormatCount(); ++i) - { + for(size_t i = 0; i < exp.GetExportFormatCount(); ++i) { const aiExportFormatDesc* const e = exp.GetExportFormatDescription(i); char tmp[256]; sprintf(tmp,"%s (%s)",e->description,e->id); @@ -1037,9 +929,9 @@ void PopulateExportMenu() } //------------------------------------------------------------------------------- +// Export function //------------------------------------------------------------------------------- -void DoExport(size_t formatId) -{ +void DoExport(size_t formatId) { if (!g_szFileName[0]) { MessageBox(g_hDlg, "No model loaded", "Export", MB_ICONERROR); return; @@ -1122,8 +1014,7 @@ void DoExport(size_t formatId) //------------------------------------------------------------------------------- // Initialize the user interface //------------------------------------------------------------------------------- -void InitUI() -{ +void InitUI() { SetDlgItemText(g_hDlg,IDC_EVERT,"0"); SetDlgItemText(g_hDlg,IDC_EFACE,"0"); SetDlgItemText(g_hDlg,IDC_EMAT,"0"); @@ -1147,13 +1038,10 @@ void InitUI() RegCreateKeyEx(HKEY_CURRENT_USER,"Software\\ASSIMP\\Viewer", 0,NULL,0,KEY_ALL_ACCESS, NULL, &g_hRegistry,NULL); - if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"LastUIState",NULL,NULL, - (BYTE*)&dwValue,&dwTemp)) - { + if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"LastUIState",NULL,NULL, (BYTE*)&dwValue,&dwTemp)) { dwValue = 1; } - if (0 == dwValue) - { + if (0 == dwValue) { // collapse the viewer // adjust the size RECT sRect; @@ -1169,22 +1057,17 @@ void InitUI() SetWindowPos(g_hDlg,NULL,0,0,sRect.right-214,sRect.bottom, SWP_NOMOVE | SWP_NOZORDER); SetWindowText(GetDlgItem(g_hDlg,IDC_BLUBB),">>"); - } - else - { + } else { CheckDlgButton(g_hDlg,IDC_BLUBB,BST_CHECKED); } // AutoRotate if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"AutoRotate",NULL,NULL, (BYTE*)&dwValue,&dwTemp))dwValue = 0; - if (0 == dwValue) - { + if (0 == dwValue) { g_sOptions.bRotate = false; CheckDlgButton(g_hDlg,IDC_AUTOROTATE,BST_UNCHECKED); - } - else - { + } else { g_sOptions.bRotate = true; CheckDlgButton(g_hDlg,IDC_AUTOROTATE,BST_CHECKED); } @@ -1192,13 +1075,10 @@ void InitUI() // MultipleLights if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"MultipleLights",NULL,NULL, (BYTE*)&dwValue,&dwTemp))dwValue = 0; - if (0 == dwValue) - { + if (0 == dwValue) { g_sOptions.b3Lights = false; CheckDlgButton(g_hDlg,IDC_3LIGHTS,BST_UNCHECKED); - } - else - { + } else { g_sOptions.b3Lights = true; CheckDlgButton(g_hDlg,IDC_3LIGHTS,BST_CHECKED); } @@ -1206,27 +1086,22 @@ void InitUI() // Light rotate if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"LightRotate",NULL,NULL, (BYTE*)&dwValue,&dwTemp))dwValue = 0; - if (0 == dwValue) - { + if (0 == dwValue) { g_sOptions.bLightRotate = false; CheckDlgButton(g_hDlg,IDC_LIGHTROTATE,BST_UNCHECKED); - } - else - { + } else { g_sOptions.bLightRotate = true; CheckDlgButton(g_hDlg,IDC_LIGHTROTATE,BST_CHECKED); } // NoSpecular - if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"NoSpecular",NULL,NULL, - (BYTE*)&dwValue,&dwTemp))dwValue = 0; - if (0 == dwValue) - { + if (ERROR_SUCCESS != RegQueryValueEx(g_hRegistry, "NoSpecular", NULL, NULL, (BYTE*)&dwValue, &dwTemp)) { + dwValue = 0; + } + if (0 == dwValue) { g_sOptions.bNoSpecular = false; CheckDlgButton(g_hDlg,IDC_NOSPECULAR,BST_UNCHECKED); - } - else - { + } else { g_sOptions.bNoSpecular = true; CheckDlgButton(g_hDlg,IDC_NOSPECULAR,BST_CHECKED); } @@ -1234,13 +1109,10 @@ void InitUI() // LowQuality if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"LowQuality",NULL,NULL, (BYTE*)&dwValue,&dwTemp))dwValue = 0; - if (0 == dwValue) - { + if (0 == dwValue) { g_sOptions.bLowQuality = false; CheckDlgButton(g_hDlg,IDC_LOWQUALITY,BST_UNCHECKED); - } - else - { + } else { g_sOptions.bLowQuality = true; CheckDlgButton(g_hDlg,IDC_LOWQUALITY,BST_CHECKED); } @@ -1248,13 +1120,10 @@ void InitUI() // LowQuality if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"NoTransparency",NULL,NULL, (BYTE*)&dwValue,&dwTemp))dwValue = 0; - if (0 == dwValue) - { + if (0 == dwValue) { g_sOptions.bNoAlphaBlending = false; CheckDlgButton(g_hDlg,IDC_NOAB,BST_UNCHECKED); - } - else - { + } else { g_sOptions.bNoAlphaBlending = true; CheckDlgButton(g_hDlg,IDC_NOAB,BST_CHECKED); } @@ -1262,27 +1131,23 @@ void InitUI() // DisplayNormals if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"RenderNormals",NULL,NULL, (BYTE*)&dwValue,&dwTemp))dwValue = 0; - if (0 == dwValue) - { + if (0 == dwValue) { g_sOptions.bRenderNormals = false; CheckDlgButton(g_hDlg,IDC_TOGGLENORMALS,BST_UNCHECKED); - } - else - { + } else { g_sOptions.bRenderNormals = true; CheckDlgButton(g_hDlg,IDC_TOGGLENORMALS,BST_CHECKED); } // NoMaterials - if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"RenderMats",NULL,NULL, - (BYTE*)&dwValue,&dwTemp))dwValue = 1; - if (0 == dwValue) - { + if (ERROR_SUCCESS != RegQueryValueEx(g_hRegistry, "RenderMats", NULL, NULL, + (BYTE*)&dwValue, &dwTemp)) { + dwValue = 1; + } + if (0 == dwValue) { g_sOptions.bRenderMats = false; CheckDlgButton(g_hDlg,IDC_TOGGLEMAT,BST_CHECKED); - } - else - { + } else { g_sOptions.bRenderMats = true; CheckDlgButton(g_hDlg,IDC_TOGGLEMAT,BST_UNCHECKED); } @@ -1294,9 +1159,7 @@ void InitUI() { g_sOptions.bMultiSample = false; CheckDlgButton(g_hDlg,IDC_TOGGLEMS,BST_UNCHECKED); - } - else - { + } else { g_sOptions.bMultiSample = true; CheckDlgButton(g_hDlg,IDC_TOGGLEMS,BST_CHECKED); } @@ -1304,13 +1167,10 @@ void InitUI() // FPS Mode if(ERROR_SUCCESS != RegQueryValueEx(g_hRegistry,"FPSView",NULL,NULL, (BYTE*)&dwValue,&dwTemp))dwValue = 0; - if (0 == dwValue) - { + if (0 == dwValue) { g_bFPSView = false; CheckDlgButton(g_hDlg,IDC_ZOOM,BST_CHECKED); - } - else - { + } else { g_bFPSView = true; CheckDlgButton(g_hDlg,IDC_ZOOM,BST_UNCHECKED); } @@ -1338,22 +1198,20 @@ void InitUI() SendDlgItemMessage(g_hDlg,IDC_SLIDERANIM,TBM_SETRANGEMIN,TRUE,0); SendDlgItemMessage(g_hDlg,IDC_SLIDERANIM,TBM_SETRANGEMAX,TRUE,10000); - return; } //------------------------------------------------------------------------------- -// Message prcoedure for the smooth normals dialog +// Message procedure for the smooth normals dialog //------------------------------------------------------------------------------- -INT_PTR CALLBACK SMMessageProc(HWND hwndDlg,UINT uMsg, - WPARAM wParam,LPARAM lParam) -{ +INT_PTR CALLBACK SMMessageProc(HWND hwndDlg,UINT uMsg, WPARAM wParam,LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); - switch (uMsg) - { + switch (uMsg) { case WM_INITDIALOG: - char s[30]; - ::sprintf(s,"%.2f",g_smoothAngle); - SetDlgItemText(hwndDlg,IDC_EDITSM,s); + { + char s[30]; + ::sprintf(s, "%.2f", g_smoothAngle); + SetDlgItemText(hwndDlg, IDC_EDITSM, s); + } return TRUE; case WM_CLOSE: @@ -1361,16 +1219,16 @@ INT_PTR CALLBACK SMMessageProc(HWND hwndDlg,UINT uMsg, return TRUE; case WM_COMMAND: + { + if (IDOK == LOWORD(wParam)) { + char s[30]; + GetDlgItemText(hwndDlg, IDC_EDITSM, s, 30); + g_smoothAngle = (float)atof(s); - if (IDOK == LOWORD(wParam)) { - char s[30]; - GetDlgItemText(hwndDlg,IDC_EDITSM,s,30); - g_smoothAngle = (float)atof(s); - - EndDialog(hwndDlg,0); - } - else if (IDCANCEL == LOWORD(wParam)) { - EndDialog(hwndDlg,1); + EndDialog(hwndDlg, 0); + } else if (IDCANCEL == LOWORD(wParam)) { + EndDialog(hwndDlg, 1); + } } return TRUE; } @@ -1385,9 +1243,7 @@ INT_PTR CALLBACK SMMessageProc(HWND hwndDlg,UINT uMsg, // NOTE: Due to the impossibility to process WM_CHAR messages in dialogs // properly the code for all hotkeys has been moved to the WndMain //------------------------------------------------------------------------------- -INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg, - WPARAM wParam,LPARAM lParam) - { +INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg, WPARAM wParam,LPARAM lParam) { UNREFERENCED_PARAMETER(lParam); UNREFERENCED_PARAMETER(wParam); @@ -1747,21 +1603,17 @@ INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg, case WM_DROPFILES: { HDROP hDrop = (HDROP)wParam; - char szFile[MAX_PATH]; DragQueryFile(hDrop,0,szFile,sizeof(szFile)); - const char* sz = strrchr(szFile,'.'); - if (!sz) + if (!sz) { sz = szFile; + } - if (CDisplay::VIEWMODE_TEXTURE == CDisplay::Instance().GetViewMode()) - { + if (CDisplay::VIEWMODE_TEXTURE == CDisplay::Instance().GetViewMode()) { // replace the selected texture with the new one ... CDisplay::Instance().ReplaceCurrentTexture(szFile); - } - else - { + } else { // check whether it is a typical texture file format ... ++sz; if (0 == ASSIMP_stricmp(sz,"png") || @@ -1803,19 +1655,17 @@ INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg, fseek(pFile,112,SEEK_SET); fread(&dwCaps,4,1,pFile); - if (dwCaps & 0x00000400L /* DDSCAPS2_CUBEMAP_POSITIVEX */) - { + if (dwCaps & 0x00000400L /* DDSCAPS2_CUBEMAP_POSITIVEX */) { CLogDisplay::Instance().AddEntry( "[INFO] Assuming this dds file is a skybox ...", D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0)); CBackgroundPainter::Instance().SetCubeMapBG(szFile); + } else { + CBackgroundPainter::Instance().SetTextureBG(szFile); } - else CBackgroundPainter::Instance().SetTextureBG(szFile); fclose(pFile); - } - else - { + } else { strcpy(g_szFileName,szFile); DeleteAsset(); @@ -1830,13 +1680,10 @@ INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg, case WM_COMMAND: HMENU hMenu = GetMenu(g_hDlg); - if (ID_VIEWER_QUIT == LOWORD(wParam)) - { + if (ID_VIEWER_QUIT == LOWORD(wParam)) { PostQuitMessage(0); DestroyWindow(hwndDlg); - } - else if (IDC_COMBO1 == LOWORD(wParam)) - { + } else if (IDC_COMBO1 == LOWORD(wParam)) { if(HIWORD(wParam) == CBN_SELCHANGE) { const size_t sel = static_cast(ComboBox_GetCurSel(GetDlgItem(hwndDlg,IDC_COMBO1))); if(g_pcAsset) { @@ -1844,9 +1691,7 @@ INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg, SendDlgItemMessage(hwndDlg,IDC_SLIDERANIM,TBM_SETPOS,TRUE,0); } } - } - else if (ID_VIEWER_RESETVIEW == LOWORD(wParam)) - { + } else if (ID_VIEWER_RESETVIEW == LOWORD(wParam)) { g_sCamera.vPos = aiVector3D(0.0f,0.0f,-10.0f); g_sCamera.vLookAt = aiVector3D(0.0f,0.0f,1.0f); g_sCamera.vUp = aiVector3D(0.0f,1.0f,0.0f); @@ -1856,102 +1701,61 @@ INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg, // don't forget to reset the st CBackgroundPainter::Instance().ResetSB(); - } - else if (ID__HELP == LOWORD(wParam)) - { + } else if (ID__HELP == LOWORD(wParam)) { DialogBox(g_hInstance,MAKEINTRESOURCE(IDD_AVHELP), hwndDlg,&HelpDialogProc); - } - else if (ID__ABOUT == LOWORD(wParam)) - { + } else if (ID__ABOUT == LOWORD(wParam)) { DialogBox(g_hInstance,MAKEINTRESOURCE(IDD_ABOUTBOX), hwndDlg,&AboutMessageProc); - } - else if (ID_TOOLS_LOGWINDOW == LOWORD(wParam)) - { - CLogWindow::Instance().Show(); - } - else if (ID__WEBSITE == LOWORD(wParam)) - { - ShellExecute(NULL,"open","http://assimp.sourceforge.net","","",SW_SHOW); - } - else if (ID__WEBSITESF == LOWORD(wParam)) - { - ShellExecute(NULL,"open","https://sourceforge.net/projects/assimp","","",SW_SHOW); - } - else if (ID_REPORTBUG == LOWORD(wParam)) - { - ShellExecute(NULL,"open","https://sourceforge.net/tracker/?func=add&group_id=226462&atid=1067632","","",SW_SHOW); - } - else if (ID_FR == LOWORD(wParam)) - { - ShellExecute(NULL,"open","https://sourceforge.net/forum/forum.php?forum_id=817653","","",SW_SHOW); - } - else if (ID_TOOLS_CLEARLOG == LOWORD(wParam)) - { - CLogWindow::Instance().Clear(); - } - else if (ID_TOOLS_SAVELOGTOFILE == LOWORD(wParam)) - { - CLogWindow::Instance().Save(); - } - else if (ID_VIEWER_MEMORYCONSUMATION == LOWORD(wParam)) - { - DisplayMemoryConsumption(); - } - else if (ID_VIEWER_H == LOWORD(wParam)) - { + } else if (ID_TOOLS_LOGWINDOW == LOWORD(wParam)) { + CLogWindow::Instance().Show(); + } else if (ID__WEBSITE == LOWORD(wParam)) { + ShellExecute(NULL,"open","http://assimp.sourceforge.net","","",SW_SHOW); + } else if (ID__WEBSITESF == LOWORD(wParam)) { + ShellExecute(NULL,"open","https://sourceforge.net/projects/assimp","","",SW_SHOW); + } else if (ID_REPORTBUG == LOWORD(wParam)) { + ShellExecute(NULL,"open","https://sourceforge.net/tracker/?func=add&group_id=226462&atid=1067632","","",SW_SHOW); + } else if (ID_FR == LOWORD(wParam)) { + ShellExecute(NULL,"open","https://sourceforge.net/forum/forum.php?forum_id=817653","","",SW_SHOW); + } else if (ID_TOOLS_CLEARLOG == LOWORD(wParam)) { + CLogWindow::Instance().Clear(); + } else if (ID_TOOLS_SAVELOGTOFILE == LOWORD(wParam)) { + CLogWindow::Instance().Save(); + } else if (ID_VIEWER_MEMORYCONSUMATION == LOWORD(wParam)) { + DisplayMemoryConsumption(); + } else if (ID_VIEWER_H == LOWORD(wParam)) { MakeFileAssociations(); - } - else if (ID_BACKGROUND_CLEAR == LOWORD(wParam)) - { + } else if (ID_BACKGROUND_CLEAR == LOWORD(wParam)) { ClearBG(); - } - else if (ID_BACKGROUND_SETCOLOR == LOWORD(wParam)) - { + } else if (ID_BACKGROUND_SETCOLOR == LOWORD(wParam)) { ChooseBGColor(); - } - else if (ID_BACKGROUND_LOADTEXTURE == LOWORD(wParam)) - { + } else if (ID_BACKGROUND_LOADTEXTURE == LOWORD(wParam)) { LoadBGTexture(); - } - else if (ID_BACKGROUND_LOADSKYBOX == LOWORD(wParam)) - { + } else if (ID_BACKGROUND_LOADSKYBOX == LOWORD(wParam)) { LoadSkybox(); - } - else if (ID_VIEWER_SAVESCREENSHOTTOFILE == LOWORD(wParam)) - { + } else if (ID_VIEWER_SAVESCREENSHOTTOFILE == LOWORD(wParam)) { SaveScreenshot(); - } - else if (ID_VIEWER_OPEN == LOWORD(wParam)) - { + } else if (ID_VIEWER_OPEN == LOWORD(wParam)) { OpenAsset(); - } - else if (ID_TOOLS_FLIPNORMALS == LOWORD(wParam)) - { - if (g_pcAsset && g_pcAsset->pcScene) - { + } else if (ID_TOOLS_FLIPNORMALS == LOWORD(wParam)) { + if (g_pcAsset && g_pcAsset->pcScene) { g_pcAsset->FlipNormals(); - } } - + } // this is ugly. anyone willing to rewrite it from scratch using wxwidgets or similar? else if (ID_VIEWER_PP_JIV == LOWORD(wParam)) { ppsteps ^= aiProcess_JoinIdenticalVertices; CheckMenuItem(hMenu,ID_VIEWER_PP_JIV,ppsteps & aiProcess_JoinIdenticalVertices ? MF_CHECKED : MF_UNCHECKED); UpdatePPSettings(); - } - else if (ID_VIEWER_PP_CTS == LOWORD(wParam)) { + } else if (ID_VIEWER_PP_CTS == LOWORD(wParam)) { ppsteps ^= aiProcess_CalcTangentSpace; CheckMenuItem(hMenu,ID_VIEWER_PP_CTS,ppsteps & aiProcess_CalcTangentSpace ? MF_CHECKED : MF_UNCHECKED); UpdatePPSettings(); - } - else if (ID_VIEWER_PP_FD == LOWORD(wParam)) { + } else if (ID_VIEWER_PP_FD == LOWORD(wParam)) { ppsteps ^= aiProcess_FindDegenerates; CheckMenuItem(hMenu,ID_VIEWER_PP_FD,ppsteps & aiProcess_FindDegenerates ? MF_CHECKED : MF_UNCHECKED); UpdatePPSettings(); - } - else if (ID_VIEWER_PP_FID == LOWORD(wParam)) { + } else if (ID_VIEWER_PP_FID == LOWORD(wParam)) { ppsteps ^= aiProcess_FindInvalidData; CheckMenuItem(hMenu,ID_VIEWER_PP_FID,ppsteps & aiProcess_FindInvalidData ? MF_CHECKED : MF_UNCHECKED); UpdatePPSettings(); @@ -2071,34 +1875,25 @@ INT_PTR CALLBACK MessageProc(HWND hwndDlg,UINT uMsg, { g_sOptions.bStereoView =! g_sOptions.bStereoView; - HMENU hMenu = GetMenu(g_hDlg); - if (g_sOptions.bStereoView) - { - ModifyMenu(hMenu,ID_TOOLS_STEREOVIEW, + HMENU menu = ::GetMenu(g_hDlg); + if (g_sOptions.bStereoView) { + ::ModifyMenu(menu,ID_TOOLS_STEREOVIEW, MF_BYCOMMAND | MF_CHECKED | MF_STRING,ID_TOOLS_STEREOVIEW,"Stereo view"); CLogDisplay::Instance().AddEntry("[INFO] Switched to stereo mode", D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0)); - } - else - { - ModifyMenu(hMenu,ID_TOOLS_STEREOVIEW, + } else { + ModifyMenu(menu,ID_TOOLS_STEREOVIEW, MF_BYCOMMAND | MF_UNCHECKED | MF_STRING,ID_TOOLS_STEREOVIEW,"Stereo view"); CLogDisplay::Instance().AddEntry("[INFO] Switched to mono mode", D3DCOLOR_ARGB(0xFF,0xFF,0xFF,0)); } - } - else if (ID_TOOLS_SETANGLELIMIT == LOWORD(wParam)) - { + } else if (ID_TOOLS_SETANGLELIMIT == LOWORD(wParam)) { DialogBox(g_hInstance,MAKEINTRESOURCE(IDD_DIALOGSMOOTH),g_hDlg,&SMMessageProc); - } - else if (ID_VIEWER_CLEARHISTORY == LOWORD(wParam)) - { + } else if (ID_VIEWER_CLEARHISTORY == LOWORD(wParam)) { ClearHistory(); - } - else if (ID_VIEWER_CLOSEASSET == LOWORD(wParam)) - { + } else if (ID_VIEWER_CLOSEASSET == LOWORD(wParam)) { DeleteAssetData(); DeleteAsset(); } @@ -2420,36 +2215,34 @@ int APIENTRY _tWinMain(HINSTANCE hInstance, SetFocus(g_hDlg); // recover background skyboxes/textures from the last session - HKEY g_hRegistry; - union - { + HKEY hRegistry; + union { char szFileName[MAX_PATH]; D3DCOLOR clrColor; - }; + }; DWORD dwTemp = MAX_PATH; RegCreateKeyEx(HKEY_CURRENT_USER, - "Software\\ASSIMP\\Viewer",0,NULL,0,KEY_ALL_ACCESS, NULL, &g_hRegistry,NULL); - if(ERROR_SUCCESS == RegQueryValueEx(g_hRegistry,"LastSkyBoxSrc",NULL,NULL, + "Software\\ASSIMP\\Viewer",0,NULL,0,KEY_ALL_ACCESS, NULL, &hRegistry,NULL); + if(ERROR_SUCCESS == RegQueryValueEx(hRegistry,"LastSkyBoxSrc",NULL,NULL, (BYTE*)szFileName,&dwTemp) && '\0' != szFileName[0]) { CBackgroundPainter::Instance().SetCubeMapBG(szFileName); } - else if(ERROR_SUCCESS == RegQueryValueEx(g_hRegistry,"LastTextureSrc",NULL,NULL, + else if(ERROR_SUCCESS == RegQueryValueEx(hRegistry,"LastTextureSrc",NULL,NULL, (BYTE*)szFileName,&dwTemp) && '\0' != szFileName[0]) { CBackgroundPainter::Instance().SetTextureBG(szFileName); } - else if(ERROR_SUCCESS == RegQueryValueEx(g_hRegistry,"Color",NULL,NULL, + else if(ERROR_SUCCESS == RegQueryValueEx(hRegistry,"Color",NULL,NULL, (BYTE*)&clrColor,&dwTemp)) { CBackgroundPainter::Instance().SetColor(clrColor); } - RegCloseKey(g_hRegistry); + RegCloseKey(hRegistry); // now handle command line arguments HandleCommandLine(lpCmdLine); - double adLast[30]; for (int i = 0; i < 30;++i)adLast[i] = 0.0f; int iCurrent = 0; @@ -2608,7 +2401,6 @@ int APIENTRY _tWinMain(HINSTANCE hInstance, // render the scene CDisplay::Instance().OnRender(); - // measure FPS, average it out g_dCurTime = timeGetTime(); g_fElpasedTime = (float)((g_dCurTime - g_dLastTime) * 0.001); @@ -2617,26 +2409,26 @@ int APIENTRY _tWinMain(HINSTANCE hInstance, adLast[iCurrent++] = 1.0f / g_fElpasedTime; double dFPS = 0.0; - for (int i = 0;i < 30;++i) - dFPS += adLast[i]; + for (int i = 0; i < 30; ++i) { + dFPS += adLast[ i ]; + } dFPS /= 30.0; - if (30 == iCurrent) - { + if (30 == iCurrent) { iCurrent = 0; - if (dFPS != g_fFPS) - { + if (dFPS != g_fFPS) { g_fFPS = dFPS; char szOut[256]; sprintf(szOut,"%i",(int)floorf((float)dFPS+0.5f)); SetDlgItemText(g_hDlg,IDC_EFPS,szOut); - } } } + } DeleteAsset(); Assimp::DefaultLogger::kill(); ShutdownDevice(); ShutdownD3D(); + return 0; - } \ No newline at end of file +} diff --git a/tools/assimp_view/Normals.cpp b/tools/assimp_view/Normals.cpp index 240825905..0ebd3dd5b 100644 --- a/tools/assimp_view/Normals.cpp +++ b/tools/assimp_view/Normals.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -39,16 +39,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------- */ - #include "assimp_view.h" -// note: these are no longer part of the public API, but they are -// exported on Windows to keep AssimpView alive. -#include "GenFaceNormalsProcess.h" -#include "GenVertexNormalsProcess.h" -#include "JoinVerticesProcess.h" -#include "CalcTangentsProcess.h" -#include "MakeVerboseFormat.h" +#include "PostProcessing/GenFaceNormalsProcess.h" +#include "PostProcessing/GenVertexNormalsProcess.h" +#include "PostProcessing/JoinVerticesProcess.h" +#include "PostProcessing/CalcTangentsProcess.h" +#include "PostProcessing/MakeVerboseFormat.h" namespace AssimpView { @@ -60,15 +57,14 @@ float g_smoothAngle = 80.f; //------------------------------------------------------------------------------- // Flip all normal vectors //------------------------------------------------------------------------------- -void AssetHelper::FlipNormalsInt() -{ +void AssetHelper::FlipNormalsInt() { // invert all normal vectors - for (unsigned int i = 0; i < this->pcScene->mNumMeshes;++i) - { + for (unsigned int i = 0; i < this->pcScene->mNumMeshes;++i) { aiMesh* pcMesh = this->pcScene->mMeshes[i]; - if (!pcMesh->mNormals) + if (!pcMesh->mNormals) { continue; + } for (unsigned int a = 0; a < pcMesh->mNumVertices;++a){ pcMesh->mNormals[a] *= -1.0f; @@ -77,8 +73,7 @@ void AssetHelper::FlipNormalsInt() } //------------------------------------------------------------------------------- -void AssetHelper::FlipNormals() -{ +void AssetHelper::FlipNormals() { FlipNormalsInt(); // recreate native data @@ -90,53 +85,42 @@ void AssetHelper::FlipNormals() //------------------------------------------------------------------------------- // Set the normal set of the scene //------------------------------------------------------------------------------- -void AssetHelper::SetNormalSet(unsigned int iSet) -{ +void AssetHelper::SetNormalSet(unsigned int iSet) { // we need to build an unique set of vertices for this ... { MakeVerboseFormatProcess* pcProcess = new MakeVerboseFormatProcess(); pcProcess->Execute(pcScene); delete pcProcess; - for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) - { - if (!apcMeshes[i]->pvOriginalNormals) - { + for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) { + if (!apcMeshes[i]->pvOriginalNormals) { apcMeshes[i]->pvOriginalNormals = new aiVector3D[pcScene->mMeshes[i]->mNumVertices]; memcpy( apcMeshes[i]->pvOriginalNormals,pcScene->mMeshes[i]->mNormals, pcScene->mMeshes[i]->mNumVertices * sizeof(aiVector3D)); } delete[] pcScene->mMeshes[i]->mNormals; - pcScene->mMeshes[i]->mNormals = NULL; + pcScene->mMeshes[i]->mNormals = nullptr; } } - // now we can start to calculate a new set of normals - if (HARD == iSet) - { + if (HARD == iSet) { GenFaceNormalsProcess* pcProcess = new GenFaceNormalsProcess(); pcProcess->Execute(pcScene); FlipNormalsInt(); delete pcProcess; - } - else if (SMOOTH == iSet) - { + } else if (SMOOTH == iSet) { GenVertexNormalsProcess* pcProcess = new GenVertexNormalsProcess(); pcProcess->SetMaxSmoothAngle((float)AI_DEG_TO_RAD(g_smoothAngle)); pcProcess->Execute(pcScene); FlipNormalsInt(); delete pcProcess; - } - else if (ORIGINAL == iSet) - { - for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) - { - if (apcMeshes[i]->pvOriginalNormals) - { + } else if (ORIGINAL == iSet) { + for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) { + if (apcMeshes[i]->pvOriginalNormals) { delete[] pcScene->mMeshes[i]->mNormals; pcScene->mMeshes[i]->mNormals = apcMeshes[i]->pvOriginalNormals; - apcMeshes[i]->pvOriginalNormals = NULL; + apcMeshes[i]->pvOriginalNormals = nullptr; } } } @@ -153,14 +137,11 @@ void AssetHelper::SetNormalSet(unsigned int iSet) iNormalSet = iSet; - if (g_bWasFlipped) - { + if (g_bWasFlipped) { // invert all normal vectors - for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) - { + for (unsigned int i = 0; i < pcScene->mNumMeshes;++i) { aiMesh* pcMesh = pcScene->mMeshes[i]; - for (unsigned int a = 0; a < pcMesh->mNumVertices;++a) - { + for (unsigned int a = 0; a < pcMesh->mNumVertices;++a) { pcMesh->mNormals[a] *= -1.0f; } } @@ -169,7 +150,6 @@ void AssetHelper::SetNormalSet(unsigned int iSet) // recreate native data DeleteAssetData(true); CreateAssetData(); - return; } -}; \ No newline at end of file +} diff --git a/tools/assimp_view/SceneAnimator.cpp b/tools/assimp_view/SceneAnimator.cpp index 6e507cb41..86fe46a9c 100644 --- a/tools/assimp_view/SceneAnimator.cpp +++ b/tools/assimp_view/SceneAnimator.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -47,21 +47,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace AssimpView; +const aiMatrix4x4 IdentityMatrix; + // ------------------------------------------------------------------------------------------------ // Constructor for a given scene. SceneAnimator::SceneAnimator( const aiScene* pScene, size_t pAnimIndex) -{ - mScene = pScene; - mCurrentAnimIndex = -1; - mAnimEvaluator = NULL; - mRootNode = NULL; - +: mScene( pScene ) +, mCurrentAnimIndex( -1 ) +, mAnimEvaluator( nullptr ) +, mRootNode( nullptr ) { // build the nodes-for-bones table - for (unsigned int i = 0; i < pScene->mNumMeshes;++i) - { + for (unsigned int i = 0; i < pScene->mNumMeshes;++i) { const aiMesh* mesh = pScene->mMeshes[i]; - for (unsigned int n = 0; n < mesh->mNumBones;++n) - { + for (unsigned int n = 0; n < mesh->mNumBones;++n) { const aiBone* bone = mesh->mBones[n]; mBoneNodesByName[bone->mName.data] = pScene->mRootNode->FindNode(bone->mName); @@ -74,34 +72,34 @@ SceneAnimator::SceneAnimator( const aiScene* pScene, size_t pAnimIndex) // ------------------------------------------------------------------------------------------------ // Destructor -SceneAnimator::~SceneAnimator() -{ +SceneAnimator::~SceneAnimator() { delete mRootNode; delete mAnimEvaluator; } // ------------------------------------------------------------------------------------------------ // Sets the animation to use for playback. -void SceneAnimator::SetAnimIndex( size_t pAnimIndex) -{ +void SceneAnimator::SetAnimIndex( size_t pAnimIndex) { // no change - if( pAnimIndex == mCurrentAnimIndex) + if (pAnimIndex == static_cast( mCurrentAnimIndex ) ) { return; + } // kill data of the previous anim - delete mRootNode; mRootNode = NULL; - delete mAnimEvaluator; mAnimEvaluator = NULL; + delete mRootNode; mRootNode = nullptr; + delete mAnimEvaluator; mAnimEvaluator = nullptr; mNodesByName.clear(); - mCurrentAnimIndex = pAnimIndex; + mCurrentAnimIndex = static_cast( pAnimIndex ); // create the internal node tree. Do this even in case of invalid animation index // so that the transformation matrices are properly set up to mimic the current scene - mRootNode = CreateNodeTree( mScene->mRootNode, NULL); + mRootNode = CreateNodeTree( mScene->mRootNode, nullptr); // invalid anim index - if( mCurrentAnimIndex >= mScene->mNumAnimations) + if (static_cast( mCurrentAnimIndex )>= mScene->mNumAnimations) { return; + } // create an evaluator for this animation mAnimEvaluator = new AnimEvaluator( mScene->mAnimations[mCurrentAnimIndex]); @@ -109,11 +107,11 @@ void SceneAnimator::SetAnimIndex( size_t pAnimIndex) // ------------------------------------------------------------------------------------------------ // Calculates the node transformations for the scene. -void SceneAnimator::Calculate( double pTime) -{ +void SceneAnimator::Calculate( double pTime) { // invalid anim - if( !mAnimEvaluator) + if (!mAnimEvaluator) { return; + } // calculate current local transformations mAnimEvaluator->Evaluate( pTime); @@ -124,36 +122,35 @@ void SceneAnimator::Calculate( double pTime) // ------------------------------------------------------------------------------------------------ // Retrieves the most recent local transformation matrix for the given node. -const aiMatrix4x4& SceneAnimator::GetLocalTransform( const aiNode* node) const -{ +const aiMatrix4x4& SceneAnimator::GetLocalTransform( const aiNode* node) const { NodeMap::const_iterator it = mNodesByName.find( node); - if( it == mNodesByName.end()) - return mIdentityMatrix; + if (it == mNodesByName.end()) { + return IdentityMatrix; + } return it->second->mLocalTransform; } // ------------------------------------------------------------------------------------------------ // Retrieves the most recent global transformation matrix for the given node. -const aiMatrix4x4& SceneAnimator::GetGlobalTransform( const aiNode* node) const -{ +const aiMatrix4x4& SceneAnimator::GetGlobalTransform( const aiNode* node) const { NodeMap::const_iterator it = mNodesByName.find( node); - if( it == mNodesByName.end()) - return mIdentityMatrix; + if (it == mNodesByName.end()) { + return IdentityMatrix; + } return it->second->mGlobalTransform; } // ------------------------------------------------------------------------------------------------ // Calculates the bone matrices for the given mesh. -const std::vector& SceneAnimator::GetBoneMatrices( const aiNode* pNode, size_t pMeshIndex /* = 0 */) -{ +const std::vector& SceneAnimator::GetBoneMatrices( const aiNode* pNode, size_t pMeshIndex /* = 0 */) { ai_assert( pMeshIndex < pNode->mNumMeshes); size_t meshIndex = pNode->mMeshes[pMeshIndex]; ai_assert( meshIndex < mScene->mNumMeshes); const aiMesh* mesh = mScene->mMeshes[meshIndex]; - // resize array and initialise it with identity matrices + // resize array and initialize it with identity matrices mTransforms.resize( mesh->mNumBones, aiMatrix4x4()); // calculate the mesh's inverse global transform @@ -162,8 +159,7 @@ const std::vector& SceneAnimator::GetBoneMatrices( const aiNode* pN // Bone matrices transform from mesh coordinates in bind pose to mesh coordinates in skinned pose // Therefore the formula is offsetMatrix * currentGlobalTransform * inverseCurrentMeshTransform - for( size_t a = 0; a < mesh->mNumBones; ++a) - { + for( size_t a = 0; a < mesh->mNumBones; ++a) { const aiBone* bone = mesh->mBones[a]; const aiMatrix4x4& currentGlobalTransform = GetGlobalTransform( mBoneNodesByName[ bone->mName.data ]); mTransforms[a] = globalInverseMeshTransform * currentGlobalTransform * bone->mOffsetMatrix; @@ -175,8 +171,7 @@ const std::vector& SceneAnimator::GetBoneMatrices( const aiNode* pN // ------------------------------------------------------------------------------------------------ // Recursively creates an internal node structure matching the current scene and animation. -SceneAnimNode* SceneAnimator::CreateNodeTree( aiNode* pNode, SceneAnimNode* pParent) -{ +SceneAnimNode* SceneAnimator::CreateNodeTree( aiNode* pNode, SceneAnimNode* pParent) { // create a node SceneAnimNode* internalNode = new SceneAnimNode( pNode->mName.data); internalNode->mParent = pParent; @@ -187,14 +182,11 @@ SceneAnimNode* SceneAnimator::CreateNodeTree( aiNode* pNode, SceneAnimNode* pPar CalculateGlobalTransform( internalNode); // find the index of the animation track affecting this node, if any - if( mCurrentAnimIndex < mScene->mNumAnimations) - { + if(static_cast( mCurrentAnimIndex ) < mScene->mNumAnimations) { internalNode->mChannelIndex = -1; const aiAnimation* currentAnim = mScene->mAnimations[mCurrentAnimIndex]; - for( unsigned int a = 0; a < currentAnim->mNumChannels; a++) - { - if( currentAnim->mChannels[a]->mNodeName.data == internalNode->mName) - { + for( unsigned int a = 0; a < currentAnim->mNumChannels; a++) { + if( currentAnim->mChannels[a]->mNodeName.data == internalNode->mName) { internalNode->mChannelIndex = a; break; } @@ -202,8 +194,7 @@ SceneAnimNode* SceneAnimator::CreateNodeTree( aiNode* pNode, SceneAnimNode* pPar } // continue for all child nodes and assign the created internal nodes as our children - for( unsigned int a = 0; a < pNode->mNumChildren; a++) - { + for( unsigned int a = 0; a < pNode->mNumChildren; ++a ) { SceneAnimNode* childNode = CreateNodeTree( pNode->mChildren[a], internalNode); internalNode->mChildren.push_back( childNode); } @@ -213,12 +204,10 @@ SceneAnimNode* SceneAnimator::CreateNodeTree( aiNode* pNode, SceneAnimNode* pPar // ------------------------------------------------------------------------------------------------ // Recursively updates the internal node transformations from the given matrix array -void SceneAnimator::UpdateTransforms( SceneAnimNode* pNode, const std::vector& pTransforms) -{ +void SceneAnimator::UpdateTransforms( SceneAnimNode* pNode, const std::vector& pTransforms) { // update node local transform - if( pNode->mChannelIndex != -1) - { - ai_assert( pNode->mChannelIndex < pTransforms.size()); + if( pNode->mChannelIndex != -1) { + ai_assert(static_cast( pNode->mChannelIndex ) < pTransforms.size()); pNode->mLocalTransform = pTransforms[pNode->mChannelIndex]; } @@ -226,19 +215,18 @@ void SceneAnimator::UpdateTransforms( SceneAnimNode* pNode, const std::vector::iterator it = pNode->mChildren.begin(); it != pNode->mChildren.end(); ++it) - UpdateTransforms( *it, pTransforms); + for (std::vector::iterator it = pNode->mChildren.begin(); it != pNode->mChildren.end(); ++it) { + UpdateTransforms(*it, pTransforms); + } } // ------------------------------------------------------------------------------------------------ // Calculates the global transformation matrix for the given internal node -void SceneAnimator::CalculateGlobalTransform( SceneAnimNode* pInternalNode) -{ +void SceneAnimator::CalculateGlobalTransform( SceneAnimNode* pInternalNode) { // concatenate all parent transforms to get the global transform for this node pInternalNode->mGlobalTransform = pInternalNode->mLocalTransform; SceneAnimNode* node = pInternalNode->mParent; - while( node) - { + while( node) { pInternalNode->mGlobalTransform = node->mLocalTransform * pInternalNode->mGlobalTransform; node = node->mParent; } diff --git a/tools/assimp_view/SceneAnimator.h b/tools/assimp_view/SceneAnimator.h index afcbac925..00d9832b6 100644 --- a/tools/assimp_view/SceneAnimator.h +++ b/tools/assimp_view/SceneAnimator.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. @@ -49,15 +49,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -namespace AssimpView { +namespace AssimpView { // --------------------------------------------------------------------------------- /** A little tree structure to match the scene's node structure, but holding * additional data. Needs to be public to allow using it in templates at * certain compilers. */ -struct SceneAnimNode -{ +struct SceneAnimNode { std::string mName; SceneAnimNode* mParent; std::vector mChildren; @@ -69,12 +68,15 @@ struct SceneAnimNode aiMatrix4x4 mGlobalTransform; //! index in the current animation's channel array. -1 if not animated. - size_t mChannelIndex; + int mChannelIndex; //! Default construction SceneAnimNode() : mName() - , mParent(NULL) + , mParent(nullptr) + , mChildren() + , mLocalTransform() + , mGlobalTransform() , mChannelIndex(-1) { // empty } @@ -82,8 +84,11 @@ struct SceneAnimNode //! Construction from a given name SceneAnimNode( const std::string& pName) : mName( pName) - , mParent(NULL) - , mChannelIndex( -1 ) { + , mParent(nullptr) + , mChildren() + , mLocalTransform() + , mGlobalTransform() + , mChannelIndex(-1) { // empty } @@ -105,8 +110,7 @@ struct SceneAnimNode * GetGlobalTransform(). A full set of bone matrices can be retrieved by * GetBoneMatrices() for a given mesh. */ -class SceneAnimator -{ +class SceneAnimator { public: // ---------------------------------------------------------------------------- @@ -186,7 +190,6 @@ public: const std::vector& GetBoneMatrices( const aiNode* pNode, size_t pMeshIndex = 0); - // ---------------------------------------------------------------------------- /** @brief Get the current animation index */ @@ -198,7 +201,7 @@ public: /** @brief Get the current animation or NULL */ aiAnimation* CurrentAnim() const { - return mCurrentAnimIndex < mScene->mNumAnimations ? mScene->mAnimations[ mCurrentAnimIndex ] : NULL; + return static_cast( mCurrentAnimIndex ) < mScene->mNumAnimations ? mScene->mAnimations[ mCurrentAnimIndex ] : NULL; } protected: @@ -221,7 +224,7 @@ protected: const aiScene* mScene; /** Current animation index */ - size_t mCurrentAnimIndex; + int mCurrentAnimIndex; /** The AnimEvaluator we use to calculate the current pose for the current animation */ AnimEvaluator* mAnimEvaluator; @@ -239,9 +242,6 @@ protected: /** Array to return transformations results inside. */ std::vector mTransforms; - - /** Identity matrix to return a reference to in case of error */ - aiMatrix4x4 mIdentityMatrix; }; } // end of namespace AssimpView diff --git a/tools/assimp_view/Shaders.cpp b/tools/assimp_view/Shaders.cpp index 1b6f3dc88..49ec5320d 100644 --- a/tools/assimp_view/Shaders.cpp +++ b/tools/assimp_view/Shaders.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2015, assimp team +Copyright (c) 2006-2019, assimp team All rights reserved. diff --git a/tools/assimp_view/assimp_view.cpp b/tools/assimp_view/assimp_view.cpp index 746a4836f..1bcdce967 100644 --- a/tools/assimp_view/assimp_view.cpp +++ b/tools/assimp_view/assimp_view.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -47,9 +47,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #ifdef __MINGW32__ -#include +# include #else -#include +# include #endif using namespace std; @@ -310,9 +310,10 @@ int LoadAsset() // Delete the loaded asset // The function does nothing is no asset is loaded //------------------------------------------------------------------------------- -int DeleteAsset(void) -{ - if (!g_pcAsset)return 0; +int DeleteAsset(void) { + if (!g_pcAsset) { + return 0; + } // don't anymore know why this was necessary ... CDisplay::Instance().OnRender(); @@ -349,9 +350,7 @@ int DeleteAsset(void) // p_avOut Receives the min/max boundaries. Must point to 2 vec3s // piMatrix Transformation matrix of the graph at this position //------------------------------------------------------------------------------- -int CalculateBounds(aiNode* piNode, aiVector3D* p_avOut, - const aiMatrix4x4& piMatrix) -{ +int CalculateBounds(aiNode* piNode, aiVector3D* p_avOut, const aiMatrix4x4& piMatrix) { ai_assert(NULL != piNode); ai_assert(NULL != p_avOut); @@ -509,19 +508,28 @@ int CreateAssetData() unsigned int nidx; switch (mesh->mPrimitiveTypes) { case aiPrimitiveType_POINT: - nidx = 1;break; + nidx = 1; + break; case aiPrimitiveType_LINE: - nidx = 2;break; + nidx = 2; + break; case aiPrimitiveType_TRIANGLE: - nidx = 3;break; - default: ai_assert(false); + nidx = 3; + break; + default: + ai_assert(false); + break; }; + unsigned int numIndices = mesh->mNumFaces * 3; + if (0 == numIndices && nidx == 1) { + numIndices = mesh->mNumVertices; + } // check whether we can use 16 bit indices - if (mesh->mNumFaces * 3 >= 65536) { + if (numIndices >= 65536) { // create 32 bit index buffer if(FAILED( g_piDevice->CreateIndexBuffer( 4 * - mesh->mNumFaces * nidx, + numIndices, D3DUSAGE_WRITEONLY | dwUsage, D3DFMT_INDEX32, D3DPOOL_DEFAULT, @@ -547,7 +555,7 @@ int CreateAssetData() else { // create 16 bit index buffer if(FAILED( g_piDevice->CreateIndexBuffer( 2 * - mesh->mNumFaces * nidx, + numIndices, D3DUSAGE_WRITEONLY | dwUsage, D3DFMT_INDEX16, D3DPOOL_DEFAULT, @@ -739,7 +747,7 @@ int DeleteAssetData(bool bNoMaterials) //------------------------------------------------------------------------------- -// Switch beetween zoom/rotate view and the standatd FPS view +// Switch between zoom/rotate view and the standard FPS view // g_bFPSView specifies the view mode to setup //------------------------------------------------------------------------------- int SetupFPSView() @@ -982,7 +990,7 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/) sParams.MultiSampleType = sMSOut; } - // preget the device capabilities. If the hardware vertex shader is too old, we prefer software vertex processing + // get the device capabilities. If the hardware vertex shader is too old, we prefer software vertex processing g_piD3D->GetDeviceCaps( 0, D3DDEVTYPE_HAL, &g_sCaps); DWORD creationFlags = D3DCREATE_MULTITHREADED; if( g_sCaps.VertexShaderVersion >= D3DVS_VERSION( 2, 0)) @@ -1099,17 +1107,13 @@ int CreateDevice (bool p_bMultiSample,bool p_bSuperSample,bool bHW /*= true*/) return 1; } - //------------------------------------------------------------------------------- -//------------------------------------------------------------------------------- -int CreateDevice (void) +int CreateDevice() { return CreateDevice(g_sOptions.bMultiSample, g_sOptions.bSuperSample); } - -//------------------------------------------------------------------------------- //------------------------------------------------------------------------------- int GetProjectionMatrix (aiMatrix4x4& p_mOut) { diff --git a/tools/assimp_view/assimp_view.h b/tools/assimp_view/assimp_view.h index 9317495c1..a32a62d04 100644 --- a/tools/assimp_view/assimp_view.h +++ b/tools/assimp_view/assimp_view.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2018, assimp team +Copyright (c) 2006-2019, assimp team @@ -72,9 +72,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include - -#include "../../code/MaterialSystem.h" // aiMaterial class -#include // ASSIMP_stricmp and ASSIMP_strincmp +#include "Material/MaterialSystem.h" // aiMaterial class +#include // ASSIMP_stricmp and ASSIMP_strincmp #include diff --git a/tools/assimp_view/stdafx.cpp b/tools/assimp_view/stdafx.cpp index 709f0fd9a..bbbb7e0c0 100644 --- a/tools/assimp_view/stdafx.cpp +++ b/tools/assimp_view/stdafx.cpp @@ -1,8 +1,8 @@ // stdafx.cpp : Quelldatei, die nur die Standard-Includes einbindet. // assimp_view.pch ist der vorkompilierte Header. -// stdafx.obj enthält die vorkompilierten Typinformationen. +// stdafx.obj enthält die vorkompilierten Typinformationen. #include "stdafx.h" -// TODO: Auf zusätzliche Header verweisen, die in STDAFX.H +// TODO: Auf zusätzliche Header verweisen, die in STDAFX.H // und nicht in dieser Datei erforderlich sind. diff --git a/tools/assimp_view/stdafx.h b/tools/assimp_view/stdafx.h index 35104d4b0..d3f4692cb 100644 --- a/tools/assimp_view/stdafx.h +++ b/tools/assimp_view/stdafx.h @@ -1,26 +1,26 @@ -// stdafx.h : Includedatei für Standardsystem-Includedateien -// oder häufig verwendete projektspezifische Includedateien, -// die nur in unregelmäßigen Abständen geändert werden. +// stdafx.h : Includedatei für Standardsystem-Includedateien +// oder häufig verwendete projektspezifische Includedateien, +// die nur in unregelmäßigen Abständen geändert werden. // #pragma once -// Ändern Sie folgende Definitionen für Plattformen, die älter als die unten angegebenen sind. -// In MSDN finden Sie die neuesten Informationen über die entsprechenden Werte für die unterschiedlichen Plattformen. -#ifndef WINVER // Lassen Sie die Verwendung spezifischer Features von Windows XP oder später zu. -# define WINVER 0x0501 // Ändern Sie dies in den geeigneten Wert für andere Versionen von Windows. +// Ändern Sie folgende Definitionen für Plattformen, die älter als die unten angegebenen sind. +// In MSDN finden Sie die neuesten Informationen über die entsprechenden Werte für die unterschiedlichen Plattformen. +#ifndef WINVER // Lassen Sie die Verwendung spezifischer Features von Windows XP oder später zu. +# define WINVER 0x0501 // Ändern Sie dies in den geeigneten Wert für andere Versionen von Windows. #endif -#ifndef _WIN32_WINNT // Lassen Sie die Verwendung spezifischer Features von Windows XP oder später zu. -# define _WIN32_WINNT 0x0501 // Ändern Sie dies in den geeigneten Wert für andere Versionen von Windows. +#ifndef _WIN32_WINNT // Lassen Sie die Verwendung spezifischer Features von Windows XP oder später zu. +# define _WIN32_WINNT 0x0501 // Ändern Sie dies in den geeigneten Wert für andere Versionen von Windows. #endif -#ifndef _WIN32_WINDOWS // Lassen Sie die Verwendung spezifischer Features von Windows 98 oder später zu. -# define _WIN32_WINDOWS 0x0410 // Ändern Sie dies in den geeigneten Wert für Windows Me oder höher. +#ifndef _WIN32_WINDOWS // Lassen Sie die Verwendung spezifischer Features von Windows 98 oder später zu. +# define _WIN32_WINDOWS 0x0410 // Ändern Sie dies in den geeigneten Wert für Windows Me oder höher. #endif -#ifndef _WIN32_IE // Lassen Sie die Verwendung spezifischer Features von IE 6.0 oder später zu. -#define _WIN32_IE 0x0600 // Ändern Sie dies in den geeigneten Wert für andere Versionen von IE. +#ifndef _WIN32_IE // Lassen Sie die Verwendung spezifischer Features von IE 6.0 oder später zu. +#define _WIN32_IE 0x0600 // Ändern Sie dies in den geeigneten Wert für andere Versionen von IE. #endif // Windows-Headerdateien: