diff --git a/.gitattributes b/.gitattributes index 7f9357f62..f3df90d38 100644 --- a/.gitattributes +++ b/.gitattributes @@ -13,3 +13,10 @@ CHANGES text eol=lf CREDITS text eol=lf LICENSE text eol=lf Readme.md text eol=lf +# make sure that repo-specific settings (.gitignore, CI-setup,...) +# are excluded from the source-package generated via 'git archive' +.git* export-ignore +/.travis* export-ignore +/.coveralls* export-ignore +appveyor.yml export-ignore + diff --git a/.travis.sh b/.travis.sh index c2852855f..f4ef271e4 100755 --- a/.travis.sh +++ b/.travis.sh @@ -1,11 +1,38 @@ function generate() { - cmake -G "Unix Makefiles" -DASSIMP_NO_EXPORT=$TRAVIS_NO_EXPORT -DBUILD_SHARED_LIBS=$SHARED_BUILD -DASSIMP_COVERALLS=$ENABLE_COVERALLS + OPTIONS="-DASSIMP_WERROR=ON" + + if [ "$DISABLE_EXPORTERS" = "YES" ] ; then + OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=YES" + else + OPTIONS="$OPTIONS -DASSIMP_NO_EXPORT=NO" + fi + + if [ "$SHARED_BUILD" = "ON" ] ; then + OPTIONS="$OPTIONS -DBUILD_SHARED_LIBS=ON" + else + OPTIONS="$OPTIONS -DBUILD_SHARED_LIBS=OFF" + fi + + if [ "$ENABLE_COVERALLS" = "ON" ] ; then + OPTIONS="$OPTIONS -DASSIMP_COVERALLS=ON" + else + OPTIONS="$OPTIONS -DASSIMP_COVERALLS=OFF" + fi + + if [ "$ASAN" = "ON" ] ; then + OPTIONS="$OPTIONS -DASSIMP_ASAN=ON" + else + OPTIONS="$OPTIONS -DASSIMP_ASAN=OFF" + fi + + cmake -G "Unix Makefiles" $OPTIONS } if [ $ANDROID ]; then ant -v -Dmy.dir=${TRAVIS_BUILD_DIR} -f ${TRAVIS_BUILD_DIR}/port/jassimp/build.xml ndk-jni -else +fi +if [ "$TRAVIS_OS_NAME" = "linux" ]; then generate \ && make -j4 \ && sudo make install \ diff --git a/.travis.yml b/.travis.yml index 66523f6a3..3ffa63176 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,58 +1,69 @@ +sudo: required +language: cpp + +cache: ccache + before_install: - - sudo apt-get update -qq - - sudo apt-get install cmake - - sudo apt-get install cmake python3 - - if [ $LINUX ]; then sudo apt-get install -qq freeglut3-dev libxmu-dev libxi-dev ; fi + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get update -qq && sudo apt-get install cmake && sudo apt-get install cmake python3 && sudo apt-get install -qq freeglut3-dev libxmu-dev libxi-dev ; echo -n | openssl s_client -connect scan.coverity.com:443 | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' | sudo tee -a /etc/ssl/certs/ca- ; fi + - 'if [ "$TRAVIS_OS_NAME" = "osx" ]; then + if brew ls --versions cmake > /dev/null; then + echo cmake already installed.; + else + brew install cmake; + fi; + brew install python3; + brew install homebrew/x11/freeglut; + fi' - echo -e "#ifndef A_R_H_INC\n#define A_R_H_INC\n#define GitVersion ${TRAVIS_JOB_ID}\n#define GitBranch \"${TRAVIS_BRANCH}\"\n#endif // A_R_H_INC" > revision.h # install latest LCOV (1.9 was failing) - - cd ${TRAVIS_BUILD_DIR} - - wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz - - tar xf lcov_1.11.orig.tar.gz - - sudo make -C lcov-1.11/ install - - gem install coveralls-lcov - - lcov --version - - g++ --version + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && wget http://ftp.de.debian.org/debian/pool/main/l/lcov/lcov_1.11.orig.tar.gz && tar xf lcov_1.11.orig.tar.gz && sudo make -C lcov-1.11/ install && gem install coveralls-lcov && lcov --version && g++ --version ; fi branches: only: - master -env: - global: - - 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: - - LINUX=1 TRAVIS_NO_EXPORT=YES ENABLE_COVERALLS=ON - - LINUX=1 TRAVIS_NO_EXPORT=NO ENABLE_COVERALLS=OFF - - LINUX=1 SHARED_BUILD=ON ENABLE_COVERALLS=OFF - - LINUX=1 SHARED_BUILD=OFF ENABLE_COVERALLS=OFF - - ANDROID=1 +os: + - linux -language: cpp - compiler: - gcc - clang +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: + - os: linux + compiler: gcc + env: DISABLE_EXPORTERS=YES ENABLE_COVERALLS=ON + - os: linux + compiler: gcc + env: SHARED_BUILD=ON + - os: linux + compiler: clang + env: ASAN=ON + - os: linux + compiler: clang + env: SHARED_BUILD=ON + 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: - - cd ${TRAVIS_BUILD_DIR} # init coverage to 0 (optional) - - lcov --directory . --zerocounters + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && lcov --directory . --zerocounters ; fi script: - export COVERALLS_SERVICE_NAME=travis-ci - export COVERALLS_REPO_TOKEN=abc12345 - . ./.travis.sh - + after_success: - - cd ${TRAVIS_BUILD_DIR} - - lcov --directory . --capture --output-file coverage.info - - lcov --remove coverage.info '/usr/*' 'contrib/*' 'test/*' --output-file coverage.info - - lcov --list coverage.info - - coveralls-lcov --source-encoding=ISO-8859-1 --repo-token=${COVERALLS_TOKEN} coverage.info + - if [ "$TRAVIS_OS_NAME" = "linux" ]; then cd ${TRAVIS_BUILD_DIR} && lcov --directory . --capture --output-file coverage.info && lcov --remove coverage.info '/usr/*' 'contrib/*' 'test/*' --output-file coverage.info && lcov --list coverage.info && coveralls-lcov --source-encoding=ISO-8859-1 --repo-token=${COVERALLS_TOKEN} coverage.info ; fi addons: coverity_scan: diff --git a/CHANGES b/CHANGES index 1d98700f8..d5faab2e0 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,155 @@ ---------------------------------------------------------------------- CHANGELOG ---------------------------------------------------------------------- +4.0.1 (2017-07-28) + - FIXES/HOUSEKEEPING: + - fix version test. + - Not compiling when using ASSIMP_DOUBLE_PRECISION + - Added support for python3 + - Check if cmake is installed with brew + - Low performance in OptimizeMeshesProcess::ProcessNode with huge numbers of meshes + - Elapsed seconds not shown correctly + - StreamReader: fix out-of-range exception + - PPdPmdParser: fix compilation for clang + + +4.0.0 (2017-07-18) + +FEATURES: + - Double precision support provided ( available via cmake option ) + - QT-Widget based assimp-viewer ( works for windows, linux, osx ) + - Open3DGC codec supported by glFT-importer + - glTF: Read and write transparency values + - Add Triangulate post-processing step to glTF exporters + - Update rapidjson to v1.0.2 + - Added method to append new metadata to structure + - Unittests: intoduce a prototype model differ + - X3D support + - AMF support + - Lugdunum3D support + - Obj-Importer: obj-homogeneous_coords support + - Obj-Importer: new streaming handling + - Added support for 64 bit version header introduced in FbxSdk2016 + - Travis: enable coverall support. + - PyAssimp: New version of the pyASSIMP 3D viewer, with much improved 3D controls + - Morph animation support for collada + - Added support for parameters Ni and Tf in OBJ/MTL file format + - aiScene: add method to add children + - Added new option to IFC importer to control tessellation angle + removed unused IFC option + - aiMetaData: introduce aiMetaData::Dealloc + - Samples: add a DX11 example + - travis ci: test on OXS ( XCode 6.3 ) as well + - travis ci: enable sudo support. + - openddlparser: integrate release v0.4.0 + - aiMetaData: Added support for metadata in assbin format + +FIXES/HOUSEKEEPING: + - Introduce usage of #pragma statement + - Put cmake-scripts into their own folder + - Fix install pathes ( issue 938 ) + - Fix object_compare in blender importer( issue 946 ) + - Fix OSX compilation error + - Fix unzip path when no other version was found ( issue 967 ) + - Set _FILE_OFFSET_BITS=64 for 32-bit linux ( issue 975 ) + - Fix constructor for radjson on OSX + - Use Assimp namespace to fix build for big-endian architectures + - Add -fPIC to C Flags for 64bit linux Shared Object builds + - MDLLoader: fix resource leak. + - MakeVerboseFormat: fix invalid delete statement + - IFC: fix possible use after free access bug + - ComputeUVMappingprocess: add missing initialization for scalar value + - Fix invalid release of mat + mesh + - IrrImporter: Fix release functions + - Split mesh before exporting gltf ( issue 995 ) + - 3MFImporter: add source group for visual studio + - IFC: Switch generated file to 2 files to fix issue related to and ( issue 1084 ) + - OBJParser: set material index when changing current material + - OBJ: check for null mesh before updating material index + - add vertex color export support ( issue 809 ) + - Fix memory leak in Collada importer ( issue 1169 ) + - add stp to the list of supported extensions for step-files ( issue 1183 ) + - fix clang build ( Issue-1169 ) + - fix for FreeBSD + - Import FindPkgMacros to main CMake Configuration + - Extended support for tessellation parameter to more IFC shapes + - defensice handling of utf-8 decode issues ( issue 1211 ) + - Fixed compiler error on clang 4.0 running on OSX + - use test extension for exported test files ( issue 1228 ) + - Set UVW index material properties for OBJ files + - Fixed no member named 'atop' in global namespace issue for Android NDK compilation + - Apply mechanism to decide use for IrrXML external or internal + - Fix static init ordering bug in OpenGEX importer + - GLTF exporter: ensure animation accessors have same count + - GLTF exporter: convert animation time from ticks to seconds + - Add support for reading texture coordinates from PLY meshes with properties named 'texture_u' and 'texture_v' + - Added TokensForSearch in BlenderLoader to allow CanRead return true for in-memory files. + - fix wrong delete ( issue 1266 ) + - OpenGEX: fix invalid handling with color4 token ( issue 1262 ) + - LWOLoader: fix link in loader description + - Fix error when custom CMAKE_C_FLAGS is specified + - Fast-atof: log overflow errors + - Obj-Importer: do not break when detecting an overflow ( issue 1244 ) + - Obj-Importer: fix parsing of multible line data definitions + - Fixed bug where IFC models with multiple IFCSite only loaded 1 site instead of the complete model + - PLYImporter: - optimize memory and speed on ply importer / change parser to use a file stream - manage texture path in ply + import - manage texture coords on faces in ply import - correction on point cloud faces generation + - Utf8: integrate new lib ( issue 1158 ) + - fixed CMAKE_MODULE_PATH overwriting previous values + - OpenGEX: Fixed bug in material color processing ( issue 1271 ) + - SceneCombiner: move header for scenecombiner to public folder. + - GLTF exporter: ensure buffer view byte offsets are correctly aligned + - X3D importer: Added EXPORT and IMPORT to the list of ignored XML tags + - X3D Exporter: fixed missing attributes + - X3D importer: Fixed import of normals for the single index / normal per vertex case + - X3D importer: Fixed handling of inlined files + - X3D importer: fixed whitespace handling (issue 1202) + - X3D importer: Fixed iterator on MSVC 2015 + - X3D importer: Fixed problems with auto, override and regex on older compilers + - X3D importer: Fixed missing header file + - X3D importer: Fixed path handling + - X3D importer: Implemented support for binary X3D files + - fix build without 3DS ( issue 1319 ) + - pyassimp: Fixed indices for IndexedTriangleFanSet, IndexedTriangleSet and IndexedTriangleStripSet + - Fixes parameters to pyassimp.load + - Obj-Importe: Fixed texture bug due simultaneously using 'usemtl' and 'usemap' attributes + - check if all exporters are disabled ( issue 1320 ) + - Remove std functions deprecated by C++11. + - X-Importer: make it deal with lines + - use correct path for compilers ( issue 1335 ) + - Collada: add workaround to deal with polygon with holes + - update python readme + - Use unique node names when loading Collada files + - Fixed many FBX bugs + +API COMPATIBILITY: + - Changed ABI-compatibility to v3.3.1, please rebuild your precompiled libraries ( see issue 1182 ) + - VS2010 outdated 3.3.1 (2016-07-08) @@ -121,8 +270,6 @@ API COMPATIBILITY: - Note: 3.0 is not binary compatible with 2.0 - - 2.0 (2010-11-21) FEATURES: @@ -159,10 +306,7 @@ API CHANGES: currently used, however ...) - Some Assimp::Importer methods are const now. - - - - + 1.1 (2010-04-17) This is the list of relevant changes from the 1.0 (r412) release to 1.1 (r700). diff --git a/CMakeLists.txt b/CMakeLists.txt index c4a08518c..c30278b7f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ # 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 ) +CMAKE_MINIMUM_REQUIRED( VERSION 2.8 ) PROJECT( Assimp ) # All supported options ############################################### @@ -62,11 +62,11 @@ OPTION( ASSIMP_BUILD_ZLIB "Build your own zlib" OFF ) -option( ASSIMP_BUILD_ASSIMP_TOOLS +OPTION( ASSIMP_BUILD_ASSIMP_TOOLS "If the supplementary tools for Assimp are built in addition to the library." ON ) -option ( ASSIMP_BUILD_SAMPLES +OPTION ( ASSIMP_BUILD_SAMPLES "If the official samples are built as well (needs Glut)." OFF ) @@ -75,12 +75,32 @@ OPTION ( ASSIMP_BUILD_TESTS ON ) OPTION ( ASSIMP_COVERALLS - "Eańable this to measure test coverage." - OFF + "Enable this to measure test coverage." + OFF +) +OPTION ( ASSIMP_WERROR + "Treat warnings as errors." + OFF +) +OPTION ( ASSIMP_ASAN + "Enable AddressSanitizer." + OFF +) +OPTION ( SYSTEM_IRRXML + "Use system installed Irrlicht/IrrXML library." + OFF +) +OPTION ( BUILD_DOCS + "Build documentation using Doxygen." + OFF ) +if (WIN32) + ADD_DEFINITIONS( -DWIN32_LEAN_AND_MEAN ) +endif() + IF(MSVC) - set (CMAKE_PREFIX_PATH "D:\\libs\\devil") + SET (CMAKE_PREFIX_PATH "D:\\libs\\devil") OPTION( ASSIMP_INSTALL_PDB "Install MSVC debug files." ON @@ -88,21 +108,24 @@ IF(MSVC) ENDIF(MSVC) IF(NOT BUILD_SHARED_LIBS) + MESSAGE(STATUS "Shared libraries disabled") SET(LINK_SEARCH_START_STATIC TRUE) +ELSE() + MESSAGE(STATUS "Shared libraries enabled") ENDIF(NOT BUILD_SHARED_LIBS) # Define here the needed parameters -SET (ASSIMP_VERSION_MAJOR 3) -SET (ASSIMP_VERSION_MINOR 3) -SET (ASSIMP_VERSION_PATCH 1) # subversion revision? +SET (ASSIMP_VERSION_MAJOR 4) +SET (ASSIMP_VERSION_MINOR 0) +SET (ASSIMP_VERSION_PATCH 1) SET (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH}) -SET (ASSIMP_SOVERSION 3) +SET (ASSIMP_SOVERSION 4) SET (PROJECT_VERSION "${ASSIMP_VERSION}") -SET(ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources") +SET( ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources" ) # Needed for openddl_parser config, no use of c++11 at this moment -add_definitions( -DOPENDDL_NO_USE_CPP11 ) +ADD_DEFINITIONS( -DOPENDDL_NO_USE_CPP11 ) set_property( GLOBAL PROPERTY CXX_STANDARD 11 ) # Get the current working branch @@ -124,66 +147,92 @@ EXECUTE_PROCESS( ) IF(NOT GIT_COMMIT_HASH) - SET(GIT_COMMIT_HASH 0) + SET(GIT_COMMIT_HASH 0) ENDIF(NOT GIT_COMMIT_HASH) IF(ASSIMP_DOUBLE_PRECISION) - ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION) + ADD_DEFINITIONS(-DASSIMP_DOUBLE_PRECISION) ENDIF(ASSIMP_DOUBLE_PRECISION) -configure_file( +CONFIGURE_FILE( ${CMAKE_CURRENT_LIST_DIR}/revision.h.in ${CMAKE_CURRENT_BINARY_DIR}/revision.h ) -configure_file( +CONFIGURE_FILE( ${CMAKE_CURRENT_LIST_DIR}/include/assimp/config.h.in - ${CMAKE_CURRENT_LIST_DIR}/include/assimp/config.h + ${CMAKE_CURRENT_BINARY_DIR}/include/assimp/config.h ) -include_directories( +INCLUDE_DIRECTORIES( ./ + include ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/include ) -SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules" ) +LIST(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules" ) SET(LIBASSIMP_COMPONENT "libassimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH}" ) SET(LIBASSIMP-DEV_COMPONENT "libassimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH}-dev" ) SET(CPACK_COMPONENTS_ALL assimp-bin ${LIBASSIMP_COMPONENT} ${LIBASSIMP-DEV_COMPONENT} assimp-dev) SET(ASSIMP_LIBRARY_SUFFIX "" CACHE STRING "Suffix to append to library names") -# Ensure that we do not run into issues like http://www.tcm.phy.cam.ac.uk/sw/inodes64.html on 32 bit linux IF( UNIX ) + # Ensure that we do not run into issues like http://www.tcm.phy.cam.ac.uk/sw/inodes64.html on 32 bit linux IF ( CMAKE_SIZEOF_VOID_P EQUAL 4) # only necessary for 32-bit linux ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64 ) ENDIF() -ENDIF() -IF((CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) AND NOT CMAKE_COMPILER_IS_MINGW) - IF (BUILD_SHARED_LIBS AND CMAKE_SIZEOF_VOID_P EQUAL 8) # -fPIC is only required for shared libs on 64 bit - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") - ENDIF() + # Use GNUInstallDirs for Unix predefined directories + INCLUDE(GNUInstallDirs) +ENDIF( UNIX ) + + +# Grouped compiler settings +IF ((CMAKE_C_COMPILER_ID MATCHES "GNU") AND NOT CMAKE_COMPILER_IS_MINGW) # hide all not-exported symbols - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -Wall -std=c++0x" ) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -std=c++0x") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + SET(LIBSTDC++_LIBRARIES -lstdc++) ELSEIF(MSVC) # enable multi-core compilation with MSVC add_compile_options(/MP) -ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -Wall -Wno-long-long -pedantic -std=c++11" ) + + # disable "elements of array '' will be default initialized" warning on MSVC2013 + IF(MSVC12) + add_compile_options(/wd4351) + ENDIF() +ELSEIF ( "${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang" ) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -fvisibility=hidden -fPIC -Wall -Wno-long-long -std=c++11" ) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") ELSEIF( CMAKE_COMPILER_IS_MINGW ) - SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wall -Wno-long-long -pedantic -std=c++11" ) - add_definitions( -U__STRICT_ANSI__ ) + SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wall -Wno-long-long -std=c++11" ) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + ADD_DEFINITIONS( -U__STRICT_ANSI__ ) ENDIF() if (ASSIMP_COVERALLS) - include(Coveralls) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") + MESSAGE(STATUS "Coveralls enabled") + INCLUDE(Coveralls) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") endif() -INCLUDE_DIRECTORIES( include ) +if (ASSIMP_WERROR) + MESSAGE(STATUS "Treating warnings as errors") + IF (MSVC) + add_compile_options(/WX) + ELSE() + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror") + ENDIF() +endif() + +if (ASSIMP_ASAN) + MESSAGE(STATUS "AddressSanitizer enabled") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") +endif() INCLUDE (FindPkgMacros) INCLUDE (PrecompiledHeader) @@ -215,20 +264,25 @@ ENDIF() # Only generate this target if no higher-level project already has IF (NOT TARGET uninstall) # add make uninstall capability - configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) + CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/cmake-modules/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" IMMEDIATE @ONLY) add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") 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}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE) +CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" @ONLY IMMEDIATE) +CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/assimp-config-version.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" @ONLY IMMEDIATE) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/assimp-config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/assimp-config-version.cmake" DESTINATION "${ASSIMP_LIB_INSTALL_DIR}/cmake/assimp-${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}" COMPONENT ${LIBASSIMP-DEV_COMPONENT}) FIND_PACKAGE( DirectX ) -IF( CMAKE_COMPILER_IS_GNUCXX ) - SET(LIBSTDC++_LIBRARIES -lstdc++) -ENDIF( CMAKE_COMPILER_IS_GNUCXX ) +IF( BUILD_DOCS ) + add_subdirectory(doc) +ENDIF( BUILD_DOCS ) + +# Look for system installed irrXML +IF ( SYSTEM_IRRXML ) + find_package( IrrXML REQUIRED ) +ENDIF( SYSTEM_IRRXML ) # Search for external dependencies, and build them from source if not found # Search for zlib @@ -238,9 +292,9 @@ ENDIF( NOT ASSIMP_BUILD_ZLIB ) IF( NOT ZLIB_FOUND ) message(STATUS "compiling zlib from souces") - include(CheckIncludeFile) - include(CheckTypeSize) - include(CheckFunctionExists) + INCLUDE(CheckIncludeFile) + INCLUDE(CheckTypeSize) + INCLUDE(CheckFunctionExists) # compile from sources add_subdirectory(contrib/zlib) SET(ZLIB_FOUND 1) @@ -324,6 +378,8 @@ ELSE (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) ADD_DEFINITIONS( -DASSIMP_BUILD_NO_C4D_IMPORTER ) ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) +ADD_SUBDIRECTORY(contrib) + ADD_SUBDIRECTORY( code/ ) IF ( ASSIMP_BUILD_ASSIMP_TOOLS ) IF ( WIN32 AND DirectX_D3DX9_LIBRARY ) @@ -427,29 +483,41 @@ IF(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES) ENDIF() if(WIN32) - if (CMAKE_SIZEOF_VOID_P EQUAL 8) - SET(BIN_DIR "${PROJECT_SOURCE_DIR}/bin64/") - SET(LIB_DIR "${PROJECT_SOURCE_DIR}/lib64/") - elseif() - SET(BIN_DIR "${PROJECT_SOURCE_DIR}/bin32/") - SET(LIB_DIR "${PROJECT_SOURCE_DIR}/lib32/") - ENDIF() + if (CMAKE_SIZEOF_VOID_P EQUAL 8) + SET(BIN_DIR "${PROJECT_SOURCE_DIR}/bin64/") + SET(LIB_DIR "${PROJECT_SOURCE_DIR}/lib64/") + elseif() + 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") - ENDIF(MSVC12) + if(MSVC12) + SET(ASSIMP_MSVC_VERSION "vc120") + elseif(MSVC14) + SET(ASSIMP_MSVC_VERSION "vc140") + ENDIF(MSVC12) - if(MSVC12 OR MSVC14) - add_custom_target(UpdateAssimpLibsDebugSymbolsAndDLLs COMMENT "Copying Assimp Libraries ..." VERBATIM) - add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.dll ${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.dll VERBATIM) - add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.exp ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.exp VERBATIM) - add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.lib ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.lib VERBATIM) - add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.dll ${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.dll VERBATIM) - add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.exp ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.exp VERBATIM) - add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.ilk ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.ilk VERBATIM) - add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.lib ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.lib VERBATIM) - add_custom_command(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM) - ENDIF(MSVC12 OR MSVC14) + if(MSVC12 OR MSVC14) + add_custom_target(UpdateAssimpLibsDebugSymbolsAndDLLs COMMENT "Copying Assimp Libraries ..." VERBATIM) + IF(CMAKE_GENERATOR MATCHES "^Visual Studio") + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.dll ${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.dll VERBATIM) + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.exp ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.exp VERBATIM) + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Release/assimp-${ASSIMP_MSVC_VERSION}-mt.lib ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.lib VERBATIM) + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.dll ${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.dll VERBATIM) + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.exp ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.exp VERBATIM) + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.ilk ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.ilk VERBATIM) + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.lib ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.lib VERBATIM) + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/Debug/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM) + ELSE() + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mt.dll ${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.dll VERBATIM) + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mt.exp ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.exp VERBATIM) + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mt.lib ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mt.lib VERBATIM) + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.dll ${BIN_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.dll VERBATIM) + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.exp ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.exp VERBATIM) + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.ilk ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.ilk VERBATIM) + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.lib ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.lib VERBATIM) + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM) + ADD_CUSTOM_COMMAND(TARGET UpdateAssimpLibsDebugSymbolsAndDLLs COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_BINARY_DIR}/code/assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb ${LIB_DIR}assimp-${ASSIMP_MSVC_VERSION}-mtd.pdb VERBATIM) + ENDIF() + ENDIF(MSVC12 OR MSVC14) ENDIF (WIN32) diff --git a/CREDITS b/CREDITS index 219079168..43134ac03 100644 --- a/CREDITS +++ b/CREDITS @@ -157,4 +157,4 @@ Contributed ExportProperties interface Contributed X File exporter Contributed Step (stp) exporter - +For a more detailed list just check: https://github.com/assimp/assimp/network/members diff --git a/Readme.md b/Readme.md index 8ba8bbf54..1eaa6b8e1 100644 --- a/Readme.md +++ b/Readme.md @@ -1,6 +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 ### [![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) @@ -8,22 +9,24 @@ Open Asset Import Library (assimp) src="https://scan.coverity.com/projects/5607/badge.svg"/> [![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)
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. 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 trunk containing the latest features and bugfixes. For productive use though, we recommend one of the stable releases available from [assimp.sf.net](http://assimp.sf.net) or from *nix package repositories. -The current build status is: +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). -Gitter chat: [![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)
- -And we also have an IRC-channel at freenode: #assetimporterlib . You can easily join us via: [KiwiIRC/freenote](https://kiwiirc.com/client/irc.freenode.net), choose your nickname and type -> /join #assetimporterlib +Monthly donations via Patreon: +
[![Patreon](https://cloud.githubusercontent.com/assets/8225057/5990484/70413560-a9ab-11e4-8942-1a63607c0b00.png)](http://www.patreon.com/assimp) + +
+ +One-off donations via PayPal: +
[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4JRJVPXC4QJM4)
-__[open3mod](https://github.com/acgessler/open3mod) is a powerful 3D model viewer based on Assimp's import and export abilities.__ Please check our Wiki as well: https://github.com/assimp/assimp/wiki @@ -31,50 +34,67 @@ Please check our Wiki as well: https://github.com/assimp/assimp/wiki A full list [is here](http://assimp.org/main_features_formats.html). __Importers__: - +- 3D - 3DS -- BLEND (Blender) -- DAE/Collada -- FBX -- IFC-STEP +- 3MF +- AC +- AC3D +- ACC +- AMJ - ASE +- ASK +- B3D; +- BLEND (Blender) +- BVH +- COB +- CMS +- DAE/Collada - DXF -- HMP +- ENFF +- FBX +- glTF 1.0 + GLB +- glTF 2.0 +- HMB +- IFC-STEP +- IRR / IRRMESH +- LWO +- LWS +- LXO - MD2 - MD3 - MD5 - MDC - MDL -- NFF -- PLY -- STL -- X -- OBJ -- OpenGEX -- SMD -- LWO -- LXO -- LWS -- TER -- AC3D +- MESH / MESH.XML +- MOT - MS3D -- COB -- Q3BSP -- XGL -- CSM -- BVH -- B3D - NDO -- Ogre Binary -- Ogre XML -- Q3D -- ASSBIN (Assimp custom format) -- glTF (partial) -- 3MF +- NFF +- OBJ +- OFF +- OGEX +- PLY +- PMX +- PRJ +- Q3O +- Q3S +- RAW +- SCN +- SIB +- SMD +- STL +- STP +- TER +- UC +- VTA +- X +- X3D +- XGL +- ZGL Additionally, some formats are supported by dependency on non-free code or external SDKs (not built by default): -- C4D (https://github.com/acgessler/assimp-cinema4d) +- C4D (https://github.com/assimp/assimp/wiki/Cinema4D-&-Melange) __Exporters__: @@ -87,7 +107,8 @@ __Exporters__: - JSON (for WebGl, via https://github.com/acgessler/assimp2json) - ASSBIN - STEP -- glTF (partial) +- glTF 1.0 (partial) +- glTF 2.0 (partial) ### Building ### Take a look into the `INSTALL` file. Our build system is CMake, if you used CMake before there is a good chance you know what to do. @@ -98,6 +119,11 @@ Take a look into the `INSTALL` file. Our build system is CMake, if you used CMak * [.NET](port/AssimpNET/Readme.md) * [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 (currently supported obj, ply, stl, ~collada) + +### 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: @@ -133,10 +159,6 @@ And we also have a Gitter-channel:Gitter [![Join the chat at https://gitter.im/a Contributions to assimp are highly appreciated. The easiest way to get involved is to submit a pull request with your changes against the main repository's `master` branch. -### Donate ### -You can get a patron of Asset-Importer-Lib: -Become a Patron! - ### License ### Our license is based on the modified, __3-clause BSD__-License. diff --git a/appveyor.yml b/appveyor.yml index 991cf5bc1..b8828710b 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -29,8 +29,8 @@ install: build_script: - cd c:\projects\assimp -- if "%platform%" equ "x64" (cmake CMakeLists.txt -G "Visual Studio %Configuration% Win64") -- if "%platform%" equ "x86" (cmake CMakeLists.txt -G "Visual Studio %Configuration%") +- if "%platform%" equ "x64" (cmake CMakeLists.txt -DASSIMP_WERROR=ON -G "Visual Studio %Configuration% Win64") +- if "%platform%" equ "x86" (cmake CMakeLists.txt -DASSIMP_WERROR=ON -G "Visual Studio %Configuration%") - if "%platform%" equ "x64" (msbuild /m /p:Configuration=Release /p:Platform="x64" Assimp.sln) - if "%platform%" equ "x86" (msbuild /m /p:Configuration=Release /p:Platform="Win32" Assimp.sln) diff --git a/cmake-modules/FindDevIL.cmake b/cmake-modules/FindDevIL.cmake new file mode 100644 index 000000000..381a75dd2 --- /dev/null +++ b/cmake-modules/FindDevIL.cmake @@ -0,0 +1,72 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#.rst: +# FindDevIL +# --------- +# +# +# +# This module locates the developer's image library. +# http://openil.sourceforge.net/ +# +# This module sets: +# +# :: +# +# IL_LIBRARIES - the name of the IL library. These include the full path to +# the core DevIL library. This one has to be linked into the +# application. +# ILU_LIBRARIES - the name of the ILU library. Again, the full path. This +# library is for filters and effects, not actual loading. It +# doesn't have to be linked if the functionality it provides +# is not used. +# ILUT_LIBRARIES - the name of the ILUT library. Full path. This part of the +# library interfaces with OpenGL. It is not strictly needed +# in applications. +# IL_INCLUDE_DIR - where to find the il.h, ilu.h and ilut.h files. +# IL_FOUND - this is set to TRUE if all the above variables were set. +# This will be set to false if ILU or ILUT are not found, +# even if they are not needed. In most systems, if one +# library is found all the others are as well. That's the +# way the DevIL developers release it. + +# TODO: Add version support. +# Tested under Linux and Windows (MSVC) + +#include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) +include(FindPackageHandleStandardArgs) + +find_path(IL_INCLUDE_DIR il.h + PATH_SUFFIXES include IL + DOC "The path to the directory that contains il.h" +) + +#message("IL_INCLUDE_DIR is ${IL_INCLUDE_DIR}") + +find_library(IL_LIBRARIES + NAMES IL DEVIL + PATH_SUFFIXES lib64 lib lib32 + DOC "The file that corresponds to the base il library." +) + +#message("IL_LIBRARIES is ${IL_LIBRARIES}") + +find_library(ILUT_LIBRARIES + NAMES ILUT + PATH_SUFFIXES lib64 lib lib32 + DOC "The file that corresponds to the il (system?) utility library." +) + +#message("ILUT_LIBRARIES is ${ILUT_LIBRARIES}") + +find_library(ILU_LIBRARIES + NAMES ILU + PATH_SUFFIXES lib64 lib lib32 + DOC "The file that corresponds to the il utility library." +) + +#message("ILU_LIBRARIES is ${ILU_LIBRARIES}") + +FIND_PACKAGE_HANDLE_STANDARD_ARGS(IL DEFAULT_MSG + IL_LIBRARIES IL_INCLUDE_DIR) diff --git a/cmake-modules/FindIrrXML.cmake b/cmake-modules/FindIrrXML.cmake new file mode 100644 index 000000000..5434e0b86 --- /dev/null +++ b/cmake-modules/FindIrrXML.cmake @@ -0,0 +1,17 @@ +# Find IrrXMl from irrlicht project +# +# Find LibIrrXML headers and library +# +# IRRXML_FOUND - IrrXML found +# IRRXML_INCLUDE_DIR - Headers location +# IRRXML_LIBRARY - IrrXML main library + +find_path(IRRXML_INCLUDE_DIR irrXML.h + PATH_SUFFIXES include/irrlicht include/irrxml) +find_library(IRRXML_LIBRARY IrrXML) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(IrrXML REQUIRED_VARS IRRXML_INCLUDE_DIR IRRXML_LIBRARY) + + +mark_as_advanced(IRRXML_INCLUDE_DIR IRRXML_LIBRARY) diff --git a/code/3DSConverter.cpp b/code/3DSConverter.cpp index 8390dd216..820c28f90 100644 --- a/code/3DSConverter.cpp +++ b/code/3DSConverter.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -55,18 +56,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; +static const unsigned int NotSet = 0xcdcdcdcd; + // ------------------------------------------------------------------------------------------------ // Setup final material indices, generae a default material if necessary void Discreet3DSImporter::ReplaceDefaultMaterial() { - // Try to find an existing material that matches the // typical default material setting: // - no textures // - diffuse color (in grey!) // NOTE: This is here to workaround the fact that some // exporters are writing a default material, too. - unsigned int idx = 0xcdcdcdcd; + unsigned int idx( NotSet ); for (unsigned int i = 0; i < mScene->mMaterials.size();++i) { std::string s = mScene->mMaterials[i].mName; @@ -92,7 +94,9 @@ void Discreet3DSImporter::ReplaceDefaultMaterial() } idx = i; } - if (0xcdcdcdcd == idx)idx = (unsigned int)mScene->mMaterials.size(); + if ( NotSet == idx ) { + idx = ( unsigned int )mScene->mMaterials.size(); + } // now iterate through all meshes and through all faces and // find all faces that are using the default material diff --git a/code/3DSExporter.cpp b/code/3DSExporter.cpp index 1d49a536b..642f7dc57 100644 --- a/code/3DSExporter.cpp +++ b/code/3DSExporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -45,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "3DSExporter.h" #include "3DSLoader.h" #include "3DSHelper.h" -#include "SceneCombiner.h" +#include #include "SplitLargeMeshes.h" #include "StringComparison.h" #include diff --git a/code/3DSExporter.h b/code/3DSExporter.h index 8bcce338d..dd3c4d427 100644 --- a/code/3DSExporter.h +++ b/code/3DSExporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/3DSHelper.h b/code/3DSHelper.h index 699767cee..d5a51dfb7 100644 --- a/code/3DSHelper.h +++ b/code/3DSHelper.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/3DSLoader.cpp b/code/3DSLoader.cpp index f0285a899..704884a57 100644 --- a/code/3DSLoader.cpp +++ b/code/3DSLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -1380,7 +1381,7 @@ void Discreet3DSImporter::ParseColorChunk( aiColor3D* out, bool acceptPercent ) bGamma = true; case Discreet3DS::CHUNK_RGBF: - if (sizeof(ai_real) * 3 > diff) { + if (sizeof(float) * 3 > diff) { *out = clrError; return; } diff --git a/code/3DSLoader.h b/code/3DSLoader.h index 26b2a935e..0e377180b 100644 --- a/code/3DSLoader.h +++ b/code/3DSLoader.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ACLoader.cpp b/code/ACLoader.cpp index bca24e948..a30baa75a 100644 --- a/code/ACLoader.cpp +++ b/code/ACLoader.cpp @@ -4,7 +4,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/ACLoader.h b/code/ACLoader.h index 52563adad..4b202b77a 100644 --- a/code/ACLoader.h +++ b/code/ACLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/AMFImporter.cpp b/code/AMFImporter.cpp index 0ebfcbcc4..e9211fe53 100644 --- a/code/AMFImporter.cpp +++ b/code/AMFImporter.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/AMFImporter.hpp b/code/AMFImporter.hpp index 9731f2e41..561ec3c8f 100644 --- a/code/AMFImporter.hpp +++ b/code/AMFImporter.hpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/AMFImporter_Geometry.cpp b/code/AMFImporter_Geometry.cpp index 493d06bff..afba3f2bc 100644 --- a/code/AMFImporter_Geometry.cpp +++ b/code/AMFImporter_Geometry.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/AMFImporter_Macro.hpp b/code/AMFImporter_Macro.hpp index 973e17490..b7c0f9863 100644 --- a/code/AMFImporter_Macro.hpp +++ b/code/AMFImporter_Macro.hpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/AMFImporter_Material.cpp b/code/AMFImporter_Material.cpp index 4550f6fe2..d15099fac 100644 --- a/code/AMFImporter_Material.cpp +++ b/code/AMFImporter_Material.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/AMFImporter_Node.hpp b/code/AMFImporter_Node.hpp index f8c3a7933..cb8b0b66d 100644 --- a/code/AMFImporter_Node.hpp +++ b/code/AMFImporter_Node.hpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -59,18 +60,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /// \class CAMFImporter_NodeElement /// Base class for elements of nodes. -class CAMFImporter_NodeElement -{ - /***********************************************/ - /******************** Types ********************/ - /***********************************************/ +class CAMFImporter_NodeElement { public: - - /// \enum EType /// Define what data type contain node element. - enum EType - { + enum EType { ENET_Color, ///< Color element: . ENET_Constellation,///< Grouping element: . ENET_Coordinates, ///< Coordinates element: . @@ -91,52 +85,37 @@ public: ENET_Invalid ///< Element has invalid type and possible contain invalid data. }; - /***********************************************/ - /****************** Constants ******************/ - /***********************************************/ - -public: - const EType Type;///< Type of element. - - /***********************************************/ - /****************** Variables ******************/ - /***********************************************/ - -public: - std::string ID;///< ID of element. - CAMFImporter_NodeElement* Parent;///< Parrent element. If nullptr then this node is root. + CAMFImporter_NodeElement* Parent;///< Parent element. If nullptr then this node is root. std::list Child;///< Child elements. - /***********************************************/ - /****************** Functions ******************/ - /***********************************************/ +public: /// Destructor, virtual.. + virtual ~CAMFImporter_NodeElement() { + // empty + } private: - - /// \fn CAMFImporter_NodeElement(const CAMFImporter_NodeElement& pNodeElement) /// Disabled copy constructor. CAMFImporter_NodeElement(const CAMFImporter_NodeElement& pNodeElement); - /// \fn CAMFImporter_NodeElement& operator=(const CAMFImporter_NodeElement& pNodeElement) /// Disabled assign operator. CAMFImporter_NodeElement& operator=(const CAMFImporter_NodeElement& pNodeElement); - /// \fn CAMFImporter_NodeElement() /// Disabled default constructor. CAMFImporter_NodeElement(); protected: - - /// \fn CAMFImporter_NodeElement(const EType pType, CAMFImporter_NodeElement* pParent) /// In constructor inheritor must set element type. /// \param [in] pType - element type. /// \param [in] pParent - parent element. CAMFImporter_NodeElement(const EType pType, CAMFImporter_NodeElement* pParent) - : Type(pType), Parent(pParent) - {} - + : Type(pType) + , ID() + , Parent(pParent) + , Child() { + // empty + } };// class IAMFImporter_NodeElement /// \struct CAMFImporter_NodeElement_Constellation @@ -399,25 +378,23 @@ struct CAMFImporter_NodeElement_Triangle : public CAMFImporter_NodeElement };// struct CAMFImporter_NodeElement_Triangle -/// \struct CAMFImporter_NodeElement_Texture /// Structure that define texture node. -struct CAMFImporter_NodeElement_Texture : public CAMFImporter_NodeElement -{ - /****************** Variables ******************/ - +struct CAMFImporter_NodeElement_Texture : public CAMFImporter_NodeElement { size_t Width, Height, Depth;///< Size of the texture. std::vector Data;///< Data of the texture. bool Tiled; - /****************** Functions ******************/ - - /// \fn CAMFImporter_NodeElement_Texture(CAMFImporter_NodeElement* pParent) /// Constructor. /// \param [in] pParent - pointer to parent node. CAMFImporter_NodeElement_Texture(CAMFImporter_NodeElement* pParent) - : CAMFImporter_NodeElement(ENET_Texture, pParent) - {} - + : CAMFImporter_NodeElement(ENET_Texture, pParent) + , Width( 0 ) + , Height( 0 ) + , Depth( 0 ) + , Data() + , Tiled( false ){ + // empty + } };// struct CAMFImporter_NodeElement_Texture #endif // INCLUDED_AI_AMF_IMPORTER_NODE_H diff --git a/code/AMFImporter_Postprocess.cpp b/code/AMFImporter_Postprocess.cpp index 6f82d5367..789a11eb8 100644 --- a/code/AMFImporter_Postprocess.cpp +++ b/code/AMFImporter_Postprocess.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -49,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AMFImporter.hpp" // Header files, Assimp. -#include "SceneCombiner.h" +#include #include "StandardShapes.h" #include "StringUtils.h" @@ -260,21 +261,20 @@ size_t AMFImporter::PostprocessHelper_GetTextureID_Or_Create(const std::string& size_t off_b = 0; // Calculate size of the target array and rule how data will be copied. - if ( nullptr != src_texture ) { - if(!pID_R.empty()) { - tex_size += src_texture[0]->Data.size(); step++, off_g++, off_b++; - } - if(!pID_G.empty()) { - tex_size += src_texture[1]->Data.size(); step++, off_b++; - } - if(!pID_B.empty()) { - tex_size += src_texture[2]->Data.size(); step++; - } - if(!pID_A.empty()) { - tex_size += src_texture[3]->Data.size(); step++; - } + if(!pID_R.empty() && nullptr != src_texture[ 0 ] ) { + tex_size += src_texture[0]->Data.size(); step++, off_g++, off_b++; } - // Create target array. + if(!pID_G.empty() && nullptr != src_texture[ 1 ] ) { + tex_size += src_texture[1]->Data.size(); step++, off_b++; + } + if(!pID_B.empty() && nullptr != src_texture[ 2 ] ) { + tex_size += src_texture[2]->Data.size(); step++; + } + if(!pID_A.empty() && nullptr != src_texture[ 3 ] ) { + tex_size += src_texture[3]->Data.size(); step++; + } + + // Create target array. converted_texture.Data = new uint8_t[tex_size]; // And copy data auto CopyTextureData = [&](const std::string& pID, const size_t pOffset, const size_t pStep, const uint8_t pSrcTexNum) -> void @@ -686,7 +686,6 @@ std::list mesh_idx; tmesh->mNumVertices = static_cast(vert_arr.size()); tmesh->mVertices = new aiVector3D[tmesh->mNumVertices]; tmesh->mColors[0] = new aiColor4D[tmesh->mNumVertices]; - tmesh->mFaces = new aiFace[face_list_cur.size()]; memcpy(tmesh->mVertices, vert_arr.data(), tmesh->mNumVertices * sizeof(aiVector3D)); memcpy(tmesh->mColors[0], col_arr.data(), tmesh->mNumVertices * sizeof(aiColor4D)); diff --git a/code/ASELoader.cpp b/code/ASELoader.cpp index 24f63d2d0..16b3c4ad9 100644 --- a/code/ASELoader.cpp +++ b/code/ASELoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -45,6 +46,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER +#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER + // internal headers #include "ASELoader.h" #include "StringComparison.h" @@ -1319,4 +1322,6 @@ bool ASEImporter::GenerateNormals(ASE::Mesh& mesh) { return false; } +#endif // ASSIMP_BUILD_NO_3DS_IMPORTER + #endif // !! ASSIMP_BUILD_NO_BASE_IMPORTER diff --git a/code/ASELoader.h b/code/ASELoader.h index 6ef4d28f8..8a8d4faa4 100644 --- a/code/ASELoader.h +++ b/code/ASELoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -52,6 +53,7 @@ struct aiNode; namespace Assimp { +#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER // -------------------------------------------------------------------------------- /** Importer class for the 3DS ASE ASCII format. @@ -62,9 +64,6 @@ public: ASEImporter(); ~ASEImporter(); - -public: - // ------------------------------------------------------------------- /** Returns whether the class can handle the format of the given file. * See BaseImporter::CanRead() for details. @@ -200,6 +199,9 @@ protected: bool noSkeletonMesh; }; +#endif // ASSIMP_BUILD_NO_3DS_IMPORTER + } // end of namespace Assimp + #endif // AI_3DSIMPORTER_H_INC diff --git a/code/ASEParser.cpp b/code/ASEParser.cpp index b06447cfa..7de80a2d8 100644 --- a/code/ASEParser.cpp +++ b/code/ASEParser.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -45,6 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_ASE_IMPORTER +#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER // internal headers #include "TextureTransform.h" @@ -2150,4 +2152,6 @@ void Parser::ParseLV4MeshLong(unsigned int& iOut) iOut = strtoul10(filePtr,&filePtr); } +#endif // ASSIMP_BUILD_NO_3DS_IMPORTER + #endif // !! ASSIMP_BUILD_NO_BASE_IMPORTER diff --git a/code/ASEParser.h b/code/ASEParser.h index 095d089d4..db64f2a16 100644 --- a/code/ASEParser.h +++ b/code/ASEParser.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -48,6 +49,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER + // for some helper routines like IsSpace() #include "ParsingUtils.h" #include "qnan.h" @@ -661,4 +664,6 @@ public: } // Namespace ASE } // Namespace ASSIMP +#endif // ASSIMP_BUILD_NO_3DS_IMPORTER + #endif // !! include guard diff --git a/code/AssbinExporter.cpp b/code/AssbinExporter.cpp index fcb32c70a..a6fbcd8f7 100644 --- a/code/AssbinExporter.cpp +++ b/code/AssbinExporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -138,6 +139,17 @@ inline size_t Write(IOStream * stream, const aiVector3D& v) return t; } +// ----------------------------------------------------------------------------------- +// Serialize a color value +template <> +inline size_t Write(IOStream * stream, const aiColor3D& v) +{ + size_t t = Write(stream,v.r); + t += Write(stream,v.g); + t += Write(stream,v.b); + return t; +} + // ----------------------------------------------------------------------------------- // Serialize a color value template <> @@ -324,10 +336,13 @@ inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size) { AssbinChunkWriter chunk( container, ASSBIN_CHUNK_AINODE ); + unsigned int nb_metadata = (node->mMetaData != NULL ? node->mMetaData->mNumProperties : 0); + Write(&chunk,node->mName); Write(&chunk,node->mTransformation); Write(&chunk,node->mNumChildren); Write(&chunk,node->mNumMeshes); + Write(&chunk,nb_metadata); for (unsigned int i = 0; i < node->mNumMeshes;++i) { Write(&chunk,node->mMeshes[i]); @@ -336,6 +351,44 @@ inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size) for (unsigned int i = 0; i < node->mNumChildren;++i) { WriteBinaryNode( &chunk, node->mChildren[i] ); } + + for (unsigned int i = 0; i < nb_metadata; ++i) { + const aiString& key = node->mMetaData->mKeys[i]; + aiMetadataType type = node->mMetaData->mValues[i].mType; + void* value = node->mMetaData->mValues[i].mData; + + Write(&chunk, key); + Write(&chunk, type); + + switch (type) { + case AI_BOOL: + Write(&chunk, *((bool*) value)); + break; + case AI_INT32: + Write(&chunk, *((int32_t*) value)); + break; + case AI_UINT64: + Write(&chunk, *((uint64_t*) value)); + break; + case AI_FLOAT: + Write(&chunk, *((float*) value)); + break; + case AI_DOUBLE: + Write(&chunk, *((double*) value)); + break; + case AI_AISTRING: + Write(&chunk, *((aiString*) value)); + break; + case AI_AIVECTOR3D: + Write(&chunk, *((aiVector3D*) value)); + break; +#ifdef SWIG + case FORCE_32BIT: +#endif // SWIG + default: + break; + } + } } // ----------------------------------------------------------------------------------- @@ -597,9 +650,9 @@ inline size_t WriteArray(IOStream * stream, const T* in, unsigned int size) Write(&chunk,l->mAttenuationQuadratic); } - Write(&chunk,(const aiVector3D&)l->mColorDiffuse); - Write(&chunk,(const aiVector3D&)l->mColorSpecular); - Write(&chunk,(const aiVector3D&)l->mColorAmbient); + Write(&chunk,l->mColorDiffuse); + Write(&chunk,l->mColorSpecular); + Write(&chunk,l->mColorAmbient); if (l->mType == aiLightSource_SPOT) { Write(&chunk,l->mAngleInnerCone); diff --git a/code/AssbinExporter.h b/code/AssbinExporter.h index 4a0219c04..55bb9fc82 100644 --- a/code/AssbinExporter.h +++ b/code/AssbinExporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/AssbinLoader.cpp b/code/AssbinLoader.cpp index 408620c3a..f418638e1 100644 --- a/code/AssbinLoader.cpp +++ b/code/AssbinLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -197,8 +198,7 @@ template void ReadBounds( IOStream * stream, T* /*p*/, unsigned int stream->Seek( sizeof(T) * n, aiOrigin_CUR ); } -void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node ) -{ +void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node, aiNode* parent ) { uint32_t chunkID = Read(stream); ai_assert(chunkID == ASSBIN_CHUNK_AINODE); /*uint32_t size =*/ Read(stream); @@ -209,23 +209,65 @@ void AssbinImporter::ReadBinaryNode( IOStream * stream, aiNode** node ) (*node)->mTransformation = Read(stream); (*node)->mNumChildren = Read(stream); (*node)->mNumMeshes = Read(stream); + unsigned int nb_metadata = Read(stream); - if ((*node)->mNumMeshes) - { + if(parent) { + (*node)->mParent = parent; + } + + if ((*node)->mNumMeshes) { (*node)->mMeshes = new unsigned int[(*node)->mNumMeshes]; for (unsigned int i = 0; i < (*node)->mNumMeshes; ++i) { (*node)->mMeshes[i] = Read(stream); } } - if ((*node)->mNumChildren) - { + if ((*node)->mNumChildren) { (*node)->mChildren = new aiNode*[(*node)->mNumChildren]; for (unsigned int i = 0; i < (*node)->mNumChildren; ++i) { - ReadBinaryNode( stream, &(*node)->mChildren[i] ); + ReadBinaryNode( stream, &(*node)->mChildren[i], *node ); } } + if ( nb_metadata > 0 ) { + (*node)->mMetaData = aiMetadata::Alloc(nb_metadata); + for (unsigned int i = 0; i < nb_metadata; ++i) { + (*node)->mMetaData->mKeys[i] = Read(stream); + (*node)->mMetaData->mValues[i].mType = (aiMetadataType) Read(stream); + void* data( nullptr ); + + switch ((*node)->mMetaData->mValues[i].mType) { + case AI_BOOL: + data = new bool(Read(stream)); + break; + case AI_INT32: + data = new int32_t(Read(stream)); + break; + case AI_UINT64: + data = new uint64_t(Read(stream)); + break; + case AI_FLOAT: + data = new float(Read(stream)); + break; + case AI_DOUBLE: + data = new double(Read(stream)); + break; + case AI_AISTRING: + data = new aiString(Read(stream)); + break; + case AI_AIVECTOR3D: + data = new aiVector3D(Read(stream)); + break; +#ifndef SWIG + case FORCE_32BIT: +#endif // SWIG + default: + break; + } + + (*node)->mMetaData->mValues[i].mData = data; + } + } } // ----------------------------------------------------------------------------------- @@ -570,7 +612,7 @@ void AssbinImporter::ReadBinaryScene( IOStream * stream, aiScene* scene ) // Read node graph scene->mRootNode = new aiNode[1]; - ReadBinaryNode( stream, &scene->mRootNode ); + ReadBinaryNode( stream, &scene->mRootNode, (aiNode*)NULL ); // Read all meshes if (scene->mNumMeshes) diff --git a/code/AssbinLoader.h b/code/AssbinLoader.h index 75c0f3a16..2eb7a6488 100644 --- a/code/AssbinLoader.h +++ b/code/AssbinLoader.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -70,7 +71,6 @@ class AssbinImporter : public BaseImporter private: bool shortened; bool compressed; -protected: public: virtual bool CanRead( @@ -85,7 +85,7 @@ public: IOSystem* pIOHandler ); void ReadBinaryScene( IOStream * stream, aiScene* pScene ); - void ReadBinaryNode( IOStream * stream, aiNode** mRootNode ); + void ReadBinaryNode( IOStream * stream, aiNode** mRootNode, aiNode* parent ); void ReadBinaryMesh( IOStream * stream, aiMesh* mesh ); void ReadBinaryBone( IOStream * stream, aiBone* bone ); void ReadBinaryMaterial(IOStream * stream, aiMaterial* mat); diff --git a/code/Assimp.cpp b/code/Assimp.cpp index 092c40979..9269f905e 100644 --- a/code/Assimp.cpp +++ b/code/Assimp.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -65,8 +66,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ------------------------------------------------------------------------------------------------ using namespace Assimp; -namespace Assimp -{ +namespace Assimp { // underlying structure for aiPropertyStore typedef BatchLoader::PropertyMap PropertyMap; @@ -109,12 +109,11 @@ static std::mutex gLogStreamMutex; // ------------------------------------------------------------------------------------------------ // Custom LogStream implementation for the C-API -class LogToCallbackRedirector : public LogStream -{ +class LogToCallbackRedirector : public LogStream { public: explicit LogToCallbackRedirector(const aiLogStream& s) - : stream (s) { - ai_assert(NULL != s.callback); + : stream (s) { + ai_assert(NULL != s.callback); } ~LogToCallbackRedirector() { @@ -145,8 +144,7 @@ private: }; // ------------------------------------------------------------------------------------------------ -void ReportSceneNotFoundError() -{ +void ReportSceneNotFoundError() { DefaultLogger::get()->error("Unable to find the Assimp::Importer for this aiScene. " "The C-API does not accept scenes produced by the C++ API and vice versa"); @@ -155,22 +153,18 @@ void ReportSceneNotFoundError() // ------------------------------------------------------------------------------------------------ // Reads the given file and returns its content. -const aiScene* aiImportFile( const char* pFile, unsigned int pFlags) -{ +const aiScene* aiImportFile( const char* pFile, unsigned int pFlags) { return aiImportFileEx(pFile,pFlags,NULL); } // ------------------------------------------------------------------------------------------------ -const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags, aiFileIO* pFS) -{ +const aiScene* aiImportFileEx( const char* pFile, unsigned int pFlags, aiFileIO* pFS) { return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL); } // ------------------------------------------------------------------------------------------------ -const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags, - aiFileIO* pFS, - const aiPropertyStore* props) -{ +const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags, + aiFileIO* pFS, const aiPropertyStore* props) { ai_assert(NULL != pFile); const aiScene* scene = NULL; @@ -189,7 +183,7 @@ const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFl pimpl->mMatrixProperties = pp->matrices; } // setup a custom IO system if necessary - if (pFS) { + if (pFS) { imp->SetIOHandler( new CIOSystemWrapper (pFS) ); } @@ -200,8 +194,7 @@ const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFl if( scene) { ScenePrivateData* priv = const_cast( ScenePriv(scene) ); priv->mOrigImporter = imp; - } - else { + } else { // if failed, extract error code and destroy the import gLastErrorString = imp->GetErrorString(); delete imp; @@ -209,6 +202,7 @@ const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFl // return imported data. If the import failed the pointer is NULL anyways ASSIMP_END_EXCEPTION_REGION(const aiScene*); + return scene; } diff --git a/code/AssimpCExport.cpp b/code/AssimpCExport.cpp index fff9d8e21..b8d3264a1 100644 --- a/code/AssimpCExport.cpp +++ b/code/AssimpCExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -44,8 +45,9 @@ Assimp C export interface. See Exporter.cpp for some notes. */ #ifndef ASSIMP_BUILD_NO_EXPORT + #include "CInterfaceIOWrapper.h" -#include "SceneCombiner.h" +#include #include "ScenePrivate.h" #include diff --git a/code/AssxmlExporter.cpp b/code/AssxmlExporter.cpp index 677bea265..8019232c0 100644 --- a/code/AssxmlExporter.cpp +++ b/code/AssxmlExporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/AssxmlExporter.h b/code/AssxmlExporter.h index ba9921f70..9694f74a3 100644 --- a/code/AssxmlExporter.h +++ b/code/AssxmlExporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/B3DImporter.cpp b/code/B3DImporter.cpp index e2a685d1a..d15676128 100644 --- a/code/B3DImporter.cpp +++ b/code/B3DImporter.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -81,6 +82,20 @@ static const aiImporterDesc desc = { //#define DEBUG_B3D +template +void DeleteAllBarePointers(std::vector& x) +{ + for(auto p : x) + { + delete p; + } +} + +B3DImporter::~B3DImporter() +{ + DeleteAllBarePointers(_animations); +} + // ------------------------------------------------------------------------------------------------ bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{ @@ -557,13 +572,19 @@ aiNode *B3DImporter::ReadNODE( aiNode *parent ){ void B3DImporter::ReadBB3D( aiScene *scene ){ _textures.clear(); + _materials.clear(); _vertices.clear(); + _meshes.clear(); + DeleteAllBarePointers(_nodes); _nodes.clear(); + _nodeAnims.clear(); + + DeleteAllBarePointers(_animations); _animations.clear(); string t=ReadChunk(); diff --git a/code/B3DImporter.h b/code/B3DImporter.h index 167078655..94644edd4 100644 --- a/code/B3DImporter.h +++ b/code/B3DImporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -58,6 +59,8 @@ namespace Assimp{ class B3DImporter : public BaseImporter{ public: + B3DImporter() = default; + virtual ~B3DImporter(); virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; diff --git a/code/BVHLoader.cpp b/code/BVHLoader.cpp index 1324dcdca..c20cbec4e 100644 --- a/code/BVHLoader.cpp +++ b/code/BVHLoader.cpp @@ -4,7 +4,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/BVHLoader.h b/code/BVHLoader.h index 8a163d1e7..6a89e1aaf 100644 --- a/code/BVHLoader.h +++ b/code/BVHLoader.h @@ -4,7 +4,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/BaseImporter.cpp b/code/BaseImporter.cpp index e96b35cf2..09b32e3ae 100644 --- a/code/BaseImporter.cpp +++ b/code/BaseImporter.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -302,24 +303,13 @@ void BaseImporter::GetExtensionList(std::set& extensions) return false; } -#include "../contrib/ConvertUTF/ConvertUTF.h" - -// ------------------------------------------------------------------------------------------------ -void ReportResult(ConversionResult res) -{ - if(res == sourceExhausted) { - DefaultLogger::get()->error("Source ends with incomplete character sequence, transformation to UTF-8 fails"); - } - else if(res == sourceIllegal) { - DefaultLogger::get()->error("Source contains illegal character sequence, transformation to UTF-8 fails"); - } -} +#include "../contrib/utf8cpp/source/utf8.h" // ------------------------------------------------------------------------------------------------ // Convert to UTF8 data void BaseImporter::ConvertToUTF8(std::vector& data) { - ConversionResult result; + //ConversionResult result; if(data.size() < 8) { throw DeadlyImportError("File is too small"); } @@ -332,7 +322,8 @@ void BaseImporter::ConvertToUTF8(std::vector& data) data.resize(data.size()-3); return; } - + + // UTF 32 BE with BOM if(*((uint32_t*)&data.front()) == 0xFFFE0000) { @@ -346,21 +337,10 @@ void BaseImporter::ConvertToUTF8(std::vector& data) if(*((uint32_t*)&data.front()) == 0x0000FFFE) { DefaultLogger::get()->debug("Found UTF-32 BOM ..."); - const uint32_t* sstart = (uint32_t*)&data.front()+1, *send = (uint32_t*)&data.back()+1; - char* dstart,*dend; std::vector output; - do { - output.resize(output.size()?output.size()*3/2:data.size()/2); - dstart = &output.front(),dend = &output.back()+1; - - result = ConvertUTF32toUTF8((const UTF32**)&sstart,(const UTF32*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion); - } while(result == targetExhausted); - - ReportResult(result); - - // copy to output buffer. - const size_t outlen = (size_t)(dstart-&output.front()); - data.assign(output.begin(),output.begin()+outlen); + int *ptr = (int*)&data[ 0 ]; + int *end = ptr + ( data.size() / sizeof(int) ) +1; + utf8::utf32to8( ptr, end, back_inserter(output)); return; } @@ -377,21 +357,8 @@ void BaseImporter::ConvertToUTF8(std::vector& data) if(*((uint16_t*)&data.front()) == 0xFEFF) { DefaultLogger::get()->debug("Found UTF-16 BOM ..."); - const uint16_t* sstart = (uint16_t*)&data.front()+1, *send = (uint16_t*)(&data.back()+1); - char* dstart,*dend; - std::vector output; - do { - output.resize(output.size()?output.size()*3/2:data.size()*3/4); - dstart = &output.front(),dend = &output.back()+1; - - result = ConvertUTF16toUTF8((const UTF16**)&sstart,(const UTF16*)send,(UTF8**)&dstart,(UTF8*)dend,lenientConversion); - } while(result == targetExhausted); - - ReportResult(result); - - // copy to output buffer. - const size_t outlen = (size_t)(dstart-&output.front()); - data.assign(output.begin(),output.begin()+outlen); + std::vector output; + utf8::utf16to8(data.begin(), data.end(), back_inserter(output)); return; } } diff --git a/code/BaseImporter.h b/code/BaseImporter.h index 781318be8..cee54c1ad 100644 --- a/code/BaseImporter.h +++ b/code/BaseImporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -60,7 +61,6 @@ class BaseProcess; class SharedPostProcessInfo; class IOStream; - // utility to do char4 to uint32 in a portable manner #define AI_MAKE_MAGIC(string) ((uint32_t)((string[0] << 24) + \ (string[1] << 16) + (string[2] << 8) + string[3])) @@ -193,14 +193,11 @@ public: const Importer* pImp ); - // ------------------------------------------------------------------- /** Called by #Importer::GetImporterInfo to get a description of * some loader features. Importers must provide this information. */ virtual const aiImporterDesc* GetInfo() const = 0; - - // ------------------------------------------------------------------- /** Called by #Importer::GetExtensionList for each loaded importer. * Take the extension list contained in the structure returned by @@ -316,7 +313,7 @@ public: // static utilities * @param Size of one token, in bytes. Maximally 16 bytes. * @return true if one of the given tokens was found * - * @note For convinence, the check is also performed for the + * @note For convenience, the check is also performed for the * byte-swapped variant of all tokens (big endian). Only for * tokens of size 2,4. */ diff --git a/code/BaseProcess.cpp b/code/BaseProcess.cpp index 580f89cdb..9e175d315 100644 --- a/code/BaseProcess.cpp +++ b/code/BaseProcess.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/BaseProcess.h b/code/BaseProcess.h index e4838fa7f..aa873f717 100644 --- a/code/BaseProcess.h +++ b/code/BaseProcess.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Bitmap.cpp b/code/Bitmap.cpp index ae6d62083..b1cf8a409 100644 --- a/code/Bitmap.cpp +++ b/code/Bitmap.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/Bitmap.h b/code/Bitmap.h index f665605b9..96c994dbe 100644 --- a/code/Bitmap.h +++ b/code/Bitmap.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/BlenderBMesh.cpp b/code/BlenderBMesh.cpp index c328947ae..8a13819a6 100644 --- a/code/BlenderBMesh.cpp +++ b/code/BlenderBMesh.cpp @@ -52,7 +52,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { - template< > const std::string LogFunctions< BlenderBMeshConverter >::log_prefix = "BLEND_BMESH: "; + template< > const char* LogFunctions< BlenderBMeshConverter >::Prefix() + { + static auto prefix = "BLEND_BMESH: "; + return prefix; + } } using namespace Assimp; diff --git a/code/BlenderDNA.cpp b/code/BlenderDNA.cpp index 5dbc950aa..23ece913f 100644 --- a/code/BlenderDNA.cpp +++ b/code/BlenderDNA.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/BlenderDNA.h b/code/BlenderDNA.h index dbddad336..4c7d0fc26 100644 --- a/code/BlenderDNA.h +++ b/code/BlenderDNA.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -252,10 +253,7 @@ public: * a compiler complain is the result. * @param dest Destination value to be written * @param db File database, including input stream. */ - template inline void Convert (T& dest, - const FileDatabase& db) const; - - + template void Convert (T& dest, const FileDatabase& db) const; // -------------------------------------------------------- // generic converter diff --git a/code/BlenderDNA.inl b/code/BlenderDNA.inl index 25aa81c91..6919c9153 100644 --- a/code/BlenderDNA.inl +++ b/code/BlenderDNA.inl @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/BlenderIntermediate.h b/code/BlenderIntermediate.h index c79bc08f2..0fc9cdafc 100644 --- a/code/BlenderIntermediate.h +++ b/code/BlenderIntermediate.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/BlenderLoader.cpp b/code/BlenderLoader.cpp index ea443b14b..6d4c97cbf 100644 --- a/code/BlenderLoader.cpp +++ b/code/BlenderLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -73,7 +74,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #endif namespace Assimp { - template<> const std::string LogFunctions::log_prefix = "BLEND: "; + template<> const char* LogFunctions::Prefix() + { + static auto prefix = "BLEND: "; + return prefix; + } } using namespace Assimp; @@ -109,6 +114,7 @@ BlenderImporter::~BlenderImporter() } static const char* Tokens[] = { "BLENDER" }; +static const char* TokensForSearch[] = { "blender" }; // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. @@ -121,7 +127,7 @@ bool BlenderImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, b else if ((!extension.length() || checkSig) && pIOHandler) { // note: this won't catch compressed files - return SearchFileHeaderForToken(pIOHandler,pFile, Tokens,1); + return SearchFileHeaderForToken(pIOHandler,pFile, TokensForSearch,1); } return false; } diff --git a/code/BlenderLoader.h b/code/BlenderLoader.h index 505409260..66fff594b 100644 --- a/code/BlenderLoader.h +++ b/code/BlenderLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/BlenderModifier.cpp b/code/BlenderModifier.cpp index f903a1380..a1ccba5f4 100644 --- a/code/BlenderModifier.cpp +++ b/code/BlenderModifier.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -42,10 +43,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of some blender modifiers (i.e subdivision, mirror). */ - #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER + #include "BlenderModifier.h" -#include "SceneCombiner.h" +#include #include "Subdivision.h" #include #include @@ -265,7 +266,7 @@ void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, co std::copy(out.mMeshes,out.mMeshes+out.mNumMeshes,nind); std::transform(out.mMeshes,out.mMeshes+out.mNumMeshes,nind+out.mNumMeshes, - std::bind1st(std::plus< unsigned int >(),out.mNumMeshes)); + [&out](unsigned int n) { return out.mNumMeshes + n; }); delete[] out.mMeshes; out.mMeshes = nind; diff --git a/code/BlenderModifier.h b/code/BlenderModifier.h index 1d176756e..9fa8c74ee 100644 --- a/code/BlenderModifier.h +++ b/code/BlenderModifier.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/BlenderScene.h b/code/BlenderScene.h index fe6d6e14c..36094eabd 100644 --- a/code/BlenderScene.h +++ b/code/BlenderScene.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -638,6 +639,7 @@ struct Base : ElemBase { Base() : ElemBase() + , prev( nullptr ) , next() , object() { // empty @@ -784,10 +786,12 @@ struct Tex : ElemBase { //char use_nodes; Tex() - : ElemBase() { + : ElemBase() + , imaflag( ImageFlags_INTERPOL ) + , type( Type_CLOUDS ) + , ima() { // empty } - }; // ------------------------------------------------------------------------------- diff --git a/code/BlenderTessellator.cpp b/code/BlenderTessellator.cpp index 60879b417..9f4c51048 100644 --- a/code/BlenderTessellator.cpp +++ b/code/BlenderTessellator.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -58,7 +59,11 @@ static const unsigned int BLEND_TESS_MAGIC = 0x83ed9ac3; namspace Assimp { - template< > const std::string LogFunctions< BlenderTessellatorGL >::log_prefix = "BLEND_TESS_GL: "; + template< > const char* LogFunctions< BlenderTessellatorGL >::Prefix() + { + static auto prefix = "BLEND_TESS_GL: "; + return prefix; + } } using namespace Assimp; @@ -251,7 +256,11 @@ void BlenderTessellatorGL::TessellateError( GLenum errorCode, void* ) namespace Assimp { - template< > const std::string LogFunctions< BlenderTessellatorP2T >::log_prefix = "BLEND_TESS_P2T: "; + template< > const char* LogFunctions< BlenderTessellatorP2T >::Prefix() + { + static auto prefix = "BLEND_TESS_P2T: "; + return prefix; + } } using namespace Assimp; diff --git a/code/BlenderTessellator.h b/code/BlenderTessellator.h index 530bd2c3e..47d3a4665 100644 --- a/code/BlenderTessellator.h +++ b/code/BlenderTessellator.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/BlobIOSystem.h b/code/BlobIOSystem.h index bb76ffadb..f406ea0fe 100644 --- a/code/BlobIOSystem.h +++ b/code/BlobIOSystem.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/ByteSwapper.h b/code/ByteSwapper.h index 37538e7cb..e5c7569f1 100644 --- a/code/ByteSwapper.h +++ b/code/ByteSwapper.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/C4DImporter.cpp b/code/C4DImporter.cpp index 252766ca6..39514f6b8 100644 --- a/code/C4DImporter.cpp +++ b/code/C4DImporter.cpp @@ -393,7 +393,7 @@ void C4DImporter::RecurseHierarchy(BaseObject* object, aiNode* parent) // ------------------------------------------------------------------------------------------------ aiMesh* C4DImporter::ReadMesh(BaseObject* object) { - assert(object != NULL && object->GetType() == Opolygon); + ai_assert(object != NULL && object->GetType() == Opolygon); // based on Melange sample code PolygonObject* const polyObject = dynamic_cast(object); @@ -635,7 +635,7 @@ unsigned int C4DImporter::ResolveMaterial(PolygonObject* obj) TextureTag& ttag = dynamic_cast(*tag); BaseMaterial* const mat = ttag.GetMaterial(); - assert(mat != NULL); + ai_assert(mat != NULL); const MaterialMap::const_iterator it = material_mapping.find(mat); if(it == material_mapping.end()) { diff --git a/code/C4DImporter.h b/code/C4DImporter.h index 3ba2a17c6..4dea82161 100644 --- a/code/C4DImporter.h +++ b/code/C4DImporter.h @@ -47,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "BaseImporter.h" #include "LogAux.h" -#include +#include struct aiNode; struct aiMesh; struct aiMaterial; diff --git a/code/CInterfaceIOWrapper.cpp b/code/CInterfaceIOWrapper.cpp index 0a80c1990..9de75b683 100644 --- a/code/CInterfaceIOWrapper.cpp +++ b/code/CInterfaceIOWrapper.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/CInterfaceIOWrapper.h b/code/CInterfaceIOWrapper.h index 0172fb49f..78cac0cf9 100644 --- a/code/CInterfaceIOWrapper.h +++ b/code/CInterfaceIOWrapper.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/CMakeLists.txt b/code/CMakeLists.txt index 24930b0ff..e87dad550 100644 --- a/code/CMakeLists.txt +++ b/code/CMakeLists.txt @@ -1,7 +1,8 @@ # Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # -# Copyright (c) 2006-2016, assimp team +# Copyright (c) 2006-2017, assimp team + # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -58,8 +59,9 @@ SET( PUBLIC_HEADERS ${HEADER_PATH}/camera.h ${HEADER_PATH}/color4.h ${HEADER_PATH}/color4.inl - ${HEADER_PATH}/config.h + ${CMAKE_CURRENT_BINARY_DIR}/../include/assimp/config.h ${HEADER_PATH}/defs.h + ${HEADER_PATH}/Defines.h ${HEADER_PATH}/cfileio.h ${HEADER_PATH}/light.h ${HEADER_PATH}/material.h @@ -95,6 +97,7 @@ SET( PUBLIC_HEADERS ${HEADER_PATH}/Exporter.hpp ${HEADER_PATH}/DefaultIOStream.h ${HEADER_PATH}/DefaultIOSystem.h + ${HEADER_PATH}/SceneCombiner.h ) SET( Core_SRCS @@ -147,7 +150,6 @@ SET( Common_SRCS SpatialSort.cpp SpatialSort.h SceneCombiner.cpp - SceneCombiner.h ScenePreprocessor.cpp ScenePreprocessor.h SkeletonMeshBuilder.cpp @@ -569,6 +571,9 @@ SET( PostProcessing_SRCS ) SOURCE_GROUP( PostProcessing FILES ${PostProcessing_SRCS}) +SET( IrrXML_SRCS irrXMLWrapper.h ) +SOURCE_GROUP( IrrXML FILES ${IrrXML_SRCS}) + ADD_ASSIMP_IMPORTER( Q3D Q3DLoader.cpp Q3DLoader.h @@ -643,6 +648,9 @@ ADD_ASSIMP_IMPORTER(X3D X3DImporter_Rendering.cpp X3DImporter_Shape.cpp X3DImporter_Texturing.cpp + FIReader.hpp + FIReader.cpp + X3DVocabulary.cpp ) ADD_ASSIMP_IMPORTER( GLTF @@ -654,6 +662,14 @@ ADD_ASSIMP_IMPORTER( GLTF glTFImporter.h glTFExporter.h glTFExporter.cpp + glTF2Asset.h + glTF2Asset.inl + glTF2AssetWriter.h + glTF2AssetWriter.inl + glTF2Importer.cpp + glTF2Importer.h + glTF2Exporter.h + glTF2Exporter.cpp ) ADD_ASSIMP_IMPORTER( 3MF @@ -663,6 +679,16 @@ ADD_ASSIMP_IMPORTER( 3MF D3MFOpcPackage.cpp ) +ADD_ASSIMP_IMPORTER( MMD + MMDCpp14.h + MMDImporter.cpp + MMDImporter.h + MMDPmdParser.h + MMDPmxParser.h + MMDPmxParser.cpp + MMDVmdParser.h +) + SET( Step_SRCS StepExporter.h StepExporter.cpp @@ -681,23 +707,6 @@ SET( Extra_SRCS ) SOURCE_GROUP( Extra FILES ${Extra_SRCS}) -SET( IrrXML_SRCS - irrXMLWrapper.h - ../contrib/irrXML/CXMLReaderImpl.h - ../contrib/irrXML/heapsort.h - ../contrib/irrXML/irrArray.h - ../contrib/irrXML/irrString.h - ../contrib/irrXML/irrTypes.h - ../contrib/irrXML/irrXML.cpp - ../contrib/irrXML/irrXML.h -) -SOURCE_GROUP( IrrXML FILES ${IrrXML_SRCS}) - -SET( ConvertUTF_SRCS - ../contrib/ConvertUTF/ConvertUTF.h - ../contrib/ConvertUTF/ConvertUTF.c -) -SOURCE_GROUP( ConvertUTF FILES ${ConvertUTF_SRCS}) SET( Clipper_SRCS ../contrib/clipper/clipper.hpp @@ -735,10 +744,12 @@ SET ( openddl_parser_SRCS ../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 ) @@ -833,7 +844,6 @@ SET( assimp_src # Third-party libraries ${IrrXML_SRCS} - ${ConvertUTF_SRCS} ${unzip_compile_SRCS} ${Poly2Tri_SRCS} ${Clipper_SRCS} @@ -848,7 +858,8 @@ SET( assimp_src ADD_DEFINITIONS( -DOPENDDLPARSER_BUILD ) INCLUDE_DIRECTORIES( - ../contrib/openddlparser/include + ${IRRXML_INCLUDE_DIR} + ../contrib/openddlparser/include ) IF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) @@ -858,7 +869,7 @@ ENDIF (ASSIMP_BUILD_NONFREE_C4D_IMPORTER) ADD_LIBRARY( assimp ${assimp_src} ) -TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES} ${OPENDDL_PARSER_LIBRARIES} ) +TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES} ${OPENDDL_PARSER_LIBRARIES} ${IRRXML_LIBRARY} ) if(ANDROID AND ASSIMP_ANDROID_JNIIOSYSTEM) set(ASSIMP_ANDROID_JNIIOSYSTEM_PATH port/AndroidJNI) @@ -932,14 +943,25 @@ if (ASSIMP_ANDROID_JNIIOSYSTEM) endif(ASSIMP_ANDROID_JNIIOSYSTEM) if(MSVC AND ASSIMP_INSTALL_PDB) - install(FILES ${Assimp_BINARY_DIR}/code/Debug/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb - DESTINATION ${ASSIMP_LIB_INSTALL_DIR} - CONFIGURATIONS Debug - ) - install(FILES ${Assimp_BINARY_DIR}/code/RelWithDebInfo/assimp${LIBRARY_SUFFIX}.pdb - DESTINATION ${ASSIMP_LIB_INSTALL_DIR} - CONFIGURATIONS RelWithDebInfo - ) + 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} + CONFIGURATIONS Debug + ) + install(FILES ${Assimp_BINARY_DIR}/code/RelWithDebInfo/assimp${LIBRARY_SUFFIX}.pdb + DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + CONFIGURATIONS RelWithDebInfo + ) + ELSE() + install(FILES ${Assimp_BINARY_DIR}/code/assimp${LIBRARY_SUFFIX}${CMAKE_DEBUG_POSTFIX}.pdb + DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + CONFIGURATIONS Debug + ) + install(FILES ${Assimp_BINARY_DIR}/code/assimp${LIBRARY_SUFFIX}.pdb + DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + CONFIGURATIONS RelWithDebInfo + ) + ENDIF() endif () if (ASSIMP_COVERALLS) diff --git a/code/COBLoader.cpp b/code/COBLoader.cpp index e1d238a1c..a92e231a5 100644 --- a/code/COBLoader.cpp +++ b/code/COBLoader.cpp @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -941,20 +941,22 @@ void COBImporter::UnsupportedChunk_Binary( StreamReaderLE& reader, const ChunkIn // ------------------------------------------------------------------------------------------------ // tiny utility guard to aid me at staying within chunk boundaries. class chunk_guard { - public: - chunk_guard(const COB::ChunkInfo& nfo, StreamReaderLE& reader) - : nfo(nfo) - , reader(reader) - , cur(reader.GetCurrentPos()) - { + : nfo(nfo) + , reader(reader) + , cur(reader.GetCurrentPos()) { } ~chunk_guard() { // don't do anything if the size is not given if(nfo.size != static_cast(-1)) { - reader.IncPtr(static_cast(nfo.size)-reader.GetCurrentPos()+cur); + try { + reader.IncPtr( static_cast< int >( nfo.size ) - reader.GetCurrentPos() + cur ); + } catch ( DeadlyImportError e ) { + // out of limit so correct the value + reader.IncPtr( reader.GetReadLimit() ); + } } } diff --git a/code/COBLoader.h b/code/COBLoader.h index efccc448d..46dc86f62 100644 --- a/code/COBLoader.h +++ b/code/COBLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/COBScene.h b/code/COBScene.h index a73a6df3a..a1d6ebc27 100644 --- a/code/COBScene.h +++ b/code/COBScene.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/CSMLoader.cpp b/code/CSMLoader.cpp index 1d10f3965..eeb6986b0 100644 --- a/code/CSMLoader.cpp +++ b/code/CSMLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/CSMLoader.h b/code/CSMLoader.h index 71abb7e91..55a632dc6 100644 --- a/code/CSMLoader.h +++ b/code/CSMLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/CalcTangentsProcess.cpp b/code/CalcTangentsProcess.cpp index c13ffcb24..2af16fcc0 100644 --- a/code/CalcTangentsProcess.cpp +++ b/code/CalcTangentsProcess.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/CalcTangentsProcess.h b/code/CalcTangentsProcess.h index 4a6122668..a22785639 100644 --- a/code/CalcTangentsProcess.h +++ b/code/CalcTangentsProcess.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ColladaExporter.cpp b/code/ColladaExporter.cpp index 8f2e4047b..691ef9500 100644 --- a/code/ColladaExporter.cpp +++ b/code/ColladaExporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -44,7 +45,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ColladaExporter.h" #include "Bitmap.h" #include "fast_atof.h" -#include "SceneCombiner.h" +#include #include "StringUtils.h" #include "XMLTools.h" #include @@ -57,6 +58,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include +#include using namespace Assimp; @@ -135,6 +138,7 @@ void ColladaExporter::WriteFile() WriteLightsLibrary(); WriteMaterials(); WriteGeometryLibrary(); + WriteControllerLibrary(); WriteSceneLibrary(); @@ -552,7 +556,7 @@ void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::strin std::stringstream imageUrlEncoded; for( std::string::const_iterator it = pSurface.texture.begin(); it != pSurface.texture.end(); ++it ) { - if( isalnum_C( (unsigned char) *it) || *it == ':' || *it == '_' || *it == '.' || *it == '/' || *it == '\\' ) + if( isalnum_C( (unsigned char) *it) || *it == ':' || *it == '_' || *it == '-' || *it == '.' || *it == '/' || *it == '\\' ) imageUrlEncoded << *it; else imageUrlEncoded << '%' << std::hex << size_t( (unsigned char) *it) << std::dec; @@ -694,7 +698,6 @@ void ColladaExporter::WriteMaterials() materials[a].shininess.exist = mat->Get( AI_MATKEY_SHININESS, materials[a].shininess.value) == aiReturn_SUCCESS; materials[a].transparency.exist = mat->Get( AI_MATKEY_OPACITY, materials[a].transparency.value) == aiReturn_SUCCESS; - materials[a].transparency.value = materials[a].transparency.value; materials[a].index_refraction.exist = mat->Get( AI_MATKEY_REFRACTI, materials[a].index_refraction.value) == aiReturn_SUCCESS; } @@ -789,6 +792,177 @@ void ColladaExporter::WriteMaterials() } } +// ------------------------------------------------------------------------------------------------ +// Writes the controller library +void ColladaExporter::WriteControllerLibrary() +{ + mOutput << startstr << "" << endstr; + PushTag(); + + for( size_t a = 0; a < mScene->mNumMeshes; ++a) + WriteController( a); + + PopTag(); + mOutput << startstr << "" << endstr; +} + +// ------------------------------------------------------------------------------------------------ +// Writes a skin controller of the given mesh +void ColladaExporter::WriteController( size_t pIndex) +{ + const aiMesh* mesh = mScene->mMeshes[pIndex]; + const std::string idstr = GetMeshId( pIndex); + const std::string idstrEscaped = XMLEscape(idstr); + + if ( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) + return; + + if ( mesh->mNumBones == 0 ) + return; + + mOutput << startstr << ""<< endstr; + PushTag(); + + mOutput << startstr << "" << endstr; + PushTag(); + + // bind pose matrix + mOutput << startstr << "" << endstr; + PushTag(); + + // I think it is identity in general cases. + aiMatrix4x4 mat; + mOutput << startstr << mat.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << endstr; + mOutput << startstr << mat.b1 << " " << mat.b2 << " " << mat.b3 << " " << mat.b4 << endstr; + mOutput << startstr << mat.c1 << " " << mat.c2 << " " << mat.c3 << " " << mat.c4 << endstr; + mOutput << startstr << mat.d1 << " " << mat.d2 << " " << mat.d3 << " " << mat.d4 << endstr; + + PopTag(); + mOutput << startstr << "" << endstr; + + mOutput << startstr << "" << endstr; + PushTag(); + + mOutput << startstr << "mNumBones << "\">"; + + for( size_t i = 0; i < mesh->mNumBones; ++i ) + mOutput << XMLEscape(mesh->mBones[i]->mName.C_Str()) << " "; + + mOutput << "" << endstr; + + mOutput << startstr << "" << endstr; + PushTag(); + + mOutput << startstr << "mNumBones << "\" stride=\"" << 1 << "\">" << endstr; + PushTag(); + + mOutput << startstr << "" << endstr; + + PopTag(); + mOutput << startstr << "" << endstr; + + PopTag(); + mOutput << startstr << "" << endstr; + + PopTag(); + mOutput << startstr << "" << endstr; + + std::vector bind_poses; + bind_poses.reserve(mesh->mNumBones * 16); + for(unsigned int i = 0; i < mesh->mNumBones; ++i) + for( unsigned int j = 0; j < 4; ++j) + bind_poses.insert(bind_poses.end(), mesh->mBones[i]->mOffsetMatrix[j], mesh->mBones[i]->mOffsetMatrix[j] + 4); + + WriteFloatArray( idstr + "-skin-bind_poses", FloatType_Mat4x4, (const ai_real*) bind_poses.data(), bind_poses.size() / 16); + + bind_poses.clear(); + + std::vector skin_weights; + skin_weights.reserve(mesh->mNumVertices * mesh->mNumBones); + for( size_t i = 0; i < mesh->mNumBones; ++i) + for( size_t j = 0; j < mesh->mBones[i]->mNumWeights; ++j) + skin_weights.push_back(mesh->mBones[i]->mWeights[j].mWeight); + + WriteFloatArray( idstr + "-skin-weights", FloatType_Weight, (const ai_real*) skin_weights.data(), skin_weights.size()); + + skin_weights.clear(); + + mOutput << startstr << "" << endstr; + PushTag(); + + mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; + + PopTag(); + mOutput << startstr << "" << endstr; + + mOutput << startstr << "mNumVertices << "\">" << endstr; + PushTag(); + + mOutput << startstr << "" << endstr; + mOutput << startstr << "" << endstr; + + mOutput << startstr << ""; + + std::vector num_influences(mesh->mNumVertices, (ai_uint)0); + for( size_t i = 0; i < mesh->mNumBones; ++i) + for( size_t j = 0; j < mesh->mBones[i]->mNumWeights; ++j) + ++num_influences[mesh->mBones[i]->mWeights[j].mVertexId]; + + for( size_t i = 0; i < mesh->mNumVertices; ++i) + mOutput << num_influences[i] << " "; + + mOutput << "" << endstr; + + mOutput << startstr << ""; + + ai_uint joint_weight_indices_length = 0; + std::vector accum_influences; + accum_influences.reserve(num_influences.size()); + for( size_t i = 0; i < num_influences.size(); ++i) + { + accum_influences.push_back(joint_weight_indices_length); + joint_weight_indices_length += num_influences[i]; + } + + ai_uint weight_index = 0; + std::vector joint_weight_indices(2 * joint_weight_indices_length, (ai_int)-1); + for( unsigned int i = 0; i < mesh->mNumBones; ++i) + for( unsigned j = 0; j < mesh->mBones[i]->mNumWeights; ++j) + { + unsigned int vId = mesh->mBones[i]->mWeights[j].mVertexId; + for( ai_uint k = 0; k < num_influences[vId]; ++k) + { + if (joint_weight_indices[2 * (accum_influences[vId] + k)] == -1) + { + joint_weight_indices[2 * (accum_influences[vId] + k)] = i; + joint_weight_indices[2 * (accum_influences[vId] + k) + 1] = weight_index; + break; + } + } + ++weight_index; + } + + for( size_t i = 0; i < joint_weight_indices.size(); ++i) + mOutput << joint_weight_indices[i] << " "; + + num_influences.clear(); + accum_influences.clear(); + joint_weight_indices.clear(); + + mOutput << "" << endstr; + + PopTag(); + mOutput << startstr << "" << endstr; + + PopTag(); + mOutput << startstr << "" << endstr; + + PopTag(); + mOutput << startstr << "" << endstr; +} + // ------------------------------------------------------------------------------------------------ // Writes the geometry library void ColladaExporter::WriteGeometryLibrary() @@ -953,6 +1127,8 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy case FloatType_TexCoord2: floatsPerElement = 2; break; case FloatType_TexCoord3: floatsPerElement = 3; break; case FloatType_Color: floatsPerElement = 3; break; + case FloatType_Mat4x4: floatsPerElement = 16; break; + case FloatType_Weight: floatsPerElement = 1; break; default: return; } @@ -1021,6 +1197,14 @@ void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataTy mOutput << startstr << "" << endstr; mOutput << startstr << "" << endstr; break; + + case FloatType_Mat4x4: + mOutput << startstr << "" << endstr; + break; + + case FloatType_Weight: + mOutput << startstr << "" << endstr; + break; } PopTag(); @@ -1082,16 +1266,24 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode) // If the node is associated with a bone, it is a joint node (JOINT) // 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())) { node_type = "NODE"; + is_joint = false; } else { node_type = "JOINT"; + is_joint = true; + if(!pNode->mParent || NULL == findBone(pScene, pNode->mParent->mName.C_Str())) + is_skeleton_root = true; } const std::string node_name_escaped = XMLEscape(pNode->mName.data); mOutput << startstr - << "" << endstr; PushTag(); @@ -1099,7 +1291,7 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode) // write transformation - we can directly put the matrix there // TODO: (thom) decompose into scale - rot - quad to allow addressing it by animations afterwards const aiMatrix4x4& mat = pNode->mTransformation; - mOutput << startstr << ""; + mOutput << startstr << ""; mOutput << mat.a1 << " " << mat.a2 << " " << mat.a3 << " " << mat.a4 << " "; mOutput << mat.b1 << " " << mat.b2 << " " << mat.b3 << " " << mat.b4 << " "; mOutput << mat.c1 << " " << mat.c2 << " " << mat.c3 << " " << mat.c4 << " "; @@ -1127,33 +1319,50 @@ void ColladaExporter::WriteNode( const aiScene* pScene, aiNode* pNode) for( size_t a = 0; a < pNode->mNumMeshes; ++a ) { const aiMesh* mesh = mScene->mMeshes[pNode->mMeshes[a]]; - // do not instanciate mesh if empty. I wonder how this could happen - if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) - continue; - mOutput << startstr << "mMeshes[a])) << "\">" << endstr; - PushTag(); - mOutput << startstr << "" << endstr; - PushTag(); - mOutput << startstr << "" << endstr; - PushTag(); - mOutput << startstr << "mMaterialIndex].name) << "\">" << endstr; - PushTag(); - for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) - { - if( mesh->HasTextureCoords( static_cast(a) ) ) - // semantic as in - // input_semantic as in - // input_set as in - mOutput << startstr << "" << endstr; - } - PopTag(); - mOutput << startstr << "" << endstr; - PopTag(); - mOutput << startstr << "" << endstr; - PopTag(); - mOutput << startstr << "" << endstr; - PopTag(); - mOutput << startstr << "" << endstr; + // do not instanciate mesh if empty. I wonder how this could happen + if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) + continue; + + if( mesh->mNumBones == 0 ) + { + mOutput << startstr << "mMeshes[a])) << "\">" << endstr; + PushTag(); + } + else + { + mOutput << startstr + << "mMeshes[a])) << "-skin\">" + << endstr; + PushTag(); + + mOutput << startstr << "#skeleton_root" << endstr; + } + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "" << endstr; + PushTag(); + mOutput << startstr << "mMaterialIndex].name) << "\">" << endstr; + PushTag(); + for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) + { + if( mesh->HasTextureCoords( static_cast(a) ) ) + // semantic as in + // input_semantic as in + // input_set as in + mOutput << startstr << "" << endstr; + } + PopTag(); + mOutput << startstr << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + PopTag(); + mOutput << startstr << "" << endstr; + + PopTag(); + if( mesh->mNumBones == 0) + mOutput << startstr << "" << endstr; + else + mOutput << startstr << "" << endstr; } // recurse into subnodes diff --git a/code/ColladaExporter.h b/code/ColladaExporter.h index e8bd9b71f..c78272726 100644 --- a/code/ColladaExporter.h +++ b/code/ColladaExporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -101,13 +102,19 @@ protected: void WriteSpotLight(const aiLight *const light); void WriteAmbienttLight(const aiLight *const light); + /// Writes the controller library + void WriteControllerLibrary(); + + /// Writes a skin controller of the given mesh + void WriteController( size_t pIndex); + /// Writes the geometry library void WriteGeometryLibrary(); /// Writes the given mesh void WriteGeometry( size_t pIndex); - enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color }; + enum FloatDataType { FloatType_Vector, FloatType_TexCoord2, FloatType_TexCoord3, FloatType_Color, FloatType_Mat4x4, FloatType_Weight }; /// Writes a float array of the given type void WriteFloatArray( const std::string& pIdString, FloatDataType pType, const ai_real* pData, size_t pElementCount); @@ -121,7 +128,10 @@ protected: /// Enters a new xml element, which increases the indentation void PushTag() { startstr.append( " "); } /// Leaves an element, decreasing the indentation - void PopTag() { ai_assert( startstr.length() > 1); startstr.erase( startstr.length() - 2); } + void PopTag() { + ai_assert( startstr.length() > 1); + startstr.erase( startstr.length() - 2); + } /// Creates a mesh ID for the given mesh std::string GetMeshId( size_t pIndex) const { diff --git a/code/ColladaHelper.h b/code/ColladaHelper.h index e805ed0a0..8ccd6cafe 100644 --- a/code/ColladaHelper.h +++ b/code/ColladaHelper.h @@ -4,7 +4,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ColladaLoader.cpp b/code/ColladaLoader.cpp index 2a30fc5e2..ccf79ed62 100644 --- a/code/ColladaLoader.cpp +++ b/code/ColladaLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -118,7 +119,7 @@ bool ColladaLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, boo * might be NULL and it's our duty to return true here. */ if (!pIOHandler)return true; - const char* tokens[] = {"collada"}; + const char* tokens[] = {"GetPropertyInteger(AI_CONFIG_IMPORT_COLLADA_IGNORE_UP_DIRECTION,0) != 0; } - // ------------------------------------------------------------------------------------------------ // Get file extension list const aiImporterDesc* ColladaLoader::GetInfo () const @@ -674,7 +674,7 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: // create morph target meshes if any std::vector targetMeshes; std::vector targetWeights; - Collada::MorphMethod method; + Collada::MorphMethod method = Collada::Normalized; for(std::map::const_iterator it = pParser.mControllerLibrary.begin(); it != pParser.mControllerLibrary.end(); it++) @@ -728,7 +728,7 @@ aiMesh* ColladaLoader::CreateMesh( const ColladaParser& pParser, const Collada:: ? aiMorphingMethod_MORPH_RELATIVE : aiMorphingMethod_MORPH_NORMALIZED; dstMesh->mAnimMeshes = new aiAnimMesh*[animMeshes.size()]; - dstMesh->mNumAnimMeshes = animMeshes.size(); + dstMesh->mNumAnimMeshes = static_cast(animMeshes.size()); for (unsigned int i = 0; i < animMeshes.size(); i++) dstMesh->mAnimMeshes[i] = animMeshes.at(i); } @@ -1377,9 +1377,9 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars { aiNodeAnim* dstAnim = new aiNodeAnim; dstAnim->mNodeName = nodeName; - dstAnim->mNumPositionKeys = resultTrafos.size(); - dstAnim->mNumRotationKeys= resultTrafos.size(); - dstAnim->mNumScalingKeys = resultTrafos.size(); + 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()]; @@ -1445,11 +1445,11 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars ++morphAnimChannelIndex; } - morphAnim->mNumKeys = morphTimeValues.size(); + morphAnim->mNumKeys = static_cast(morphTimeValues.size()); morphAnim->mKeys = new aiMeshMorphKey[morphAnim->mNumKeys]; for (unsigned int key = 0; key < morphAnim->mNumKeys; key++) { - morphAnim->mKeys[key].mNumValuesAndWeights = morphChannels.size(); + 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()]; @@ -1470,13 +1470,13 @@ void ColladaLoader::CreateAnimation( aiScene* pScene, const ColladaParser& pPars { aiAnimation* anim = new aiAnimation; anim->mName.Set( pName); - anim->mNumChannels = anims.size(); + anim->mNumChannels = static_cast(anims.size()); if (anim->mNumChannels > 0) { anim->mChannels = new aiNodeAnim*[anims.size()]; std::copy( anims.begin(), anims.end(), anim->mChannels); } - anim->mNumMorphMeshChannels = morphAnims.size(); + anim->mNumMorphMeshChannels = static_cast(morphAnims.size()); if (anim->mNumMorphMeshChannels > 0) { anim->mMorphMeshChannels = new aiMeshMorphAnim*[anim->mNumMorphMeshChannels]; @@ -1725,6 +1725,8 @@ void ColladaLoader::BuildMaterials( ColladaParser& pParser, aiScene* /*pScene*/) 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) @@ -1743,11 +1745,17 @@ aiString ColladaLoader::FindFilenameForEffectTexture( const ColladaParser& pPars ColladaParser::ImageLibrary::const_iterator imIt = pParser.mImageLibrary.find( name); if( imIt == pParser.mImageLibrary.end()) { - throw DeadlyImportError( format() << - "Collada: Unable to resolve effect texture entry \"" << pName << "\", ended up at ID \"" << name << "\"." ); - } + //missing texture should not stop the conversion + //throw DeadlyImportError( format() << + // "Collada: Unable to resolve effect texture entry \"" << pName << "\", ended up at ID \"" << name << "\"." ); - aiString result; + DefaultLogger::get()->warn("Collada: Unable to resolve effect texture entry \"" + pName + "\", ended up at ID \"" + name + "\"."); + + //set default texture file name + result.Set(name + ".jpg"); + ConvertPath(result); + return result; + } // if this is an embedded texture image setup an aiTexture for it if (imIt->second.mFileName.empty()) @@ -1895,14 +1903,13 @@ const Collada::Node* ColladaLoader::FindNodeBySID( const Collada::Node* pNode, c } // ------------------------------------------------------------------------------------------------ -// Finds a proper name for a node derived from the collada-node's properties +// 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) { - // now setup the name of the node. We take the name if not empty, otherwise the collada ID - // FIX: Workaround for XSI calling the instanced visual scene 'untitled' by default. - if (!pNode->mName.empty() && pNode->mName != "untitled") - return pNode->mName; - else if (!pNode->mID.empty()) + // 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; diff --git a/code/ColladaLoader.h b/code/ColladaLoader.h index 2b31531d2..8388ab01e 100644 --- a/code/ColladaLoader.h +++ b/code/ColladaLoader.h @@ -4,7 +4,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ColladaParser.cpp b/code/ColladaParser.cpp index 3ed41a441..7b6592351 100644 --- a/code/ColladaParser.cpp +++ b/code/ColladaParser.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -43,7 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of the Collada parser helper */ - #ifndef ASSIMP_BUILD_NO_COLLADA_IMPORTER #include @@ -1865,7 +1865,7 @@ void ColladaParser::ReadMesh( Mesh* pMesh) ReadIndexData( pMesh); } else { - // ignore the rest + // ignore the restf SkipElement(); } } @@ -2215,8 +2215,9 @@ void ColladaParser::ReadIndexData( Mesh* pMesh) else if (IsElement("extra")) { SkipElement("extra"); - } else - { + } else if ( IsElement("ph")) { + SkipElement("ph"); + } else { ThrowException( format() << "Unexpected sub element <" << mReader->getNodeName() << "> in tag <" << elementName << ">" ); } } @@ -2230,7 +2231,7 @@ void ColladaParser::ReadIndexData( Mesh* pMesh) } #ifdef ASSIMP_BUILD_DEBUG - if (primType != Prim_TriFans && primType != Prim_TriStrips && + 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); } @@ -2399,6 +2400,10 @@ size_t ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector& pP size_t numberOfVertices = indices.size() / numOffsets; numPrimitives = numberOfVertices - 2; } + if (pPrimType == Prim_LineStrip) { + size_t numberOfVertices = indices.size() / numOffsets; + numPrimitives = numberOfVertices - 1; + } pMesh->mFaceSize.reserve( numPrimitives); pMesh->mFacePosIndices.reserve( indices.size() / numOffsets); @@ -2415,6 +2420,11 @@ size_t ColladaParser::ReadPrimitives( Mesh* pMesh, std::vector& pP 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++) diff --git a/code/ColladaParser.h b/code/ColladaParser.h index 4f2b6b8ce..b34974470 100644 --- a/code/ColladaParser.h +++ b/code/ColladaParser.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- - Copyright (c) 2006-2016, assimp team + Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ComputeUVMappingProcess.cpp b/code/ComputeUVMappingProcess.cpp index 0fee43a70..c49666de8 100644 --- a/code/ComputeUVMappingProcess.cpp +++ b/code/ComputeUVMappingProcess.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ComputeUVMappingProcess.h b/code/ComputeUVMappingProcess.h index db4287863..1de97961d 100644 --- a/code/ComputeUVMappingProcess.h +++ b/code/ComputeUVMappingProcess.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ConvertToLHProcess.cpp b/code/ConvertToLHProcess.cpp index 017282796..6a43d5c2d 100644 --- a/code/ConvertToLHProcess.cpp +++ b/code/ConvertToLHProcess.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/ConvertToLHProcess.h b/code/ConvertToLHProcess.h index 0c5f91c96..130fdcafd 100644 --- a/code/ConvertToLHProcess.h +++ b/code/ConvertToLHProcess.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/CreateAnimMesh.h b/code/CreateAnimMesh.h index c5ceb4028..84cab8932 100644 --- a/code/CreateAnimMesh.h +++ b/code/CreateAnimMesh.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/D3MFImporter.cpp b/code/D3MFImporter.cpp index 0d006d9a5..e97e22859 100644 --- a/code/D3MFImporter.cpp +++ b/code/D3MFImporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -87,28 +88,36 @@ namespace XmlTag { static const std::string transform = "transform"; } -class XmlSerializer { + +class XmlSerializer +{ public: XmlSerializer(XmlReader* xmlReader) - : xmlReader(xmlReader) { - // empty + : xmlReader(xmlReader) + { + // empty } void ImportXml(aiScene* scene) { scene->mRootNode = new aiNode(); std::vector children; - while(ReadToEndElement(D3MF::XmlTag::model)) { - if(xmlReader->getNodeName() == D3MF::XmlTag::object) { + while(ReadToEndElement(D3MF::XmlTag::model)) + { + + if(xmlReader->getNodeName() == D3MF::XmlTag::object) + { children.push_back(ReadObject(scene)); - } else if(xmlReader->getNodeName() == D3MF::XmlTag::build) { - // ??? + } + else if(xmlReader->getNodeName() == D3MF::XmlTag::build) + { + } } - if ( scene->mRootNode->mName.length == 0 ) { - scene->mRootNode->mName.Set( "3MF" ); - } + if(scene->mRootNode->mName.length == 0) + scene->mRootNode->mName.Set("3MF"); + scene->mNumMeshes = static_cast(meshes.size()); scene->mMeshes = new aiMesh*[scene->mNumMeshes](); @@ -119,10 +128,12 @@ public: scene->mRootNode->mChildren = new aiNode*[scene->mRootNode->mNumChildren](); std::copy(children.begin(), children.end(), scene->mRootNode->mChildren); + } private: - aiNode* ReadObject(aiScene* scene) { + aiNode* ReadObject(aiScene* scene) + { ScopeGuard node(new aiNode()); std::vector meshIds; @@ -143,14 +154,17 @@ private: size_t meshIdx = meshes.size(); - while(ReadToEndElement(D3MF::XmlTag::object)) { - if(xmlReader->getNodeName() == D3MF::XmlTag::mesh) { + while(ReadToEndElement(D3MF::XmlTag::object)) + { + if(xmlReader->getNodeName() == D3MF::XmlTag::mesh) + { auto mesh = ReadMesh(); mesh->mName.Set(name); meshes.push_back(mesh); meshIds.push_back(static_cast(meshIdx)); meshIdx++; + } } @@ -161,35 +175,49 @@ private: std::copy(meshIds.begin(), meshIds.end(), node->mMeshes); return node.dismiss(); + } - aiMesh* ReadMesh() { + aiMesh* ReadMesh() + { aiMesh* mesh = new aiMesh(); - while(ReadToEndElement(D3MF::XmlTag::mesh)) { - if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) { + + while(ReadToEndElement(D3MF::XmlTag::mesh)) + { + if(xmlReader->getNodeName() == D3MF::XmlTag::vertices) + { ImportVertices(mesh); - } else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles) { + } + else if(xmlReader->getNodeName() == D3MF::XmlTag::triangles) + { ImportTriangles(mesh); } + } + return mesh; } - void ImportVertices(aiMesh* mesh) { + void ImportVertices(aiMesh* mesh) + { std::vector vertices; - while ( ReadToEndElement(D3MF::XmlTag::vertices) ) { - if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) { + while(ReadToEndElement(D3MF::XmlTag::vertices)) + { + if(xmlReader->getNodeName() == D3MF::XmlTag::vertex) + { vertices.push_back(ReadVertex()); } } mesh->mNumVertices = static_cast(vertices.size()); mesh->mVertices = new aiVector3D[mesh->mNumVertices]; - std::copy(vertices.begin(), vertices.end(), mesh->mVertices); - } - aiVector3D ReadVertex() { + std::copy(vertices.begin(), vertices.end(), mesh->mVertices); + + } + aiVector3D ReadVertex() + { aiVector3D vertex; vertex.x = ai_strtof(xmlReader->getAttributeValue(D3MF::XmlTag::x.c_str()), nullptr); @@ -199,11 +227,15 @@ private: return vertex; } - void ImportTriangles(aiMesh* mesh) { + void ImportTriangles(aiMesh* mesh) + { std::vector faces; - while(ReadToEndElement(D3MF::XmlTag::triangles)) { - if(xmlReader->getNodeName() == D3MF::XmlTag::triangle) { + + while(ReadToEndElement(D3MF::XmlTag::triangles)) + { + if(xmlReader->getNodeName() == D3MF::XmlTag::triangle) + { faces.push_back(ReadTriangle()); } } @@ -212,12 +244,13 @@ private: mesh->mFaces = new aiFace[mesh->mNumFaces]; mesh->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; - std::copy(faces.begin(), faces.end(), mesh->mFaces); } - aiFace ReadTriangle() { + aiFace ReadTriangle() + { aiFace face; + face.mNumIndices = 3; face.mIndices = new unsigned int[face.mNumIndices]; face.mIndices[0] = static_cast(std::atoi(xmlReader->getAttributeValue(D3MF::XmlTag::v1.c_str()))); @@ -228,25 +261,35 @@ private: } private: - bool ReadToStartElement(const std::string& startTag) { - while(xmlReader->read()) { - if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && xmlReader->getNodeName() == startTag) { + + bool ReadToStartElement(const std::string& startTag) + { + while(xmlReader->read()) + { + if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT && xmlReader->getNodeName() == startTag) + { return true; - } else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && - xmlReader->getNodeName() == startTag) { + } + else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END && + xmlReader->getNodeName() == startTag) + { return false; } } -// DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag"); + //DefaultLogger::get()->error("unexpected EOF, expected closing <" + closeTag + "> tag"); return false; } - bool ReadToEndElement(const std::string& closeTag) { - while(xmlReader->read()) { + bool ReadToEndElement(const std::string& closeTag) + { + while(xmlReader->read()) + { if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT) { return true; - } else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END - && xmlReader->getNodeName() == closeTag) { + } + else if (xmlReader->getNodeType() == irr::io::EXN_ELEMENT_END + && xmlReader->getNodeName() == closeTag) + { return false; } } @@ -254,6 +297,7 @@ private: return false; } + private: std::vector meshes; XmlReader* xmlReader; @@ -261,6 +305,7 @@ private: } //namespace D3MF + static const aiImporterDesc desc = { "3mf Importer", "", @@ -274,15 +319,19 @@ static const aiImporterDesc desc = { "3mf" }; -D3MFImporter::D3MFImporter() { - // empty + +D3MFImporter::D3MFImporter() +{ + } -D3MFImporter::~D3MFImporter() { - // empty +D3MFImporter::~D3MFImporter() +{ + } -bool D3MFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const { +bool D3MFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool checkSig) const +{ const std::string extension = GetExtension(pFile); if(extension == "3mf") { return true; @@ -295,15 +344,18 @@ bool D3MFImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, bool return false; } -void D3MFImporter::SetupProperties(const Importer *pImp) { - // empty +void D3MFImporter::SetupProperties(const Importer *pImp) +{ + } -const aiImporterDesc *D3MFImporter::GetInfo() const { +const aiImporterDesc *D3MFImporter::GetInfo() const +{ return &desc; } -void D3MFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) { +void D3MFImporter::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) +{ D3MF::D3MFOpcPackage opcPackage(pIOHandler, pFile); std::unique_ptr xmlStream(new CIrrXML_IOStreamReader(opcPackage.RootStream())); diff --git a/code/D3MFImporter.h b/code/D3MFImporter.h index 372dc59ed..fb65d8606 100644 --- a/code/D3MFImporter.h +++ b/code/D3MFImporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/D3MFOpcPackage.cpp b/code/D3MFOpcPackage.cpp index a9633b6a5..b6b1ba170 100644 --- a/code/D3MFOpcPackage.cpp +++ b/code/D3MFOpcPackage.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -48,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include #include @@ -227,7 +229,7 @@ ZipFile::~ZipFile() { size_t ZipFile::Read(void* pvBuffer, size_t pSize, size_t pCount) { const size_t size = pSize * pCount; - assert(size <= m_Size); + ai_assert(size <= m_Size); std::memcpy(pvBuffer, m_Buffer, size); diff --git a/code/D3MFOpcPackage.h b/code/D3MFOpcPackage.h index e63243676..e46eb7636 100644 --- a/code/D3MFOpcPackage.h +++ b/code/D3MFOpcPackage.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/DXFHelper.h b/code/DXFHelper.h index 1947469a8..e16b7f1aa 100644 --- a/code/DXFHelper.h +++ b/code/DXFHelper.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/DXFLoader.cpp b/code/DXFLoader.cpp index f1acb65f2..1e932e509 100644 --- a/code/DXFLoader.cpp +++ b/code/DXFLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/DXFLoader.h b/code/DXFLoader.h index 2b61c19a9..64822e9e2 100644 --- a/code/DXFLoader.h +++ b/code/DXFLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/DeboneProcess.cpp b/code/DeboneProcess.cpp index 41941b4ac..b43dcad84 100644 --- a/code/DeboneProcess.cpp +++ b/code/DeboneProcess.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/DeboneProcess.h b/code/DeboneProcess.h index 5920473e2..75f158c03 100644 --- a/code/DeboneProcess.h +++ b/code/DeboneProcess.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/DefaultIOStream.cpp b/code/DefaultIOStream.cpp index db1b6baf8..cce9af19d 100644 --- a/code/DefaultIOStream.cpp +++ b/code/DefaultIOStream.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/DefaultIOSystem.cpp b/code/DefaultIOSystem.cpp index 711476806..ca4ae4564 100644 --- a/code/DefaultIOSystem.cpp +++ b/code/DefaultIOSystem.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/DefaultLogger.cpp b/code/DefaultLogger.cpp index 106c51561..b69e18ea9 100644 --- a/code/DefaultLogger.cpp +++ b/code/DefaultLogger.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -252,8 +253,8 @@ void DefaultLogger::kill() // Debug message void DefaultLogger::OnDebug( const char* message ) { - if ( m_Severity == Logger::NORMAL ) - return; + if ( m_Severity == Logger::NORMAL ) + return; static const size_t Size = MAX_LOG_MESSAGE_LENGTH + 16; char msg[Size]; diff --git a/code/DefaultProgressHandler.h b/code/DefaultProgressHandler.h index b729e4bfa..6cd872eaa 100644 --- a/code/DefaultProgressHandler.h +++ b/code/DefaultProgressHandler.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Exporter.cpp b/code/Exporter.cpp index 65e40eec2..1e2d7cbf1 100644 --- a/code/Exporter.cpp +++ b/code/Exporter.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -53,7 +54,7 @@ Here we implement only the C++ interface (Assimp::Exporter). #ifndef ASSIMP_BUILD_NO_EXPORT #include "BlobIOSystem.h" -#include "SceneCombiner.h" +#include #include "BaseProcess.h" #include "Importer.h" // need this for GetPostProcessingStepInstanceList() @@ -89,6 +90,7 @@ void ExportScenePlyBinary(const char*, IOSystem*, const aiScene*, const ExportPr void ExportScene3DS(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneGLTF(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneGLB(const char*, IOSystem*, const aiScene*, const ExportProperties*); +void ExportSceneGLTF2(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneAssbin(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneAssxml(const char*, IOSystem*, const aiScene*, const ExportProperties*); void ExportSceneX3D(const char*, IOSystem*, const aiScene*, const ExportProperties*); @@ -143,6 +145,8 @@ Exporter::ExportFormatEntry gExporters[] = aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType), Exporter::ExportFormatEntry( "glb", "GL Transmission Format (binary)", "glb", &ExportSceneGLB, aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType), + Exporter::ExportFormatEntry( "gltf2", "GL Transmission Format v. 2", "gltf2", &ExportSceneGLTF2, + aiProcess_JoinIdenticalVertices | aiProcess_Triangulate | aiProcess_SortByPType), #endif #ifndef ASSIMP_BUILD_NO_ASSBIN_EXPORTER @@ -171,8 +175,10 @@ public: GetPostProcessingStepInstanceList(mPostProcessingSteps); // grab all built-in exporters - mExporters.resize(ASSIMP_NUM_EXPORTERS); - std::copy(gExporters,gExporters+ASSIMP_NUM_EXPORTERS,mExporters.begin()); + if ( 0 != ( ASSIMP_NUM_EXPORTERS ) ) { + mExporters.resize( ASSIMP_NUM_EXPORTERS ); + std::copy( gExporters, gExporters + ASSIMP_NUM_EXPORTERS, mExporters.begin() ); + } } ~ExporterPimpl() @@ -186,7 +192,6 @@ public: } public: - aiExportDataBlob* blob; std::shared_ptr< Assimp::IOSystem > mIOSystem; bool mIsDefaultIOHandler; @@ -407,6 +412,7 @@ aiReturn Exporter::Export( const aiScene* pScene, const char* pFormatId, const c pimpl->mError = std::string("Found no exporter to handle this file format: ") + pFormatId; ASSIMP_END_EXCEPTION_REGION(aiReturn); + return AI_FAILURE; } @@ -491,7 +497,6 @@ ExportProperties::ExportProperties(const ExportProperties &other) // empty } - // ------------------------------------------------------------------------------------------------ // Set a configuration property bool ExportProperties::SetPropertyInteger(const char* szName, int iValue) { diff --git a/code/FBXAnimation.cpp b/code/FBXAnimation.cpp index 09d7c184d..6f9613f0d 100644 --- a/code/FBXAnimation.cpp +++ b/code/FBXAnimation.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -49,12 +50,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "FBXDocument.h" #include "FBXImporter.h" #include "FBXDocumentUtil.h" -#include "FBXProperties.h" namespace Assimp { namespace FBX { - using namespace Util; +using namespace Util; // ------------------------------------------------------------------------------------------------ AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::string& name, const Document& /*doc*/) @@ -87,17 +87,16 @@ AnimationCurve::AnimationCurve(uint64_t id, const Element& element, const std::s } } - // ------------------------------------------------------------------------------------------------ AnimationCurve::~AnimationCurve() { - + // empty } - // ------------------------------------------------------------------------------------------------ -AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, const Document& doc, - const char* const * target_prop_whitelist /*= NULL*/, size_t whitelist_size /*= 0*/) +AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, const std::string& name, + const Document& doc, const char* const * target_prop_whitelist /*= NULL*/, + size_t whitelist_size /*= 0*/) : Object(id, element, name) , target() , doc(doc) @@ -154,18 +153,16 @@ AnimationCurveNode::AnimationCurveNode(uint64_t id, const Element& element, cons props = GetPropertyTable(doc,"AnimationCurveNode.FbxAnimCurveNode",element,sc,false); } - // ------------------------------------------------------------------------------------------------ AnimationCurveNode::~AnimationCurveNode() { - + // empty } - // ------------------------------------------------------------------------------------------------ const AnimationCurveMap& AnimationCurveNode::Curves() const { - if(curves.empty()) { + if ( curves.empty() ) { // resolve attached animation curves const std::vector& conns = doc.GetConnectionsByDestinationSequenced(ID(),"AnimationCurve"); @@ -195,7 +192,6 @@ const AnimationCurveMap& AnimationCurveNode::Curves() const return curves; } - // ------------------------------------------------------------------------------------------------ AnimationLayer::AnimationLayer(uint64_t id, const Element& element, const std::string& name, const Document& doc) : Object(id, element, name) @@ -207,14 +203,12 @@ AnimationLayer::AnimationLayer(uint64_t id, const Element& element, const std::s props = GetPropertyTable(doc,"AnimationLayer.FbxAnimLayer",element,sc, true); } - // ------------------------------------------------------------------------------------------------ AnimationLayer::~AnimationLayer() { - + // empty } - // ------------------------------------------------------------------------------------------------ AnimationCurveNodeList AnimationLayer::Nodes(const char* const * target_prop_whitelist /*= NULL*/, size_t whitelist_size /*= 0*/) const @@ -298,14 +292,13 @@ AnimationStack::AnimationStack(uint64_t id, const Element& element, const std::s } } - // ------------------------------------------------------------------------------------------------ AnimationStack::~AnimationStack() { - + // empty } } //!FBX } //!Assimp -#endif +#endif // ASSIMP_BUILD_NO_FBX_IMPORTER diff --git a/code/FBXBinaryTokenizer.cpp b/code/FBXBinaryTokenizer.cpp index 550859345..ede32d7b7 100644 --- a/code/FBXBinaryTokenizer.cpp +++ b/code/FBXBinaryTokenizer.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -55,47 +56,46 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { namespace FBX { -enum Flag -{ - e_unknown_0 = 1 << 0, - e_unknown_1 = 1 << 1, - e_unknown_2 = 1 << 2, - e_unknown_3 = 1 << 3, - e_unknown_4 = 1 << 4, - e_unknown_5 = 1 << 5, - e_unknown_6 = 1 << 6, - e_unknown_7 = 1 << 7, - e_unknown_8 = 1 << 8, - e_unknown_9 = 1 << 9, - e_unknown_10 = 1 << 10, - e_unknown_11 = 1 << 11, - e_unknown_12 = 1 << 12, - e_unknown_13 = 1 << 13, - e_unknown_14 = 1 << 14, - e_unknown_15 = 1 << 15, - e_unknown_16 = 1 << 16, - e_unknown_17 = 1 << 17, - e_unknown_18 = 1 << 18, - e_unknown_19 = 1 << 19, - e_unknown_20 = 1 << 20, - 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_unknown_25 = 1 << 25, - e_unknown_26 = 1 << 26, - e_unknown_27 = 1 << 27, - e_unknown_28 = 1 << 28, - e_unknown_29 = 1 << 29, - e_unknown_30 = 1 << 30, - e_unknown_31 = 1 << 31 -}; - -bool check_flag(uint32_t flags, Flag to_check) -{ - return (flags & to_check) != 0; -} - +//enum Flag +//{ +// e_unknown_0 = 1 << 0, +// e_unknown_1 = 1 << 1, +// e_unknown_2 = 1 << 2, +// e_unknown_3 = 1 << 3, +// e_unknown_4 = 1 << 4, +// e_unknown_5 = 1 << 5, +// e_unknown_6 = 1 << 6, +// e_unknown_7 = 1 << 7, +// e_unknown_8 = 1 << 8, +// e_unknown_9 = 1 << 9, +// e_unknown_10 = 1 << 10, +// e_unknown_11 = 1 << 11, +// e_unknown_12 = 1 << 12, +// e_unknown_13 = 1 << 13, +// e_unknown_14 = 1 << 14, +// e_unknown_15 = 1 << 15, +// e_unknown_16 = 1 << 16, +// e_unknown_17 = 1 << 17, +// e_unknown_18 = 1 << 18, +// e_unknown_19 = 1 << 19, +// e_unknown_20 = 1 << 20, +// 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_unknown_25 = 1 << 25, +// e_unknown_26 = 1 << 26, +// e_unknown_27 = 1 << 27, +// e_unknown_28 = 1 << 28, +// e_unknown_29 = 1 << 29, +// e_unknown_30 = 1 << 30, +// e_unknown_31 = 1 << 31 +//}; +// +//bool check_flag(uint32_t flags, Flag to_check) +//{ +// return (flags & to_check) != 0; +//} // ------------------------------------------------------------------------------------------------ Token::Token(const char* sbegin, const char* send, TokenType type, unsigned int offset) : @@ -160,8 +160,7 @@ uint32_t ReadWord(const char* input, const char*& cursor, const char* end) } // ------------------------------------------------------------------------------------------------ -uint64_t ReadDoubleWord(const char* input, const char*& cursor, const char* end) -{ +uint64_t ReadDoubleWord(const char* input, const char*& cursor, const char* end) { const size_t k_to_read = sizeof(uint64_t); if(Offset(cursor, end) < k_to_read) { TokenizeError("cannot ReadDoubleWord, out of bounds",input, cursor); @@ -175,7 +174,6 @@ uint64_t ReadDoubleWord(const char* input, const char*& cursor, const char* end) return dword; } - // ------------------------------------------------------------------------------------------------ uint8_t ReadByte(const char* input, const char*& cursor, const char* end) { @@ -342,10 +340,10 @@ void ReadData(const char*& sbegin_out, const char*& send_out, const char* input, // ------------------------------------------------------------------------------------------------ -bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, const char* end, uint32_t const flags) +bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, const char* end, bool const is64bits) { // the first word contains the offset at which this block ends - const uint64_t end_offset = /*check_flag(flags, e_flag_field_size_64_bit) ? ReadDoubleWord(input, cursor, end) : */ReadWord(input, cursor, end); + const uint64_t end_offset = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); // we may get 0 if reading reached the end of the file - // fbx files have a mysterious extra footer which I don't know @@ -363,10 +361,10 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, } // the second data word contains the number of properties in the scope - const uint64_t prop_count = /*check_flag(flags, e_flag_field_size_64_bit) ? ReadDoubleWord(input, cursor, end) : */ReadWord(input, cursor, end); + const uint64_t prop_count = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); // the third data word contains the length of the property list - const uint64_t prop_length = /*check_flag(flags, e_flag_field_size_64_bit) ? ReadDoubleWord(input, cursor, end) :*/ ReadWord(input, cursor, end); + const uint64_t prop_length = is64bits ? ReadDoubleWord(input, cursor, end) : ReadWord(input, cursor, end); // now comes the name of the scope/key const char* sbeg, *send; @@ -393,7 +391,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, // at the end of each nested block, there is a NUL record to indicate // that the sub-scope exists (i.e. to distinguish between P: and P : {}) // this NUL record is 13 bytes long on 32 bit version and 25 bytes long on 64 bit. - const size_t sentinel_block_length = /*check_flag(flags, e_flag_field_size_64_bit) ? (sizeof(uint64_t) * 3 + 1) : */(sizeof(uint32_t) * 3 + 1); + const size_t sentinel_block_length = is64bits ? (sizeof(uint64_t)* 3 + 1) : (sizeof(uint32_t)* 3 + 1); if (Offset(input, cursor) < end_offset) { if (end_offset - Offset(input, cursor) < sentinel_block_length) { @@ -404,7 +402,7 @@ bool ReadScope(TokenList& output_tokens, const char* input, const char*& cursor, // XXX this is vulnerable to stack overflowing .. while(Offset(input, cursor) < end_offset - sentinel_block_length) { - ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, flags); + ReadScope(output_tokens, input, cursor, input + end_offset - sentinel_block_length, is64bits); } output_tokens.push_back(new_Token(cursor, cursor + 1, TokenType_CLOSE_BRACKET, Offset(input, cursor) )); @@ -427,6 +425,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) { ai_assert(input); @@ -439,18 +438,17 @@ void TokenizeBinary(TokenList& output_tokens, const char* input, unsigned int le TokenizeError("magic bytes not found",0); } - - //uint32_t offset = 0x15; - const char* cursor = input + 0x15; - - const uint32_t flags = ReadWord(input, cursor, input + length); - - const uint8_t padding_0 = ReadByte(input, cursor, input + length); // unused - const uint8_t padding_1 = ReadByte(input, cursor, input + length); // unused - + const char* cursor = input + 18; + /*Result ignored*/ ReadByte(input, cursor, input + length); + /*Result ignored*/ ReadByte(input, cursor, input + length); + /*Result ignored*/ ReadByte(input, cursor, input + length); + /*Result ignored*/ ReadByte(input, cursor, input + length); + /*Result ignored*/ ReadByte(input, cursor, input + length); + const uint32_t version = ReadWord(input, cursor, input + length); + const bool is64bits = version >= 7500; while (cursor < input + length) { - if(!ReadScope(output_tokens, input, cursor, input + length, flags)) { + if (!ReadScope(output_tokens, input, cursor, input + length, is64bits)) { break; } } diff --git a/code/FBXCompileConfig.h b/code/FBXCompileConfig.h index c3934e0c8..56aa1c787 100644 --- a/code/FBXCompileConfig.h +++ b/code/FBXCompileConfig.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -65,4 +66,4 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # endif #endif -#endif +#endif // INCLUDED_AI_FBX_COMPILECONFIG_H diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index 30d332f5b..1a80fa4f5 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -54,9 +55,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "StringComparison.h" #include + #include #include - #include #include @@ -435,6 +436,19 @@ private: aiScene* const out; const FBX::Document& doc; + + bool FindTextureIndexByFilename(const Video& video, unsigned int& index) { + index = 0; + const char* videoFileName = video.FileName().c_str(); + for (auto texture = textures_converted.begin(); texture != textures_converted.end(); ++texture) + { + if (!strcmp(texture->first->FileName().c_str(), videoFileName)) { + return true; + } + index++; + } + return false; + } }; Converter::Converter( aiScene* out, const Document& doc ) @@ -917,7 +931,7 @@ bool Converter::NeedsComplexTransformationChain( const Model& model ) const TransformationComp comp = static_cast< TransformationComp >( i ); if ( comp == TransformationComp_Rotation || comp == TransformationComp_Scaling || comp == TransformationComp_Translation || - comp == TransformationComp_GeometricScaling || comp == TransformationComp_GeometricRotation || comp == TransformationComp_GeometricTranslation ) { + comp == TransformationComp_GeometricScaling || comp == TransformationComp_GeometricRotation || comp == TransformationComp_GeometricTranslation ) { continue; } @@ -935,8 +949,7 @@ std::string Converter::NameTransformationChainNode( const std::string& name, Tra return name + std::string( MAGIC_NODE_TAG ) + "_" + NameTransformationComp( comp ); } -void Converter::GenerateTransformationNodeChain( const Model& model, - std::vector& output_nodes ) +void Converter::GenerateTransformationNodeChain( const Model& model, std::vector& output_nodes ) { const PropertyTable& props = model.Props(); const Model::RotOrder rot = model.RotationOrder(); @@ -1051,6 +1064,10 @@ void Converter::GenerateTransformationNodeChain( const Model& model, continue; } + if ( comp == TransformationComp_PostRotation ) { + chain[ i ] = chain[ i ].Inverse(); + } + aiNode* nd = new aiNode(); output_nodes.push_back( nd ); @@ -1079,7 +1096,7 @@ void Converter::SetupNodeMetadata( const Model& model, aiNode& nd ) DirectPropertyMap unparsedProperties = props.GetUnparsedProperties(); // create metadata on node - std::size_t numStaticMetaData = 2; + const std::size_t numStaticMetaData = 2; aiMetadata* data = aiMetadata::Alloc( static_cast(unparsedProperties.size() + numStaticMetaData) ); nd.mMetaData = data; int index = 0; @@ -1748,7 +1765,7 @@ unsigned int Converter::ConvertVideo( const Video& video ) 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 + // 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 @@ -1782,22 +1799,32 @@ void Converter::TrySetTextureProperties( aiMaterial* out_mat, const TextureMap& path.Set( tex->RelativeFilename() ); const Video* media = tex->Media(); - if ( media != 0 && media->ContentLength() > 0 ) { - unsigned int index; + if (media != 0) { + bool textureReady = false; //tells if our texture is ready (if it was loaded or if it was found) + unsigned int index; - VideoMap::const_iterator it = textures_converted.find( media ); - if ( it != textures_converted.end() ) { - index = ( *it ).second; - } - else { - index = ConvertVideo( *media ); - textures_converted[ media ] = 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; + } + else if (doc.Settings().searchEmbeddedTextures) { //try to find the texture on the already-loaded textures by the filename, if the flag is on + textureReady = FindTextureIndexByFilename(*media, index); + } + } - // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture) - path.data[ 0 ] = '*'; - path.length = 1 + ASSIMP_itoa10( path.data + 1, MAXLEN - 1, index ); - } + // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture), if the texture is ready + if (textureReady) { + path.data[0] = '*'; + path.length = 1 + ASSIMP_itoa10(path.data + 1, MAXLEN - 1, index); + } + } out_mat->AddProperty( &path, _AI_MATKEY_TEXTURE_BASE, target, 0 ); @@ -2344,8 +2371,13 @@ void Converter::ConvertAnimationStack( const AnimationStack& st ) int64_t start_time = st.LocalStart(); int64_t stop_time = st.LocalStop(); - double start_timeF = CONVERT_FBX_TIME( start_time ); - double stop_timeF = CONVERT_FBX_TIME( stop_time ); + 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 ) { @@ -2377,27 +2409,23 @@ void Converter::ConvertAnimationStack( const AnimationStack& st ) return; } - //adjust relative timing for animation - { - double start_fps = start_timeF * anim_fps; + 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; - 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_fps; - for ( uint32_t i = 0; i < channel->mNumRotationKeys; i++ ) - channel->mRotationKeys[ i ].mTime -= start_fps; - for ( uint32_t i = 0; i < channel->mNumScalingKeys; i++ ) - channel->mScalingKeys[ i ].mTime -= start_fps; - } - - max_time -= min_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_timeF - start_timeF ) * anim_fps; + anim->mDuration = stop_time_fps - start_time_fps; anim->mTicksPerSecond = anim_fps; } @@ -3095,7 +3123,6 @@ void Converter::InterpolateKeys( aiVectorKey* valOut, const KeyTimeList& keys, c } } - void Converter::InterpolateKeys( aiQuatKey* valOut, const KeyTimeList& keys, const KeyFrameListList& inputs, const aiVector3D& def_value, double& maxTime, @@ -3116,7 +3143,6 @@ void Converter::InterpolateKeys( aiQuatKey* valOut, const KeyTimeList& keys, con valOut[ i ].mTime = temp[ i ].mTime; - GetRotationMatrix( order, temp[ i ].mValue, m ); aiQuaternion quat = aiQuaternion( aiMatrix3x3( m ) ); @@ -3135,7 +3161,6 @@ void Converter::InterpolateKeys( aiQuatKey* valOut, const KeyTimeList& keys, con } } - void Converter::ConvertTransformOrder_TRStoSRT( aiQuatKey* out_quat, aiVectorKey* out_scale, aiVectorKey* out_translation, const KeyFrameListList& scaling, @@ -3194,7 +3219,6 @@ void Converter::ConvertTransformOrder_TRStoSRT( aiQuatKey* out_quat, aiVectorKey } } - aiQuaternion Converter::EulerToQuaternion( const aiVector3D& rot, Model::RotOrder order ) { aiMatrix4x4 m; @@ -3203,7 +3227,6 @@ aiQuaternion Converter::EulerToQuaternion( const aiVector3D& rot, Model::RotOrde return aiQuaternion( aiMatrix3x3( m ) ); } - void Converter::ConvertScaleKeys( aiNodeAnim* na, const std::vector& nodes, const LayerMap& /*layers*/, int64_t start, int64_t stop, double& maxTime, @@ -3224,7 +3247,6 @@ void Converter::ConvertScaleKeys( aiNodeAnim* na, const std::vectormScalingKeys, keys, inputs, aiVector3D( 1.0f, 1.0f, 1.0f ), maxTime, minTime ); } - void Converter::ConvertTranslationKeys( aiNodeAnim* na, const std::vector& nodes, const LayerMap& /*layers*/, int64_t start, int64_t stop, @@ -3243,7 +3265,6 @@ void Converter::ConvertTranslationKeys( aiNodeAnim* na, const std::vectormPositionKeys, keys, inputs, aiVector3D( 0.0f, 0.0f, 0.0f ), maxTime, minTime ); } - void Converter::ConvertRotationKeys( aiNodeAnim* na, const std::vector& nodes, const LayerMap& /*layers*/, int64_t start, int64_t stop, @@ -3265,7 +3286,8 @@ void Converter::ConvertRotationKeys( aiNodeAnim* na, const std::vectormMeshes && !out->mNumMeshes ); + 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 diff --git a/code/FBXConverter.h b/code/FBXConverter.h index ddbbbbf25..8a62d8811 100644 --- a/code/FBXConverter.h +++ b/code/FBXConverter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXDeformer.cpp b/code/FBXDeformer.cpp index c7cc52e5f..637144ab1 100644 --- a/code/FBXDeformer.cpp +++ b/code/FBXDeformer.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXDocument.cpp b/code/FBXDocument.cpp index 0d5e24f96..9592bf31f 100644 --- a/code/FBXDocument.cpp +++ b/code/FBXDocument.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -69,13 +70,13 @@ LazyObject::LazyObject(uint64_t id, const Element& element, const Document& doc) , id(id) , flags() { - + // empty } // ------------------------------------------------------------------------------------------------ LazyObject::~LazyObject() { - + // empty } // ------------------------------------------------------------------------------------------------ @@ -231,16 +232,15 @@ Object::Object(uint64_t id, const Element& element, const std::string& name) , name(name) , id(id) { - + // empty } // ------------------------------------------------------------------------------------------------ Object::~Object() { - + // empty } - // ------------------------------------------------------------------------------------------------ FileGlobalSettings::FileGlobalSettings(const Document& doc, std::shared_ptr props) : props(props) @@ -291,11 +291,10 @@ Document::~Document() } // ------------------------------------------------------------------------------------------------ -static const int LowerSupportedVersion = 7100; -static const int UpperSupportedVersion = 7400; +static const unsigned int LowerSupportedVersion = 7100; +static const unsigned int UpperSupportedVersion = 7400; -void Document::ReadHeader() -{ +void Document::ReadHeader() { // Read ID objects from "Objects" section const Scope& sc = parser.GetRootScope(); const Element* const ehead = sc["FBXHeaderExtension"]; @@ -361,7 +360,6 @@ void Document::ReadGlobalSettings() globals.reset(new FileGlobalSettings(*this, props)); } - // ------------------------------------------------------------------------------------------------ void Document::ReadObjects() { @@ -387,7 +385,6 @@ void Document::ReadObjects() } const char* err; - const uint64_t id = ParseTokenAsID(*tok[0], err); if(err) { DOMError(err,el.second); @@ -469,8 +466,6 @@ void Document::ReadPropertyTemplates() } } - - // ------------------------------------------------------------------------------------------------ void Document::ReadConnections() { @@ -482,7 +477,6 @@ void Document::ReadConnections() } uint64_t insertionOrder = 0l; - const Scope& sconns = *econns->Compound(); const ElementCollection conns = sconns.GetCollection("C"); for(ElementMap::const_iterator it = conns.first; it != conns.second; ++it) { @@ -491,7 +485,9 @@ void Document::ReadConnections() // PP = property-property connection, ignored for now // (tokens: "PP", ID1, "Property1", ID2, "Property2") - if(type == "PP") continue; + if ( type == "PP" ) { + continue; + } const uint64_t src = ParseTokenAsID(GetRequiredToken(el,1)); const uint64_t dest = ParseTokenAsID(GetRequiredToken(el,2)); @@ -518,11 +514,10 @@ void Document::ReadConnections() } } - // ------------------------------------------------------------------------------------------------ const std::vector& Document::AnimationStacks() const { - if (!animationStacksResolved.empty() || !animationStacks.size()) { + if (!animationStacksResolved.empty() || animationStacks.empty()) { return animationStacksResolved; } @@ -540,7 +535,6 @@ const std::vector& Document::AnimationStacks() const return animationStacksResolved; } - // ------------------------------------------------------------------------------------------------ LazyObject* Document::GetObject(uint64_t id) const { @@ -551,8 +545,7 @@ LazyObject* Document::GetObject(uint64_t id) const #define MAX_CLASSNAMES 6 // ------------------------------------------------------------------------------------------------ -std::vector Document::GetConnectionsSequenced(uint64_t id, - const ConnectionMap& conns) const +std::vector Document::GetConnectionsSequenced(uint64_t id, const ConnectionMap& conns) const { std::vector temp; @@ -564,12 +557,11 @@ std::vector Document::GetConnectionsSequenced(uint64_t id, temp.push_back((*it).second); } - std::sort(temp.begin(), temp.end(), std::mem_fun(&Connection::Compare)); + std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare)); return temp; // NRVO should handle this } - // ------------------------------------------------------------------------------------------------ std::vector Document::GetConnectionsSequenced(uint64_t id, bool is_src, const ConnectionMap& conns, @@ -578,17 +570,17 @@ std::vector Document::GetConnectionsSequenced(uint64_t id, bo { ai_assert(classnames); - ai_assert(count != 0 && count <= MAX_CLASSNAMES); + ai_assert( count != 0 ); + ai_assert( count <= MAX_CLASSNAMES); size_t lenghts[MAX_CLASSNAMES]; const size_t c = count; for (size_t i = 0; i < c; ++i) { - lenghts[i] = strlen(classnames[i]); + lenghts[ i ] = strlen(classnames[i]); } std::vector temp; - const std::pair range = conns.equal_range(id); @@ -616,53 +608,44 @@ std::vector Document::GetConnectionsSequenced(uint64_t id, bo temp.push_back((*it).second); } - std::sort(temp.begin(), temp.end(), std::mem_fun(&Connection::Compare)); + std::sort(temp.begin(), temp.end(), std::mem_fn(&Connection::Compare)); return temp; // NRVO should handle this } - // ------------------------------------------------------------------------------------------------ std::vector Document::GetConnectionsBySourceSequenced(uint64_t source) const { return GetConnectionsSequenced(source, ConnectionsBySource()); } - - // ------------------------------------------------------------------------------------------------ -std::vector Document::GetConnectionsBySourceSequenced(uint64_t dest, - const char* classname) const +std::vector Document::GetConnectionsBySourceSequenced(uint64_t dest, const char* classname) const { const char* arr[] = {classname}; return GetConnectionsBySourceSequenced(dest, arr,1); } - - // ------------------------------------------------------------------------------------------------ -std::vector Document::GetConnectionsBySourceSequenced(uint64_t source, - const char* const* classnames, size_t count) const +std::vector Document::GetConnectionsBySourceSequenced(uint64_t source, + const char* const* classnames, size_t count) const { return GetConnectionsSequenced(source, true, ConnectionsBySource(),classnames, count); } - // ------------------------------------------------------------------------------------------------ std::vector Document::GetConnectionsByDestinationSequenced(uint64_t dest, - const char* classname) const + const char* classname) const { const char* arr[] = {classname}; return GetConnectionsByDestinationSequenced(dest, arr,1); } - // ------------------------------------------------------------------------------------------------ std::vector Document::GetConnectionsByDestinationSequenced(uint64_t dest) const { return GetConnectionsSequenced(dest, ConnectionsByDestination()); } - // ------------------------------------------------------------------------------------------------ std::vector Document::GetConnectionsByDestinationSequenced(uint64_t dest, const char* const* classnames, size_t count) const @@ -671,10 +654,9 @@ std::vector Document::GetConnectionsByDestinationSequenced(ui return GetConnectionsSequenced(dest, false, ConnectionsByDestination(),classnames, count); } - // ------------------------------------------------------------------------------------------------ Connection::Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, const std::string& prop, - const Document& doc) + const Document& doc) : insertionOrder(insertionOrder) , prop(prop) @@ -687,14 +669,12 @@ Connection::Connection(uint64_t insertionOrder, uint64_t src, uint64_t dest, co ai_assert(!dest || doc.Objects().find(dest) != doc.Objects().end()); } - // ------------------------------------------------------------------------------------------------ Connection::~Connection() { - + // empty } - // ------------------------------------------------------------------------------------------------ LazyObject& Connection::LazySourceObject() const { @@ -703,7 +683,6 @@ LazyObject& Connection::LazySourceObject() const return *lazy; } - // ------------------------------------------------------------------------------------------------ LazyObject& Connection::LazyDestinationObject() const { @@ -712,7 +691,6 @@ LazyObject& Connection::LazyDestinationObject() const return *lazy; } - // ------------------------------------------------------------------------------------------------ const Object* Connection::SourceObject() const { @@ -721,7 +699,6 @@ const Object* Connection::SourceObject() const return lazy->Get(); } - // ------------------------------------------------------------------------------------------------ const Object* Connection::DestinationObject() const { @@ -734,4 +711,3 @@ const Object* Connection::DestinationObject() const } // !Assimp #endif - diff --git a/code/FBXDocument.h b/code/FBXDocument.h index 9c446250b..a4e28b2aa 100644 --- a/code/FBXDocument.h +++ b/code/FBXDocument.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -337,12 +338,7 @@ public: class Model : public Object { public: - Model(uint64_t id, const Element& element, const Document& doc, const std::string& name); - virtual ~Model(); - -public: - enum RotOrder - { + enum RotOrder { RotOrder_EulerXYZ = 0, RotOrder_EulerXZY, RotOrder_EulerYZX, @@ -356,8 +352,7 @@ public: }; - enum TransformInheritance - { + enum TransformInheritance { TransformInheritance_RrSs = 0, TransformInheritance_RSrs, TransformInheritance_Rrs, @@ -365,7 +360,10 @@ public: TransformInheritance_MAX // end-of-enum sentinel }; -public: + Model(uint64_t id, const Element& element, const Document& doc, const std::string& name); + + virtual ~Model(); + fbx_simple_property(QuaternionInterpolate, int, 0) fbx_simple_property(RotationOffset, aiVector3D, aiVector3D()) @@ -442,7 +440,6 @@ public: fbx_simple_property(LODBox, bool, false) fbx_simple_property(Freeze, bool, false) -public: const std::string& Shading() const { return shading; } @@ -461,13 +458,11 @@ public: return materials; } - /** Get geometry links */ const std::vector& GetGeometry() const { return geometry; } - /** Get node attachments */ const std::vector& GetAttributes() const { return attributes; @@ -476,7 +471,6 @@ public: /** convenience method to check if the node has a Null node marker */ bool IsNull() const; - private: void ResolveLinks(const Element& element, const Document& doc); @@ -602,10 +596,10 @@ public: return textures[index]; } - const int textureCount() const { + int textureCount() const { return static_cast(textures.size()); } - const BlendMode GetBlendMode() const + BlendMode GetBlendMode() const { return blendMode; } @@ -653,7 +647,7 @@ public: return content; } - const uint32_t ContentLength() const { + uint32_t ContentLength() const { return contentLength; } @@ -804,7 +798,6 @@ private: typedef std::vector AnimationCurveNodeList; - /** Represents a FBX animation layer (i.e. a list of node animations) */ class AnimationLayer : public Object { @@ -827,10 +820,8 @@ private: const Document& doc; }; - typedef std::vector AnimationLayerList; - /** Represents a FBX animation stack (i.e. a list of animation layers) */ class AnimationStack : public Object { @@ -838,7 +829,6 @@ public: AnimationStack(uint64_t id, const Element& element, const std::string& name, const Document& doc); virtual ~AnimationStack(); -public: fbx_simple_property(LocalStart, int64_t, 0L) fbx_simple_property(LocalStop, int64_t, 0L) fbx_simple_property(ReferenceStart, int64_t, 0L) @@ -878,7 +868,6 @@ private: typedef std::vector WeightArray; typedef std::vector WeightIndexArray; - /** DOM class for skin deformer clusters (aka subdeformers) */ class Cluster : public Deformer { @@ -923,8 +912,6 @@ private: const Model* node; }; - - /** DOM class for skin deformers */ class Skin : public Deformer { @@ -1008,10 +995,8 @@ public: typedef std::map ObjectMap; typedef std::fbx_unordered_map > PropertyTemplateMap; - typedef std::multimap ConnectionMap; - /** DOM class for global document settings, a single instance per document can * be accessed via Document.Globals(). */ class FileGlobalSettings @@ -1073,9 +1058,6 @@ private: const Document& doc; }; - - - /** DOM root for a FBX file */ class Document { @@ -1153,8 +1135,6 @@ private: const ConnectionMap&, const char* const* classnames, size_t count) const; - -private: void ReadHeader(); void ReadObjects(); void ReadPropertyTemplates(); diff --git a/code/FBXDocumentUtil.cpp b/code/FBXDocumentUtil.cpp index 442c60b5d..27921b920 100644 --- a/code/FBXDocumentUtil.cpp +++ b/code/FBXDocumentUtil.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXImportSettings.h b/code/FBXImportSettings.h index df7cdbd37..53fa64ec6 100644 --- a/code/FBXImportSettings.h +++ b/code/FBXImportSettings.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -62,6 +63,7 @@ struct ImportSettings , readWeights(true) , preservePivots(true) , optimizeEmptyAnimationCurves(true) + , searchEmbeddedTextures(false) {} @@ -136,6 +138,10 @@ struct ImportSettings * values matching the corresponding node transformation. * The default value is true. */ bool optimizeEmptyAnimationCurves; + + /** search for embedded loaded textures, where no embedded texture data is provided. + * The default value is false. */ + bool searchEmbeddedTextures; }; diff --git a/code/FBXImporter.cpp b/code/FBXImporter.cpp index 83b74f8cd..51e41b8f4 100644 --- a/code/FBXImporter.cpp +++ b/code/FBXImporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -58,7 +59,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include namespace Assimp { - template<> const std::string LogFunctions::log_prefix = "FBX: "; + template<> const char* LogFunctions::Prefix() + { + static auto prefix = "FBX: "; + return prefix; + } } using namespace Assimp; @@ -130,6 +135,7 @@ void FBXImporter::SetupProperties(const Importer* pImp) settings.strictMode = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_STRICT_MODE, false); 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.searchEmbeddedTextures = pImp->GetPropertyBool(AI_CONFIG_IMPORT_FBX_SEARCH_EMBEDDED_TEXTURES, false); } // ------------------------------------------------------------------------------------------------ diff --git a/code/FBXImporter.h b/code/FBXImporter.h index 350ecfb67..43be97ffa 100644 --- a/code/FBXImporter.h +++ b/code/FBXImporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXMaterial.cpp b/code/FBXMaterial.cpp index e5e9cd259..a80f243ba 100644 --- a/code/FBXMaterial.cpp +++ b/code/FBXMaterial.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -280,7 +281,7 @@ Video::Video(uint64_t id, const Element& element, const Document& doc, const std const Scope& sc = GetRequiredScope(element); const Element* const Type = sc["Type"]; - const Element* const FileName = sc["FileName"]; + const Element* const FileName = sc.FindElementCaseInsensitive("FileName"); //some files retain the information as "Filename", others "FileName", who knows const Element* const RelativeFilename = sc["RelativeFilename"]; const Element* const Content = sc["Content"]; @@ -290,35 +291,40 @@ Video::Video(uint64_t id, const Element& element, const Document& doc, const std if(FileName) { fileName = ParseTokenAsString(GetRequiredToken(*FileName,0)); - } + } if(RelativeFilename) { relativeFileName = ParseTokenAsString(GetRequiredToken(*RelativeFilename,0)); } if(Content) { - const Token& token = GetRequiredToken(*Content, 0); - const char* data = token.begin(); - if(!token.IsBinary()) { - DOMWarning("video content is not binary data, ignoring", &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); - } - else if(*data != 'R') { - DOMWarning("video content is not raw binary data, ignoring", &element); - } - else { - // read number of elements - uint32_t len = 0; - ::memcpy(&len, data + 1, sizeof(len)); - AI_SWAP4(len); + //this field is ommited 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); + } + 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); + } + else if (*data != 'R') { + DOMWarning("video content is not raw binary data, ignoring", &element); + } + else { + // read number of elements + uint32_t len = 0; + ::memcpy(&len, data + 1, sizeof(len)); + AI_SWAP4(len); - contentLength = len; + contentLength = len; - content = new uint8_t[len]; - ::memcpy(content, data + 5, len); - } + content = new uint8_t[len]; + ::memcpy(content, data + 5, len); + } + } catch (runtime_error runtimeError) { + //we don´t need the content data for contents that has already been loaded + } } props = GetPropertyTable(doc,"Video.FbxVideo",element,sc); diff --git a/code/FBXMeshGeometry.cpp b/code/FBXMeshGeometry.cpp index e7a105d45..8d43a2436 100644 --- a/code/FBXMeshGeometry.cpp +++ b/code/FBXMeshGeometry.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -242,7 +243,6 @@ const unsigned int* MeshGeometry::ToOutputVertexIndex( unsigned int in_index, un ai_assert( m_mapping_counts.size() == m_mapping_offsets.size() ); count = m_mapping_counts[ in_index ]; -// ai_assert( count != 0 ); ai_assert( m_mapping_offsets[ in_index ] + count <= m_mappings.size() ); return &m_mappings[ m_mapping_offsets[ in_index ] ]; @@ -356,7 +356,7 @@ void MeshGeometry::ReadVertexData(const std::string& type, int index, const Scop // avoids losing the material if there are more material layers // coming of which at least one contains actual data (did observe // that with one test file). - const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),std::bind2nd(std::less(),0)); + const size_t count_neg = std::count_if(temp_materials.begin(),temp_materials.end(),[](int n) { return n < 0; }); if(count_neg == temp_materials.size()) { FBXImporter::LogWarn("ignoring dummy material layer (all entries -1)"); return; diff --git a/code/FBXMeshGeometry.h b/code/FBXMeshGeometry.h index 690a86a01..19f7b0a9c 100644 --- a/code/FBXMeshGeometry.h +++ b/code/FBXMeshGeometry.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXModel.cpp b/code/FBXModel.cpp index 27e5429c3..3d694d7d8 100644 --- a/code/FBXModel.cpp +++ b/code/FBXModel.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -76,14 +77,12 @@ Model::Model(uint64_t id, const Element& element, const Document& doc, const std ResolveLinks(element,doc); } - // ------------------------------------------------------------------------------------------------ Model::~Model() { } - // ------------------------------------------------------------------------------------------------ void Model::ResolveLinks(const Element& element, const Document& doc) { @@ -131,7 +130,6 @@ void Model::ResolveLinks(const Element& element, const Document& doc) } } - // ------------------------------------------------------------------------------------------------ bool Model::IsNull() const { diff --git a/code/FBXNodeAttribute.cpp b/code/FBXNodeAttribute.cpp index 1638d6751..545343c09 100644 --- a/code/FBXNodeAttribute.cpp +++ b/code/FBXNodeAttribute.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -52,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { namespace FBX { - using namespace Util; +using namespace Util; // ------------------------------------------------------------------------------------------------ NodeAttribute::NodeAttribute(uint64_t id, const Element& element, const Document& doc, const std::string& name) @@ -74,7 +75,7 @@ NodeAttribute::NodeAttribute(uint64_t id, const Element& element, const Document // ------------------------------------------------------------------------------------------------ NodeAttribute::~NodeAttribute() { - + // empty } @@ -100,33 +101,30 @@ CameraSwitcher::CameraSwitcher(uint64_t id, const Element& element, const Docume } } - // ------------------------------------------------------------------------------------------------ CameraSwitcher::~CameraSwitcher() { - + // empty } - // ------------------------------------------------------------------------------------------------ Camera::Camera(uint64_t id, const Element& element, const Document& doc, const std::string& name) : NodeAttribute(id,element,doc,name) { - + // empty } - // ------------------------------------------------------------------------------------------------ Camera::~Camera() { + // empty } - // ------------------------------------------------------------------------------------------------ Light::Light(uint64_t id, const Element& element, const Document& doc, const std::string& name) : NodeAttribute(id,element,doc,name) { - + // empty } diff --git a/code/FBXParser.cpp b/code/FBXParser.cpp index 6562ef41d..b5661caf8 100644 --- a/code/FBXParser.cpp +++ b/code/FBXParser.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -223,41 +224,36 @@ Parser::Parser (const TokenList& tokens, bool is_binary) root.reset(new Scope(*this,true)); } - // ------------------------------------------------------------------------------------------------ Parser::~Parser() { + // empty } - // ------------------------------------------------------------------------------------------------ TokenPtr Parser::AdvanceToNextToken() { last = current; if (cursor == tokens.end()) { current = NULL; - } - else { + } else { current = *cursor++; } return current; } - // ------------------------------------------------------------------------------------------------ TokenPtr Parser::CurrentToken() const { return current; } - // ------------------------------------------------------------------------------------------------ TokenPtr Parser::LastToken() const { return last; } - // ------------------------------------------------------------------------------------------------ uint64_t ParseTokenAsID(const Token& t, const char*& err_out) { @@ -285,7 +281,7 @@ uint64_t ParseTokenAsID(const Token& t, const char*& err_out) unsigned int length = static_cast(t.end() - t.begin()); ai_assert(length > 0); - const char* out; + const char* out = nullptr; const uint64_t id = strtoul10_64(t.begin(),&out,&length); if (out > t.end()) { err_out = "failed to parse ID (text)"; @@ -295,7 +291,6 @@ uint64_t ParseTokenAsID(const Token& t, const char*& err_out) return id; } - // ------------------------------------------------------------------------------------------------ size_t ParseTokenAsDim(const Token& t, const char*& err_out) { @@ -332,7 +327,7 @@ size_t ParseTokenAsDim(const Token& t, const char*& err_out) return 0; } - const char* out; + const char* out = nullptr; const size_t id = static_cast(strtoul10_64(t.begin() + 1,&out,&length)); if (out > t.end()) { err_out = "failed to parse ID"; @@ -445,7 +440,7 @@ int64_t ParseTokenAsInt64(const Token& t, const char*& err_out) unsigned int length = static_cast(t.end() - t.begin()); ai_assert(length > 0); - const char* out; + const char* out = nullptr; const int64_t id = strtol10_64(t.begin(), &out, &length); if (out > t.end()) { err_out = "failed to parse Int64 (text)"; diff --git a/code/FBXParser.h b/code/FBXParser.h index 6bc34272a..4d3766d70 100644 --- a/code/FBXParser.h +++ b/code/FBXParser.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -48,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include "LogAux.h" +#include "fast_atof.h" #include "FBXCompileConfig.h" #include "FBXTokenizer.h" @@ -83,12 +85,9 @@ typedef std::pair Element class Element { public: - Element(const Token& key_token, Parser& parser); ~Element(); -public: - const Scope* Compound() const { return compound.get(); } @@ -102,14 +101,11 @@ public: } private: - const Token& key_token; TokenList tokens; std::unique_ptr compound; }; - - /** FBX data entity that consists of a 'scope', a collection * of not necessarily unique #Element instances. * @@ -123,19 +119,26 @@ private: * @endverbatim */ class Scope { - public: - Scope(Parser& parser, bool topLevel = false); ~Scope(); -public: - const Element* operator[] (const std::string& index) const { ElementMap::const_iterator it = elements.find(index); return it == elements.end() ? NULL : (*it).second; } + const Element* FindElementCaseInsensitive(const std::string& elementName) const { + const char* elementNameCStr = elementName.c_str(); + for (auto element = elements.begin(); element != elements.end(); ++element) + { + if (!ASSIMP_strincmp(element->first.c_str(), elementNameCStr, MAXLEN)) { + return element->second; + } + } + return NULL; + } + ElementCollection GetCollection(const std::string& index) const { return elements.equal_range(index); } @@ -145,28 +148,23 @@ public: } private: - ElementMap elements; }; - /** FBX parsing class, takes a list of input tokens and generates a hierarchy * of nested #Scope instances, representing the fbx DOM.*/ class Parser { public: - /** Parse given a token list. Does not take ownership of the tokens - * the objects must persist during the entire parser lifetime */ Parser (const TokenList& tokens,bool is_binary); ~Parser(); -public: const Scope& GetRootScope() const { return *root.get(); } - bool IsBinary() const { return is_binary; } @@ -220,8 +218,6 @@ void ParseVectorDataArray(std::vector& out, const Element& el); void ParseVectorDataArray(std::vector& out, const Element& e); void ParseVectorDataArray(std::vector& out, const Element& el); - - // extract a required element from a scope, abort if the element cannot be found const Element& GetRequiredElement(const Scope& sc, const std::string& index, const Element* element = NULL); @@ -230,8 +226,6 @@ const Scope& GetRequiredScope(const Element& el); // get token at a particular index const Token& GetRequiredToken(const Element& el, unsigned int index); - - // read a 4x4 matrix from an array of 16 floats aiMatrix4x4 ReadMatrix(const Element& element); diff --git a/code/FBXProperties.cpp b/code/FBXProperties.cpp index 23d072b18..774beac3c 100644 --- a/code/FBXProperties.cpp +++ b/code/FBXProperties.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXProperties.h b/code/FBXProperties.h index ed7af673d..09b8aa94c 100644 --- a/code/FBXProperties.h +++ b/code/FBXProperties.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -54,17 +55,14 @@ namespace FBX { // Forward declarations class Element; - /** Represents a dynamic property. Type info added by deriving classes, * see #TypedProperty. Example: @verbatim P: "ShininessExponent", "double", "Number", "",0.5 @endvebatim - */ -class Property -{ +class Property { protected: Property(); @@ -78,17 +76,14 @@ public: } }; - template -class TypedProperty : public Property -{ +class TypedProperty : public Property { public: explicit TypedProperty(const T& value) - : value(value) - { + : value(value) { + // empty } -public: const T& Value() const { return value; } @@ -99,21 +94,19 @@ private: typedef std::fbx_unordered_map > DirectPropertyMap; -typedef std::fbx_unordered_map PropertyMap; -typedef std::fbx_unordered_map LazyPropertyMap; +typedef std::fbx_unordered_map PropertyMap; +typedef std::fbx_unordered_map LazyPropertyMap; /** * Represents a property table as can be found in the newer FBX files (Properties60, Properties70) */ -class PropertyTable -{ +class PropertyTable { public: // in-memory property table with no source element PropertyTable(); PropertyTable(const Element& element, std::shared_ptr templateProps); ~PropertyTable(); -public: const Property* Get(const std::string& name) const; // PropertyTable's need not be coupled with FBX elements so this can be NULL @@ -134,41 +127,37 @@ private: const Element* const element; }; - // ------------------------------------------------------------------------------------------------ template -inline T PropertyGet(const PropertyTable& in, const std::string& name, - const T& defaultValue) -{ +inline +T PropertyGet(const PropertyTable& in, const std::string& name, const T& defaultValue) { const Property* const prop = in.Get(name); - if(!prop) { + if( nullptr == prop) { return defaultValue; } // strong typing, no need to be lenient const TypedProperty* const tprop = prop->As< TypedProperty >(); - if(!tprop) { + if( nullptr == tprop) { return defaultValue; } return tprop->Value(); } - // ------------------------------------------------------------------------------------------------ template -inline T PropertyGet(const PropertyTable& in, const std::string& name, - bool& result) -{ +inline +T PropertyGet(const PropertyTable& in, const std::string& name, bool& result) { const Property* const prop = in.Get(name); - if(!prop) { + if( nullptr == prop) { result = false; return T(); } // strong typing, no need to be lenient const TypedProperty* const tprop = prop->As< TypedProperty >(); - if(!tprop) { + if( nullptr == tprop) { result = false; return T(); } @@ -177,7 +166,6 @@ inline T PropertyGet(const PropertyTable& in, const std::string& name, return tprop->Value(); } - } //! FBX } //! Assimp diff --git a/code/FBXTokenizer.cpp b/code/FBXTokenizer.cpp index 7ede49f39..881dcf53d 100644 --- a/code/FBXTokenizer.cpp +++ b/code/FBXTokenizer.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXTokenizer.h b/code/FBXTokenizer.h index 3b60142e4..e00ff5b79 100644 --- a/code/FBXTokenizer.h +++ b/code/FBXTokenizer.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -100,7 +101,6 @@ public: return std::string(begin(),end()); } -public: bool IsBinary() const { return column == BINARY_MARKER; } diff --git a/code/FBXUtil.cpp b/code/FBXUtil.cpp index 280349d20..4fd91e18f 100644 --- a/code/FBXUtil.cpp +++ b/code/FBXUtil.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FBXUtil.h b/code/FBXUtil.h index 7da51dac8..c1d9459b3 100644 --- a/code/FBXUtil.h +++ b/code/FBXUtil.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FIReader.cpp b/code/FIReader.cpp new file mode 100755 index 000000000..95b22a1b8 --- /dev/null +++ b/code/FIReader.cpp @@ -0,0 +1,1824 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 FIReader.cpp +/// \brief Reader for Fast Infoset encoded binary XML files. +/// \date 2017 +/// \author Patrick Daehne + +#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER + +// Workaround for issue #1361 +// https://github.com/assimp/assimp/issues/1361 +#ifdef __ANDROID__ +#define _GLIBCXX_USE_C99 1 +#endif + +#include "FIReader.hpp" +#include "Exceptional.h" +#include +#include +#include "MemoryIOWrapper.h" +#include "irrXMLWrapper.h" +#include "../contrib/utf8cpp/source/utf8.h" +#include +#include +#include +#include +#include + +namespace Assimp { + +static const std::string parseErrorMessage = "Fast Infoset parse error"; + +static const char *xmlDeclarations[] = { + "", + "", + "", + "", + "", + "", + "", + "", + "" +}; + +static size_t parseMagic(const uint8_t *data, const uint8_t *dataEnd) { + if (dataEnd - data < 4) { + return 0; + } + uint32_t magic = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + switch (magic) { + case 0xe0000001: + return 4; + case 0x3c3f786d: // "= xmlDeclarationLength) && (memcmp(xmlDeclaration, data, xmlDeclarationLength) == 0)) { + data += xmlDeclarationLength; + if (dataEnd - data < 4) { + return 0; + } + magic = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + return magic == 0xe0000001 ? xmlDeclarationLength + 4 : 0; + } + } + return 0; + } + default: + return 0; + } +} + +static std::string parseUTF8String(const uint8_t *data, size_t len) { + return std::string((char*)data, len); +} + +static std::string parseUTF16String(const uint8_t *data, size_t len) { + if (len & 1) { + throw DeadlyImportError(parseErrorMessage); + } + size_t numShorts = len / 2; + std::vector utf16; + utf16.reserve(numShorts); + for (size_t i = 0; i < numShorts; ++i) { + short v = (data[0] << 8) | data[1]; + utf16.push_back(v); + data += 2; + } + std::string result; + utf8::utf16to8(utf16.begin(), utf16.end(), back_inserter(result)); + return result; +} + +struct FIStringValueImpl: public FIStringValue { + inline FIStringValueImpl(std::string &&value_) { value = std::move(value_); } + virtual const std::string &toString() const /*override*/ { return value; } +}; + +std::shared_ptr FIStringValue::create(std::string &&value) { + return std::make_shared(std::move(value)); +} + +struct FIHexValueImpl: public FIHexValue { + mutable std::string strValue; + mutable bool strValueValid; + inline FIHexValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } + virtual const std::string &toString() const /*override*/ { + if (!strValueValid) { + strValueValid = true; + std::ostringstream os; + os << std::hex << std::uppercase << std::setfill('0'); + std::for_each(value.begin(), value.end(), [&](uint8_t c) { os << std::setw(2) << static_cast(c); }); + strValue = os.str(); + } + return strValue; + }; +}; + +std::shared_ptr FIHexValue::create(std::vector &&value) { + return std::make_shared(std::move(value)); +} + +struct FIBase64ValueImpl: public FIBase64Value { + mutable std::string strValue; + mutable bool strValueValid; + inline FIBase64ValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } + virtual const std::string &toString() const /*override*/ { + if (!strValueValid) { + strValueValid = true; + std::ostringstream os; + uint8_t c1 = 0, c2; + int imod3 = 0; + std::vector::size_type valueSize = value.size(); + for (std::vector::size_type i = 0; i < valueSize; ++i) { + c2 = value[i]; + switch (imod3) { + case 0: + os << basis_64[c2 >> 2]; + imod3 = 1; + break; + case 1: + os << basis_64[((c1 & 0x03) << 4) | ((c2 & 0xf0) >> 4)]; + imod3 = 2; + break; + case 2: + os << basis_64[((c1 & 0x0f) << 2) | ((c2 & 0xc0) >> 6)] << basis_64[c2 & 0x3f]; + imod3 = 0; + break; + } + c1 = c2; + } + switch (imod3) { + case 1: + os << basis_64[(c1 & 0x03) << 4] << "=="; + break; + case 2: + os << basis_64[(c1 & 0x0f) << 2] << '='; + break; + } + strValue = os.str(); + } + return strValue; + }; + static const char basis_64[]; +}; + +const char FIBase64ValueImpl::basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +std::shared_ptr FIBase64Value::create(std::vector &&value) { + return std::make_shared(std::move(value)); +} + +struct FIShortValueImpl: public FIShortValue { + mutable std::string strValue; + mutable bool strValueValid; + inline FIShortValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } + virtual const std::string &toString() const /*override*/ { + if (!strValueValid) { + strValueValid = true; + std::ostringstream os; + int n = 0; + std::for_each(value.begin(), value.end(), [&](int16_t s) { if (++n > 1) os << ' '; os << s; }); + strValue = os.str(); + } + return strValue; + } +}; + +std::shared_ptr FIShortValue::create(std::vector &&value) { + return std::make_shared(std::move(value)); +} + +struct FIIntValueImpl: public FIIntValue { + mutable std::string strValue; + mutable bool strValueValid; + inline FIIntValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } + virtual const std::string &toString() const /*override*/ { + if (!strValueValid) { + strValueValid = true; + std::ostringstream os; + int n = 0; + std::for_each(value.begin(), value.end(), [&](int32_t i) { if (++n > 1) os << ' '; os << i; }); + strValue = os.str(); + } + return strValue; + }; +}; + +std::shared_ptr FIIntValue::create(std::vector &&value) { + return std::make_shared(std::move(value)); +} + +struct FILongValueImpl: public FILongValue { + mutable std::string strValue; + mutable bool strValueValid; + inline FILongValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } + virtual const std::string &toString() const /*override*/ { + if (!strValueValid) { + strValueValid = true; + std::ostringstream os; + int n = 0; + std::for_each(value.begin(), value.end(), [&](int64_t l) { if (++n > 1) os << ' '; os << l; }); + strValue = os.str(); + } + return strValue; + }; +}; + +std::shared_ptr FILongValue::create(std::vector &&value) { + return std::make_shared(std::move(value)); +} + +struct FIBoolValueImpl: public FIBoolValue { + mutable std::string strValue; + mutable bool strValueValid; + inline FIBoolValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } + virtual const std::string &toString() const /*override*/ { + if (!strValueValid) { + strValueValid = true; + std::ostringstream os; + os << std::boolalpha; + int n = 0; + std::for_each(value.begin(), value.end(), [&](bool b) { if (++n > 1) os << ' '; os << b; }); + strValue = os.str(); + } + return strValue; + }; +}; + +std::shared_ptr FIBoolValue::create(std::vector &&value) { + return std::make_shared(std::move(value)); +} + +struct FIFloatValueImpl: public FIFloatValue { + mutable std::string strValue; + mutable bool strValueValid; + inline FIFloatValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } + virtual const std::string &toString() const /*override*/ { + if (!strValueValid) { + strValueValid = true; + std::ostringstream os; + int n = 0; + std::for_each(value.begin(), value.end(), [&](float f) { if (++n > 1) os << ' '; os << f; }); + strValue = os.str(); + } + return strValue; + } +}; + +std::shared_ptr FIFloatValue::create(std::vector &&value) { + return std::make_shared(std::move(value)); +} + +struct FIDoubleValueImpl: public FIDoubleValue { + mutable std::string strValue; + mutable bool strValueValid; + inline FIDoubleValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } + virtual const std::string &toString() const /*override*/ { + if (!strValueValid) { + strValueValid = true; + std::ostringstream os; + int n = 0; + std::for_each(value.begin(), value.end(), [&](double d) { if (++n > 1) os << ' '; os << d; }); + strValue = os.str(); + } + return strValue; + } +}; + +std::shared_ptr FIDoubleValue::create(std::vector &&value) { + return std::make_shared(std::move(value)); +} + +struct FIUUIDValueImpl: public FIUUIDValue { + mutable std::string strValue; + mutable bool strValueValid; + inline FIUUIDValueImpl(std::vector &&value_): strValueValid(false) { value = std::move(value_); } + virtual const std::string &toString() const /*override*/ { + if (!strValueValid) { + strValueValid = true; + std::ostringstream os; + os << std::hex << std::uppercase << std::setfill('0'); + std::vector::size_type valueSize = value.size(); + for (std::vector::size_type i = 0; i < valueSize; ++i) { + switch (i & 15) { + case 0: + if (i > 0) { + os << ' '; + } + os << std::setw(2) << static_cast(value[i]); + break; + case 4: + case 6: + case 8: + case 10: + os << '-'; + // intentionally fall through! + case 1: + case 2: + case 3: + case 5: + case 7: + case 9: + case 11: + case 12: + case 13: + case 14: + case 15: + os << std::setw(2) << static_cast(value[i]); + break; + } + } + strValue = os.str(); + } + return strValue; + }; +}; + +std::shared_ptr FIUUIDValue::create(std::vector &&value) { + return std::make_shared(std::move(value)); +} + +struct FICDATAValueImpl: public FICDATAValue { + inline FICDATAValueImpl(std::string &&value_) { value = std::move(value_); } + virtual const std::string &toString() const /*override*/ { return value; } +}; + +std::shared_ptr FICDATAValue::create(std::string &&value) { + return std::make_shared(std::move(value)); +} + +struct FIHexDecoder: public FIDecoder { + virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { + return FIHexValue::create(std::vector(data, data + len)); + } +}; + +struct FIBase64Decoder: public FIDecoder { + virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { + return FIBase64Value::create(std::vector(data, data + len)); + } +}; + +struct FIShortDecoder: public FIDecoder { + virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { + if (len & 1) { + throw DeadlyImportError(parseErrorMessage); + } + std::vector value; + size_t numShorts = len / 2; + value.reserve(numShorts); + for (size_t i = 0; i < numShorts; ++i) { + int16_t v = (data[0] << 8) | data[1]; + value.push_back(v); + data += 2; + } + return FIShortValue::create(std::move(value)); + } +}; + +struct FIIntDecoder: public FIDecoder { + virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { + if (len & 3) { + throw DeadlyImportError(parseErrorMessage); + } + std::vector value; + size_t numInts = len / 4; + value.reserve(numInts); + for (size_t i = 0; i < numInts; ++i) { + int32_t v = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + value.push_back(v); + data += 4; + } + return FIIntValue::create(std::move(value)); + } +}; + +struct FILongDecoder: public FIDecoder { + virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { + if (len & 7) { + throw DeadlyImportError(parseErrorMessage); + } + std::vector value; + size_t numLongs = len / 8; + value.reserve(numLongs); + for (size_t i = 0; i < numLongs; ++i) { + int64_t b0 = data[0], b1 = data[1], b2 = data[2], b3 = data[3], b4 = data[4], b5 = data[5], b6 = data[6], b7 = data[7]; + int64_t v = (b0 << 56) | (b1 << 48) | (b2 << 40) | (b3 << 32) | (b4 << 24) | (b5 << 16) | (b6 << 8) | b7; + value.push_back(v); + data += 8; + } + return FILongValue::create(std::move(value)); + } +}; + +struct FIBoolDecoder: public FIDecoder { + virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { + if (len < 1) { + throw DeadlyImportError(parseErrorMessage); + } + std::vector value; + uint8_t b = *data++; + size_t unusedBits = b >> 4; + size_t numBools = (len * 8) - 4 - unusedBits; + value.reserve(numBools); + uint8_t mask = 1 << 3; + for (size_t i = 0; i < numBools; ++i) { + if (!mask) { + mask = 1 << 7; + b = *data++; + } + value.push_back((b & mask) != 0); + } + return FIBoolValue::create(std::move(value)); + } +}; + +struct FIFloatDecoder: public FIDecoder { + virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { + if (len & 3) { + throw DeadlyImportError(parseErrorMessage); + } + std::vector value; + size_t numFloats = len / 4; + value.reserve(numFloats); + for (size_t i = 0; i < numFloats; ++i) { + int v = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + value.push_back(*(float*)&v); + data += 4; + } + return FIFloatValue::create(std::move(value)); + } +}; + +struct FIDoubleDecoder: public FIDecoder { + virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { + if (len & 7) { + throw DeadlyImportError(parseErrorMessage); + } + std::vector value; + size_t numDoubles = len / 8; + value.reserve(numDoubles); + for (size_t i = 0; i < numDoubles; ++i) { + long long b0 = data[0], b1 = data[1], b2 = data[2], b3 = data[3], b4 = data[4], b5 = data[5], b6 = data[6], b7 = data[7]; + long long v = (b0 << 56) | (b1 << 48) | (b2 << 40) | (b3 << 32) | (b4 << 24) | (b5 << 16) | (b6 << 8) | b7; + value.push_back(*(double*)&v); + data += 8; + } + return FIDoubleValue::create(std::move(value)); + } +}; + +struct FIUUIDDecoder: public FIDecoder { + virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { + if (len & 15) { + throw DeadlyImportError(parseErrorMessage); + } + return FIUUIDValue::create(std::vector(data, data + len)); + } +}; + +struct FICDATADecoder: public FIDecoder { + virtual std::shared_ptr decode(const uint8_t *data, size_t len) /*override*/ { + return FICDATAValue::create(parseUTF8String(data, len)); + } +}; + +class CFIReaderImpl: public FIReader { +public: + + CFIReaderImpl(std::unique_ptr data_, size_t size): + data(std::move(data_)), dataP(data.get()), dataEnd(data.get() + size), currentNodeType(irr::io::EXN_NONE), + emptyElement(false), headerPending(true), terminatorPending(false) + {} + + virtual ~CFIReaderImpl() {} + + virtual bool read() /*override*/ { + if (headerPending) { + headerPending = false; + parseHeader(); + } + if (terminatorPending) { + terminatorPending = false; + if (elementStack.empty()) { + return false; + } + else { + nodeName = elementStack.top(); + elementStack.pop(); + currentNodeType = nodeName.empty() ? irr::io::EXN_UNKNOWN : irr::io::EXN_ELEMENT_END; + return true; + } + } + if (dataP >= dataEnd) { + return false; + } + uint8_t b = *dataP; + if (b < 0x80) { // Element (C.2.11.2, C.3.7.2) + // C.3 + parseElement(); + return true; + } + else if (b < 0xc0) { // Characters (C.3.7.5) + // C.7 + auto chars = parseNonIdentifyingStringOrIndex3(vocabulary.charactersTable); + nodeName = chars->toString(); + currentNodeType = irr::io::EXN_TEXT; + return true; + } + else if (b < 0xe0) { + if ((b & 0xfc) == 0xc4) { // DTD (C.2.11.5) + // C.9 + ++dataP; + if (b & 0x02) { + /*const std::string &systemID =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable); + } + if (b & 0x01) { + /*const std::string &publicID =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable); + } + elementStack.push(EmptyString); + currentNodeType = irr::io::EXN_UNKNOWN; + return true; + } + else if ((b & 0xfc) == 0xc8) { // Unexpanded entity reference (C.3.7.4) + // C.6 + ++dataP; + /*const std::string &name =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable); + if (b & 0x02) { + /*const std::string &systemID =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable); + } + if (b & 0x01) { + /*const std::string &publicID =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable); + } + currentNodeType = irr::io::EXN_UNKNOWN; + return true; + } + } + else if (b < 0xf0) { + if (b == 0xe1) { // Processing instruction (C.2.11.3, C.3.7.3) + // C.5 + ++dataP; + /*const std::string &target =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable); + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + /*std::shared_ptr data =*/ parseNonIdentifyingStringOrIndex1(vocabulary.otherStringTable); + currentNodeType = irr::io::EXN_UNKNOWN; + return true; + } + else if (b == 0xe2) { // Comment (C.2.11.4, C.3.7.6) + // C.8 + ++dataP; + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + std::shared_ptr comment = parseNonIdentifyingStringOrIndex1(vocabulary.otherStringTable); + nodeName = comment->toString(); + currentNodeType = irr::io::EXN_COMMENT; + return true; + } + } + else { // Terminator (C.2.12, C.3.8) + ++dataP; + if (b == 0xff) { + terminatorPending = true; + } + if (elementStack.empty()) { + return false; + } + else { + nodeName = elementStack.top(); + elementStack.pop(); + currentNodeType = nodeName.empty() ? irr::io::EXN_UNKNOWN : irr::io::EXN_ELEMENT_END; + return true; + } + } + throw DeadlyImportError(parseErrorMessage); + } + + virtual irr::io::EXML_NODE getNodeType() const /*override*/ { + return currentNodeType; + } + + virtual int getAttributeCount() const /*override*/ { + return static_cast(attributes.size()); + } + + virtual const char* getAttributeName(int idx) const /*override*/ { + if (idx < 0 || idx >= (int)attributes.size()) { + return nullptr; + } + return attributes[idx].name.c_str(); + } + + virtual const char* getAttributeValue(int idx) const /*override*/ { + if (idx < 0 || idx >= (int)attributes.size()) { + return nullptr; + } + return attributes[idx].value->toString().c_str(); + } + + virtual const char* getAttributeValue(const char* name) const /*override*/ { + const Attribute* attr = getAttributeByName(name); + if (!attr) { + return nullptr; + } + return attr->value->toString().c_str(); + } + + virtual const char* getAttributeValueSafe(const char* name) const /*override*/ { + const Attribute* attr = getAttributeByName(name); + if (!attr) { + return EmptyString.c_str(); + } + return attr->value->toString().c_str(); + } + + virtual int getAttributeValueAsInt(const char* name) const /*override*/ { + const Attribute* attr = getAttributeByName(name); + if (!attr) { + return 0; + } + std::shared_ptr intValue = std::dynamic_pointer_cast(attr->value); + if (intValue) { + return intValue->value.size() == 1 ? intValue->value.front() : 0; + } + return stoi(attr->value->toString()); + } + + virtual int getAttributeValueAsInt(int idx) const /*override*/ { + if (idx < 0 || idx >= (int)attributes.size()) { + return 0; + } + std::shared_ptr intValue = std::dynamic_pointer_cast(attributes[idx].value); + if (intValue) { + return intValue->value.size() == 1 ? intValue->value.front() : 0; + } + return stoi(attributes[idx].value->toString()); + } + + virtual float getAttributeValueAsFloat(const char* name) const /*override*/ { + const Attribute* attr = getAttributeByName(name); + if (!attr) { + return 0; + } + std::shared_ptr floatValue = std::dynamic_pointer_cast(attr->value); + if (floatValue) { + return floatValue->value.size() == 1 ? floatValue->value.front() : 0; + } + return stof(attr->value->toString()); + } + + virtual float getAttributeValueAsFloat(int idx) const /*override*/ { + if (idx < 0 || idx >= (int)attributes.size()) { + return 0; + } + std::shared_ptr floatValue = std::dynamic_pointer_cast(attributes[idx].value); + if (floatValue) { + return floatValue->value.size() == 1 ? floatValue->value.front() : 0; + } + return stof(attributes[idx].value->toString()); + } + + virtual const char* getNodeName() const /*override*/ { + return nodeName.c_str(); + } + + virtual const char* getNodeData() const /*override*/ { + return nodeName.c_str(); + } + + virtual bool isEmptyElement() const /*override*/ { + return emptyElement; + } + + virtual irr::io::ETEXT_FORMAT getSourceFormat() const /*override*/ { + return irr::io::ETF_UTF8; + } + + virtual irr::io::ETEXT_FORMAT getParserFormat() const /*override*/ { + return irr::io::ETF_UTF8; + } + + virtual std::shared_ptr getAttributeEncodedValue(int idx) const /*override*/ { + if (idx < 0 || idx >= (int)attributes.size()) { + return nullptr; + } + return attributes[idx].value; + } + + virtual std::shared_ptr getAttributeEncodedValue(const char* name) const /*override*/ { + const Attribute* attr = getAttributeByName(name); + if (!attr) { + return nullptr; + } + return attr->value; + } + + virtual void registerDecoder(const std::string &algorithmUri, std::unique_ptr decoder) /*override*/ { + decoderMap[algorithmUri] = std::move(decoder); + } + + virtual void registerVocabulary(const std::string &vocabularyUri, const FIVocabulary *vocabulary) /*override*/ { + vocabularyMap[vocabularyUri] = vocabulary; + } + +private: + + struct QName { + std::string prefix; + std::string uri; + std::string name; + inline QName() {} + inline QName(const FIQName &qname): prefix(qname.prefix ? qname.prefix : ""), uri(qname.uri ? qname.uri : ""), name(qname.name) {} + }; + + struct Attribute { + QName qname; + std::string name; + std::shared_ptr value; + }; + + struct Vocabulary { + std::vector restrictedAlphabetTable; + std::vector encodingAlgorithmTable; + std::vector prefixTable; + std::vector namespaceNameTable; + std::vector localNameTable; + std::vector otherNCNameTable; + std::vector otherURITable; + std::vector> attributeValueTable; + std::vector> charactersTable; + std::vector> otherStringTable; + std::vector elementNameTable; + std::vector attributeNameTable; + Vocabulary() { + prefixTable.push_back("xml"); + namespaceNameTable.push_back("http://www.w3.org/XML/1998/namespace"); + } + }; + + const Attribute* getAttributeByName(const char* name) const { + if (!name) { + return 0; + } + std::string n = name; + for (int i=0; i<(int)attributes.size(); ++i) { + if (attributes[i].name == n) { + return &attributes[i]; + } + } + return 0; + } + + size_t parseInt2() { // C.25 + uint8_t b = *dataP++; + if (!(b & 0x40)) { // x0...... (C.25.2) + return b & 0x3f; + } + else if ((b & 0x60) == 0x40) { // x10..... ........ (C.25.3) + if (dataEnd - dataP > 0) { + return (((b & 0x1f) << 8) | *dataP++) + 0x40; + } + } + else if ((b & 0x70) == 0x60) { // x110.... ........ ........ (C.25.4) + if (dataEnd - dataP > 1) { + size_t result = (((b & 0x0f) << 16) | (dataP[0] << 8) | dataP[1]) + 0x2040; + dataP += 2; + return result; + } + } + throw DeadlyImportError(parseErrorMessage); + } + + size_t parseInt3() { // C.27 + uint8_t b = *dataP++; + if (!(b & 0x20)) { // xx0..... (C.27.2) + return b & 0x1f; + } + else if ((b & 0x38) == 0x20) { // xx100... ........ (C.27.3) + if (dataEnd - dataP > 0) { + return (((b & 0x07) << 8) | *dataP++) + 0x20; + } + } + else if ((b & 0x38) == 0x28) { // xx101... ........ ........ (C.27.4) + if (dataEnd - dataP > 1) { + size_t result = (((b & 0x07) << 16) | (dataP[0] << 8) | dataP[1]) + 0x820; + dataP += 2; + return result; + } + } + else if ((b & 0x3f) == 0x30) { // xx110000 0000.... ........ ........ (C.27.5) + if ((dataEnd - dataP > 2) && !(dataP[0] & 0xf0)) { + size_t result = (((dataP[0] & 0x0f) << 16) | (dataP[1] << 8) | dataP[2]) + 0x80820; + dataP += 3; + return result; + } + } + throw DeadlyImportError(parseErrorMessage); + } + + size_t parseInt4() { // C.28 + uint8_t b = *dataP++; + if (!(b & 0x10)) { // xxx0.... (C.28.2) + return b & 0x0f; + } + else if ((b & 0x1c) == 0x10) { // xxx100.. ........ (C.28.3) + if (dataEnd - dataP > 0) { + return (((b & 0x03) << 8) | *dataP++) + 0x10; + } + } + else if ((b & 0x1c) == 0x14) { // xxx101.. ........ ........ (C.28.4) + if (dataEnd - dataP > 1) { + size_t result = (((b & 0x03) << 16) | (dataP[0] << 8) | dataP[1]) + 0x410; + dataP += 2; + return result; + } + } + else if ((b & 0x1f) == 0x18) { // xxx11000 0000.... ........ ........ (C.28.5) + if ((dataEnd - dataP > 2) && !(dataP[0] & 0xf0)) { + size_t result = (((dataP[0] & 0x0f) << 16) | (dataP[1] << 8) | dataP[2]) + 0x40410; + dataP += 3; + return result; + } + } + throw DeadlyImportError(parseErrorMessage); + } + + size_t parseSequenceLen() { // C.21 + if (dataEnd - dataP > 0) { + uint8_t b = *dataP++; + if (b < 0x80) { // 0....... (C.21.2) + return b; + } + else if ((b & 0xf0) == 0x80) { // 1000.... ........ ........ (C.21.3) + if (dataEnd - dataP > 1) { + size_t result = (((b & 0x0f) << 16) | (dataP[0] << 8) | dataP[1]) + 0x80; + dataP += 2; + return result; + } + } + } + throw DeadlyImportError(parseErrorMessage); + } + + std::string parseNonEmptyOctetString2() { // C.22 + // Parse the length of the string + uint8_t b = *dataP++ & 0x7f; + size_t len; + if (!(b & 0x40)) { // x0...... (C.22.3.1) + len = b + 1; + } + else if (b == 0x40) { // x1000000 ........ (C.22.3.2) + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + len = *dataP++ + 0x41; + } + else if (b == 0x60) { // x1100000 ........ ........ ........ ........ (C.22.3.3) + if (dataEnd - dataP < 4) { + throw DeadlyImportError(parseErrorMessage); + } + len = ((dataP[0] << 24) | (dataP[1] << 16) | (dataP[2] << 8) | dataP[3]) + 0x141; + dataP += 4; + } + else { + throw DeadlyImportError(parseErrorMessage); + } + + // Parse the string (C.22.4) + if (dataEnd - dataP < static_cast(len)) { + throw DeadlyImportError(parseErrorMessage); + } + std::string s = parseUTF8String(dataP, len); + dataP += len; + + return s; + } + + size_t parseNonEmptyOctetString5Length() { // C.23 + // Parse the length of the string + size_t b = *dataP++ & 0x0f; + if (!(b & 0x08)) { // xxxx0... (C.23.3.1) + return b + 1; + } + else if (b == 0x08) { // xxxx1000 ........ (C.23.3.2) + if (dataEnd - dataP > 0) { + return *dataP++ + 0x09; + } + } + else if (b == 0x0c) { // xxxx1100 ........ ........ ........ ........ (C.23.3.3) + if (dataEnd - dataP > 3) { + size_t result = ((dataP[0] << 24) | (dataP[1] << 16) | (dataP[2] << 8) | dataP[3]) + 0x109; + dataP += 4; + return result; + } + } + throw DeadlyImportError(parseErrorMessage); + } + + size_t parseNonEmptyOctetString7Length() { // C.24 + // Parse the length of the string + size_t b = *dataP++ & 0x03; + if (!(b & 0x02)) { // xxxxxx0. (C.24.3.1) + return b + 1; + } + else if (b == 0x02) { // xxxxxx10 ........ (C.24.3.2) + if (dataEnd - dataP > 0) { + return *dataP++ + 0x3; + } + } + else if (b == 0x03) { // xxxxxx11 ........ ........ ........ ........ (C.24.3.3) + if (dataEnd - dataP > 3) { + size_t result = ((dataP[0] << 24) | (dataP[1] << 16) | (dataP[2] << 8) | dataP[3]) + 0x103; + dataP += 4; + return result; + } + } + throw DeadlyImportError(parseErrorMessage); + } + + std::shared_ptr parseEncodedData(size_t index, size_t len) { + if (index < 32) { + FIDecoder *decoder = defaultDecoder[index]; + if (!decoder) { + throw DeadlyImportError("Invalid encoding algorithm index " + std::to_string(index)); + } + return decoder->decode(dataP, len); + } + else { + if (index - 32 >= vocabulary.encodingAlgorithmTable.size()) { + throw DeadlyImportError("Invalid encoding algorithm index " + std::to_string(index)); + } + std::string uri = vocabulary.encodingAlgorithmTable[index - 32]; + auto it = decoderMap.find(uri); + if (it == decoderMap.end()) { + throw DeadlyImportError("Unsupported encoding algorithm " + uri); + } + else { + return it->second->decode(dataP, len); + } + } + } + + std::shared_ptr parseRestrictedAlphabet(size_t index, size_t len) { + std::string alphabet; + if (index < 16) { + switch (index) { + case 0: // numeric + alphabet = "0123456789-+.e "; + break; + case 1: // date and time + alphabet = "0123456789-:TZ "; + break; + default: + throw DeadlyImportError("Invalid restricted alphabet index " + std::to_string(index)); + } + } + else { + if (index - 16 >= vocabulary.restrictedAlphabetTable.size()) { + throw DeadlyImportError("Invalid restricted alphabet index " + std::to_string(index)); + } + alphabet = vocabulary.restrictedAlphabetTable[index - 16]; + } + std::vector alphabetUTF32; + utf8::utf8to32(alphabet.begin(), alphabet.end(), back_inserter(alphabetUTF32)); + std::string::size_type alphabetLength = alphabetUTF32.size(); + if (alphabetLength < 2) { + throw DeadlyImportError("Invalid restricted alphabet length " + std::to_string(alphabetLength)); + } + std::string::size_type bitsPerCharacter = 1; + while ((1ull << bitsPerCharacter) <= alphabetLength) { + ++bitsPerCharacter; + } + size_t bitsAvail = 0; + uint8_t mask = (1 << bitsPerCharacter) - 1; + uint32_t bits = 0; + std::string s; + for (size_t i = 0; i < len; ++i) { + bits = (bits << 8) | dataP[i]; + bitsAvail += 8; + while (bitsAvail >= bitsPerCharacter) { + bitsAvail -= bitsPerCharacter; + size_t charIndex = (bits >> bitsAvail) & mask; + if (charIndex < alphabetLength) { + s.push_back(alphabetUTF32[charIndex]); + } + else if (charIndex != mask) { + throw DeadlyImportError(parseErrorMessage); + } + } + } + return FIStringValue::create(std::move(s)); + } + + std::shared_ptr parseEncodedCharacterString3() { // C.19 + std::shared_ptr result; + size_t len; + uint8_t b = *dataP; + if (b & 0x20) { + ++dataP; + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + size_t index = ((b & 0x0f) << 4) | ((*dataP & 0xf0) >> 4); // C.29 + len = parseNonEmptyOctetString5Length(); + if (dataEnd - dataP < static_cast(len)) { + throw DeadlyImportError(parseErrorMessage); + } + if (b & 0x10) { + // encoding algorithm (C.19.3.4) + result = parseEncodedData(index, len); + } + else { + // Restricted alphabet (C.19.3.3) + result = parseRestrictedAlphabet(index, len); + } + } + else { + len = parseNonEmptyOctetString5Length(); + if (dataEnd - dataP < static_cast(len)) { + throw DeadlyImportError(parseErrorMessage); + } + if (b & 0x10) { + // UTF-16 (C.19.3.2) + if (len & 1) { + throw DeadlyImportError(parseErrorMessage); + } + result = FIStringValue::create(parseUTF16String(dataP, len)); + } + else { + // UTF-8 (C.19.3.1) + result = FIStringValue::create(parseUTF8String(dataP, len)); + } + } + dataP += len; + return result; + } + + std::shared_ptr parseEncodedCharacterString5() { // C.20 + std::shared_ptr result; + size_t len; + uint8_t b = *dataP; + if (b & 0x08) { + ++dataP; + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + size_t index = ((b & 0x03) << 6) | ((*dataP & 0xfc) >> 2); /* C.29 */ + len = parseNonEmptyOctetString7Length(); + if (dataEnd - dataP < static_cast(len)) { + throw DeadlyImportError(parseErrorMessage); + } + if (b & 0x04) { + // encoding algorithm (C.20.3.4) + result = parseEncodedData(index, len); + } + else { + // Restricted alphabet (C.20.3.3) + result = parseRestrictedAlphabet(index, len); + } + } + else { + len = parseNonEmptyOctetString7Length(); + if (dataEnd - dataP < static_cast(len)) { + throw DeadlyImportError(parseErrorMessage); + } + if (b & 0x04) { + // UTF-16 (C.20.3.2) + if (len & 1) { + throw DeadlyImportError(parseErrorMessage); + } + result = FIStringValue::create(parseUTF16String(dataP, len)); + } + else { + // UTF-8 (C.20.3.1) + result = FIStringValue::create(parseUTF8String(dataP, len)); + } + } + dataP += len; + return result; + } + + const std::string &parseIdentifyingStringOrIndex(std::vector &stringTable) { // C.13 + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + uint8_t b = *dataP; + if (b & 0x80) { + // We have an index (C.13.4) + size_t index = parseInt2(); + if (index >= stringTable.size()) { + throw DeadlyImportError(parseErrorMessage); + } + return stringTable[index]; + } + else { + // We have a string (C.13.3) + stringTable.push_back(parseNonEmptyOctetString2()); + return stringTable.back(); + } + } + + QName parseNameSurrogate() { // C.16 + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + uint8_t b = *dataP++; + if (b & 0xfc) { // Padding '000000' C.2.5.5 + throw DeadlyImportError(parseErrorMessage); + } + QName result; + size_t index; + if (b & 0x02) { // prefix (C.16.3) + if ((dataEnd - dataP < 1) || (*dataP & 0x80)) { + throw DeadlyImportError(parseErrorMessage); + } + index = parseInt2(); + if (index >= vocabulary.prefixTable.size()) { + throw DeadlyImportError(parseErrorMessage); + } + result.prefix = vocabulary.prefixTable[index]; + } + if (b & 0x01) { // namespace-name (C.16.4) + if ((dataEnd - dataP < 1) || (*dataP & 0x80)) { + throw DeadlyImportError(parseErrorMessage); + } + index = parseInt2(); + if (index >= vocabulary.namespaceNameTable.size()) { + throw DeadlyImportError(parseErrorMessage); + } + result.uri = vocabulary.namespaceNameTable[index]; + } + // local-name + if ((dataEnd - dataP < 1) || (*dataP & 0x80)) { + throw DeadlyImportError(parseErrorMessage); + } + index = parseInt2(); + if (index >= vocabulary.localNameTable.size()) { + throw DeadlyImportError(parseErrorMessage); + } + result.name = vocabulary.localNameTable[index]; + return result; + } + + const QName &parseQualifiedNameOrIndex2(std::vector &qNameTable) { // C.17 + uint8_t b = *dataP; + if ((b & 0x7c) == 0x78) { // x11110.. + // We have a literal (C.17.3) + ++dataP; + QName result; + // prefix (C.17.3.1) + result.prefix = b & 0x02 ? parseIdentifyingStringOrIndex(vocabulary.prefixTable) : std::string(); + // namespace-name (C.17.3.1) + result.uri = b & 0x01 ? parseIdentifyingStringOrIndex(vocabulary.namespaceNameTable) : std::string(); + // local-name + result.name = parseIdentifyingStringOrIndex(vocabulary.localNameTable); + qNameTable.push_back(result); + return qNameTable.back(); + } + else { + // We have an index (C.17.4) + size_t index = parseInt2(); + if (index >= qNameTable.size()) { + throw DeadlyImportError(parseErrorMessage); + } + return qNameTable[index]; + } + } + + const QName &parseQualifiedNameOrIndex3(std::vector &qNameTable) { // C.18 + uint8_t b = *dataP; + if ((b & 0x3c) == 0x3c) { // xx1111.. + // We have a literal (C.18.3) + ++dataP; + QName result; + // prefix (C.18.3.1) + result.prefix = b & 0x02 ? parseIdentifyingStringOrIndex(vocabulary.prefixTable) : std::string(); + // namespace-name (C.18.3.1) + result.uri = b & 0x01 ? parseIdentifyingStringOrIndex(vocabulary.namespaceNameTable) : std::string(); + // local-name + result.name = parseIdentifyingStringOrIndex(vocabulary.localNameTable); + qNameTable.push_back(result); + return qNameTable.back(); + } + else { + // We have an index (C.18.4) + size_t index = parseInt3(); + if (index >= qNameTable.size()) { + throw DeadlyImportError(parseErrorMessage); + } + return qNameTable[index]; + } + } + + std::shared_ptr parseNonIdentifyingStringOrIndex1(std::vector> &valueTable) { // C.14 + uint8_t b = *dataP; + if (b == 0xff) { // C.26.2 + // empty string + ++dataP; + return EmptyFIString; + } + else if (b & 0x80) { // C.14.4 + // We have an index + size_t index = parseInt2(); + if (index >= valueTable.size()) { + throw DeadlyImportError(parseErrorMessage); + } + return valueTable[index]; + } + else { // C.14.3 + // We have a literal + std::shared_ptr result = parseEncodedCharacterString3(); + if (b & 0x40) { // C.14.3.1 + valueTable.push_back(result); + } + return result; + } + } + + std::shared_ptr parseNonIdentifyingStringOrIndex3(std::vector> &valueTable) { // C.15 + uint8_t b = *dataP; + if (b & 0x20) { // C.15.4 + // We have an index + size_t index = parseInt4(); + if (index >= valueTable.size()) { + throw DeadlyImportError(parseErrorMessage); + } + return valueTable[index]; + } + else { // C.15.3 + // We have a literal + std::shared_ptr result = parseEncodedCharacterString5(); + if (b & 0x10) { // C.15.3.1 + valueTable.push_back(result); + } + return result; + } + } + + void parseElement() { + // C.3 + + attributes.clear(); + + uint8_t b = *dataP; + bool hasAttributes = (b & 0x40) != 0; // C.3.3 + if ((b & 0x3f) == 0x38) { // C.3.4.1 + // Parse namespaces + ++dataP; + for (;;) { + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + b = *dataP++; + if (b == 0xf0) { // C.3.4.3 + break; + } + if ((b & 0xfc) != 0xcc) { // C.3.4.2 + throw DeadlyImportError(parseErrorMessage); + } + // C.12 + Attribute attr; + attr.qname.prefix = "xmlns"; + attr.qname.name = b & 0x02 ? parseIdentifyingStringOrIndex(vocabulary.prefixTable) : std::string(); + attr.qname.uri = b & 0x01 ? parseIdentifyingStringOrIndex(vocabulary.namespaceNameTable) : std::string(); + attr.name = attr.qname.name.empty() ? "xmlns" : "xmlns:" + attr.qname.name; + attr.value = FIStringValue::create(std::string(attr.qname.uri)); + attributes.push_back(attr); + } + if ((dataEnd - dataP < 1) || (*dataP & 0xc0)) { + throw DeadlyImportError(parseErrorMessage); + } + } + + // Parse Element name (C.3.5) + const QName &elemName = parseQualifiedNameOrIndex3(vocabulary.elementNameTable); + nodeName = elemName.prefix.empty() ? elemName.name : elemName.prefix + ':' + elemName.name; + + if (hasAttributes) { + for (;;) { + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + b = *dataP; + if (b < 0x80) { // C.3.6.1 + // C.4 + Attribute attr; + attr.qname = parseQualifiedNameOrIndex2(vocabulary.attributeNameTable); + attr.name = attr.qname.prefix.empty() ? attr.qname.name : attr.qname.prefix + ':' + attr.qname.name; + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + attr.value = parseNonIdentifyingStringOrIndex1(vocabulary.attributeValueTable); + attributes.push_back(attr); + } + else { + if ((b & 0xf0) != 0xf0) { // C.3.6.2 + throw DeadlyImportError(parseErrorMessage); + } + emptyElement = b == 0xff; // C.3.6.2, C.3.8 + ++dataP; + break; + } + } + } + else { + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + b = *dataP; + switch (b) { + case 0xff: + terminatorPending = true; + // Intentionally fall through + case 0xf0: + emptyElement = true; + ++dataP; + break; + default: + emptyElement = false; + } + } + if (!emptyElement) { + elementStack.push(nodeName); + } + + currentNodeType = irr::io::EXN_ELEMENT; + } + + void parseHeader() { + // Parse header (C.1.3) + size_t magicSize = parseMagic(dataP, dataEnd); + if (!magicSize) { + throw DeadlyImportError(parseErrorMessage); + } + dataP += magicSize; + // C.2.3 + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + uint8_t b = *dataP++; + if (b & 0x40) { + // Parse additional data (C.2.4) + size_t len = parseSequenceLen(); + for (size_t i = 0; i < len; ++i) { + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + /*std::string id =*/ parseNonEmptyOctetString2(); + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + /*std::string data =*/ parseNonEmptyOctetString2(); + } + } + if (b & 0x20) { + // Parse initial vocabulary (C.2.5) + if (dataEnd - dataP < 2) { + throw DeadlyImportError(parseErrorMessage); + } + uint16_t b1 = (dataP[0] << 8) | dataP[1]; + dataP += 2; + if (b1 & 0x1000) { + // External vocabulary (C.2.5.2) + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + std::string uri = parseNonEmptyOctetString2(); + auto it = vocabularyMap.find(uri); + if (it == vocabularyMap.end()) { + throw DeadlyImportError("Unknown vocabulary " + uri); + } + const FIVocabulary *externalVocabulary = it->second; + if (externalVocabulary->restrictedAlphabetTable) { + std::copy(externalVocabulary->restrictedAlphabetTable, externalVocabulary->restrictedAlphabetTable + externalVocabulary->restrictedAlphabetTableSize, std::back_inserter(vocabulary.restrictedAlphabetTable)); + } + if (externalVocabulary->encodingAlgorithmTable) { + std::copy(externalVocabulary->encodingAlgorithmTable, externalVocabulary->encodingAlgorithmTable + externalVocabulary->encodingAlgorithmTableSize, std::back_inserter(vocabulary.encodingAlgorithmTable)); + } + if (externalVocabulary->prefixTable) { + std::copy(externalVocabulary->prefixTable, externalVocabulary->prefixTable + externalVocabulary->prefixTableSize, std::back_inserter(vocabulary.prefixTable)); + } + if (externalVocabulary->namespaceNameTable) { + std::copy(externalVocabulary->namespaceNameTable, externalVocabulary->namespaceNameTable + externalVocabulary->namespaceNameTableSize, std::back_inserter(vocabulary.namespaceNameTable)); + } + if (externalVocabulary->localNameTable) { + std::copy(externalVocabulary->localNameTable, externalVocabulary->localNameTable + externalVocabulary->localNameTableSize, std::back_inserter(vocabulary.localNameTable)); + } + if (externalVocabulary->otherNCNameTable) { + std::copy(externalVocabulary->otherNCNameTable, externalVocabulary->otherNCNameTable + externalVocabulary->otherNCNameTableSize, std::back_inserter(vocabulary.otherNCNameTable)); + } + if (externalVocabulary->otherURITable) { + std::copy(externalVocabulary->otherURITable, externalVocabulary->otherURITable + externalVocabulary->otherURITableSize, std::back_inserter(vocabulary.otherURITable)); + } + if (externalVocabulary->attributeValueTable) { + std::copy(externalVocabulary->attributeValueTable, externalVocabulary->attributeValueTable + externalVocabulary->attributeValueTableSize, std::back_inserter(vocabulary.attributeValueTable)); + } + if (externalVocabulary->charactersTable) { + std::copy(externalVocabulary->charactersTable, externalVocabulary->charactersTable + externalVocabulary->charactersTableSize, std::back_inserter(vocabulary.charactersTable)); + } + if (externalVocabulary->otherStringTable) { + std::copy(externalVocabulary->otherStringTable, externalVocabulary->otherStringTable + externalVocabulary->otherStringTableSize, std::back_inserter(vocabulary.otherStringTable)); + } + if (externalVocabulary->elementNameTable) { + std::copy(externalVocabulary->elementNameTable, externalVocabulary->elementNameTable + externalVocabulary->elementNameTableSize, std::back_inserter(vocabulary.elementNameTable)); + } + if (externalVocabulary->attributeNameTable) { + std::copy(externalVocabulary->attributeNameTable, externalVocabulary->attributeNameTable + externalVocabulary->attributeNameTableSize, std::back_inserter(vocabulary.attributeNameTable)); + } + } + if (b1 & 0x0800) { + // Parse restricted alphabets (C.2.5.3) + for (size_t len = parseSequenceLen(); len > 0; --len) { + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + vocabulary.restrictedAlphabetTable.push_back(parseNonEmptyOctetString2()); + } + } + if (b1 & 0x0400) { + // Parse encoding algorithms (C.2.5.3) + for (size_t len = parseSequenceLen(); len > 0; --len) { + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + vocabulary.encodingAlgorithmTable.push_back(parseNonEmptyOctetString2()); + } + } + if (b1 & 0x0200) { + // Parse prefixes (C.2.5.3) + for (size_t len = parseSequenceLen(); len > 0; --len) { + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + vocabulary.prefixTable.push_back(parseNonEmptyOctetString2()); + } + } + if (b1 & 0x0100) { + // Parse namespace names (C.2.5.3) + for (size_t len = parseSequenceLen(); len > 0; --len) { + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + vocabulary.namespaceNameTable.push_back(parseNonEmptyOctetString2()); + } + } + if (b1 & 0x0080) { + // Parse local names (C.2.5.3) + for (size_t len = parseSequenceLen(); len > 0; --len) { + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + vocabulary.localNameTable.push_back(parseNonEmptyOctetString2()); + } + } + if (b1 & 0x0040) { + // Parse other ncnames (C.2.5.3) + for (size_t len = parseSequenceLen(); len > 0; --len) { + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + vocabulary.otherNCNameTable.push_back(parseNonEmptyOctetString2()); + } + } + if (b1 & 0x0020) { + // Parse other uris (C.2.5.3) + for (size_t len = parseSequenceLen(); len > 0; --len) { + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + vocabulary.otherURITable.push_back(parseNonEmptyOctetString2()); + } + } + if (b1 & 0x0010) { + // Parse attribute values (C.2.5.4) + for (size_t len = parseSequenceLen(); len > 0; --len) { + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + vocabulary.attributeValueTable.push_back(parseEncodedCharacterString3()); + } + } + if (b1 & 0x0008) { + // Parse content character chunks (C.2.5.4) + for (size_t len = parseSequenceLen(); len > 0; --len) { + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + vocabulary.charactersTable.push_back(parseEncodedCharacterString3()); + } + } + if (b1 & 0x0004) { + // Parse other strings (C.2.5.4) + for (size_t len = parseSequenceLen(); len > 0; --len) { + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + vocabulary.otherStringTable.push_back(parseEncodedCharacterString3()); + } + } + if (b1 & 0x0002) { + // Parse element name surrogates (C.2.5.5) + for (size_t len = parseSequenceLen(); len > 0; --len) { + vocabulary.elementNameTable.push_back(parseNameSurrogate()); + } + } + if (b1 & 0x0001) { + // Parse attribute name surrogates (C.2.5.5) + for (size_t len = parseSequenceLen(); len > 0; --len) { + vocabulary.attributeNameTable.push_back(parseNameSurrogate()); + } + } + } + if (b & 0x10) { + // Parse notations (C.2.6) + for (;;) { + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + uint8_t b1 = *dataP++; + if (b1 == 0xf0) { + break; + } + if ((b1 & 0xfc) != 0xc0) { + throw DeadlyImportError(parseErrorMessage); + } + /* C.11 */ + /*const std::string &name =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable); + if (b1 & 0x02) { + /*const std::string &systemId =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable); + } + if (b1 & 0x01) { + /*const std::string &publicId =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable); + } + } + } + if (b & 0x08) { + // Parse unparsed entities (C.2.7) + for (;;) { + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + uint8_t b1 = *dataP++; + if (b1 == 0xf0) { + break; + } + if ((b1 & 0xfe) != 0xd0) { + throw DeadlyImportError(parseErrorMessage); + } + /* C.10 */ + /*const std::string &name =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable); + /*const std::string &systemId =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable); + if (b1 & 0x01) { + /*const std::string &publicId =*/ parseIdentifyingStringOrIndex(vocabulary.otherURITable); + } + /*const std::string ¬ationName =*/ parseIdentifyingStringOrIndex(vocabulary.otherNCNameTable); + } + } + if (b & 0x04) { + // Parse character encoding scheme (C.2.8) + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + /*std::string characterEncodingScheme =*/ parseNonEmptyOctetString2(); + } + if (b & 0x02) { + // Parse standalone flag (C.2.9) + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + uint8_t b1 = *dataP++; + if (b1 & 0xfe) { + throw DeadlyImportError(parseErrorMessage); + } + //bool standalone = b1 & 0x01; + } + if (b & 0x01) { + // Parse version (C.2.10) + if (dataEnd - dataP < 1) { + throw DeadlyImportError(parseErrorMessage); + } + /*std::shared_ptr version =*/ parseNonIdentifyingStringOrIndex1(vocabulary.otherStringTable); + } + } + + std::unique_ptr data; + uint8_t *dataP, *dataEnd; + irr::io::EXML_NODE currentNodeType; + bool emptyElement; + bool headerPending; + bool terminatorPending; + Vocabulary vocabulary; + std::vector attributes; + std::stack elementStack; + std::string nodeName; + std::map> decoderMap; + std::map vocabularyMap; + + static const std::string EmptyString; + static std::shared_ptr EmptyFIString; + + static FIHexDecoder hexDecoder; + static FIBase64Decoder base64Decoder; + static FIShortDecoder shortDecoder; + static FIIntDecoder intDecoder; + static FILongDecoder longDecoder; + static FIBoolDecoder boolDecoder; + static FIFloatDecoder floatDecoder; + static FIDoubleDecoder doubleDecoder; + static FIUUIDDecoder uuidDecoder; + static FICDATADecoder cdataDecoder; + static FIDecoder *defaultDecoder[32]; +}; + +const std::string CFIReaderImpl::EmptyString; +std::shared_ptr CFIReaderImpl::EmptyFIString = FIStringValue::create(std::string()); + +FIHexDecoder CFIReaderImpl::hexDecoder; +FIBase64Decoder CFIReaderImpl::base64Decoder; +FIShortDecoder CFIReaderImpl::shortDecoder; +FIIntDecoder CFIReaderImpl::intDecoder; +FILongDecoder CFIReaderImpl::longDecoder; +FIBoolDecoder CFIReaderImpl::boolDecoder; +FIFloatDecoder CFIReaderImpl::floatDecoder; +FIDoubleDecoder CFIReaderImpl::doubleDecoder; +FIUUIDDecoder CFIReaderImpl::uuidDecoder; +FICDATADecoder CFIReaderImpl::cdataDecoder; + +FIDecoder *CFIReaderImpl::defaultDecoder[32] = { + &hexDecoder, + &base64Decoder, + &shortDecoder, + &intDecoder, + &longDecoder, + &boolDecoder, + &floatDecoder, + &doubleDecoder, + &uuidDecoder, + &cdataDecoder +}; + +class CXMLReaderImpl : public FIReader +{ +public: + + //! Constructor + CXMLReaderImpl(std::unique_ptr> reader_) + : reader(std::move(reader_)) + {} + + virtual ~CXMLReaderImpl() {} + + virtual bool read() /*override*/ { + return reader->read(); + } + + virtual irr::io::EXML_NODE getNodeType() const /*override*/ { + return reader->getNodeType(); + } + + virtual int getAttributeCount() const /*override*/ { + return reader->getAttributeCount(); + } + + virtual const char* getAttributeName(int idx) const /*override*/ { + return reader->getAttributeName(idx); + } + + virtual const char* getAttributeValue(int idx) const /*override*/ { + return reader->getAttributeValue(idx); + } + + virtual const char* getAttributeValue(const char* name) const /*override*/ { + return reader->getAttributeValue(name); + } + + virtual const char* getAttributeValueSafe(const char* name) const /*override*/ { + return reader->getAttributeValueSafe(name); + } + + virtual int getAttributeValueAsInt(const char* name) const /*override*/ { + return reader->getAttributeValueAsInt(name); + } + + virtual int getAttributeValueAsInt(int idx) const /*override*/ { + return reader->getAttributeValueAsInt(idx); + } + + virtual float getAttributeValueAsFloat(const char* name) const /*override*/ { + return reader->getAttributeValueAsFloat(name); + } + + virtual float getAttributeValueAsFloat(int idx) const /*override*/ { + return reader->getAttributeValueAsFloat(idx); + } + + virtual const char* getNodeName() const /*override*/ { + return reader->getNodeName(); + } + + virtual const char* getNodeData() const /*override*/ { + return reader->getNodeData(); + } + + virtual bool isEmptyElement() const /*override*/ { + return reader->isEmptyElement(); + } + + virtual irr::io::ETEXT_FORMAT getSourceFormat() const /*override*/ { + return reader->getSourceFormat(); + } + + virtual irr::io::ETEXT_FORMAT getParserFormat() const /*override*/ { + return reader->getParserFormat(); + } + + virtual std::shared_ptr getAttributeEncodedValue(int idx) const /*override*/ { + return nullptr; + } + + virtual std::shared_ptr getAttributeEncodedValue(const char* name) const /*override*/ { + return nullptr; + } + + virtual void registerDecoder(const std::string &algorithmUri, std::unique_ptr decoder) /*override*/ {} + + virtual void registerVocabulary(const std::string &vocabularyUri, const FIVocabulary *vocabulary) /*override*/ {} + +private: + + std::unique_ptr> reader; +}; + +static std::unique_ptr readFile(IOStream *stream, size_t &size, bool &isFI) { + size = stream->FileSize(); + std::unique_ptr data = std::unique_ptr(new uint8_t[size]); + if (stream->Read(data.get(), size, 1) != 1) { + size = 0; + data.reset(); + } + isFI = parseMagic(data.get(), data.get() + size) > 0; + return data; +} + +std::unique_ptr FIReader::create(IOStream *stream) +{ + size_t size; + bool isFI; + auto data = readFile(stream, size, isFI); + if (isFI) { + return std::unique_ptr(new CFIReaderImpl(std::move(data), size)); + } + else { + auto memios = std::unique_ptr(new MemoryIOStream(data.release(), size, true)); + auto callback = std::unique_ptr(new CIrrXML_IOStreamReader(memios.get())); + return std::unique_ptr(new CXMLReaderImpl(std::unique_ptr>(createIrrXMLReader(callback.get())))); + } +} + +}// namespace Assimp + +#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/FIReader.hpp b/code/FIReader.hpp new file mode 100644 index 000000000..ebc12ae31 --- /dev/null +++ b/code/FIReader.hpp @@ -0,0 +1,172 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 FIReader.hpp +/// \brief Reader for Fast Infoset encoded binary XML files. +/// \date 2017 +/// \author Patrick Daehne + +#ifndef INCLUDED_AI_FI_READER_H +#define INCLUDED_AI_FI_READER_H + +#include +#include +#include +#include +#include + +namespace Assimp { + +struct FIValue { + virtual const std::string &toString() const = 0; +}; + +struct FIStringValue: public FIValue { + std::string value; + static std::shared_ptr create(std::string &&value); +}; + +struct FIByteValue: public FIValue { + std::vector value; +}; + +struct FIHexValue: public FIByteValue { + static std::shared_ptr create(std::vector &&value); +}; + +struct FIBase64Value: public FIByteValue { + static std::shared_ptr create(std::vector &&value); +}; + +struct FIShortValue: public FIValue { + std::vector value; + static std::shared_ptr create(std::vector &&value); +}; + +struct FIIntValue: public FIValue { + std::vector value; + static std::shared_ptr create(std::vector &&value); +}; + +struct FILongValue: public FIValue { + std::vector value; + static std::shared_ptr create(std::vector &&value); +}; + +struct FIBoolValue: public FIValue { + std::vector value; + static std::shared_ptr create(std::vector &&value); +}; + +struct FIFloatValue: public FIValue { + std::vector value; + static std::shared_ptr create(std::vector &&value); +}; + +struct FIDoubleValue: public FIValue { + std::vector value; + static std::shared_ptr create(std::vector &&value); +}; + +struct FIUUIDValue: public FIByteValue { + static std::shared_ptr create(std::vector &&value); +}; + +struct FICDATAValue: public FIStringValue { + static std::shared_ptr create(std::string &&value); +}; + +struct FIDecoder { + virtual std::shared_ptr decode(const uint8_t *data, size_t len) = 0; +}; + +struct FIQName { + const char *name; + const char *prefix; + const char *uri; +}; + +struct FIVocabulary { + const char **restrictedAlphabetTable; + size_t restrictedAlphabetTableSize; + const char **encodingAlgorithmTable; + size_t encodingAlgorithmTableSize; + const char **prefixTable; + size_t prefixTableSize; + const char **namespaceNameTable; + size_t namespaceNameTableSize; + const char **localNameTable; + size_t localNameTableSize; + const char **otherNCNameTable; + size_t otherNCNameTableSize; + const char **otherURITable; + size_t otherURITableSize; + const std::shared_ptr *attributeValueTable; + size_t attributeValueTableSize; + const std::shared_ptr *charactersTable; + size_t charactersTableSize; + const std::shared_ptr *otherStringTable; + size_t otherStringTableSize; + const FIQName *elementNameTable; + size_t elementNameTableSize; + const FIQName *attributeNameTable; + size_t attributeNameTableSize; +}; + +class IOStream; + +class FIReader: public irr::io::IIrrXMLReader { +public: + + virtual std::shared_ptr getAttributeEncodedValue(int idx) const = 0; + + virtual std::shared_ptr getAttributeEncodedValue(const char *name) const = 0; + + virtual void registerDecoder(const std::string &algorithmUri, std::unique_ptr decoder) = 0; + + virtual void registerVocabulary(const std::string &vocabularyUri, const FIVocabulary *vocabulary) = 0; + + static std::unique_ptr create(IOStream *stream); + +};// class IFIReader + +}// namespace Assimp + +#endif // INCLUDED_AI_FI_READER_H diff --git a/code/FindDegenerates.cpp b/code/FindDegenerates.cpp index 62750bfad..32a09f0c0 100644 --- a/code/FindDegenerates.cpp +++ b/code/FindDegenerates.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/FindDegenerates.h b/code/FindDegenerates.h index 7b945ea3a..9bd410dcd 100644 --- a/code/FindDegenerates.h +++ b/code/FindDegenerates.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FindInstancesProcess.cpp b/code/FindInstancesProcess.cpp index 479f6561e..ab2d2257b 100644 --- a/code/FindInstancesProcess.cpp +++ b/code/FindInstancesProcess.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/FindInstancesProcess.h b/code/FindInstancesProcess.h index 14876045c..dc4396566 100644 --- a/code/FindInstancesProcess.h +++ b/code/FindInstancesProcess.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FindInvalidDataProcess.cpp b/code/FindInvalidDataProcess.cpp index bed2eee06..77915bc4e 100644 --- a/code/FindInvalidDataProcess.cpp +++ b/code/FindInvalidDataProcess.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/FindInvalidDataProcess.h b/code/FindInvalidDataProcess.h index 8a1df21fd..cc0ef946d 100644 --- a/code/FindInvalidDataProcess.h +++ b/code/FindInvalidDataProcess.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/FixNormalsStep.cpp b/code/FixNormalsStep.cpp index 0325f8dfb..05d05e873 100644 --- a/code/FixNormalsStep.cpp +++ b/code/FixNormalsStep.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/FixNormalsStep.h b/code/FixNormalsStep.h index 5dea5d868..b47155ccd 100644 --- a/code/FixNormalsStep.h +++ b/code/FixNormalsStep.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/GenFaceNormalsProcess.cpp b/code/GenFaceNormalsProcess.cpp index 9218d9db8..82d80db77 100644 --- a/code/GenFaceNormalsProcess.cpp +++ b/code/GenFaceNormalsProcess.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/GenFaceNormalsProcess.h b/code/GenFaceNormalsProcess.h index f56570078..024c74a28 100644 --- a/code/GenFaceNormalsProcess.h +++ b/code/GenFaceNormalsProcess.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/GenVertexNormalsProcess.cpp b/code/GenVertexNormalsProcess.cpp index c205ac5ac..93c0e1351 100644 --- a/code/GenVertexNormalsProcess.cpp +++ b/code/GenVertexNormalsProcess.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/GenVertexNormalsProcess.h b/code/GenVertexNormalsProcess.h index caa327aa3..0471ed6b0 100644 --- a/code/GenVertexNormalsProcess.h +++ b/code/GenVertexNormalsProcess.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/GenericProperty.h b/code/GenericProperty.h index 507bfb693..454f4952b 100644 --- a/code/GenericProperty.h +++ b/code/GenericProperty.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -110,7 +111,7 @@ inline void SetGenericPropertyPtr(std::map< unsigned int, T* >& list, // ------------------------------------------------------------------------------------------------ template -inline const bool HasGenericProperty(const std::map< unsigned int, T >& list, +inline bool HasGenericProperty(const std::map< unsigned int, T >& list, const char* szName) { ai_assert(NULL != szName); diff --git a/code/HMPFileData.h b/code/HMPFileData.h index cff3b6b18..3c060ba1a 100644 --- a/code/HMPFileData.h +++ b/code/HMPFileData.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/HMPLoader.cpp b/code/HMPLoader.cpp index fce0daf4a..2a669201e 100644 --- a/code/HMPLoader.cpp +++ b/code/HMPLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -447,7 +448,8 @@ void HMPImporter::CreateOutputFaceList(unsigned int width,unsigned int height) void HMPImporter::ReadFirstSkin(unsigned int iNumSkins, const unsigned char* szCursor, const unsigned char** szCursorOut) { - ai_assert(0 != iNumSkins && NULL != szCursor); + ai_assert( 0 != iNumSkins ); + ai_assert( nullptr != szCursor); // read the type of the skin ... // sometimes we need to skip 12 bytes here, I don't know why ... diff --git a/code/HMPLoader.h b/code/HMPLoader.h index 036b37894..546643e8d 100644 --- a/code/HMPLoader.h +++ b/code/HMPLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/HalfLifeFileData.h b/code/HalfLifeFileData.h index 9837a4e29..3a36d2422 100644 --- a/code/HalfLifeFileData.h +++ b/code/HalfLifeFileData.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -65,8 +66,7 @@ namespace MDL { * \brief Data structure for the HL2 main header */ // --------------------------------------------------------------------------- -struct Header_HL2 -{ +struct Header_HL2 { //! magic number: "IDST"/"IDSQ" char ident[4]; @@ -138,7 +138,7 @@ struct Header_HL2 //! Number of animation transitions int32_t numtransitions; int32_t transitionindex; -} PACK_STRUCT; +} /* PACK_STRUCT */; #include "./../include/assimp/Compiler/poppack1.h" diff --git a/code/Hash.h b/code/Hash.h index cd7ca6def..a567adbc3 100644 --- a/code/Hash.h +++ b/code/Hash.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/IFCBoolean.cpp b/code/IFCBoolean.cpp index 98b230392..8571a3c79 100644 --- a/code/IFCBoolean.cpp +++ b/code/IFCBoolean.cpp @@ -381,7 +381,6 @@ bool PointInPoly(const IfcVector3& p, const std::vector& boundary) IntersectsBoundaryProfile(p, p + IfcVector3(0.6, -0.6, 0.0), boundary, true, intersected_boundary, true); votes += intersected_boundary.size() % 2; -// ai_assert(votes == 3 || votes == 0); return votes > 1; } diff --git a/code/IFCCurve.cpp b/code/IFCCurve.cpp index 97d9fd574..176fe3c13 100644 --- a/code/IFCCurve.cpp +++ b/code/IFCCurve.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -547,8 +548,6 @@ bool Curve :: InRange(IfcFloat u) const const ParamRange range = GetParametricRange(); if (IsClosed()) { return true; - //ai_assert(range.first != std::numeric_limits::infinity() && range.second != std::numeric_limits::infinity()); - //u = range.first + std::fmod(u-range.first,range.second-range.first); } const IfcFloat epsilon = 1e-5; return u - range.first > -epsilon && range.second - u > -epsilon; diff --git a/code/IFCLoader.cpp b/code/IFCLoader.cpp index 0021ceb86..85382d467 100644 --- a/code/IFCLoader.cpp +++ b/code/IFCLoader.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -65,7 +66,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace Assimp { - template<> const std::string LogFunctions::log_prefix = "IFC: "; + template<> const char* LogFunctions::Prefix() + { + static auto prefix = "IFC: "; + return prefix; + } } using namespace Assimp; @@ -154,7 +159,7 @@ void IFCImporter::SetupProperties(const Importer* pImp) { settings.skipSpaceRepresentations = pImp->GetPropertyBool(AI_CONFIG_IMPORT_IFC_SKIP_SPACE_REPRESENTATIONS,true); settings.useCustomTriangulation = pImp->GetPropertyBool(AI_CONFIG_IMPORT_IFC_CUSTOM_TRIANGULATION,true); - settings.conicSamplingAngle = std::min(std::max(pImp->GetPropertyFloat(AI_CONFIG_IMPORT_IFC_SMOOTHING_ANGLE, AI_IMPORT_IFC_DEFAULT_SMOOTHING_ANGLE), 5.0f), 120.0f); + settings.conicSamplingAngle = std::min(std::max((float) pImp->GetPropertyFloat(AI_CONFIG_IMPORT_IFC_SMOOTHING_ANGLE, AI_IMPORT_IFC_DEFAULT_SMOOTHING_ANGLE), 5.0f), 120.0f); settings.cylindricalTessellation = std::min(std::max(pImp->GetPropertyInteger(AI_CONFIG_IMPORT_IFC_CYLINDRICAL_TESSELLATION, AI_IMPORT_IFC_DEFAULT_CYLINDRICAL_TESSELLATION), 3), 180); settings.skipAnnotations = true; } @@ -881,6 +886,7 @@ void ProcessSpatialStructures(ConversionData& conv) } } + std::vector nodes; for(const STEP::LazyObject* lz : *range) { const IfcSpatialStructureElement* const prod = lz->ToPtr(); @@ -889,20 +895,19 @@ void ProcessSpatialStructures(ConversionData& conv) } IFCImporter::LogDebug("looking at spatial structure `" + (prod->Name ? prod->Name.Get() : "unnamed") + "`" + (prod->ObjectType? " which is of type " + prod->ObjectType.Get():"")); - // the primary site is referenced by an IFCRELAGGREGATES element which assigns it to the IFCPRODUCT + // the primary sites are referenced by an IFCRELAGGREGATES element which assigns them to the IFCPRODUCT const STEP::DB::RefMap& refs = conv.db.GetRefs(); - STEP::DB::RefMapRange range = refs.equal_range(conv.proj.GetID()); - for(;range.first != range.second; ++range.first) { - if(const IfcRelAggregates* const aggr = conv.db.GetObject((*range.first).second)->ToPtr()) { + STEP::DB::RefMapRange ref_range = refs.equal_range(conv.proj.GetID()); + for(; ref_range.first != ref_range.second; ++ref_range.first) { + if(const IfcRelAggregates* const aggr = conv.db.GetObject((*ref_range.first).second)->ToPtr()) { for(const IfcObjectDefinition& def : aggr->RelatedObjects) { // comparing pointer values is not sufficient, we would need to cast them to the same type first // as there is multiple inheritance in the game. if (def.GetID() == prod->GetID()) { IFCImporter::LogDebug("selecting this spatial structure as root structure"); - // got it, this is the primary site. - conv.out->mRootNode = ProcessSpatialStructure(NULL,*prod,conv,NULL); - return; + // got it, this is one primary site. + nodes.push_back(ProcessSpatialStructure(NULL, *prod, conv, NULL)); } } @@ -910,19 +915,42 @@ void ProcessSpatialStructures(ConversionData& conv) } } + size_t nb_nodes = nodes.size(); - IFCImporter::LogWarn("failed to determine primary site element, taking the first IfcSite"); - for(const STEP::LazyObject* lz : *range) { - const IfcSpatialStructureElement* const prod = lz->ToPtr(); - if(!prod) { - continue; - } + if (nb_nodes == 0) { + IFCImporter::LogWarn("failed to determine primary site element, taking all the IfcSite"); + for (const STEP::LazyObject* lz : *range) { + const IfcSpatialStructureElement* const prod = lz->ToPtr(); + if (!prod) { + continue; + } - conv.out->mRootNode = ProcessSpatialStructure(NULL,*prod,conv,NULL); - return; - } + nodes.push_back(ProcessSpatialStructure(NULL, *prod, conv, NULL)); + } - IFCImporter::ThrowException("failed to determine primary site element"); + nb_nodes = nodes.size(); + } + + if (nb_nodes == 1) { + conv.out->mRootNode = nodes[0]; + } + else if (nb_nodes > 1) { + conv.out->mRootNode = new aiNode("Root"); + conv.out->mRootNode->mParent = NULL; + conv.out->mRootNode->mNumChildren = static_cast(nb_nodes); + conv.out->mRootNode->mChildren = new aiNode*[conv.out->mRootNode->mNumChildren]; + + for (size_t i = 0; i < nb_nodes; ++i) { + aiNode* node = nodes[i]; + + node->mParent = conv.out->mRootNode; + + conv.out->mRootNode->mChildren[i] = node; + } + } + else { + IFCImporter::ThrowException("failed to determine primary site element"); + } } // ------------------------------------------------------------------------------------------------ diff --git a/code/IFCLoader.h b/code/IFCLoader.h index 9fa6cba38..4cf116f8e 100644 --- a/code/IFCLoader.h +++ b/code/IFCLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/IFCMaterial.cpp b/code/IFCMaterial.cpp index ae2fa3619..aa11c5c22 100644 --- a/code/IFCMaterial.cpp +++ b/code/IFCMaterial.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -42,19 +43,17 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * @brief Implementation of conversion routines to convert IFC materials to aiMaterial */ - - #ifndef ASSIMP_BUILD_NO_IFC_IMPORTER + #include "IFCUtil.h" #include #include namespace Assimp { - namespace IFC { +namespace IFC { // ------------------------------------------------------------------------------------------------ -int ConvertShadingMode(const std::string& name) -{ +static int ConvertShadingMode(const std::string& name) { if (name == "BLINN") { return aiShadingMode_Blinn; } @@ -69,8 +68,7 @@ int ConvertShadingMode(const std::string& name) } // ------------------------------------------------------------------------------------------------ -void FillMaterial(aiMaterial* mat,const IFC::IfcSurfaceStyle* surf,ConversionData& conv) -{ +static void FillMaterial(aiMaterial* mat,const IFC::IfcSurfaceStyle* surf,ConversionData& conv) { aiString name; name.Set((surf->Name? surf->Name.Get() : "IfcSurfaceStyle_Unnamed")); mat->AddProperty(&name,AI_MATKEY_NAME); @@ -134,8 +132,7 @@ void FillMaterial(aiMaterial* mat,const IFC::IfcSurfaceStyle* surf,ConversionDat } // ------------------------------------------------------------------------------------------------ -unsigned int ProcessMaterials(uint64_t id, unsigned int prevMatId, ConversionData& conv, bool forceDefaultMat) -{ +unsigned int ProcessMaterials(uint64_t id, unsigned int prevMatId, ConversionData& conv, bool forceDefaultMat) { STEP::DB::RefMapRange range = conv.db.GetRefs().equal_range(id); for(;range.first != range.second; ++range.first) { if(const IFC::IfcStyledItem* const styled = conv.db.GetObject((*range.first).second)->ToPtr()) { @@ -162,31 +159,33 @@ unsigned int ProcessMaterials(uint64_t id, unsigned int prevMatId, ConversionDat unsigned int matindex = static_cast(conv.materials.size() - 1); conv.cached_materials[surf] = matindex; return matindex; + } + } } } } - } - } // no local material defined. If there's global one, use that instead - if( prevMatId != std::numeric_limits::max() ) + if ( prevMatId != std::numeric_limits::max() ) { return prevMatId; + } // we're still here - create an default material if required, or simply fail otherwise - if( !forceDefaultMat ) + if ( !forceDefaultMat ) { return std::numeric_limits::max(); + } aiString name; name.Set(""); // ConvertColorToString( color, name); // look if there's already a default material with this base color - for( size_t a = 0; a < conv.materials.size(); ++a ) - { + for( size_t a = 0; a < conv.materials.size(); ++a ) { aiString mname; conv.materials[a]->Get(AI_MATKEY_NAME, mname); - if( name == mname ) - return (unsigned int)a; + if ( name == mname ) { + return ( unsigned int )a; + } } // we're here, yet - no default material with suitable color available. Generate one @@ -203,4 +202,4 @@ unsigned int ProcessMaterials(uint64_t id, unsigned int prevMatId, ConversionDat } // ! IFC } // ! Assimp -#endif +#endif // ASSIMP_BUILD_NO_IFC_IMPORTER diff --git a/code/IFCOpenings.cpp b/code/IFCOpenings.cpp index f40b49fe4..45e0d1b90 100644 --- a/code/IFCOpenings.cpp +++ b/code/IFCOpenings.cpp @@ -1492,7 +1492,7 @@ bool TryAddOpenings_Poly2Tri(const std::vector& openings,const std: vmax -= vmin; // If this happens then the projection must have been wrong. - assert(vmax.Length()); + ai_assert(vmax.Length()); ClipperLib::ExPolygons clipped; ClipperLib::Polygons holes_union; @@ -1616,7 +1616,7 @@ bool TryAddOpenings_Poly2Tri(const std::vector& openings,const std: std::vector tmpvec; for(ClipperLib::Polygon& opening : holes_union) { - assert(ClipperLib::Orientation(opening)); + ai_assert(ClipperLib::Orientation(opening)); tmpvec.clear(); @@ -1705,7 +1705,7 @@ bool TryAddOpenings_Poly2Tri(const std::vector& openings,const std: static_cast( tri->GetPoint(i)->y ) ); - assert(v.x <= 1.0 && v.x >= 0.0 && v.y <= 1.0 && v.y >= 0.0); + ai_assert(v.x <= 1.0 && v.x >= 0.0 && v.y <= 1.0 && v.y >= 0.0); const IfcVector3 v3 = minv * IfcVector3(vmin.x + v.x * vmax.x, vmin.y + v.y * vmax.y,coord) ; curmesh.verts.push_back(v3); diff --git a/code/IFCProfile.cpp b/code/IFCProfile.cpp index 866b874c9..595159a6b 100644 --- a/code/IFCProfile.cpp +++ b/code/IFCProfile.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -127,7 +128,7 @@ void ProcessParametrizedProfile(const IfcParameterizedProfileDef& def, TempMesh& meshout.verts.push_back( IfcVector3( std::cos(angle)*radius, std::sin(angle)*radius, 0.f )); } - meshout.vertcnt.push_back(segments); + meshout.vertcnt.push_back(static_cast(segments)); } else if( const IfcIShapeProfileDef* const ishape = def.ToPtr()) { // construct simplified IBeam shape diff --git a/code/IFCUtil.cpp b/code/IFCUtil.cpp index d7e4d5d54..f5bd56a00 100644 --- a/code/IFCUtil.cpp +++ b/code/IFCUtil.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/IFCUtil.h b/code/IFCUtil.h index 43d20a434..f90f421d6 100644 --- a/code/IFCUtil.h +++ b/code/IFCUtil.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/IOStreamBuffer.h b/code/IOStreamBuffer.h index 5208d020c..d7528de7e 100644 --- a/code/IOStreamBuffer.h +++ b/code/IOStreamBuffer.h @@ -4,7 +4,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -44,6 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "ParsingUtils.h" +#include + namespace Assimp { // --------------------------------------------------------------------------- @@ -68,8 +71,8 @@ public: /// @return true if successful. bool close(); - /// @brief Returns the filesize. - /// @return The filesize. + /// @brief Returns the file-size. + /// @return The file-size. size_t size() const; /// @brief Returns the cache size. @@ -95,7 +98,17 @@ public: /// @brief Will read the next line. /// @param buffer The buffer for the next line. /// @return true if successful. - bool getNextLine( std::vector &buffer ); + bool getNextDataLine( std::vector &buffer, T continuationToken ); + + /// @brief Will read the next line ascii or binary end line char. + /// @param buffer The buffer for the next line. + /// @return true if successful. + bool getNextLine(std::vector &buffer); + + /// @brief Will read the next block. + /// @param buffer The buffer for the next block. + /// @return true if successful. + bool getNextBlock( std::vector &buffer ); private: IOStream *m_stream; @@ -226,15 +239,35 @@ size_t IOStreamBuffer::getFilePos() const { template inline -bool IOStreamBuffer::getNextLine( std::vector &buffer ) { +bool IOStreamBuffer::getNextDataLine( std::vector &buffer, T continuationToken ) { buffer.resize( m_cacheSize ); if ( m_cachePos == m_cacheSize || 0 == m_filePos ) { if ( !readNextBlock() ) { return false; } } + + bool continuationFound( false ), endOfDataLine( false ); size_t i = 0; - while ( !IsLineEnd( m_cache[ m_cachePos ] ) ) { + while ( !endOfDataLine ) { + if ( continuationToken == m_cache[ m_cachePos ] ) { + continuationFound = true; + ++m_cachePos; + } + if ( IsLineEnd( m_cache[ m_cachePos ] ) ) { + if ( !continuationFound ) { + // the end of the data line + break; + } else { + // skip line end + while ( m_cache[m_cachePos] != '\n') { + ++m_cachePos; + } + ++m_cachePos; + continuationFound = false; + } + } + buffer[ i ] = m_cache[ m_cachePos ]; m_cachePos++; i++; @@ -244,10 +277,74 @@ bool IOStreamBuffer::getNextLine( std::vector &buffer ) { } } } + buffer[ i ] = '\n'; m_cachePos++; return true; } +static +inline +bool isEndOfCache( size_t pos, size_t cacheSize ) { + return ( pos == cacheSize ); +} + +template +inline +bool IOStreamBuffer::getNextLine(std::vector &buffer) { + buffer.resize(m_cacheSize); + if ( isEndOfCache( m_cachePos, m_cacheSize ) || 0 == m_filePos) { + if (!readNextBlock()) { + return false; + } + } + + if (IsLineEnd(m_cache[m_cachePos])) { + // skip line end + while (m_cache[m_cachePos] != '\n') { + ++m_cachePos; + } + ++m_cachePos; + if ( isEndOfCache( m_cachePos, m_cacheSize ) ) { + if ( !readNextBlock() ) { + return false; + } + } + } + + size_t i = 0; + while (!IsLineEnd(m_cache[ m_cachePos ])) { + buffer[i] = m_cache[ m_cachePos ]; + m_cachePos++; + i++; + if (m_cachePos >= m_cacheSize) { + if (!readNextBlock()) { + return false; + } + } + } + buffer[i] = '\n'; + m_cachePos++; + + return true; +} + +template +inline +bool IOStreamBuffer::getNextBlock( std::vector &buffer) { + //just return the last blockvalue if getNextLine was used before + if ( m_cachePos != 0) { + buffer = std::vector(m_cache.begin() + m_cachePos, m_cache.end()); + m_cachePos = 0; + } + else { + if ( !readNextBlock() ) + return false; + + buffer = std::vector(m_cache.begin(), m_cache.end()); + } + return true; +} + } // !ns Assimp diff --git a/code/IRRLoader.cpp b/code/IRRLoader.cpp index e552601b8..8cc4acaad 100644 --- a/code/IRRLoader.cpp +++ b/code/IRRLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -52,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "fast_atof.h" #include "GenericProperty.h" -#include "SceneCombiner.h" +#include #include "StandardShapes.h" #include "Importer.h" diff --git a/code/IRRLoader.h b/code/IRRLoader.h index fab2391d6..d07199c0b 100644 --- a/code/IRRLoader.h +++ b/code/IRRLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -47,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_IRRLOADER_H_INCLUDED #include "IRRShared.h" -#include "SceneCombiner.h" +#include #include "Importer.h" #include "StringUtils.h" #include diff --git a/code/IRRMeshLoader.cpp b/code/IRRMeshLoader.cpp index 88439459a..a63a2a134 100644 --- a/code/IRRMeshLoader.cpp +++ b/code/IRRMeshLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/IRRMeshLoader.h b/code/IRRMeshLoader.h index 6c208224c..312dbbfe0 100644 --- a/code/IRRMeshLoader.h +++ b/code/IRRMeshLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/IRRShared.cpp b/code/IRRShared.cpp index e38ad1378..bfe408629 100644 --- a/code/IRRShared.cpp +++ b/code/IRRShared.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/Importer.cpp b/code/Importer.cpp index 094774544..379daab02 100644 --- a/code/Importer.cpp +++ b/code/Importer.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -830,8 +831,8 @@ const aiScene* Importer::ApplyPostProcessing(unsigned int pFlags) pimpl->mProgressHandler->UpdatePostProcess( static_cast(pimpl->mPostProcessingSteps.size()), static_cast(pimpl->mPostProcessingSteps.size()) ); // update private scene flags - if( pimpl->mScene ) - ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags; + if( pimpl->mScene ) + ScenePriv(pimpl->mScene)->mPPStepsApplied |= pFlags; // clear any data allocated by post-process steps pimpl->mPPShared->Clean(); diff --git a/code/Importer.h b/code/Importer.h index 6beca45ba..e0fb57f5b 100644 --- a/code/Importer.h +++ b/code/Importer.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ImporterRegistry.cpp b/code/ImporterRegistry.cpp index f77193c2f..b4d2c3dcf 100644 --- a/code/ImporterRegistry.cpp +++ b/code/ImporterRegistry.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -181,6 +182,7 @@ corresponding preprocessor flag to selectively disable formats. #endif #ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER # include "glTFImporter.h" +# include "glTF2Importer.h" #endif #ifndef ASSIMP_BUILD_NO_C4D_IMPORTER # include "C4DImporter.h" @@ -191,6 +193,9 @@ corresponding preprocessor flag to selectively disable formats. #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER # include "X3DImporter.hpp" #endif +#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER +# include "MMDImporter.h" +#endif namespace Assimp { @@ -227,7 +232,9 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out) out.push_back( new MDLImporter()); #endif #if (!defined ASSIMP_BUILD_NO_ASE_IMPORTER) + #if (!defined ASSIMP_BUILD_NO_3DS_IMPORTER) out.push_back( new ASEImporter()); +# endif #endif #if (!defined ASSIMP_BUILD_NO_HMP_IMPORTER) out.push_back( new HMPImporter()); @@ -330,16 +337,20 @@ void GetImporterInstanceList(std::vector< BaseImporter* >& out) #endif #if ( !defined ASSIMP_BUILD_NO_GLTF_IMPORTER ) out.push_back( new glTFImporter() ); + out.push_back( new glTF2Importer() ); #endif #if ( !defined ASSIMP_BUILD_NO_C4D_IMPORTER ) out.push_back( new C4DImporter() ); #endif #if ( !defined ASSIMP_BUILD_NO_3MF_IMPORTER ) - out.push_back(new D3MFImporter() ); + out.push_back( new D3MFImporter() ); #endif #ifndef ASSIMP_BUILD_NO_X3D_IMPORTER out.push_back( new X3DImporter() ); #endif +#ifndef ASSIMP_BUILD_NO_MMD_IMPORTER + out.push_back( new MMDImporter() ); +#endif } /** will delete all registered importers. */ diff --git a/code/ImproveCacheLocality.cpp b/code/ImproveCacheLocality.cpp index 9fd76508b..7f0727e8b 100644 --- a/code/ImproveCacheLocality.cpp +++ b/code/ImproveCacheLocality.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/ImproveCacheLocality.h b/code/ImproveCacheLocality.h index d43f37f50..d91388c41 100644 --- a/code/ImproveCacheLocality.h +++ b/code/ImproveCacheLocality.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/JoinVerticesProcess.cpp b/code/JoinVerticesProcess.cpp index 9cd34e1d0..17b0ab07f 100644 --- a/code/JoinVerticesProcess.cpp +++ b/code/JoinVerticesProcess.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/JoinVerticesProcess.h b/code/JoinVerticesProcess.h index b1a9aa910..a3204782a 100644 --- a/code/JoinVerticesProcess.h +++ b/code/JoinVerticesProcess.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/LWOAnimation.cpp b/code/LWOAnimation.cpp index 10bc54b16..61c696453 100644 --- a/code/LWOAnimation.cpp +++ b/code/LWOAnimation.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -53,6 +54,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers #include "LWOFileData.h" +#include using namespace Assimp; using namespace Assimp::LWO; @@ -162,7 +164,7 @@ void AnimResolver::UpdateAnimRangeSetup() { const double start_time = delta - std::fmod(my_first-first,delta); std::vector::iterator n = std::find_if((*it).keys.begin(),(*it).keys.end(), - std::bind1st(std::greater(),start_time)),m; + [start_time](double t) { return start_time > t; }),m; size_t ofs = 0; if (n != (*it).keys.end()) { diff --git a/code/LWOAnimation.h b/code/LWOAnimation.h index 257abecdd..f0c578ad9 100644 --- a/code/LWOAnimation.h +++ b/code/LWOAnimation.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -47,11 +48,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_LWO_ANIMATION_INCLUDED #define AI_LWO_ANIMATION_INCLUDED -#include +// #include #include struct aiNodeAnim; +struct aiVectorKey; namespace Assimp { namespace LWO { @@ -165,7 +167,6 @@ struct Envelope //! Keyframes for this envelope std::vector keys; - // temporary data for AnimResolver size_t old_first,old_last; }; @@ -197,8 +198,7 @@ public: * @param Output tick rate, per second * @note The input envelopes are possibly modified. */ - AnimResolver(std::list& envelopes, - double tick); + AnimResolver(std::list& envelopes, double tick); public: diff --git a/code/LWOBLoader.cpp b/code/LWOBLoader.cpp index 639675294..6a07f81a7 100644 --- a/code/LWOBLoader.cpp +++ b/code/LWOBLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/LWOFileData.h b/code/LWOFileData.h index d67cf7ec8..7fa9a216d 100644 --- a/code/LWOFileData.h +++ b/code/LWOFileData.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/LWOLoader.cpp b/code/LWOLoader.cpp index 5d8b84aab..5ec07800d 100644 --- a/code/LWOLoader.cpp +++ b/code/LWOLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -66,7 +67,7 @@ static const aiImporterDesc desc = { "LightWave/Modo Object Importer", "", "", - "http://www.newtek.com/lightwave.html\nhttp://www.luxology.com/modo/", + "https://www.lightwave3d.com/lightwave_sdk/", aiImporterFlags_SupportTextFlavour, 0, 0, diff --git a/code/LWOLoader.h b/code/LWOLoader.h index 9907d691d..b92e5aab4 100644 --- a/code/LWOLoader.h +++ b/code/LWOLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/LWOMaterial.cpp b/code/LWOMaterial.cpp index 42a6f8c5e..e2ba894af 100644 --- a/code/LWOMaterial.cpp +++ b/code/LWOMaterial.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/LWSLoader.cpp b/code/LWSLoader.cpp index 52d0c522c..302228556 100644 --- a/code/LWSLoader.cpp +++ b/code/LWSLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -50,7 +51,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ParsingUtils.h" #include "fast_atof.h" -#include "SceneCombiner.h" +#include #include "GenericProperty.h" #include "SkeletonMeshBuilder.h" #include "ConvertToLHProcess.h" diff --git a/code/LWSLoader.h b/code/LWSLoader.h index 9547b67bb..e36d27b77 100644 --- a/code/LWSLoader.h +++ b/code/LWSLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -45,7 +46,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define AI_LWSLOADER_H_INCLUDED #include "LWOFileData.h" -#include "SceneCombiner.h" +#include #include "BaseImporter.h" struct aiImporterDesc; diff --git a/code/LimitBoneWeightsProcess.cpp b/code/LimitBoneWeightsProcess.cpp index e35fe1462..0bb4a4be3 100644 --- a/code/LimitBoneWeightsProcess.cpp +++ b/code/LimitBoneWeightsProcess.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/LimitBoneWeightsProcess.h b/code/LimitBoneWeightsProcess.h index f6907cf26..3826dbe58 100644 --- a/code/LimitBoneWeightsProcess.h +++ b/code/LimitBoneWeightsProcess.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/LineSplitter.h b/code/LineSplitter.h index 0fa47380e..10ca1d35a 100644 --- a/code/LineSplitter.h +++ b/code/LineSplitter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/LogAux.h b/code/LogAux.h index f754903c6..08b1b3c17 100644 --- a/code/LogAux.h +++ b/code/LogAux.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -59,34 +60,34 @@ public: // ------------------------------------------------------------------------------------------------ static void ThrowException(const std::string& msg) { - throw DeadlyImportError(log_prefix+msg); + throw DeadlyImportError(Prefix()+msg); } // ------------------------------------------------------------------------------------------------ static void LogWarn(const Formatter::format& message) { if (!DefaultLogger::isNullLogger()) { - DefaultLogger::get()->warn(log_prefix+(std::string)message); + DefaultLogger::get()->warn(Prefix() +(std::string)message); } } // ------------------------------------------------------------------------------------------------ static void LogError(const Formatter::format& message) { if (!DefaultLogger::isNullLogger()) { - DefaultLogger::get()->error(log_prefix+(std::string)message); + DefaultLogger::get()->error(Prefix() +(std::string)message); } } // ------------------------------------------------------------------------------------------------ static void LogInfo(const Formatter::format& message) { if (!DefaultLogger::isNullLogger()) { - DefaultLogger::get()->info(log_prefix+(std::string)message); + DefaultLogger::get()->info(Prefix() +(std::string)message); } } // ------------------------------------------------------------------------------------------------ static void LogDebug(const Formatter::format& message) { if (!DefaultLogger::isNullLogger()) { - DefaultLogger::get()->debug(log_prefix+(std::string)message); + DefaultLogger::get()->debug(Prefix() +(std::string)message); } } @@ -124,8 +125,7 @@ public: #endif private: - - static const std::string log_prefix; + static const char* Prefix(); }; diff --git a/code/MD2FileData.h b/code/MD2FileData.h index b56f6c76b..f65193264 100644 --- a/code/MD2FileData.h +++ b/code/MD2FileData.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MD2Loader.cpp b/code/MD2Loader.cpp index ffcda3916..cb494d5b2 100644 --- a/code/MD2Loader.cpp +++ b/code/MD2Loader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/MD2Loader.h b/code/MD2Loader.h index 126c16359..a7566dc64 100644 --- a/code/MD2Loader.h +++ b/code/MD2Loader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MD2NormalTable.h b/code/MD2NormalTable.h index 5b1344bd6..98fbc1d7a 100644 --- a/code/MD2NormalTable.h +++ b/code/MD2NormalTable.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MD3FileData.h b/code/MD3FileData.h index 3a59d0d1d..19740c30e 100644 --- a/code/MD3FileData.h +++ b/code/MD3FileData.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -141,14 +142,14 @@ struct Frame //! name of frame char name[ AI_MD3_MAXFRAME ]; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------- -/** @brief Data structure for the tag header +/** + * @brief Data structure for the tag header */ -struct Tag -{ +struct Tag { //! name of the tag char NAME[ AI_MD3_MAXQPATH ]; @@ -156,14 +157,13 @@ struct Tag aiVector3D origin; ai_real orientation[3][3]; -} PACK_STRUCT; +} /* PACK_STRUCT */; // ------------------------------------------------------------------------------- /** @brief Data structure for the surface header */ -struct Surface -{ +struct Surface { //! magic number int32_t IDENT; @@ -185,7 +185,6 @@ struct Surface //! number of triangles in the surface uint32_t NUM_TRIANGLES; - //! offset to the triangle data uint32_t OFS_TRIANGLES; @@ -200,19 +199,18 @@ struct Surface //! offset to the end of the Surface object int32_t OFS_END; -} PACK_STRUCT; +} /*PACK_STRUCT*/; // ------------------------------------------------------------------------------- /** @brief Data structure for a shader defined in there */ -struct Shader -{ +struct Shader { //! filename of the shader char NAME[ AI_MD3_MAXQPATH ]; //! index of the shader uint32_t SHADER_INDEX; -} PACK_STRUCT; +} /*PACK_STRUCT*/; // ------------------------------------------------------------------------------- @@ -222,7 +220,7 @@ struct Triangle { //! triangle indices uint32_t INDEXES[3]; -} PACK_STRUCT; +} /*PACK_STRUCT*/; // ------------------------------------------------------------------------------- @@ -232,7 +230,7 @@ struct TexCoord { //! UV coordinates ai_real U,V; -} PACK_STRUCT; +} /*PACK_STRUCT*/; // ------------------------------------------------------------------------------- @@ -245,7 +243,7 @@ struct Vertex //! encoded normal vector uint16_t NORMAL; -} PACK_STRUCT; +} /*PACK_STRUCT*/; #include "./../include/assimp/Compiler/poppack1.h" diff --git a/code/MD3Loader.cpp b/code/MD3Loader.cpp index f469a4c95..f6a3a85dd 100644 --- a/code/MD3Loader.cpp +++ b/code/MD3Loader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -52,7 +53,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_MD3_IMPORTER #include "MD3Loader.h" -#include "SceneCombiner.h" +#include #include "GenericProperty.h" #include "RemoveComments.h" #include "ParsingUtils.h" diff --git a/code/MD3Loader.h b/code/MD3Loader.h index 6b8143a97..ff5b56a52 100644 --- a/code/MD3Loader.h +++ b/code/MD3Loader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MD5Loader.cpp b/code/MD5Loader.cpp index d2477a2c5..172c98a30 100644 --- a/code/MD5Loader.cpp +++ b/code/MD5Loader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/MD5Loader.h b/code/MD5Loader.h index 9dfc08226..afb07a62d 100644 --- a/code/MD5Loader.h +++ b/code/MD5Loader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MD5Parser.cpp b/code/MD5Parser.cpp index 9379deab1..8076e5bc4 100644 --- a/code/MD5Parser.cpp +++ b/code/MD5Parser.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/MD5Parser.h b/code/MD5Parser.h index 78ade8430..bafcaf962 100644 --- a/code/MD5Parser.h +++ b/code/MD5Parser.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MDCFileData.h b/code/MDCFileData.h index c98828c28..9ea3d8f5e 100644 --- a/code/MDCFileData.h +++ b/code/MDCFileData.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -156,7 +157,7 @@ struct Frame //! Name of the frame char name [ 16 ] ; -} PACK_STRUCT; +} /*PACK_STRUCT*/; // --------------------------------------------------------------------------- /** \brief Data structure for a MDC triangle diff --git a/code/MDCLoader.cpp b/code/MDCLoader.cpp index db109bf83..21aca53ff 100644 --- a/code/MDCLoader.cpp +++ b/code/MDCLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/MDCLoader.h b/code/MDCLoader.h index fcfbc642d..5f3b365fd 100644 --- a/code/MDCLoader.h +++ b/code/MDCLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MDLDefaultColorMap.h b/code/MDLDefaultColorMap.h index 6db696af0..800c717c5 100644 --- a/code/MDLDefaultColorMap.h +++ b/code/MDLDefaultColorMap.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MDLFileData.h b/code/MDLFileData.h index 536bf082a..3ef58ca5a 100644 --- a/code/MDLFileData.h +++ b/code/MDLFileData.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -52,10 +53,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_MDLFILEHELPER_H_INC #define AI_MDLFILEHELPER_H_INC +#include +#include +#include #include "ByteSwapper.h" -#include "./../include/assimp/anim.h" -#include "./../include/assimp/mesh.h" -#include "./../include/assimp/Compiler/pushpack1.h" #include #include @@ -89,7 +90,6 @@ namespace MDL { #define AI_MDL_MAGIC_NUMBER_BE_GS7 AI_MAKE_MAGIC("MDL7") #define AI_MDL_MAGIC_NUMBER_LE_GS7 AI_MAKE_MAGIC("7LDM") - // common limitations for Quake1 meshes. The loader does not check them, // (however it warns) but models should not exceed these limits. #if (!defined AI_MDL_VERSION) @@ -118,8 +118,7 @@ namespace MDL { /** \struct Header * \brief Data structure for the MDL main header */ -struct Header -{ +struct Header { //! magic number: "IDPO" uint32_t ident; @@ -127,16 +126,16 @@ struct Header int32_t version; //! scale factors for each axis - aiVector3D scale; + ai_real scale[3]; //! translation factors for each axis - aiVector3D translate; + ai_real translate[3]; //! bounding radius of the mesh float boundingradius; //! Position of the viewer's exe. Ignored - aiVector3D vEyePos; + ai_real vEyePos[3]; //! Number of textures int32_t num_skins; @@ -172,8 +171,7 @@ struct Header /** \struct Header_MDL7 * \brief Data structure for the MDL 7 main header */ -struct Header_MDL7 -{ +struct Header_MDL7 { //! magic number: "MDL7" char ident[4]; @@ -232,8 +230,7 @@ struct Header_MDL7 /** \struct Bone_MDL7 * \brief Data structure for a bone in a MDL7 file */ -struct Bone_MDL7 -{ +struct Bone_MDL7 { //! Index of the parent bone of *this* bone. 0xffff means: //! "hey, I have no parent, I'm an orphan" uint16_t parent_index; @@ -267,8 +264,7 @@ struct Bone_MDL7 /** \struct Group_MDL7 * \brief Group in a MDL7 file */ -struct Group_MDL7 -{ +struct Group_MDL7 { //! = '1' -> triangle based Mesh unsigned char typ; @@ -309,8 +305,7 @@ struct Group_MDL7 /** \struct Deformer_MDL7 * \brief Deformer in a MDL7 file */ -struct Deformer_MDL7 -{ +struct Deformer_MDL7 { int8_t deformer_version; // 0 int8_t deformer_typ; // 0 - bones int8_t _unused_[2]; @@ -324,27 +319,23 @@ struct Deformer_MDL7 /** \struct DeformerElement_MDL7 * \brief Deformer element in a MDL7 file */ -struct DeformerElement_MDL7 -{ +struct DeformerElement_MDL7 { //! bei deformer_typ==0 (==bones) element_index == bone index int32_t element_index; char element_name[AI_MDL7_MAX_BONENAMESIZE]; int32_t weights; } PACK_STRUCT; - // ------------------------------------------------------------------------------------- /** \struct DeformerWeight_MDL7 * \brief Deformer weight in a MDL7 file */ -struct DeformerWeight_MDL7 -{ +struct DeformerWeight_MDL7 { //! for deformer_typ==0 (==bones) index == vertex index int32_t index; float weight; } PACK_STRUCT; - // don't know why this was in the original headers ... typedef int32_t MD7_MATERIAL_ASCDEFSIZE; @@ -352,8 +343,7 @@ typedef int32_t MD7_MATERIAL_ASCDEFSIZE; /** \struct ColorValue_MDL7 * \brief Data structure for a color value in a MDL7 file */ -struct ColorValue_MDL7 -{ +struct ColorValue_MDL7 { float r,g,b,a; } PACK_STRUCT; @@ -361,8 +351,7 @@ struct ColorValue_MDL7 /** \struct Material_MDL7 * \brief Data structure for a Material in a MDL7 file */ -struct Material_MDL7 -{ +struct Material_MDL7 { //! Diffuse base color of the material ColorValue_MDL7 Diffuse; @@ -379,13 +368,11 @@ struct Material_MDL7 float Power; } PACK_STRUCT; - // ------------------------------------------------------------------------------------- /** \struct Skin * \brief Skin data structure #1 - used by Quake1, MDL2, MDL3 and MDL4 */ -struct Skin -{ +struct Skin { //! 0 = single (Skin), 1 = group (GroupSkin) //! For MDL3-5: Defines the type of the skin and there //! fore the size of the data to skip: @@ -409,8 +396,7 @@ struct Skin * \brief Skin data structure #2 - used by MDL5, MDL6 and MDL7 * \see Skin */ -struct Skin_MDL5 -{ +struct Skin_MDL5 { int32_t size, width, height; uint8_t *data; } PACK_STRUCT; @@ -424,8 +410,7 @@ struct Skin_MDL5 /** \struct Skin_MDL7 * \brief Skin data structure #3 - used by MDL7 and HMP7 */ -struct Skin_MDL7 -{ +struct Skin_MDL7 { uint8_t typ; int8_t _unused_[3]; int32_t width; @@ -437,8 +422,7 @@ struct Skin_MDL7 /** \struct RGB565 * \brief Data structure for a RGB565 pixel in a texture */ -struct RGB565 -{ +struct RGB565 { uint16_t r : 5; uint16_t g : 6; uint16_t b : 5; @@ -448,20 +432,18 @@ struct RGB565 /** \struct ARGB4 * \brief Data structure for a ARGB4444 pixel in a texture */ -struct ARGB4 -{ +struct ARGB4 { uint16_t a : 4; uint16_t r : 4; uint16_t g : 4; uint16_t b : 4; -} PACK_STRUCT; +} /*PACK_STRUCT*/; // ------------------------------------------------------------------------------------- /** \struct GroupSkin * \brief Skin data structure #2 (group of pictures) */ -struct GroupSkin -{ +struct GroupSkin { //! 0 = single (Skin), 1 = group (GroupSkin) int32_t group; @@ -479,8 +461,7 @@ struct GroupSkin /** \struct TexCoord * \brief Texture coordinate data structure used by the Quake1 MDL format */ -struct TexCoord -{ +struct TexCoord { //! Is the vertex on the noundary between front and back piece? int32_t onseam; @@ -495,8 +476,7 @@ struct TexCoord /** \struct TexCoord_MDL3 * \brief Data structure for an UV coordinate in the 3DGS MDL3 format */ -struct TexCoord_MDL3 -{ +struct TexCoord_MDL3 { //! position, horizontally in range 0..skinwidth-1 int16_t u; @@ -508,8 +488,7 @@ struct TexCoord_MDL3 /** \struct TexCoord_MDL7 * \brief Data structure for an UV coordinate in the 3DGS MDL7 format */ -struct TexCoord_MDL7 -{ +struct TexCoord_MDL7 { //! position, horizontally in range 0..1 float u; @@ -626,7 +605,6 @@ struct Vertex_MDL7 }; } PACK_STRUCT; - // ------------------------------------------------------------------------------------- /** \struct BoneTransform_MDL7 * \brief bone transformation matrix structure used in MDL7 files @@ -647,7 +625,6 @@ struct BoneTransform_MDL7 #define AI_MDL7_MAX_FRAMENAMESIZE 16 - // ------------------------------------------------------------------------------------- /** \struct Frame_MDL7 * \brief Frame data structure used by MDL7 files @@ -737,8 +714,7 @@ struct GroupFrame /** \struct IntFace_MDL7 * \brief Internal data structure to temporarily represent a face */ -struct IntFace_MDL7 -{ +struct IntFace_MDL7 { // provide a constructor for our own convenience IntFace_MDL7() { diff --git a/code/MDLLoader.cpp b/code/MDLLoader.cpp index 4aeff43e5..2025d79b3 100644 --- a/code/MDLLoader.cpp +++ b/code/MDLLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -1131,7 +1132,9 @@ bool MDLImporter::ProcessFrames_3DGS_MDL7(const MDL::IntGroupInfo_MDL7& groupInf const unsigned char* szCurrent, const unsigned char** szCurrentOut) { - ai_assert(NULL != szCurrent && NULL != szCurrentOut); + ai_assert( nullptr != szCurrent ); + ai_assert( nullptr != szCurrentOut); + const MDL::Header_MDL7 *pcHeader = (const MDL::Header_MDL7*)mBuffer; // if we have no bones we can simply skip all frames, diff --git a/code/MDLLoader.h b/code/MDLLoader.h index 62e451cbe..8709426e6 100644 --- a/code/MDLLoader.h +++ b/code/MDLLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MDLMaterialLoader.cpp b/code/MDLMaterialLoader.cpp index 64cebc7d5..91dcb49cc 100644 --- a/code/MDLMaterialLoader.cpp +++ b/code/MDLMaterialLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -545,10 +546,6 @@ void MDLImporter::ParseSkinLump_3DGS_MDL7( } else if (iMasked || !iType || (iType && iWidth && iHeight)) { - // ***** STANDARD COLOR TEXTURE ***** - if(pcNew!= nullptr) - delete pcNew; - pcNew = new aiTexture(); if (!iHeight || !iWidth) { diff --git a/code/MMDCpp14.h b/code/MMDCpp14.h new file mode 100644 index 000000000..f6f81f827 --- /dev/null +++ b/code/MMDCpp14.h @@ -0,0 +1,82 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 + +#ifndef MMD_CPP14_H +#define MMD_CPP14_H + +#include +#include +#include +#include + +namespace mmd { + template struct _Unique_if { + typedef std::unique_ptr _Single_object; + }; + + template struct _Unique_if { + typedef std::unique_ptr _Unknown_bound; + }; + + template struct _Unique_if { + typedef void _Known_bound; + }; + + template + typename _Unique_if::_Single_object + make_unique(Args&&... args) { + return std::unique_ptr(new T(std::forward(args)...)); + } + + template + typename _Unique_if::_Unknown_bound + make_unique(size_t n) { + typedef typename std::remove_extent::type U; + return std::unique_ptr(new U[n]()); + } + + template + typename _Unique_if::_Known_bound + make_unique(Args&&...) = delete; +} + +#endif diff --git a/code/MMDImporter.cpp b/code/MMDImporter.cpp new file mode 100644 index 000000000..c40978c0e --- /dev/null +++ b/code/MMDImporter.cpp @@ -0,0 +1,370 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2016, 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_MMD_IMPORTER + +#include "MMDImporter.h" +#include "MMDPmdParser.h" +#include "MMDPmxParser.h" +#include "MMDVmdParser.h" +#include "ConvertToLHProcess.h" +#include +#include +#include +#include +#include +#include +#include + +static const aiImporterDesc desc = {"MMD Importer", + "", + "", + "surfaces supported?", + aiImporterFlags_SupportTextFlavour, + 0, + 0, + 0, + 0, + "pmx"}; + +namespace Assimp { + +using namespace std; + +// ------------------------------------------------------------------------------------------------ +// Default constructor +MMDImporter::MMDImporter() + : m_Buffer(), + // m_pRootObject( NULL ), + m_strAbsPath("") { + DefaultIOSystem io; + m_strAbsPath = io.getOsSeparator(); +} + +// ------------------------------------------------------------------------------------------------ +// Destructor. +MMDImporter::~MMDImporter() { + // delete m_pRootObject; + // m_pRootObject = NULL; +} + +// ------------------------------------------------------------------------------------------------ +// Returns true, if file is an pmx file. +bool MMDImporter::CanRead(const std::string &pFile, IOSystem *pIOHandler, + bool checkSig) const { + if (!checkSig) // Check File Extension + { + return SimpleExtensionCheck(pFile, "pmx"); + } else // Check file Header + { + static const char *pTokens[] = {"PMX "}; + return BaseImporter::SearchFileHeaderForToken(pIOHandler, pFile, pTokens, + 1); + } +} + +// ------------------------------------------------------------------------------------------------ +const aiImporterDesc *MMDImporter::GetInfo() const { return &desc; } + +// ------------------------------------------------------------------------------------------------ +// MMD import implementation +void MMDImporter::InternReadFile(const std::string &file, aiScene *pScene, + IOSystem *pIOHandler) { + // Read file by istream + std::filebuf fb; + if (!fb.open(file, std::ios::in | std::ios::binary)) { + throw DeadlyImportError("Failed to open file " + file + "."); + } + + std::istream fileStream(&fb); + + // Get the file-size and validate it, throwing an exception when fails + fileStream.seekg(0, fileStream.end); + size_t fileSize = static_cast(fileStream.tellg()); + fileStream.seekg(0, fileStream.beg); + + if (fileSize < sizeof(pmx::PmxModel)) { + throw DeadlyImportError(file + " is too small."); + } + + pmx::PmxModel model; + model.Read(&fileStream); + + CreateDataFromImport(&model, pScene); +} + +// ------------------------------------------------------------------------------------------------ +void MMDImporter::CreateDataFromImport(const pmx::PmxModel *pModel, + aiScene *pScene) { + if (pModel == NULL) { + return; + } + + aiNode *pNode = new aiNode; + if (!pModel->model_name.empty()) { + pNode->mName.Set(pModel->model_name); + } else { + ai_assert(false); + } + + pScene->mRootNode = pNode; + + pNode = new aiNode; + pScene->mRootNode->addChildren(1, &pNode); + pNode->mName.Set(string(pModel->model_name) + string("_mesh")); + + // split mesh by materials + pNode->mNumMeshes = pModel->material_count; + pNode->mMeshes = new unsigned int[pNode->mNumMeshes]; + for (unsigned int index = 0; index < pNode->mNumMeshes; index++) { + pNode->mMeshes[index] = index; + } + + pScene->mNumMeshes = pModel->material_count; + pScene->mMeshes = new aiMesh *[pScene->mNumMeshes]; + for (unsigned int i = 0, indexStart = 0; i < pScene->mNumMeshes; i++) { + const int indexCount = pModel->materials[i].index_count; + + pScene->mMeshes[i] = CreateMesh(pModel, indexStart, indexCount); + pScene->mMeshes[i]->mName = pModel->materials[i].material_name; + pScene->mMeshes[i]->mMaterialIndex = i; + indexStart += indexCount; + } + + // create node hierarchy for bone position + aiNode **ppNode = new aiNode *[pModel->bone_count]; + for (auto i = 0; i < pModel->bone_count; i++) { + ppNode[i] = new aiNode(pModel->bones[i].bone_name); + } + + for (auto i = 0; i < pModel->bone_count; i++) { + const pmx::PmxBone &bone = pModel->bones[i]; + + if (bone.parent_index < 0) { + pScene->mRootNode->addChildren(1, ppNode + i); + } else { + ppNode[bone.parent_index]->addChildren(1, ppNode + i); + + aiVector3D v3 = aiVector3D( + bone.position[0] - pModel->bones[bone.parent_index].position[0], + bone.position[1] - pModel->bones[bone.parent_index].position[1], + bone.position[2] - pModel->bones[bone.parent_index].position[2]); + aiMatrix4x4::Translation(v3, ppNode[i]->mTransformation); + } + } + + // create materials + pScene->mNumMaterials = pModel->material_count; + pScene->mMaterials = new aiMaterial *[pScene->mNumMaterials]; + for (unsigned int i = 0; i < pScene->mNumMaterials; i++) { + pScene->mMaterials[i] = CreateMaterial(&pModel->materials[i], pModel); + } + + // Convert everything to OpenGL space + MakeLeftHandedProcess convertProcess; + convertProcess.Execute(pScene); + + FlipUVsProcess uvFlipper; + uvFlipper.Execute(pScene); + + FlipWindingOrderProcess windingFlipper; + windingFlipper.Execute(pScene); +} + +// ------------------------------------------------------------------------------------------------ +aiMesh *MMDImporter::CreateMesh(const pmx::PmxModel *pModel, + const int indexStart, const int indexCount) { + aiMesh *pMesh = new aiMesh; + + pMesh->mNumVertices = indexCount; + + pMesh->mNumFaces = indexCount / 3; + pMesh->mFaces = new aiFace[pMesh->mNumFaces]; + + const int numIndices = 3; // trianglular face + for (unsigned int index = 0; index < pMesh->mNumFaces; index++) { + pMesh->mFaces[index].mNumIndices = numIndices; + unsigned int *indices = new unsigned int[numIndices]; + indices[0] = numIndices * index; + indices[1] = numIndices * index + 1; + indices[2] = numIndices * index + 2; + pMesh->mFaces[index].mIndices = indices; + } + + pMesh->mVertices = new aiVector3D[pMesh->mNumVertices]; + pMesh->mNormals = new aiVector3D[pMesh->mNumVertices]; + pMesh->mTextureCoords[0] = new aiVector3D[pMesh->mNumVertices]; + pMesh->mNumUVComponents[0] = 2; + + // additional UVs + for (int i = 1; i <= pModel->setting.uv; i++) { + pMesh->mTextureCoords[i] = new aiVector3D[pMesh->mNumVertices]; + pMesh->mNumUVComponents[i] = 4; + } + + map> bone_vertex_map; + + // fill in contents and create bones + for (int index = 0; index < indexCount; index++) { + const pmx::PmxVertex *v = + &pModel->vertices[pModel->indices[indexStart + index]]; + const float *position = v->position; + pMesh->mVertices[index].Set(position[0], position[1], position[2]); + const float *normal = v->normal; + + pMesh->mNormals[index].Set(normal[0], normal[1], normal[2]); + pMesh->mTextureCoords[0][index].x = v->uv[0]; + pMesh->mTextureCoords[0][index].y = v->uv[1]; + + for (int i = 1; i <= pModel->setting.uv; i++) { + // TODO: wrong here? use quaternion transform? + pMesh->mTextureCoords[i][index].x = v->uva[i][0]; + pMesh->mTextureCoords[i][index].y = v->uva[i][1]; + } + + // handle bone map + const auto vsBDEF1_ptr = + dynamic_cast(v->skinning.get()); + const auto vsBDEF2_ptr = + dynamic_cast(v->skinning.get()); + const auto vsBDEF4_ptr = + dynamic_cast(v->skinning.get()); + const auto vsSDEF_ptr = + dynamic_cast(v->skinning.get()); + switch (v->skinning_type) { + case pmx::PmxVertexSkinningType::BDEF1: + bone_vertex_map[vsBDEF1_ptr->bone_index].push_back( + aiVertexWeight(index, 1.0)); + break; + case pmx::PmxVertexSkinningType::BDEF2: + bone_vertex_map[vsBDEF2_ptr->bone_index1].push_back( + aiVertexWeight(index, vsBDEF2_ptr->bone_weight)); + bone_vertex_map[vsBDEF2_ptr->bone_index2].push_back( + aiVertexWeight(index, 1.0f - vsBDEF2_ptr->bone_weight)); + break; + case pmx::PmxVertexSkinningType::BDEF4: + bone_vertex_map[vsBDEF4_ptr->bone_index1].push_back( + aiVertexWeight(index, vsBDEF4_ptr->bone_weight1)); + bone_vertex_map[vsBDEF4_ptr->bone_index2].push_back( + aiVertexWeight(index, vsBDEF4_ptr->bone_weight2)); + bone_vertex_map[vsBDEF4_ptr->bone_index3].push_back( + aiVertexWeight(index, vsBDEF4_ptr->bone_weight3)); + bone_vertex_map[vsBDEF4_ptr->bone_index4].push_back( + aiVertexWeight(index, vsBDEF4_ptr->bone_weight4)); + break; + case pmx::PmxVertexSkinningType::SDEF: // TODO: how to use sdef_c, sdef_r0, + // sdef_r1? + bone_vertex_map[vsSDEF_ptr->bone_index1].push_back( + aiVertexWeight(index, vsSDEF_ptr->bone_weight)); + bone_vertex_map[vsSDEF_ptr->bone_index2].push_back( + aiVertexWeight(index, 1.0f - vsSDEF_ptr->bone_weight)); + break; + case pmx::PmxVertexSkinningType::QDEF: + const auto vsQDEF_ptr = + dynamic_cast(v->skinning.get()); + bone_vertex_map[vsQDEF_ptr->bone_index1].push_back( + aiVertexWeight(index, vsQDEF_ptr->bone_weight1)); + bone_vertex_map[vsQDEF_ptr->bone_index2].push_back( + aiVertexWeight(index, vsQDEF_ptr->bone_weight2)); + bone_vertex_map[vsQDEF_ptr->bone_index3].push_back( + aiVertexWeight(index, vsQDEF_ptr->bone_weight3)); + bone_vertex_map[vsQDEF_ptr->bone_index4].push_back( + aiVertexWeight(index, vsQDEF_ptr->bone_weight4)); + break; + } + } + + // make all bones for each mesh + // assign bone weights to skinned bones (otherwise just initialize) + auto bone_ptr_ptr = new aiBone *[pModel->bone_count]; + pMesh->mNumBones = pModel->bone_count; + pMesh->mBones = bone_ptr_ptr; + for (auto ii = 0; ii < pModel->bone_count; ++ii) { + auto pBone = new aiBone; + const auto &pmxBone = pModel->bones[ii]; + pBone->mName = pmxBone.bone_name; + aiVector3D pos(pmxBone.position[0], pmxBone.position[1], pmxBone.position[2]); + aiMatrix4x4::Translation(-pos, pBone->mOffsetMatrix); + auto it = bone_vertex_map.find(ii); + if (it != bone_vertex_map.end()) { + pBone->mNumWeights = static_cast(it->second.size()); + pBone->mWeights = it->second.data(); + it->second.swap(*(new vector)); + } + bone_ptr_ptr[ii] = pBone; + } + + return pMesh; +} + +// ------------------------------------------------------------------------------------------------ +aiMaterial *MMDImporter::CreateMaterial(const pmx::PmxMaterial *pMat, + const pmx::PmxModel *pModel) { + aiMaterial *mat = new aiMaterial(); + aiString name(pMat->material_english_name); + mat->AddProperty(&name, AI_MATKEY_NAME); + + aiColor3D diffuse(pMat->diffuse[0], pMat->diffuse[1], pMat->diffuse[2]); + mat->AddProperty(&diffuse, 1, AI_MATKEY_COLOR_DIFFUSE); + aiColor3D specular(pMat->specular[0], pMat->specular[1], pMat->specular[2]); + mat->AddProperty(&specular, 1, AI_MATKEY_COLOR_SPECULAR); + aiColor3D ambient(pMat->ambient[0], pMat->ambient[1], pMat->ambient[2]); + mat->AddProperty(&ambient, 1, AI_MATKEY_COLOR_AMBIENT); + + float opacity = pMat->diffuse[3]; + mat->AddProperty(&opacity, 1, AI_MATKEY_OPACITY); + float shininess = pMat->specularlity; + mat->AddProperty(&shininess, 1, AI_MATKEY_SHININESS_STRENGTH); + + aiString texture_path(pModel->textures[pMat->diffuse_texture_index]); + mat->AddProperty(&texture_path, AI_MATKEY_TEXTURE(aiTextureType_DIFFUSE, 0)); + int mapping_uvwsrc = 0; + mat->AddProperty(&mapping_uvwsrc, 1, + AI_MATKEY_UVWSRC(aiTextureType_DIFFUSE, 0)); + + return mat; +} + +// ------------------------------------------------------------------------------------------------ + +} // Namespace Assimp + +#endif // !! ASSIMP_BUILD_NO_MMD_IMPORTER diff --git a/code/MMDImporter.h b/code/MMDImporter.h new file mode 100644 index 000000000..e660abaaa --- /dev/null +++ b/code/MMDImporter.h @@ -0,0 +1,96 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2016, 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 MMD_FILE_IMPORTER_H_INC +#define MMD_FILE_IMPORTER_H_INC + +#include "BaseImporter.h" +#include "MMDPmxParser.h" +#include +#include + +struct aiMesh; + +namespace Assimp { + +// ------------------------------------------------------------------------------------------------ +/// \class MMDImporter +/// \brief Imports MMD a pmx/pmd/vmd file +// ------------------------------------------------------------------------------------------------ +class MMDImporter : public BaseImporter { +public: + /// \brief Default constructor + MMDImporter(); + + /// \brief Destructor + ~MMDImporter(); + +public: + /// \brief Returns whether the class can handle the format of the given file. + /// \remark See BaseImporter::CanRead() for details. + bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; + +private: + //! \brief Appends the supported extension. + const aiImporterDesc* GetInfo () const; + + //! \brief File import implementation. + void InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); + + //! \brief Create the data from imported content. + void CreateDataFromImport(const pmx::PmxModel* pModel, aiScene* pScene); + + //! \brief Create the mesh + aiMesh* CreateMesh(const pmx::PmxModel* pModel, const int indexStart, const int indexCount); + + //! \brief Create the material + aiMaterial* CreateMaterial(const pmx::PmxMaterial* pMat, const pmx::PmxModel* pModel); + +private: + //! Data buffer + std::vector m_Buffer; + //! Absolute pathname of model in file system + std::string m_strAbsPath; +}; + +// ------------------------------------------------------------------------------------------------ + +} // Namespace Assimp + +#endif \ No newline at end of file diff --git a/code/MMDPmdParser.h b/code/MMDPmdParser.h new file mode 100644 index 000000000..586f20a5f --- /dev/null +++ b/code/MMDPmdParser.h @@ -0,0 +1,596 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 + +#include +#include +#include +#include +#include +#include "MMDCpp14.h" + +namespace pmd +{ + class PmdHeader + { + public: + std::string name; + std::string name_english; + std::string comment; + std::string comment_english; + + bool Read(std::ifstream* stream) + { + char buffer[256]; + stream->read(buffer, 20); + name = std::string(buffer); + stream->read(buffer, 256); + comment = std::string(buffer); + return true; + } + + bool ReadExtension(std::ifstream* stream) + { + char buffer[256]; + stream->read(buffer, 20); + name_english = std::string(buffer); + stream->read(buffer, 256); + comment_english = std::string(buffer); + return true; + } + }; + + class PmdVertex + { + public: + float position[3]; + + float normal[3]; + + float uv[2]; + + uint16_t bone_index[2]; + + uint8_t bone_weight; + + bool edge_invisible; + + bool Read(std::ifstream* stream) + { + stream->read((char*) position, sizeof(float) * 3); + stream->read((char*) normal, sizeof(float) * 3); + stream->read((char*) uv, sizeof(float) * 2); + stream->read((char*) bone_index, sizeof(uint16_t) * 2); + stream->read((char*) &bone_weight, sizeof(uint8_t)); + stream->read((char*) &edge_invisible, sizeof(uint8_t)); + return true; + } + }; + + class PmdMaterial + { + public: + float diffuse[4]; + float power; + float specular[3]; + float ambient[3]; + uint8_t toon_index; + uint8_t edge_flag; + uint32_t index_count; + std::string texture_filename; + std::string sphere_filename; + + bool Read(std::ifstream* stream) + { + char buffer[20]; + stream->read((char*) &diffuse, sizeof(float) * 4); + stream->read((char*) &power, sizeof(float)); + stream->read((char*) &specular, sizeof(float) * 3); + stream->read((char*) &ambient, sizeof(float) * 3); + stream->read((char*) &toon_index, sizeof(uint8_t)); + stream->read((char*) &edge_flag, sizeof(uint8_t)); + stream->read((char*) &index_count, sizeof(uint32_t)); + stream->read((char*) &buffer, sizeof(char) * 20); + char* pstar = strchr(buffer, '*'); + if (NULL == pstar) + { + texture_filename = std::string(buffer); + sphere_filename.clear(); + } + else { + *pstar = 0; + texture_filename = std::string(buffer); + sphere_filename = std::string(pstar+1); + } + return true; + } + }; + + enum class BoneType : uint8_t + { + Rotation, + RotationAndMove, + IkEffector, + Unknown, + IkEffectable, + RotationEffectable, + IkTarget, + Invisible, + Twist, + RotationMovement + }; + + class PmdBone + { + public: + std::string name; + std::string name_english; + uint16_t parent_bone_index; + uint16_t tail_pos_bone_index; + BoneType bone_type; + uint16_t ik_parent_bone_index; + float bone_head_pos[3]; + + void Read(std::istream *stream) + { + char buffer[20]; + stream->read(buffer, 20); + name = std::string(buffer); + stream->read((char*) &parent_bone_index, sizeof(uint16_t)); + stream->read((char*) &tail_pos_bone_index, sizeof(uint16_t)); + stream->read((char*) &bone_type, sizeof(uint8_t)); + stream->read((char*) &ik_parent_bone_index, sizeof(uint16_t)); + stream->read((char*) &bone_head_pos, sizeof(float) * 3); + } + + void ReadExpantion(std::istream *stream) + { + char buffer[20]; + stream->read(buffer, 20); + name_english = std::string(buffer); + } + }; + + class PmdIk + { + public: + uint16_t ik_bone_index; + uint16_t target_bone_index; + uint16_t interations; + float angle_limit; + std::vector ik_child_bone_index; + + void Read(std::istream *stream) + { + stream->read((char *) &ik_bone_index, sizeof(uint16_t)); + stream->read((char *) &target_bone_index, sizeof(uint16_t)); + uint8_t ik_chain_length; + stream->read((char*) &ik_chain_length, sizeof(uint8_t)); + stream->read((char *) &interations, sizeof(uint16_t)); + stream->read((char *) &angle_limit, sizeof(float)); + ik_child_bone_index.resize(ik_chain_length); + for (int i = 0; i < ik_chain_length; i++) + { + stream->read((char *) &ik_child_bone_index[i], sizeof(uint16_t)); + } + } + }; + + class PmdFaceVertex + { + public: + int vertex_index; + float position[3]; + + void Read(std::istream *stream) + { + stream->read((char *) &vertex_index, sizeof(int)); + stream->read((char *) position, sizeof(float) * 3); + } + }; + + enum class FaceCategory : uint8_t + { + Base, + Eyebrow, + Eye, + Mouth, + Other + }; + + class PmdFace + { + public: + std::string name; + FaceCategory type; + std::vector vertices; + std::string name_english; + + void Read(std::istream *stream) + { + char buffer[20]; + stream->read(buffer, 20); + name = std::string(buffer); + int vertex_count; + stream->read((char*) &vertex_count, sizeof(int)); + stream->read((char*) &type, sizeof(uint8_t)); + vertices.resize(vertex_count); + for (int i = 0; i < vertex_count; i++) + { + vertices[i].Read(stream); + } + } + + void ReadExpantion(std::istream *stream) + { + char buffer[20]; + stream->read(buffer, 20); + name_english = std::string(buffer); + } + }; + + class PmdBoneDispName + { + public: + std::string bone_disp_name; + std::string bone_disp_name_english; + + void Read(std::istream *stream) + { + char buffer[50]; + stream->read(buffer, 50); + bone_disp_name = std::string(buffer); + bone_disp_name_english.clear(); + } + void ReadExpantion(std::istream *stream) + { + char buffer[50]; + stream->read(buffer, 50); + bone_disp_name_english = std::string(buffer); + } + }; + + class PmdBoneDisp + { + public: + uint16_t bone_index; + uint8_t bone_disp_index; + + void Read(std::istream *stream) + { + stream->read((char*) &bone_index, sizeof(uint16_t)); + stream->read((char*) &bone_disp_index, sizeof(uint8_t)); + } + }; + + enum class RigidBodyShape : uint8_t + { + Sphere = 0, + Box = 1, + Cpusel = 2 + }; + + enum class RigidBodyType : uint8_t + { + BoneConnected = 0, + Physics = 1, + ConnectedPhysics = 2 + }; + + class PmdRigidBody + { + public: + std::string name; + uint16_t related_bone_index; + uint8_t group_index; + uint16_t mask; + RigidBodyShape shape; + float size[3]; + float position[3]; + float orientation[3]; + float weight; + float linear_damping; + float anglar_damping; + float restitution; + float friction; + RigidBodyType rigid_type; + + void Read(std::istream *stream) + { + char buffer[20]; + stream->read(buffer, sizeof(char) * 20); + name = (std::string(buffer)); + stream->read((char*) &related_bone_index, sizeof(uint16_t)); + stream->read((char*) &group_index, sizeof(uint8_t)); + stream->read((char*) &mask, sizeof(uint16_t)); + stream->read((char*) &shape, sizeof(uint8_t)); + stream->read((char*) size, sizeof(float) * 3); + stream->read((char*) position, sizeof(float) * 3); + stream->read((char*) orientation, sizeof(float) * 3); + stream->read((char*) &weight, sizeof(float)); + stream->read((char*) &linear_damping, sizeof(float)); + stream->read((char*) &anglar_damping, sizeof(float)); + stream->read((char*) &restitution, sizeof(float)); + stream->read((char*) &friction, sizeof(float)); + stream->read((char*) &rigid_type, sizeof(char)); + } + }; + + class PmdConstraint + { + public: + std::string name; + uint32_t rigid_body_index_a; + uint32_t rigid_body_index_b; + float position[3]; + float orientation[3]; + float linear_lower_limit[3]; + float linear_upper_limit[3]; + float angular_lower_limit[3]; + float angular_upper_limit[3]; + float linear_stiffness[3]; + float angular_stiffness[3]; + + void Read(std::istream *stream) + { + char buffer[20]; + stream->read(buffer, 20); + name = std::string(buffer); + stream->read((char *) &rigid_body_index_a, sizeof(uint32_t)); + stream->read((char *) &rigid_body_index_b, sizeof(uint32_t)); + stream->read((char *) position, sizeof(float) * 3); + stream->read((char *) orientation, sizeof(float) * 3); + stream->read((char *) linear_lower_limit, sizeof(float) * 3); + stream->read((char *) linear_upper_limit, sizeof(float) * 3); + stream->read((char *) angular_lower_limit, sizeof(float) * 3); + stream->read((char *) angular_upper_limit, sizeof(float) * 3); + stream->read((char *) linear_stiffness, sizeof(float) * 3); + stream->read((char *) angular_stiffness, sizeof(float) * 3); + } + }; + + class PmdModel + { + public: + float version; + PmdHeader header; + std::vector vertices; + std::vector indices; + std::vector materials; + std::vector bones; + std::vector iks; + std::vector faces; + std::vector faces_indices; + std::vector bone_disp_name; + std::vector bone_disp; + std::vector toon_filenames; + std::vector rigid_bodies; + std::vector constraints; + + static std::unique_ptr LoadFromFile(const char *filename) + { + std::ifstream stream(filename, std::ios::binary); + if (stream.fail()) + { + std::cerr << "could not open \"" << filename << "\"" << std::endl; + return nullptr; + } + auto result = LoadFromStream(&stream); + stream.close(); + return result; + } + + static std::unique_ptr LoadFromStream(std::ifstream *stream) + { + auto result = mmd::make_unique(); + char buffer[100]; + + // magic + char magic[3]; + stream->read(magic, 3); + if (magic[0] != 'P' || magic[1] != 'm' || magic[2] != 'd') + { + std::cerr << "invalid file" << std::endl; + return nullptr; + } + + // version + stream->read((char*) &(result->version), sizeof(float)); + if (result ->version != 1.0f) + { + std::cerr << "invalid version" << std::endl; + return nullptr; + } + + // header + result->header.Read(stream); + + // vertices + uint32_t vertex_num; + stream->read((char*) &vertex_num, sizeof(uint32_t)); + result->vertices.resize(vertex_num); + for (uint32_t i = 0; i < vertex_num; i++) + { + result->vertices[i].Read(stream); + } + + // indices + uint32_t index_num; + stream->read((char*) &index_num, sizeof(uint32_t)); + result->indices.resize(index_num); + for (uint32_t i = 0; i < index_num; i++) + { + stream->read((char*) &result->indices[i], sizeof(uint16_t)); + } + + // materials + uint32_t material_num; + stream->read((char*) &material_num, sizeof(uint32_t)); + result->materials.resize(material_num); + for (uint32_t i = 0; i < material_num; i++) + { + result->materials[i].Read(stream); + } + + // bones + uint16_t bone_num; + stream->read((char*) &bone_num, sizeof(uint16_t)); + result->bones.resize(bone_num); + for (uint32_t i = 0; i < bone_num; i++) + { + result->bones[i].Read(stream); + } + + // iks + uint16_t ik_num; + stream->read((char*) &ik_num, sizeof(uint16_t)); + result->iks.resize(ik_num); + for (uint32_t i = 0; i < ik_num; i++) + { + result->iks[i].Read(stream); + } + + // faces + uint16_t face_num; + stream->read((char*) &face_num, sizeof(uint16_t)); + result->faces.resize(face_num); + for (uint32_t i = 0; i < face_num; i++) + { + result->faces[i].Read(stream); + } + + // face frames + uint8_t face_frame_num; + stream->read((char*) &face_frame_num, sizeof(uint8_t)); + result->faces_indices.resize(face_frame_num); + for (uint32_t i = 0; i < face_frame_num; i++) + { + stream->read((char*) &result->faces_indices[i], sizeof(uint16_t)); + } + + // bone names + uint8_t bone_disp_num; + stream->read((char*) &bone_disp_num, sizeof(uint8_t)); + result->bone_disp_name.resize(bone_disp_num); + for (uint32_t i = 0; i < bone_disp_num; i++) + { + result->bone_disp_name[i].Read(stream); + } + + // bone frame + uint32_t bone_frame_num; + stream->read((char*) &bone_frame_num, sizeof(uint32_t)); + result->bone_disp.resize(bone_frame_num); + for (uint32_t i = 0; i < bone_frame_num; i++) + { + result->bone_disp[i].Read(stream); + } + + // english name + bool english; + stream->read((char*) &english, sizeof(char)); + if (english) + { + result->header.ReadExtension(stream); + for (uint32_t i = 0; i < bone_num; i++) + { + result->bones[i].ReadExpantion(stream); + } + for (uint32_t i = 0; i < face_num; i++) + { + if (result->faces[i].type == pmd::FaceCategory::Base) + { + continue; + } + result->faces[i].ReadExpantion(stream); + } + for (uint32_t i = 0; i < result->bone_disp_name.size(); i++) + { + result->bone_disp_name[i].ReadExpantion(stream); + } + } + + // toon textures + if (stream->peek() == std::ios::traits_type::eof()) + { + result->toon_filenames.clear(); + } + else { + result->toon_filenames.resize(10); + for (uint32_t i = 0; i < 10; i++) + { + stream->read(buffer, 100); + result->toon_filenames[i] = std::string(buffer); + } + } + + // physics + if (stream->peek() == std::ios::traits_type::eof()) + { + result->rigid_bodies.clear(); + result->constraints.clear(); + } + else { + uint32_t rigid_body_num; + stream->read((char*) &rigid_body_num, sizeof(uint32_t)); + result->rigid_bodies.resize(rigid_body_num); + for (uint32_t i = 0; i < rigid_body_num; i++) + { + result->rigid_bodies[i].Read(stream); + } + uint32_t constraint_num; + stream->read((char*) &constraint_num, sizeof(uint32_t)); + result->constraints.resize(constraint_num); + for (uint32_t i = 0; i < constraint_num; i++) + { + result->constraints[i].Read(stream); + } + } + + if (stream->peek() != std::ios::traits_type::eof()) + { + std::cerr << "there is unknown data" << std::endl; + } + + return result; + } + }; +} diff --git a/code/MMDPmxParser.cpp b/code/MMDPmxParser.cpp new file mode 100644 index 000000000..3af23529a --- /dev/null +++ b/code/MMDPmxParser.cpp @@ -0,0 +1,637 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 +#include "MMDPmxParser.h" +#include "../contrib/utf8cpp/source/utf8.h" +#include "Exceptional.h" + +namespace pmx +{ + int ReadIndex(std::istream *stream, int size) + { + switch (size) + { + case 1: + uint8_t tmp8; + stream->read((char*) &tmp8, sizeof(uint8_t)); + if (255 == tmp8) + { + return -1; + } + else { + return (int) tmp8; + } + case 2: + uint16_t tmp16; + stream->read((char*) &tmp16, sizeof(uint16_t)); + if (65535 == tmp16) + { + return -1; + } + else { + return (int) tmp16; + } + case 4: + int tmp32; + stream->read((char*) &tmp32, sizeof(int)); + return tmp32; + default: + return -1; + } + } + + std::string ReadString(std::istream *stream, uint8_t encoding) + { + int size; + stream->read((char*) &size, sizeof(int)); + std::vector buffer; + if (size == 0) + { + return std::string(""); + } + buffer.reserve(size); + stream->read((char*) buffer.data(), size); + if (encoding == 0) + { + // UTF16 to UTF8 + std::string result; + + const char* sourceStart = buffer.data(); + const unsigned int targetSize = size * 3; // enough to encode + char* targetStart = new char[targetSize](); + const char* targetReserved = targetStart; + utf8::utf16to8( sourceStart, sourceStart + size, targetStart ); + + result.assign(targetReserved, targetStart - targetReserved); + delete[] targetReserved; + return result; + } + else + { + // the name is already UTF8 + return std::string((const char*)buffer.data(), size); + } + } + + void PmxSetting::Read(std::istream *stream) + { + uint8_t count; + stream->read((char*) &count, sizeof(uint8_t)); + if (count < 8) + { + throw; + } + stream->read((char*) &encoding, sizeof(uint8_t)); + stream->read((char*) &uv, sizeof(uint8_t)); + stream->read((char*) &vertex_index_size, sizeof(uint8_t)); + stream->read((char*) &texture_index_size, sizeof(uint8_t)); + stream->read((char*) &material_index_size, sizeof(uint8_t)); + stream->read((char*) &bone_index_size, sizeof(uint8_t)); + stream->read((char*) &morph_index_size, sizeof(uint8_t)); + stream->read((char*) &rigidbody_index_size, sizeof(uint8_t)); + uint8_t temp; + for (int i = 8; i < count; i++) + { + stream->read((char*)&temp, sizeof(uint8_t)); + } + } + + void PmxVertexSkinningBDEF1::Read(std::istream *stream, PmxSetting *setting) + { + this->bone_index = ReadIndex(stream, setting->bone_index_size); + } + + void PmxVertexSkinningBDEF2::Read(std::istream *stream, PmxSetting *setting) + { + this->bone_index1 = ReadIndex(stream, setting->bone_index_size); + this->bone_index2 = ReadIndex(stream, setting->bone_index_size); + stream->read((char*) &this->bone_weight, sizeof(float)); + } + + void PmxVertexSkinningBDEF4::Read(std::istream *stream, PmxSetting *setting) + { + this->bone_index1 = ReadIndex(stream, setting->bone_index_size); + this->bone_index2 = ReadIndex(stream, setting->bone_index_size); + this->bone_index3 = ReadIndex(stream, setting->bone_index_size); + this->bone_index4 = ReadIndex(stream, setting->bone_index_size); + stream->read((char*) &this->bone_weight1, sizeof(float)); + stream->read((char*) &this->bone_weight2, sizeof(float)); + stream->read((char*) &this->bone_weight3, sizeof(float)); + stream->read((char*) &this->bone_weight4, sizeof(float)); + } + + void PmxVertexSkinningSDEF::Read(std::istream *stream, PmxSetting *setting) + { + this->bone_index1 = ReadIndex(stream, setting->bone_index_size); + this->bone_index2 = ReadIndex(stream, setting->bone_index_size); + stream->read((char*) &this->bone_weight, sizeof(float)); + stream->read((char*) this->sdef_c, sizeof(float) * 3); + stream->read((char*) this->sdef_r0, sizeof(float) * 3); + stream->read((char*) this->sdef_r1, sizeof(float) * 3); + } + + void PmxVertexSkinningQDEF::Read(std::istream *stream, PmxSetting *setting) + { + this->bone_index1 = ReadIndex(stream, setting->bone_index_size); + this->bone_index2 = ReadIndex(stream, setting->bone_index_size); + this->bone_index3 = ReadIndex(stream, setting->bone_index_size); + this->bone_index4 = ReadIndex(stream, setting->bone_index_size); + stream->read((char*) &this->bone_weight1, sizeof(float)); + stream->read((char*) &this->bone_weight2, sizeof(float)); + stream->read((char*) &this->bone_weight3, sizeof(float)); + stream->read((char*) &this->bone_weight4, sizeof(float)); + } + + void PmxVertex::Read(std::istream *stream, PmxSetting *setting) + { + stream->read((char*) this->position, sizeof(float) * 3); + stream->read((char*) this->normal, sizeof(float) * 3); + stream->read((char*) this->uv, sizeof(float) * 2); + for (int i = 0; i < setting->uv; ++i) + { + stream->read((char*) this->uva[i], sizeof(float) * 4); + } + stream->read((char*) &this->skinning_type, sizeof(PmxVertexSkinningType)); + switch (this->skinning_type) + { + case PmxVertexSkinningType::BDEF1: + this->skinning = mmd::make_unique(); + break; + case PmxVertexSkinningType::BDEF2: + this->skinning = mmd::make_unique(); + break; + case PmxVertexSkinningType::BDEF4: + this->skinning = mmd::make_unique(); + break; + case PmxVertexSkinningType::SDEF: + this->skinning = mmd::make_unique(); + break; + case PmxVertexSkinningType::QDEF: + this->skinning = mmd::make_unique(); + break; + default: + throw "invalid skinning type"; + } + this->skinning->Read(stream, setting); + stream->read((char*) &this->edge, sizeof(float)); + } + + void PmxMaterial::Read(std::istream *stream, PmxSetting *setting) + { + this->material_name = ReadString(stream, setting->encoding); + this->material_english_name = ReadString(stream, setting->encoding); + stream->read((char*) this->diffuse, sizeof(float) * 4); + stream->read((char*) this->specular, sizeof(float) * 3); + stream->read((char*) &this->specularlity, sizeof(float)); + stream->read((char*) this->ambient, sizeof(float) * 3); + stream->read((char*) &this->flag, sizeof(uint8_t)); + stream->read((char*) this->edge_color, sizeof(float) * 4); + stream->read((char*) &this->edge_size, sizeof(float)); + this->diffuse_texture_index = ReadIndex(stream, setting->texture_index_size); + this->sphere_texture_index = ReadIndex(stream, setting->texture_index_size); + stream->read((char*) &this->sphere_op_mode, sizeof(uint8_t)); + stream->read((char*) &this->common_toon_flag, sizeof(uint8_t)); + if (this->common_toon_flag) + { + stream->read((char*) &this->toon_texture_index, sizeof(uint8_t)); + } + else { + this->toon_texture_index = ReadIndex(stream, setting->texture_index_size); + } + this->memo = ReadString(stream, setting->encoding); + stream->read((char*) &this->index_count, sizeof(int)); + } + + void PmxIkLink::Read(std::istream *stream, PmxSetting *setting) + { + this->link_target = ReadIndex(stream, setting->bone_index_size); + stream->read((char*) &this->angle_lock, sizeof(uint8_t)); + if (angle_lock == 1) + { + stream->read((char*) this->max_radian, sizeof(float) * 3); + stream->read((char*) this->min_radian, sizeof(float) * 3); + } + } + + void PmxBone::Read(std::istream *stream, PmxSetting *setting) + { + this->bone_name = ReadString(stream, setting->encoding); + this->bone_english_name = ReadString(stream, setting->encoding); + stream->read((char*) this->position, sizeof(float) * 3); + this->parent_index = ReadIndex(stream, setting->bone_index_size); + stream->read((char*) &this->level, sizeof(int)); + stream->read((char*) &this->bone_flag, sizeof(uint16_t)); + if (this->bone_flag & 0x0001) { + this->target_index = ReadIndex(stream, setting->bone_index_size); + } + else { + stream->read((char*)this->offset, sizeof(float) * 3); + } + if (this->bone_flag & (0x0100 | 0x0200)) { + this->grant_parent_index = ReadIndex(stream, setting->bone_index_size); + stream->read((char*) &this->grant_weight, sizeof(float)); + } + if (this->bone_flag & 0x0400) { + stream->read((char*)this->lock_axis_orientation, sizeof(float) * 3); + } + if (this->bone_flag & 0x0800) { + stream->read((char*)this->local_axis_x_orientation, sizeof(float) * 3); + stream->read((char*)this->local_axis_y_orientation, sizeof(float) * 3); + } + if (this->bone_flag & 0x2000) { + stream->read((char*) &this->key, sizeof(int)); + } + if (this->bone_flag & 0x0020) { + this->ik_target_bone_index = ReadIndex(stream, setting->bone_index_size); + stream->read((char*) &ik_loop, sizeof(int)); + stream->read((char*) &ik_loop_angle_limit, sizeof(float)); + stream->read((char*) &ik_link_count, sizeof(int)); + this->ik_links = mmd::make_unique(ik_link_count); + for (int i = 0; i < ik_link_count; i++) { + ik_links[i].Read(stream, setting); + } + } + } + + void PmxMorphVertexOffset::Read(std::istream *stream, PmxSetting *setting) + { + this->vertex_index = ReadIndex(stream, setting->vertex_index_size); + stream->read((char*)this->position_offset, sizeof(float) * 3); + } + + void PmxMorphUVOffset::Read(std::istream *stream, PmxSetting *setting) + { + this->vertex_index = ReadIndex(stream, setting->vertex_index_size); + stream->read((char*)this->uv_offset, sizeof(float) * 4); + } + + void PmxMorphBoneOffset::Read(std::istream *stream, PmxSetting *setting) + { + this->bone_index = ReadIndex(stream, setting->bone_index_size); + stream->read((char*)this->translation, sizeof(float) * 3); + stream->read((char*)this->rotation, sizeof(float) * 4); + } + + void PmxMorphMaterialOffset::Read(std::istream *stream, PmxSetting *setting) + { + this->material_index = ReadIndex(stream, setting->material_index_size); + stream->read((char*) &this->offset_operation, sizeof(uint8_t)); + stream->read((char*)this->diffuse, sizeof(float) * 4); + stream->read((char*)this->specular, sizeof(float) * 3); + stream->read((char*) &this->specularity, sizeof(float)); + stream->read((char*)this->ambient, sizeof(float) * 3); + stream->read((char*)this->edge_color, sizeof(float) * 4); + stream->read((char*) &this->edge_size, sizeof(float)); + stream->read((char*)this->texture_argb, sizeof(float) * 4); + stream->read((char*)this->sphere_texture_argb, sizeof(float) * 4); + stream->read((char*)this->toon_texture_argb, sizeof(float) * 4); + } + + void PmxMorphGroupOffset::Read(std::istream *stream, PmxSetting *setting) + { + this->morph_index = ReadIndex(stream, setting->morph_index_size); + stream->read((char*) &this->morph_weight, sizeof(float)); + } + + void PmxMorphFlipOffset::Read(std::istream *stream, PmxSetting *setting) + { + this->morph_index = ReadIndex(stream, setting->morph_index_size); + stream->read((char*) &this->morph_value, sizeof(float)); + } + + void PmxMorphImplusOffset::Read(std::istream *stream, PmxSetting *setting) + { + this->rigid_body_index = ReadIndex(stream, setting->rigidbody_index_size); + stream->read((char*) &this->is_local, sizeof(uint8_t)); + stream->read((char*)this->velocity, sizeof(float) * 3); + stream->read((char*)this->angular_torque, sizeof(float) * 3); + } + + void PmxMorph::Read(std::istream *stream, PmxSetting *setting) + { + this->morph_name = ReadString(stream, setting->encoding); + this->morph_english_name = ReadString(stream, setting->encoding); + stream->read((char*) &category, sizeof(MorphCategory)); + stream->read((char*) &morph_type, sizeof(MorphType)); + stream->read((char*) &this->offset_count, sizeof(int)); + switch (this->morph_type) + { + case MorphType::Group: + group_offsets = mmd::make_unique(this->offset_count); + for (int i = 0; i < offset_count; i++) + { + group_offsets[i].Read(stream, setting); + } + break; + case MorphType::Vertex: + vertex_offsets = mmd::make_unique(this->offset_count); + for (int i = 0; i < offset_count; i++) + { + vertex_offsets[i].Read(stream, setting); + } + break; + case MorphType::Bone: + bone_offsets = mmd::make_unique(this->offset_count); + for (int i = 0; i < offset_count; i++) + { + bone_offsets[i].Read(stream, setting); + } + break; + case MorphType::Matrial: + material_offsets = mmd::make_unique(this->offset_count); + for (int i = 0; i < offset_count; i++) + { + material_offsets[i].Read(stream, setting); + } + break; + case MorphType::UV: + case MorphType::AdditionalUV1: + case MorphType::AdditionalUV2: + case MorphType::AdditionalUV3: + case MorphType::AdditionalUV4: + uv_offsets = mmd::make_unique(this->offset_count); + for (int i = 0; i < offset_count; i++) + { + uv_offsets[i].Read(stream, setting); + } + break; + default: + throw; + } + } + + void PmxFrameElement::Read(std::istream *stream, PmxSetting *setting) + { + stream->read((char*) &this->element_target, sizeof(uint8_t)); + if (this->element_target == 0x00) + { + this->index = ReadIndex(stream, setting->bone_index_size); + } + else { + this->index = ReadIndex(stream, setting->morph_index_size); + } + } + + void PmxFrame::Read(std::istream *stream, PmxSetting *setting) + { + this->frame_name = ReadString(stream, setting->encoding); + this->frame_english_name = ReadString(stream, setting->encoding); + stream->read((char*) &this->frame_flag, sizeof(uint8_t)); + stream->read((char*) &this->element_count, sizeof(int)); + this->elements = mmd::make_unique(this->element_count); + for (int i = 0; i < this->element_count; i++) + { + this->elements[i].Read(stream, setting); + } + } + + void PmxRigidBody::Read(std::istream *stream, PmxSetting *setting) + { + this->girid_body_name = ReadString(stream, setting->encoding); + this->girid_body_english_name = ReadString(stream, setting->encoding); + this->target_bone = ReadIndex(stream, setting->bone_index_size); + stream->read((char*) &this->group, sizeof(uint8_t)); + stream->read((char*) &this->mask, sizeof(uint16_t)); + stream->read((char*) &this->shape, sizeof(uint8_t)); + stream->read((char*) this->size, sizeof(float) * 3); + stream->read((char*) this->position, sizeof(float) * 3); + stream->read((char*) this->orientation, sizeof(float) * 3); + stream->read((char*) &this->mass, sizeof(float)); + stream->read((char*) &this->move_attenuation, sizeof(float)); + stream->read((char*) &this->rotation_attenuation, sizeof(float)); + stream->read((char*) &this->repulsion, sizeof(float)); + stream->read((char*) &this->friction, sizeof(float)); + stream->read((char*) &this->physics_calc_type, sizeof(uint8_t)); + } + + void PmxJointParam::Read(std::istream *stream, PmxSetting *setting) + { + this->rigid_body1 = ReadIndex(stream, setting->rigidbody_index_size); + this->rigid_body2 = ReadIndex(stream, setting->rigidbody_index_size); + stream->read((char*) this->position, sizeof(float) * 3); + stream->read((char*) this->orientaiton, sizeof(float) * 3); + stream->read((char*) this->move_limitation_min, sizeof(float) * 3); + stream->read((char*) this->move_limitation_max, sizeof(float) * 3); + stream->read((char*) this->rotation_limitation_min, sizeof(float) * 3); + stream->read((char*) this->rotation_limitation_max, sizeof(float) * 3); + stream->read((char*) this->spring_move_coefficient, sizeof(float) * 3); + stream->read((char*) this->spring_rotation_coefficient, sizeof(float) * 3); + } + + void PmxJoint::Read(std::istream *stream, PmxSetting *setting) + { + this->joint_name = ReadString(stream, setting->encoding); + this->joint_english_name = ReadString(stream, setting->encoding); + stream->read((char*) &this->joint_type, sizeof(uint8_t)); + this->param.Read(stream, setting); + } + + void PmxAncherRigidBody::Read(std::istream *stream, PmxSetting *setting) + { + this->related_rigid_body = ReadIndex(stream, setting->rigidbody_index_size); + this->related_vertex = ReadIndex(stream, setting->vertex_index_size); + stream->read((char*) &this->is_near, sizeof(uint8_t)); + } + + void PmxSoftBody::Read(std::istream *stream, PmxSetting *setting) + { + // 未実装 + std::cerr << "Not Implemented Exception" << std::endl; + throw; + } + + void PmxModel::Init() + { + this->version = 0.0f; + this->model_name.clear(); + this->model_english_name.clear(); + this->model_comment.clear(); + this->model_english_comment.clear(); + this->vertex_count = 0; + this->vertices = nullptr; + this->index_count = 0; + this->indices = nullptr; + this->texture_count = 0; + this->textures = nullptr; + this->material_count = 0; + this->materials = nullptr; + this->bone_count = 0; + this->bones = nullptr; + this->morph_count = 0; + this->morphs = nullptr; + this->frame_count = 0; + this->frames = nullptr; + this->rigid_body_count = 0; + this->rigid_bodies = nullptr; + this->joint_count = 0; + this->joints = nullptr; + this->soft_body_count = 0; + this->soft_bodies = nullptr; + } + + void PmxModel::Read(std::istream *stream) + { + // マジック + char magic[4]; + stream->read((char*) magic, sizeof(char) * 4); + if (magic[0] != 0x50 || magic[1] != 0x4d || magic[2] != 0x58 || magic[3] != 0x20) + { + std::cerr << "invalid magic number." << std::endl; + throw; + } + // ãƒãƒ¼ã‚¸ãƒ§ãƒ³ + stream->read((char*) &version, sizeof(float)); + if (version != 2.0f && version != 2.1f) + { + std::cerr << "this is not ver2.0 or ver2.1 but " << version << "." << std::endl; + throw; + } + // ファイル設定 + this->setting.Read(stream); + + // モデル情報 + this->model_name = ReadString(stream, setting.encoding); + this->model_english_name = ReadString(stream, setting.encoding); + this->model_comment = ReadString(stream, setting.encoding); + this->model_english_comment = ReadString(stream, setting.encoding); + + // 頂点 + stream->read((char*) &vertex_count, sizeof(int)); + this->vertices = mmd::make_unique(vertex_count); + for (int i = 0; i < vertex_count; i++) + { + vertices[i].Read(stream, &setting); + } + + // é¢ + stream->read((char*) &index_count, sizeof(int)); + this->indices = mmd::make_unique(index_count); + for (int i = 0; i < index_count; i++) + { + this->indices[i] = ReadIndex(stream, setting.vertex_index_size); + } + + // テクスãƒãƒ£ + stream->read((char*) &texture_count, sizeof(int)); + this->textures = mmd::make_unique(texture_count); + for (int i = 0; i < texture_count; i++) + { + this->textures[i] = ReadString(stream, setting.encoding); + } + + // マテリアル + stream->read((char*) &material_count, sizeof(int)); + this->materials = mmd::make_unique(material_count); + for (int i = 0; i < material_count; i++) + { + this->materials[i].Read(stream, &setting); + } + + // ボーン + stream->read((char*) &this->bone_count, sizeof(int)); + this->bones = mmd::make_unique(this->bone_count); + for (int i = 0; i < this->bone_count; i++) + { + this->bones[i].Read(stream, &setting); + } + + // モーフ + stream->read((char*) &this->morph_count, sizeof(int)); + this->morphs = mmd::make_unique(this->morph_count); + for (int i = 0; i < this->morph_count; i++) + { + this->morphs[i].Read(stream, &setting); + } + + // 表示枠 + stream->read((char*) &this->frame_count, sizeof(int)); + this->frames = mmd::make_unique(this->frame_count); + for (int i = 0; i < this->frame_count; i++) + { + this->frames[i].Read(stream, &setting); + } + + // 剛体 + stream->read((char*) &this->rigid_body_count, sizeof(int)); + this->rigid_bodies = mmd::make_unique(this->rigid_body_count); + for (int i = 0; i < this->rigid_body_count; i++) + { + this->rigid_bodies[i].Read(stream, &setting); + } + + // ジョイント + stream->read((char*) &this->joint_count, sizeof(int)); + this->joints = mmd::make_unique(this->joint_count); + for (int i = 0; i < this->joint_count; i++) + { + this->joints[i].Read(stream, &setting); + } + + //if (this->version == 2.1f) + //{ + // stream->read((char*) &this->soft_body_count, sizeof(int)); + // this->soft_bodies = mmd::make_unique(this->soft_body_count); + // for (int i = 0; i < this->soft_body_count; i++) + // { + // this->soft_bodies[i].Read(stream, &setting); + // } + //} + } + + //std::unique_ptr ReadFromFile(const char *filename) + //{ + // auto stream = std::ifstream(filename, std::ios_base::binary); + // auto pmx = PmxModel::ReadFromStream(&stream); + // if (!stream.eof()) + // { + // std::cerr << "don't reach the end of file." << std::endl; + // } + // stream.close(); + // return pmx; + //} + + //std::unique_ptr ReadFromStream(std::istream *stream) + //{ + // auto pmx = mmd::make_unique(); + // pmx->Read(stream); + // return pmx; + //} +} diff --git a/code/MMDPmxParser.h b/code/MMDPmxParser.h new file mode 100644 index 000000000..989cffed6 --- /dev/null +++ b/code/MMDPmxParser.h @@ -0,0 +1,780 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 + +#include +#include +#include +#include +#include +#include "MMDCpp14.h" + +namespace pmx +{ + class PmxSetting + { + public: + PmxSetting() + : encoding(0) + , uv(0) + , vertex_index_size(0) + , texture_index_size(0) + , material_index_size(0) + , bone_index_size(0) + , morph_index_size(0) + , rigidbody_index_size(0) + {} + + uint8_t encoding; + uint8_t uv; + uint8_t vertex_index_size; + uint8_t texture_index_size; + uint8_t material_index_size; + uint8_t bone_index_size; + uint8_t morph_index_size; + uint8_t rigidbody_index_size; + void Read(std::istream *stream); + }; + + enum class PmxVertexSkinningType : uint8_t + { + BDEF1 = 0, + BDEF2 = 1, + BDEF4 = 2, + SDEF = 3, + QDEF = 4, + }; + + class PmxVertexSkinning + { + public: + virtual void Read(std::istream *stream, PmxSetting *setting) = 0; + }; + + class PmxVertexSkinningBDEF1 : public PmxVertexSkinning + { + public: + PmxVertexSkinningBDEF1() + : bone_index(0) + {} + + int bone_index; + void Read(std::istream *stresam, PmxSetting *setting); + }; + + class PmxVertexSkinningBDEF2 : public PmxVertexSkinning + { + public: + PmxVertexSkinningBDEF2() + : bone_index1(0) + , bone_index2(0) + , bone_weight(0.0f) + {} + + int bone_index1; + int bone_index2; + float bone_weight; + void Read(std::istream *stresam, PmxSetting *setting); + }; + + class PmxVertexSkinningBDEF4 : public PmxVertexSkinning + { + public: + PmxVertexSkinningBDEF4() + : bone_index1(0) + , bone_index2(0) + , bone_index3(0) + , bone_index4(0) + , bone_weight1(0.0f) + , bone_weight2(0.0f) + , bone_weight3(0.0f) + , bone_weight4(0.0f) + {} + + int bone_index1; + int bone_index2; + int bone_index3; + int bone_index4; + float bone_weight1; + float bone_weight2; + float bone_weight3; + float bone_weight4; + void Read(std::istream *stresam, PmxSetting *setting); + }; + + class PmxVertexSkinningSDEF : public PmxVertexSkinning + { + public: + PmxVertexSkinningSDEF() + : bone_index1(0) + , bone_index2(0) + , bone_weight(0.0f) + { + for (int i = 0; i < 3; ++i) { + sdef_c[i] = 0.0f; + sdef_r0[i] = 0.0f; + sdef_r1[i] = 0.0f; + } + } + + int bone_index1; + int bone_index2; + float bone_weight; + float sdef_c[3]; + float sdef_r0[3]; + float sdef_r1[3]; + void Read(std::istream *stresam, PmxSetting *setting); + }; + + class PmxVertexSkinningQDEF : public PmxVertexSkinning + { + public: + PmxVertexSkinningQDEF() + : bone_index1(0) + , bone_index2(0) + , bone_index3(0) + , bone_index4(0) + , bone_weight1(0.0f) + , bone_weight2(0.0f) + , bone_weight3(0.0f) + , bone_weight4(0.0f) + {} + + int bone_index1; + int bone_index2; + int bone_index3; + int bone_index4; + float bone_weight1; + float bone_weight2; + float bone_weight3; + float bone_weight4; + void Read(std::istream *stresam, PmxSetting *setting); + }; + + class PmxVertex + { + public: + PmxVertex() + : edge(0.0f) + { + uv[0] = uv[1] = 0.0f; + for (int i = 0; i < 3; ++i) { + position[i] = 0.0f; + normal[i] = 0.0f; + } + for (int i = 0; i < 4; ++i) { + for (int k = 0; k < 4; ++k) { + uva[i][k] = 0.0f; + } + } + } + + float position[3]; + float normal[3]; + float uv[2]; + float uva[4][4]; + PmxVertexSkinningType skinning_type; + std::unique_ptr skinning; + float edge; + void Read(std::istream *stream, PmxSetting *setting); + }; + + class PmxMaterial + { + public: + PmxMaterial() + : specularlity(0.0f) + , flag(0) + , edge_size(0.0f) + , diffuse_texture_index(0) + , sphere_texture_index(0) + , sphere_op_mode(0) + , common_toon_flag(0) + , toon_texture_index(0) + , index_count(0) + { + for (int i = 0; i < 3; ++i) { + specular[i] = 0.0f; + ambient[i] = 0.0f; + edge_color[i] = 0.0f; + } + for (int i = 0; i < 4; ++i) { + diffuse[i] = 0.0f; + } + } + + std::string material_name; + std::string material_english_name; + float diffuse[4]; + float specular[3]; + float specularlity; + float ambient[3]; + uint8_t flag; + float edge_color[4]; + float edge_size; + int diffuse_texture_index; + int sphere_texture_index; + uint8_t sphere_op_mode; + uint8_t common_toon_flag; + int toon_texture_index; + std::string memo; + int index_count; + void Read(std::istream *stream, PmxSetting *setting); + }; + + class PmxIkLink + { + public: + PmxIkLink() + : link_target(0) + , angle_lock(0) + { + for (int i = 0; i < 3; ++i) { + max_radian[i] = 0.0f; + min_radian[i] = 0.0f; + } + } + + int link_target; + uint8_t angle_lock; + float max_radian[3]; + float min_radian[3]; + void Read(std::istream *stream, PmxSetting *settingn); + }; + + class PmxBone + { + public: + PmxBone() + : parent_index(0) + , level(0) + , bone_flag(0) + , target_index(0) + , grant_parent_index(0) + , grant_weight(0.0f) + , key(0) + , ik_target_bone_index(0) + , ik_loop(0) + , ik_loop_angle_limit(0.0f) + , ik_link_count(0) + { + for (int i = 0; i < 3; ++i) { + position[i] = 0.0f; + offset[i] = 0.0f; + lock_axis_orientation[i] = 0.0f; + local_axis_x_orientation[i] = 0.0f; + local_axis_y_orientation[i] = 0.0f; + } + } + + std::string bone_name; + std::string bone_english_name; + float position[3]; + int parent_index; + int level; + uint16_t bone_flag; + float offset[3]; + int target_index; + int grant_parent_index; + float grant_weight; + float lock_axis_orientation[3]; + float local_axis_x_orientation[3]; + float local_axis_y_orientation[3]; + int key; + int ik_target_bone_index; + int ik_loop; + float ik_loop_angle_limit; + int ik_link_count; + std::unique_ptr ik_links; + void Read(std::istream *stream, PmxSetting *setting); + }; + + enum class MorphType : uint8_t + { + Group = 0, + Vertex = 1, + Bone = 2, + UV = 3, + AdditionalUV1 = 4, + AdditionalUV2 = 5, + AdditionalUV3 = 6, + AdditionalUV4 = 7, + Matrial = 8, + Flip = 9, + Implus = 10, + }; + + enum class MorphCategory : uint8_t + { + ReservedCategory = 0, + Eyebrow = 1, + Eye = 2, + Mouth = 3, + Other = 4, + }; + + class PmxMorphOffset + { + public: + void virtual Read(std::istream *stream, PmxSetting *setting) = 0; + }; + + class PmxMorphVertexOffset : public PmxMorphOffset + { + public: + PmxMorphVertexOffset() + : vertex_index(0) + { + for (int i = 0; i < 3; ++i) { + position_offset[i] = 0.0f; + } + } + int vertex_index; + float position_offset[3]; + void Read(std::istream *stream, PmxSetting *setting); //override; + }; + + class PmxMorphUVOffset : public PmxMorphOffset + { + public: + PmxMorphUVOffset() + : vertex_index(0) + { + for (int i = 0; i < 4; ++i) { + uv_offset[i] = 0.0f; + } + } + int vertex_index; + float uv_offset[4]; + void Read(std::istream *stream, PmxSetting *setting); //override; + }; + + class PmxMorphBoneOffset : public PmxMorphOffset + { + public: + PmxMorphBoneOffset() + : bone_index(0) + { + for (int i = 0; i < 3; ++i) { + translation[i] = 0.0f; + } + for (int i = 0; i < 4; ++i) { + rotation[i] = 0.0f; + } + } + int bone_index; + float translation[3]; + float rotation[4]; + void Read(std::istream *stream, PmxSetting *setting); //override; + }; + + class PmxMorphMaterialOffset : public PmxMorphOffset + { + public: + PmxMorphMaterialOffset() + : specularity(0.0f) + , edge_size(0.0f) + { + for (int i = 0; i < 3; ++i) { + specular[i] = 0.0f; + ambient[i] = 0.0f; + } + for (int i = 0; i < 4; ++i) { + diffuse[i] = 0.0f; + edge_color[i] = 0.0f; + texture_argb[i] = 0.0f; + sphere_texture_argb[i] = 0.0f; + toon_texture_argb[i] = 0.0f; + } + } + int material_index; + uint8_t offset_operation; + float diffuse[4]; + float specular[3]; + float specularity; + float ambient[3]; + float edge_color[4]; + float edge_size; + float texture_argb[4]; + float sphere_texture_argb[4]; + float toon_texture_argb[4]; + void Read(std::istream *stream, PmxSetting *setting); //override; + }; + + class PmxMorphGroupOffset : public PmxMorphOffset + { + public: + PmxMorphGroupOffset() + : morph_index(0) + , morph_weight(0.0f) + {} + int morph_index; + float morph_weight; + void Read(std::istream *stream, PmxSetting *setting); //override; + }; + + class PmxMorphFlipOffset : public PmxMorphOffset + { + public: + PmxMorphFlipOffset() + : morph_index(0) + , morph_value(0.0f) + {} + int morph_index; + float morph_value; + void Read(std::istream *stream, PmxSetting *setting); //override; + }; + + class PmxMorphImplusOffset : public PmxMorphOffset + { + public: + PmxMorphImplusOffset() + : rigid_body_index(0) + , is_local(0) + { + for (int i = 0; i < 3; ++i) { + velocity[i] = 0.0f; + angular_torque[i] = 0.0f; + } + } + int rigid_body_index; + uint8_t is_local; + float velocity[3]; + float angular_torque[3]; + void Read(std::istream *stream, PmxSetting *setting); //override; + }; + + class PmxMorph + { + public: + PmxMorph() + : offset_count(0) + { + } + std::string morph_name; + std::string morph_english_name; + MorphCategory category; + MorphType morph_type; + int offset_count; + std::unique_ptr vertex_offsets; + std::unique_ptr uv_offsets; + std::unique_ptr bone_offsets; + std::unique_ptr material_offsets; + std::unique_ptr group_offsets; + std::unique_ptr flip_offsets; + std::unique_ptr implus_offsets; + void Read(std::istream *stream, PmxSetting *setting); + }; + + class PmxFrameElement + { + public: + PmxFrameElement() + : element_target(0) + , index(0) + { + } + uint8_t element_target; + int index; + void Read(std::istream *stream, PmxSetting *setting); + }; + + class PmxFrame + { + public: + PmxFrame() + : frame_flag(0) + , element_count(0) + { + } + std::string frame_name; + std::string frame_english_name; + uint8_t frame_flag; + int element_count; + std::unique_ptr elements; + void Read(std::istream *stream, PmxSetting *setting); + }; + + class PmxRigidBody + { + public: + PmxRigidBody() + : target_bone(0) + , group(0) + , mask(0) + , shape(0) + , mass(0.0f) + , move_attenuation(0.0f) + , rotation_attenuation(0.0f) + , repulsion(0.0f) + , friction(0.0f) + , physics_calc_type(0) + { + for (int i = 0; i < 3; ++i) { + size[i] = 0.0f; + position[i] = 0.0f; + orientation[i] = 0.0f; + } + } + std::string girid_body_name; + std::string girid_body_english_name; + int target_bone; + uint8_t group; + uint16_t mask; + uint8_t shape; + float size[3]; + float position[3]; + float orientation[3]; + float mass; + float move_attenuation; + float rotation_attenuation; + float repulsion; + float friction; + uint8_t physics_calc_type; + void Read(std::istream *stream, PmxSetting *setting); + }; + + enum class PmxJointType : uint8_t + { + Generic6DofSpring = 0, + Generic6Dof = 1, + Point2Point = 2, + ConeTwist = 3, + Slider = 5, + Hinge = 6 + }; + + class PmxJointParam + { + public: + PmxJointParam() + : rigid_body1(0) + , rigid_body2(0) + { + for (int i = 0; i < 3; ++i) { + position[i] = 0.0f; + orientaiton[i] = 0.0f; + move_limitation_min[i] = 0.0f; + move_limitation_max[i] = 0.0f; + rotation_limitation_min[i] = 0.0f; + rotation_limitation_max[i] = 0.0f; + spring_move_coefficient[i] = 0.0f; + spring_rotation_coefficient[i] = 0.0f; + } + } + int rigid_body1; + int rigid_body2; + float position[3]; + float orientaiton[3]; + float move_limitation_min[3]; + float move_limitation_max[3]; + float rotation_limitation_min[3]; + float rotation_limitation_max[3]; + float spring_move_coefficient[3]; + float spring_rotation_coefficient[3]; + void Read(std::istream *stream, PmxSetting *setting); + }; + + class PmxJoint + { + public: + std::string joint_name; + std::string joint_english_name; + PmxJointType joint_type; + PmxJointParam param; + void Read(std::istream *stream, PmxSetting *setting); + }; + + enum PmxSoftBodyFlag : uint8_t + { + BLink = 0x01, + Cluster = 0x02, + Link = 0x04 + }; + + class PmxAncherRigidBody + { + public: + PmxAncherRigidBody() + : related_rigid_body(0) + , related_vertex(0) + , is_near(false) + {} + int related_rigid_body; + int related_vertex; + bool is_near; + void Read(std::istream *stream, PmxSetting *setting); + }; + + class PmxSoftBody + { + public: + PmxSoftBody() + : shape(0) + , target_material(0) + , group(0) + , mask(0) + , blink_distance(0) + , cluster_count(0) + , mass(0.0) + , collisioni_margin(0.0) + , aero_model(0) + , VCF(0.0f) + , DP(0.0f) + , DG(0.0f) + , LF(0.0f) + , PR(0.0f) + , VC(0.0f) + , DF(0.0f) + , MT(0.0f) + , CHR(0.0f) + , KHR(0.0f) + , SHR(0.0f) + , AHR(0.0f) + , SRHR_CL(0.0f) + , SKHR_CL(0.0f) + , SSHR_CL(0.0f) + , SR_SPLT_CL(0.0f) + , SK_SPLT_CL(0.0f) + , SS_SPLT_CL(0.0f) + , V_IT(0) + , P_IT(0) + , D_IT(0) + , C_IT(0) + , LST(0.0f) + , AST(0.0f) + , VST(0.0f) + , anchor_count(0) + , pin_vertex_count(0) + {} + std::string soft_body_name; + std::string soft_body_english_name; + uint8_t shape; + int target_material; + uint8_t group; + uint16_t mask; + PmxSoftBodyFlag flag; + int blink_distance; + int cluster_count; + float mass; + float collisioni_margin; + int aero_model; + float VCF; + float DP; + float DG; + float LF; + float PR; + float VC; + float DF; + float MT; + float CHR; + float KHR; + float SHR; + float AHR; + float SRHR_CL; + float SKHR_CL; + float SSHR_CL; + float SR_SPLT_CL; + float SK_SPLT_CL; + float SS_SPLT_CL; + int V_IT; + int P_IT; + int D_IT; + int C_IT; + float LST; + float AST; + float VST; + int anchor_count; + std::unique_ptr anchers; + int pin_vertex_count; + std::unique_ptr pin_vertices; + void Read(std::istream *stream, PmxSetting *setting); + }; + + class PmxModel + { + public: + PmxModel() + : version(0.0f) + , vertex_count(0) + , index_count(0) + , texture_count(0) + , material_count(0) + , bone_count(0) + , morph_count(0) + , frame_count(0) + , rigid_body_count(0) + , joint_count(0) + , soft_body_count(0) + {} + + float version; + PmxSetting setting; + std::string model_name; + std::string model_english_name; + std::string model_comment; + std::string model_english_comment; + int vertex_count; + std::unique_ptr vertices; + int index_count; + std::unique_ptr indices; + int texture_count; + std::unique_ptr< std::string []> textures; + int material_count; + std::unique_ptr materials; + int bone_count; + std::unique_ptr bones; + int morph_count; + std::unique_ptr morphs; + int frame_count; + std::unique_ptr frames; + int rigid_body_count; + std::unique_ptr rigid_bodies; + int joint_count; + std::unique_ptr joints; + int soft_body_count; + std::unique_ptr soft_bodies; + void Init(); + void Read(std::istream *stream); + //static std::unique_ptr ReadFromFile(const char *filename); + //static std::unique_ptr ReadFromStream(std::istream *stream); + }; +} diff --git a/code/MMDVmdParser.h b/code/MMDVmdParser.h new file mode 100644 index 000000000..778ee1161 --- /dev/null +++ b/code/MMDVmdParser.h @@ -0,0 +1,375 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 + +#include +#include +#include +#include +#include +#include +#include "MMDCpp14.h" + +namespace vmd +{ + class VmdBoneFrame + { + public: + std::string name; + int frame; + float position[3]; + float orientation[4]; + char interpolation[4][4][4]; + + void Read(std::istream* stream) + { + char buffer[15]; + stream->read((char*) buffer, sizeof(char)*15); + name = std::string(buffer); + stream->read((char*) &frame, sizeof(int)); + stream->read((char*) position, sizeof(float)*3); + stream->read((char*) orientation, sizeof(float)*4); + stream->read((char*) interpolation, sizeof(char) * 4 * 4 * 4); + } + + void Write(std::ostream* stream) + { + stream->write((char*)name.c_str(), sizeof(char) * 15); + stream->write((char*)&frame, sizeof(int)); + stream->write((char*)position, sizeof(float) * 3); + stream->write((char*)orientation, sizeof(float) * 4); + stream->write((char*)interpolation, sizeof(char) * 4 * 4 * 4); + } + }; + + class VmdFaceFrame + { + public: + std::string face_name; + float weight; + uint32_t frame; + + void Read(std::istream* stream) + { + char buffer[15]; + stream->read((char*) &buffer, sizeof(char) * 15); + face_name = std::string(buffer); + stream->read((char*) &frame, sizeof(int)); + stream->read((char*) &weight, sizeof(float)); + } + + void Write(std::ostream* stream) + { + stream->write((char*)face_name.c_str(), sizeof(char) * 15); + stream->write((char*)&frame, sizeof(int)); + stream->write((char*)&weight, sizeof(float)); + } + }; + + class VmdCameraFrame + { + public: + int frame; + float distance; + float position[3]; + float orientation[3]; + char interpolation[6][4]; + float angle; + char unknown[3]; + + void Read(std::istream *stream) + { + stream->read((char*) &frame, sizeof(int)); + stream->read((char*) &distance, sizeof(float)); + stream->read((char*) position, sizeof(float) * 3); + stream->read((char*) orientation, sizeof(float) * 3); + stream->read((char*) interpolation, sizeof(char) * 24); + stream->read((char*) &angle, sizeof(float)); + stream->read((char*) unknown, sizeof(char) * 3); + } + + void Write(std::ostream *stream) + { + stream->write((char*)&frame, sizeof(int)); + stream->write((char*)&distance, sizeof(float)); + stream->write((char*)position, sizeof(float) * 3); + stream->write((char*)orientation, sizeof(float) * 3); + stream->write((char*)interpolation, sizeof(char) * 24); + stream->write((char*)&angle, sizeof(float)); + stream->write((char*)unknown, sizeof(char) * 3); + } + }; + + class VmdLightFrame + { + public: + int frame; + float color[3]; + float position[3]; + + void Read(std::istream* stream) + { + stream->read((char*) &frame, sizeof(int)); + stream->read((char*) color, sizeof(float) * 3); + stream->read((char*) position, sizeof(float) * 3); + } + + void Write(std::ostream* stream) + { + stream->write((char*)&frame, sizeof(int)); + stream->write((char*)color, sizeof(float) * 3); + stream->write((char*)position, sizeof(float) * 3); + } + }; + + class VmdIkEnable + { + public: + std::string ik_name; + bool enable; + }; + + class VmdIkFrame + { + public: + int frame; + bool display; + std::vector ik_enable; + + void Read(std::istream *stream) + { + char buffer[20]; + stream->read((char*) &frame, sizeof(int)); + stream->read((char*) &display, sizeof(uint8_t)); + int ik_count; + stream->read((char*) &ik_count, sizeof(int)); + ik_enable.resize(ik_count); + for (int i = 0; i < ik_count; i++) + { + stream->read(buffer, 20); + ik_enable[i].ik_name = std::string(buffer); + stream->read((char*) &ik_enable[i].enable, sizeof(uint8_t)); + } + } + + void Write(std::ostream *stream) + { + stream->write((char*)&frame, sizeof(int)); + stream->write((char*)&display, sizeof(uint8_t)); + int ik_count = static_cast(ik_enable.size()); + stream->write((char*)&ik_count, sizeof(int)); + for (int i = 0; i < ik_count; i++) + { + const VmdIkEnable& ik_enable = this->ik_enable.at(i); + stream->write(ik_enable.ik_name.c_str(), 20); + stream->write((char*)&ik_enable.enable, sizeof(uint8_t)); + } + } + }; + + class VmdMotion + { + public: + std::string model_name; + int version; + std::vector bone_frames; + std::vector face_frames; + std::vector camera_frames; + std::vector light_frames; + std::vector ik_frames; + + static std::unique_ptr LoadFromFile(char const *filename) + { + std::ifstream stream(filename, std::ios::binary); + auto result = LoadFromStream(&stream); + stream.close(); + return result; + } + + static std::unique_ptr LoadFromStream(std::ifstream *stream) + { + + char buffer[30]; + auto result = mmd::make_unique(); + + // magic and version + stream->read((char*) buffer, 30); + if (strncmp(buffer, "Vocaloid Motion Data", 20)) + { + std::cerr << "invalid vmd file." << std::endl; + return nullptr; + } + result->version = std::atoi(buffer + 20); + + // name + stream->read(buffer, 20); + result->model_name = std::string(buffer); + + // bone frames + int bone_frame_num; + stream->read((char*) &bone_frame_num, sizeof(int)); + result->bone_frames.resize(bone_frame_num); + for (int i = 0; i < bone_frame_num; i++) + { + result->bone_frames[i].Read(stream); + } + + // face frames + int face_frame_num; + stream->read((char*) &face_frame_num, sizeof(int)); + result->face_frames.resize(face_frame_num); + for (int i = 0; i < face_frame_num; i++) + { + result->face_frames[i].Read(stream); + } + + // camera frames + int camera_frame_num; + stream->read((char*) &camera_frame_num, sizeof(int)); + result->camera_frames.resize(camera_frame_num); + for (int i = 0; i < camera_frame_num; i++) + { + result->camera_frames[i].Read(stream); + } + + // light frames + int light_frame_num; + stream->read((char*) &light_frame_num, sizeof(int)); + result->light_frames.resize(light_frame_num); + for (int i = 0; i < light_frame_num; i++) + { + result->light_frames[i].Read(stream); + } + + // unknown2 + stream->read(buffer, 4); + + // ik frames + if (stream->peek() != std::ios::traits_type::eof()) + { + int ik_num; + stream->read((char*) &ik_num, sizeof(int)); + result->ik_frames.resize(ik_num); + for (int i = 0; i < ik_num; i++) + { + result->ik_frames[i].Read(stream); + } + } + + if (stream->peek() != std::ios::traits_type::eof()) + { + std::cerr << "vmd stream has unknown data." << std::endl; + } + + return result; + } + + bool SaveToFile(const std::u16string& filename) + { + // TODO: How to adapt u16string to string? + /* + std::ofstream stream(filename.c_str(), std::ios::binary); + auto result = SaveToStream(&stream); + stream.close(); + return result; + */ + return false; + } + + bool SaveToStream(std::ofstream *stream) + { + std::string magic = "Vocaloid Motion Data 0002\0"; + magic.resize(30); + + // magic and version + stream->write(magic.c_str(), 30); + + // name + stream->write(model_name.c_str(), 20); + + // bone frames + const int bone_frame_num = static_cast(bone_frames.size()); + stream->write(reinterpret_cast(&bone_frame_num), sizeof(int)); + for (int i = 0; i < bone_frame_num; i++) + { + bone_frames[i].Write(stream); + } + + // face frames + const int face_frame_num = static_cast(face_frames.size()); + stream->write(reinterpret_cast(&face_frame_num), sizeof(int)); + for (int i = 0; i < face_frame_num; i++) + { + face_frames[i].Write(stream); + } + + // camera frames + const int camera_frame_num = static_cast(camera_frames.size()); + stream->write(reinterpret_cast(&camera_frame_num), sizeof(int)); + for (int i = 0; i < camera_frame_num; i++) + { + camera_frames[i].Write(stream); + } + + // light frames + const int light_frame_num = static_cast(light_frames.size()); + stream->write(reinterpret_cast(&light_frame_num), sizeof(int)); + for (int i = 0; i < light_frame_num; i++) + { + light_frames[i].Write(stream); + } + + // self shadow datas + const int self_shadow_num = 0; + stream->write(reinterpret_cast(&self_shadow_num), sizeof(int)); + + // ik frames + const int ik_num = static_cast(ik_frames.size()); + stream->write(reinterpret_cast(&ik_num), sizeof(int)); + for (int i = 0; i < ik_num; i++) + { + ik_frames[i].Write(stream); + } + + return true; + } + }; +} diff --git a/code/MS3DLoader.cpp b/code/MS3DLoader.cpp index 07a3d9b17..64ec1e076 100644 --- a/code/MS3DLoader.cpp +++ b/code/MS3DLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/MS3DLoader.h b/code/MS3DLoader.h index 22d12e3cf..b4b19b3ad 100644 --- a/code/MS3DLoader.h +++ b/code/MS3DLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MakeVerboseFormat.cpp b/code/MakeVerboseFormat.cpp index be68bf3d6..720d44519 100644 --- a/code/MakeVerboseFormat.cpp +++ b/code/MakeVerboseFormat.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -192,14 +193,14 @@ bool MakeVerboseFormatProcess::MakeVerboseFormat(aiMesh* pcMesh) p = 0; while (pcMesh->HasTextureCoords(p)) { - delete pcMesh->mTextureCoords[p]; + delete[] pcMesh->mTextureCoords[p]; pcMesh->mTextureCoords[p] = apvTextureCoords[p]; ++p; } p = 0; while (pcMesh->HasVertexColors(p)) { - delete pcMesh->mColors[p]; + delete[] pcMesh->mColors[p]; pcMesh->mColors[p] = apvColorSets[p]; ++p; } diff --git a/code/MakeVerboseFormat.h b/code/MakeVerboseFormat.h index 1b32cf19e..9832a3f65 100644 --- a/code/MakeVerboseFormat.h +++ b/code/MakeVerboseFormat.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MaterialSystem.cpp b/code/MaterialSystem.cpp index 5fcf28a4f..55f1a4ff5 100644 --- a/code/MaterialSystem.cpp +++ b/code/MaterialSystem.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -455,6 +456,9 @@ aiReturn aiMaterial::AddBinaryProperty (const void* pInput, ai_assert (pKey != NULL); ai_assert (0 != pSizeInBytes); + if ( 0 == pSizeInBytes ) { + + } // first search the list whether there is already an entry with this key unsigned int iOutIndex = UINT_MAX; for (unsigned int i = 0; i < mNumProperties;++i) { diff --git a/code/MaterialSystem.h b/code/MaterialSystem.h index 6726e0518..b083a5bb8 100644 --- a/code/MaterialSystem.h +++ b/code/MaterialSystem.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/MemoryIOWrapper.h b/code/MemoryIOWrapper.h index d6aaafae0..9bd245337 100644 --- a/code/MemoryIOWrapper.h +++ b/code/MemoryIOWrapper.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/NDOLoader.cpp b/code/NDOLoader.cpp index 2ce3983dc..2586bac3e 100644 --- a/code/NDOLoader.cpp +++ b/code/NDOLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/NFFLoader.cpp b/code/NFFLoader.cpp index 24ca24cce..fa005ede4 100644 --- a/code/NFFLoader.cpp +++ b/code/NFFLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/NFFLoader.h b/code/NFFLoader.h index 2b5232645..0640d4405 100644 --- a/code/NFFLoader.h +++ b/code/NFFLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OFFLoader.cpp b/code/OFFLoader.cpp index fee36b03a..5038176e2 100644 --- a/code/OFFLoader.cpp +++ b/code/OFFLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -93,7 +94,7 @@ bool OFFImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool { if (!pIOHandler)return true; const char* tokens[] = {"off"}; - return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); + return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1,3); } return false; } diff --git a/code/OFFLoader.h b/code/OFFLoader.h index f01dc6244..29a4927bd 100644 --- a/code/OFFLoader.h +++ b/code/OFFLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ObjExporter.cpp b/code/ObjExporter.cpp index ea3e19cd9..692eac0e6 100644 --- a/code/ObjExporter.cpp +++ b/code/ObjExporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -90,11 +91,16 @@ static const std::string MaterialExt = ".mtl"; ObjExporter::ObjExporter(const char* _filename, const aiScene* pScene) : filename(_filename) , pScene(pScene) -, endl("\n") , vp() , vn() , vt() -, vc() { +, vc() +, mVpMap() +, mVnMap() +, mVtMap() +, mVcMap() +, mMeshes() +, endl("\n") { // 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); @@ -125,22 +131,31 @@ std::string ObjExporter :: GetMaterialLibName() } // ------------------------------------------------------------------------------------------------ -std::string ObjExporter :: GetMaterialLibFileName() -{ +std::string ObjExporter::GetMaterialLibFileName() { + // Remove existing .obj file extention so that the final material file name will be fileName.mtl and not fileName.obj.mtl + size_t lastdot = filename.find_last_of('.'); + if (lastdot != std::string::npos) + return filename.substr(0, lastdot) + MaterialExt; + return filename + MaterialExt; } // ------------------------------------------------------------------------------------------------ -void ObjExporter :: WriteHeader(std::ostringstream& out) -{ +void ObjExporter::WriteHeader(std::ostringstream& out) { out << "# File produced by Open Asset Import Library (http://www.assimp.sf.net)" << endl; - out << "# (assimp v" << aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.' << aiGetVersionRevision() << ")" << endl << endl; + out << "# (assimp v" << aiGetVersionMajor() << '.' << aiGetVersionMinor() << '.' + << aiGetVersionRevision() << ")" << endl << endl; } // ------------------------------------------------------------------------------------------------ -std::string ObjExporter :: GetMaterialName(unsigned int index) +std::string ObjExporter::GetMaterialName(unsigned int index) { const aiMaterial* const mat = pScene->mMaterials[index]; + if ( nullptr == mat ) { + static const std::string EmptyStr; + return EmptyStr; + } + aiString s; if(AI_SUCCESS == mat->Get(AI_MATKEY_NAME,s)) { return std::string(s.data,s.length); @@ -230,8 +245,8 @@ void ObjExporter::WriteGeometryFile() { AddNode(pScene->mRootNode, mBase); // write vertex positions with colors, if any - vpMap.getVectors( vp ); - vcMap.getColors( vc ); + mVpMap.getVectors( vp ); + mVcMap.getColors( vc ); if ( vc.empty() ) { mOutput << "# " << vp.size() << " vertex positions" << endl; for ( const aiVector3D& v : vp ) { @@ -248,7 +263,7 @@ void ObjExporter::WriteGeometryFile() { mOutput << endl; // write uv coordinates - vtMap.getVectors(vt); + mVtMap.getVectors(vt); mOutput << "# " << vt.size() << " UV coordinates" << endl; for(const aiVector3D& v : vt) { mOutput << "vt " << v.x << " " << v.y << " " << v.z << endl; @@ -256,7 +271,7 @@ void ObjExporter::WriteGeometryFile() { mOutput << endl; // write vertex normals - vnMap.getVectors(vn); + mVnMap.getVectors(vn); mOutput << "# " << vn.size() << " vertex normals" << endl; for(const aiVector3D& v : vn) { mOutput << "vn " << v.x << " " << v.y << " " << v.z << endl; @@ -264,7 +279,7 @@ void ObjExporter::WriteGeometryFile() { mOutput << endl; // now write all mesh instances - for(const MeshInstance& m : meshes) { + for(const MeshInstance& m : mMeshes) { mOutput << "# Mesh \'" << m.name << "\' with " << m.faces.size() << " faces" << endl; if (!m.name.empty()) { mOutput << "g " << m.name << endl; @@ -340,8 +355,8 @@ void ObjExporter::colIndexMap::getColors( std::vector &colors ) { // ------------------------------------------------------------------------------------------------ void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat) { - meshes.push_back(MeshInstance()); - MeshInstance& mesh = meshes.back(); + mMeshes.push_back(MeshInstance()); + MeshInstance& mesh = mMeshes.back(); mesh.name = std::string(name.data,name.length) + (m->mName.length ? "_" + std::string(m->mName.data,m->mName.length) : ""); mesh.matname = GetMaterialName(m->mMaterialIndex); @@ -368,24 +383,24 @@ void ObjExporter::AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4 const unsigned int idx = f.mIndices[a]; aiVector3D vert = mat * m->mVertices[idx]; - face.indices[a].vp = vpMap.getIndex(vert); + face.indices[a].vp = mVpMap.getIndex(vert); if (m->mNormals) { aiVector3D norm = aiMatrix3x3(mat) * m->mNormals[idx]; - face.indices[a].vn = vnMap.getIndex(norm); + face.indices[a].vn = mVnMap.getIndex(norm); } else { face.indices[a].vn = 0; } if ( nullptr != m->mColors[ 0 ] ) { aiColor4D col4 = m->mColors[ 0 ][ idx ]; - face.indices[ a ].vc = vcMap.getIndex( col4 ); + face.indices[ a ].vc = mVcMap.getIndex( col4 ); } else { face.indices[ a ].vc = 0; } if ( m->mTextureCoords[ 0 ] ) { - face.indices[a].vt = vtMap.getIndex(m->mTextureCoords[0][idx]); + face.indices[a].vt = mVtMap.getIndex(m->mTextureCoords[0][idx]); } else { face.indices[a].vt = 0; } diff --git a/code/ObjExporter.h b/code/ObjExporter.h index 8e92a7db5..fb60402d7 100644 --- a/code/ObjExporter.h +++ b/code/ObjExporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -97,16 +98,13 @@ private: void WriteHeader(std::ostringstream& out); void WriteMaterialFile(); void WriteGeometryFile(); - std::string GetMaterialName(unsigned int index); - void AddMesh(const aiString& name, const aiMesh* m, const aiMatrix4x4& mat); void AddNode(const aiNode* nd, const aiMatrix4x4& mParent); private: - const std::string filename; + std::string filename; const aiScene* const pScene; - std::vector vp, vn, vt; std::vector vc; @@ -165,9 +163,9 @@ private: void getColors( std::vector &colors ); }; - vecIndexMap vpMap, vnMap, vtMap; - colIndexMap vcMap; - std::vector meshes; + vecIndexMap mVpMap, mVnMap, mVtMap; + colIndexMap mVcMap; + std::vector mMeshes; // this endl() doesn't flush() the stream const std::string endl; diff --git a/code/ObjFileData.h b/code/ObjFileData.h index 1c6f80ce1..2658f8a2a 100644 --- a/code/ObjFileData.h +++ b/code/ObjFileData.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ObjFileImporter.cpp b/code/ObjFileImporter.cpp index 1b9b92f62..9f3bdef97 100644 --- a/code/ObjFileImporter.cpp +++ b/code/ObjFileImporter.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -614,9 +615,12 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc mat->AddProperty( &pCurrentMaterial->ior, 1, AI_MATKEY_REFRACTI ); // Adding textures + const int uvwIndex = 0; + if ( 0 != pCurrentMaterial->texture.length ) { mat->AddProperty( &pCurrentMaterial->texture, AI_MATKEY_TEXTURE_DIFFUSE(0)); + mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_DIFFUSE(0) ); if (pCurrentMaterial->clamp[ObjFile::Material::TextureDiffuseType]) { addTextureMappingModeProperty(mat, aiTextureType_DIFFUSE); @@ -626,6 +630,7 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc if ( 0 != pCurrentMaterial->textureAmbient.length ) { mat->AddProperty( &pCurrentMaterial->textureAmbient, AI_MATKEY_TEXTURE_AMBIENT(0)); + mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_AMBIENT(0) ); if (pCurrentMaterial->clamp[ObjFile::Material::TextureAmbientType]) { addTextureMappingModeProperty(mat, aiTextureType_AMBIENT); @@ -633,11 +638,15 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc } if ( 0 != pCurrentMaterial->textureEmissive.length ) + { mat->AddProperty( &pCurrentMaterial->textureEmissive, AI_MATKEY_TEXTURE_EMISSIVE(0)); + mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_EMISSIVE(0) ); + } if ( 0 != pCurrentMaterial->textureSpecular.length ) { mat->AddProperty( &pCurrentMaterial->textureSpecular, AI_MATKEY_TEXTURE_SPECULAR(0)); + mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_SPECULAR(0) ); if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularType]) { addTextureMappingModeProperty(mat, aiTextureType_SPECULAR); @@ -647,6 +656,7 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc if ( 0 != pCurrentMaterial->textureBump.length ) { mat->AddProperty( &pCurrentMaterial->textureBump, AI_MATKEY_TEXTURE_HEIGHT(0)); + mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_HEIGHT(0) ); if (pCurrentMaterial->clamp[ObjFile::Material::TextureBumpType]) { addTextureMappingModeProperty(mat, aiTextureType_HEIGHT); @@ -656,6 +666,7 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc if ( 0 != pCurrentMaterial->textureNormal.length ) { mat->AddProperty( &pCurrentMaterial->textureNormal, AI_MATKEY_TEXTURE_NORMALS(0)); + mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_NORMALS(0) ); if (pCurrentMaterial->clamp[ObjFile::Material::TextureNormalType]) { addTextureMappingModeProperty(mat, aiTextureType_NORMALS); @@ -672,6 +683,7 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc for( unsigned i = 0; i < count; i++ ) { mat->AddProperty(&pCurrentMaterial->textureReflection[i], AI_MATKEY_TEXTURE_REFLECTION(i)); + mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_REFLECTION(i) ); if(pCurrentMaterial->clamp[type]) addTextureMappingModeProperty(mat, aiTextureType_REFLECTION, 1, i); @@ -681,6 +693,7 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc if ( 0 != pCurrentMaterial->textureDisp.length ) { mat->AddProperty( &pCurrentMaterial->textureDisp, AI_MATKEY_TEXTURE_DISPLACEMENT(0) ); + mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_DISPLACEMENT(0) ); if (pCurrentMaterial->clamp[ObjFile::Material::TextureDispType]) { addTextureMappingModeProperty(mat, aiTextureType_DISPLACEMENT); @@ -690,6 +703,7 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc if ( 0 != pCurrentMaterial->textureOpacity.length ) { mat->AddProperty( &pCurrentMaterial->textureOpacity, AI_MATKEY_TEXTURE_OPACITY(0)); + mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_OPACITY(0) ); if (pCurrentMaterial->clamp[ObjFile::Material::TextureOpacityType]) { addTextureMappingModeProperty(mat, aiTextureType_OPACITY); @@ -699,6 +713,7 @@ void ObjFileImporter::createMaterials(const ObjFile::Model* pModel, aiScene* pSc if ( 0 != pCurrentMaterial->textureSpecularity.length ) { mat->AddProperty( &pCurrentMaterial->textureSpecularity, AI_MATKEY_TEXTURE_SHININESS(0)); + mat->AddProperty( &uvwIndex, 1, AI_MATKEY_UVWSRC_SHININESS(0) ); if (pCurrentMaterial->clamp[ObjFile::Material::TextureSpecularityType]) { addTextureMappingModeProperty(mat, aiTextureType_SHININESS); diff --git a/code/ObjFileImporter.h b/code/ObjFileImporter.h index bd3f42f27..302cf951a 100644 --- a/code/ObjFileImporter.h +++ b/code/ObjFileImporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ObjFileMtlImporter.cpp b/code/ObjFileMtlImporter.cpp index 4759f10e2..36bb6c2cb 100644 --- a/code/ObjFileMtlImporter.cpp +++ b/code/ObjFileMtlImporter.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -303,7 +304,7 @@ void ObjFileMtlImporter::createMaterial() m_pModel->m_pCurrentMaterial = new ObjFile::Material(); m_pModel->m_pCurrentMaterial->MaterialName.Set( name ); if (m_pModel->m_pCurrentMesh) { - m_pModel->m_pCurrentMesh->m_uiMaterialIndex = m_pModel->m_MaterialLib.size() - 1; + m_pModel->m_pCurrentMesh->m_uiMaterialIndex = static_cast(m_pModel->m_MaterialLib.size() - 1); } m_pModel->m_MaterialLib.push_back( name ); m_pModel->m_MaterialMap[ name ] = m_pModel->m_pCurrentMaterial; diff --git a/code/ObjFileMtlImporter.h b/code/ObjFileMtlImporter.h index 54e4b7cef..c9bcc9a9f 100644 --- a/code/ObjFileMtlImporter.h +++ b/code/ObjFileMtlImporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -112,4 +113,4 @@ private: } // Namespace Assimp -#endif +#endif // OBJFILEMTLIMPORTER_H_INC diff --git a/code/ObjFileParser.cpp b/code/ObjFileParser.cpp index 3b058f677..41677fce5 100644 --- a/code/ObjFileParser.cpp +++ b/code/ObjFileParser.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -56,8 +57,17 @@ namespace Assimp { const std::string ObjFileParser::DEFAULT_MATERIAL = AI_DEFAULT_MATERIAL_NAME; -// ------------------------------------------------------------------- -// Constructor with loaded data and directories. +ObjFileParser::ObjFileParser() +: m_DataIt() +, m_DataItEnd() +, m_pModel( NULL ) +, m_uiLine( 0 ) +, m_pIO( nullptr ) +, m_progress( nullptr ) +, m_originalObjFileName() { + // empty +} + ObjFileParser::ObjFileParser( IOStreamBuffer &streamBuffer, const std::string &modelName, IOSystem *io, ProgressHandler* progress, const std::string &originalObjFileName) : @@ -85,44 +95,20 @@ ObjFileParser::ObjFileParser( IOStreamBuffer &streamBuffer, const std::str parseFile( streamBuffer ); } -// ------------------------------------------------------------------- -// Destructor ObjFileParser::~ObjFileParser() { delete m_pModel; m_pModel = NULL; } -// ------------------------------------------------------------------- -// Returns a pointer to the model instance. +void ObjFileParser::setBuffer( std::vector &buffer ) { + m_DataIt = buffer.begin(); + m_DataItEnd = buffer.end(); +} + ObjFile::Model *ObjFileParser::GetModel() const { return m_pModel; } -void ignoreNewLines(IOStreamBuffer &streamBuffer, std::vector &buffer) -{ - std::vector buf(buffer); - auto copyPosition = buffer.begin(); - auto curPosition = buf.cbegin(); - do - { - while (*curPosition != '\n'&&*curPosition != '\\') - { - ++curPosition; - } - if (*curPosition == '\\') - { - copyPosition = std::copy(buf.cbegin(), curPosition, copyPosition); - *(copyPosition++) = ' '; - do - { - streamBuffer.getNextLine(buf); - } while (buf[0] == '\n'); - curPosition = buf.cbegin(); - } - } while (*curPosition != '\n'); - std::copy(buf.cbegin(), curPosition, copyPosition); -} -// ------------------------------------------------------------------- -// File parsing method. + void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { // only update every 100KB or it'll be too slow //const unsigned int updateProgressEveryBytes = 100 * 1024; @@ -134,7 +120,7 @@ void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { size_t lastFilePos( 0 ); std::vector buffer; - while ( streamBuffer.getNextLine( buffer ) ) { + while ( streamBuffer.getNextDataLine( buffer, '\\' ) ) { m_DataIt = buffer.begin(); m_DataItEnd = buffer.end(); @@ -146,14 +132,14 @@ void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { progressCounter++; m_progress->UpdateFileRead( progressOffset + processed * 2, progressTotal ); } - ignoreNewLines(streamBuffer, buffer); + // parse line switch (*m_DataIt) { case 'v': // Parse a vertex texture coordinate { ++m_DataIt; if (*m_DataIt == ' ' || *m_DataIt == '\t') { - size_t numComponents = getNumComponentsInLine(); + size_t numComponents = getNumComponentsInDataDefinition(); if (numComponents == 3) { // read in vertex definition getVector3(m_pModel->m_Vertices); @@ -193,7 +179,18 @@ void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { case 'u': // Parse a material desc. setter { - getMaterialDesc(); + std::string name; + + getNameNoSpace(m_DataIt, m_DataItEnd, name); + + size_t nextSpace = name.find(" "); + if (nextSpace != std::string::npos) + name = name.substr(0, nextSpace); + + if(name == "usemtl") + { + getMaterialDesc(); + } } break; @@ -237,7 +234,6 @@ void ObjFileParser::parseFile( IOStreamBuffer &streamBuffer ) { default: { pf_skip_line: - m_DataIt = skipLine( m_DataIt, m_DataItEnd, m_uiLine ); } break; @@ -245,11 +241,14 @@ pf_skip_line: } } -// ------------------------------------------------------------------- -// Copy the next word in a temporary buffer 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 = getNextWord( m_DataIt, m_DataItEnd ); + } while( m_DataIt != m_DataItEnd && !IsSpaceOrNewLine( *m_DataIt ) ) { pBuffer[index] = *m_DataIt; index++; @@ -263,21 +262,44 @@ void ObjFileParser::copyNextWord(char *pBuffer, size_t length) { pBuffer[index] = '\0'; } -size_t ObjFileParser::getNumComponentsInLine() { +static bool isDataDefinitionEnd( const char *tmp ) { + if ( *tmp == '\\' ) { + tmp++; + if ( IsLineEnd( *tmp ) ) { + tmp++; + return true; + } + } + return false; +} + +size_t ObjFileParser::getNumComponentsInDataDefinition() { size_t numComponents( 0 ); const char* tmp( &m_DataIt[0] ); - while( !IsLineEnd( *tmp ) ) { + bool end_of_definition = false; + while ( !end_of_definition ) { + if ( isDataDefinitionEnd( tmp ) ) { + tmp += 2; + } else if ( IsLineEnd( *tmp ) ) { + end_of_definition = true; + } if ( !SkipSpaces( &tmp ) ) { break; } + const bool isNum( IsNumeric( *tmp ) ); SkipToken( tmp ); - ++numComponents; + if ( isNum ) { + ++numComponents; + } + if ( !SkipSpaces( &tmp ) ) { + break; + } } return numComponents; } void ObjFileParser::getVector( std::vector &point3d_array ) { - size_t numComponents = getNumComponentsInLine(); + size_t numComponents = getNumComponentsInDataDefinition(); ai_real x, y, z; if( 2 == numComponents ) { copyNextWord( m_buffer, Buffersize ); @@ -302,8 +324,6 @@ void ObjFileParser::getVector( std::vector &point3d_array ) { m_DataIt = skipLine( m_DataIt, m_DataItEnd, m_uiLine ); } -// ------------------------------------------------------------------- -// Get values for a new 3D vector instance void ObjFileParser::getVector3( std::vector &point3d_array ) { ai_real x, y, z; copyNextWord(m_buffer, Buffersize); @@ -388,10 +408,6 @@ static const std::string DefaultObjName = "defaultobject"; // ------------------------------------------------------------------- // Get values for a new face instance void ObjFileParser::getFace( aiPrimitiveType type ) { - //copyNextLine(m_buffer, Buffersize); - //char *pPtr = m_DataIt; - //char *pPtr = m_buffer; - //char *pEnd = &pPtr[Buffersize]; m_DataIt = getNextToken( m_DataIt, m_DataItEnd ); if ( m_DataIt == m_DataItEnd || *m_DataIt == '\0' ) { return; @@ -539,10 +555,15 @@ void ObjFileParser::getMaterialDesc() { // Search for material std::map::iterator it = m_pModel->m_MaterialMap.find(strName); if (it == m_pModel->m_MaterialMap.end()) { - // Not found, use default material - m_pModel->m_pCurrentMaterial = m_pModel->m_pDefaultMaterial; - DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", skipping"); - strName = m_pModel->m_pDefaultMaterial->MaterialName.C_Str(); + // Not found, so we don't know anything about the material except for its name. + // This may be the case if the material library is missing. We don't want to lose all + // materials if that happens, so create a new named material instead of discarding it + // completely. + DefaultLogger::get()->error("OBJ: failed to locate material " + strName + ", creating new material"); + m_pModel->m_pCurrentMaterial = new ObjFile::Material(); + m_pModel->m_pCurrentMaterial->MaterialName.Set(strName); + m_pModel->m_MaterialLib.push_back(strName); + m_pModel->m_MaterialMap[strName] = m_pModel->m_pCurrentMaterial; } else { // Found, using detected material m_pModel->m_pCurrentMaterial = (*it).second; @@ -562,14 +583,7 @@ void ObjFileParser::getMaterialDesc() { // ------------------------------------------------------------------- // Get a comment, values will be skipped void ObjFileParser::getComment() { - while (m_DataIt != m_DataItEnd) { - if ( '\n' == (*m_DataIt)) { - ++m_DataIt; - break; - } else { - ++m_DataIt; - } - } + m_DataIt = skipLine( m_DataIt, m_DataItEnd, m_uiLine ); } // ------------------------------------------------------------------- diff --git a/code/ObjFileParser.h b/code/ObjFileParser.h index 55be305bb..fa5b3ca31 100644 --- a/code/ObjFileParser.h +++ b/code/ObjFileParser.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -64,7 +65,7 @@ class ProgressHandler; /// \class ObjFileParser /// \brief Parser for a obj waveform file -class ObjFileParser { +class ASSIMP_API ObjFileParser { public: static const size_t Buffersize = 4096; typedef std::vector DataArray; @@ -72,20 +73,26 @@ public: typedef std::vector::const_iterator ConstDataArrayIt; public: - /// \brief Constructor with data array. - ObjFileParser( IOStreamBuffer &streamBuffer, const std::string &strModelName, IOSystem* io, ProgressHandler* progress, const std::string &originalObjFileName); - /// \brief Destructor + /// @brief The default constructor. + ObjFileParser(); + /// @brief Constructor with data array. + ObjFileParser( IOStreamBuffer &streamBuffer, const std::string &modelName, IOSystem* io, ProgressHandler* progress, const std::string &originalObjFileName); + /// @brief Destructor ~ObjFileParser(); - /// \brief Model getter. + /// @brief If you want to load in-core data. + void setBuffer( std::vector &buffer ); + /// @brief Model getter. ObjFile::Model *GetModel() const; -private: +protected: /// Parse the loaded file void parseFile( IOStreamBuffer &streamBuffer ); /// Method to copy the new delimited word in the current line. void copyNextWord(char *pBuffer, size_t length); /// Method to copy the new line. // void copyNextLine(char *pBuffer, size_t length); + /// Get the number of components in a line. + size_t getNumComponentsInDataDefinition(); /// Stores the vector void getVector( std::vector &point3d_array ); /// Stores the following 3d vector. @@ -124,8 +131,6 @@ private: bool needsNewMesh( const std::string &rMaterialName ); /// Error report in token void reportErrorTokenInFace(); - /// Get the number of components in a line. - size_t getNumComponentsInLine(); private: // Copy and assignment constructor should be private @@ -149,9 +154,8 @@ private: IOSystem *m_pIO; //! Pointer to progress handler ProgressHandler* m_progress; - /// Path to the current model - // name of the obj file where the buffer comes from - const std::string& m_originalObjFileName; + /// Path to the current model, name of the obj file where the buffer comes from + const std::string m_originalObjFileName; }; } // Namespace Assimp diff --git a/code/ObjTools.h b/code/ObjTools.h index 8dee62f18..7236cedc0 100644 --- a/code/ObjTools.h +++ b/code/ObjTools.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -78,8 +79,10 @@ inline Char_T getNextWord( Char_T pBuffer, Char_T pEnd ) { while ( !isEndOfBuffer( pBuffer, pEnd ) ) { - if( !IsSpaceOrNewLine( *pBuffer ) || IsLineEnd( *pBuffer ) ) - break; + if ( !IsSpaceOrNewLine( *pBuffer ) || IsLineEnd( *pBuffer ) ) { + //if ( *pBuffer != '\\' ) + break; + } pBuffer++; } return pBuffer; @@ -113,14 +116,16 @@ inline char_t skipLine( char_t it, char_t end, unsigned int &uiLine ) { while( !isEndOfBuffer( it, end ) && !IsLineEnd( *it ) ) { ++it; } - if ( it != end ) - { + + if ( it != end ) { ++it; ++uiLine; } // fix .. from time to time there are spaces at the beginning of a material line - while ( it != end && (*it == '\t' || *it == ' ') ) + while ( it != end && ( *it == '\t' || *it == ' ' ) ) { ++it; + } + return it; } diff --git a/code/OgreBinarySerializer.cpp b/code/OgreBinarySerializer.cpp index 59bd0d92d..95aec221f 100644 --- a/code/OgreBinarySerializer.cpp +++ b/code/OgreBinarySerializer.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OgreBinarySerializer.h b/code/OgreBinarySerializer.h index 067e36a63..c48e33dd6 100644 --- a/code/OgreBinarySerializer.h +++ b/code/OgreBinarySerializer.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OgreImporter.cpp b/code/OgreImporter.cpp index 744be0965..4dc802574 100644 --- a/code/OgreImporter.cpp +++ b/code/OgreImporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OgreImporter.h b/code/OgreImporter.h index 8b2179502..2b3009096 100644 --- a/code/OgreImporter.h +++ b/code/OgreImporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OgreMaterial.cpp b/code/OgreMaterial.cpp index bdcd0285a..dfb77ffef 100644 --- a/code/OgreMaterial.cpp +++ b/code/OgreMaterial.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OgreParsingUtils.h b/code/OgreParsingUtils.h index def3cf733..b0c31e5be 100644 --- a/code/OgreParsingUtils.h +++ b/code/OgreParsingUtils.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -90,11 +91,11 @@ static inline std::string &TrimLeft(std::string &s, bool newlines = true) { if (!newlines) { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(Assimp::IsSpace)))); + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpace(c); })); } else { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(Assimp::IsSpaceOrNewLine)))); + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine(c); })); } return s; } @@ -104,11 +105,11 @@ static inline std::string &TrimRight(std::string &s, bool newlines = true) { if (!newlines) { - s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(Assimp::IsSpace))).base(),s.end()); + s.erase(std::find_if(s.rbegin(), s.rend(), [](char c) { return !Assimp::IsSpace(c); }).base(),s.end()); } else { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun(Assimp::IsSpaceOrNewLine)))); + s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !Assimp::IsSpaceOrNewLine(c); })); } return s; } diff --git a/code/OgreStructs.cpp b/code/OgreStructs.cpp index d9cd547d6..09597950a 100644 --- a/code/OgreStructs.cpp +++ b/code/OgreStructs.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OgreStructs.h b/code/OgreStructs.h index c4e86a805..04383bc4e 100644 --- a/code/OgreStructs.h +++ b/code/OgreStructs.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OgreXmlSerializer.cpp b/code/OgreXmlSerializer.cpp index 16767252d..b5d20cdf6 100644 --- a/code/OgreXmlSerializer.cpp +++ b/code/OgreXmlSerializer.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OgreXmlSerializer.h b/code/OgreXmlSerializer.h index 47b4cafc0..01b9a7b23 100644 --- a/code/OgreXmlSerializer.h +++ b/code/OgreXmlSerializer.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OpenGEXExporter.cpp b/code/OpenGEXExporter.cpp index cf06c9f39..ea3c770ec 100644 --- a/code/OpenGEXExporter.cpp +++ b/code/OpenGEXExporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OpenGEXExporter.h b/code/OpenGEXExporter.h index f9757f41c..9df9d853e 100644 --- a/code/OpenGEXExporter.h +++ b/code/OpenGEXExporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OpenGEXImporter.cpp b/code/OpenGEXImporter.cpp index 5df6d1646..47e3e3e8c 100644 --- a/code/OpenGEXImporter.cpp +++ b/code/OpenGEXImporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -52,8 +53,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include -static const std::string OpenGexExt = "ogex"; - static const aiImporterDesc desc = { "Open Game Engine Exchange", "", @@ -64,7 +63,7 @@ static const aiImporterDesc desc = { 0, 0, 0, - OpenGexExt.c_str() + "ogex" }; namespace Grammar { @@ -197,7 +196,6 @@ namespace Grammar { return NoneType; } - } // Namespace Grammar namespace Assimp { @@ -263,6 +261,7 @@ OpenGEXImporter::OpenGEXImporter() , m_nodeChildMap() , m_meshCache() , m_mesh2refMap() +, m_material2refMap() , m_ctx( nullptr ) , m_metrics() , m_currentNode( nullptr ) @@ -289,7 +288,7 @@ OpenGEXImporter::~OpenGEXImporter() { bool OpenGEXImporter::CanRead( const std::string &file, IOSystem *pIOHandler, bool checkSig ) const { bool canRead( false ); if( !checkSig ) { - canRead = SimpleExtensionCheck( file, OpenGexExt.c_str() ); + canRead = SimpleExtensionCheck( file, "ogex" ); } else { static const char *token[] = { "Metric", "GeometryNode", "VertexArray (attrib", "IndexArray" }; canRead = BaseImporter::SearchFileHeaderForToken( pIOHandler, file, token, 4 ); @@ -308,6 +307,7 @@ void OpenGEXImporter::InternReadFile( const std::string &filename, aiScene *pSce std::vector buffer; TextFileToBuffer( file, buffer ); + pIOHandler->Close( file ); OpenDDLParser myParser; myParser.setBuffer( &buffer[ 0 ], buffer.size() ); @@ -322,6 +322,7 @@ void OpenGEXImporter::InternReadFile( const std::string &filename, aiScene *pSce copyMeshes( pScene ); copyCameras( pScene ); copyLights( pScene ); + copyMaterials( pScene ); resolveReferences(); createNodeTree( pScene ); } @@ -484,7 +485,10 @@ void OpenGEXImporter::handleNameNode( DDLNode *node, aiScene *pScene ) { || m_tokenType == Grammar::CameraNodeToken ) { m_currentNode->mName.Set( name.c_str() ); } else if( m_tokenType == Grammar::MaterialToken ) { - + aiString aiName; + aiName.Set( name ); + m_currentMaterial->AddProperty( &aiName, AI_MATKEY_NAME ); + m_material2refMap[ name ] = m_materialCache.size() - 1; } } } @@ -522,8 +526,12 @@ void OpenGEXImporter::handleObjectRefNode( DDLNode *node, aiScene *pScene ) { m_currentNode->mNumMeshes = static_cast(objRefNames.size()); m_currentNode->mMeshes = new unsigned int[ objRefNames.size() ]; if ( !objRefNames.empty() ) { - m_unresolvedRefStack.push_back( new RefInfo( m_currentNode, RefInfo::MeshRef, objRefNames ) ); + m_unresolvedRefStack.push_back( std::unique_ptr( new RefInfo( m_currentNode, RefInfo::MeshRef, objRefNames ) ) ); } + } else if ( m_tokenType == Grammar::LightNodeToken ) { + // TODO! + } else if ( m_tokenType == Grammar::CameraNodeToken ) { + // TODO! } } @@ -537,7 +545,7 @@ void OpenGEXImporter::handleMaterialRefNode( ODDLParser::DDLNode *node, aiScene std::vector matRefNames; getRefNames( node, matRefNames ); if( !matRefNames.empty() ) { - m_unresolvedRefStack.push_back( new RefInfo( m_currentNode, RefInfo::MaterialRef, matRefNames ) ); + m_unresolvedRefStack.push_back( std::unique_ptr( new RefInfo( m_currentNode, RefInfo::MaterialRef, matRefNames ) ) ); } } @@ -603,6 +611,13 @@ void OpenGEXImporter::handleCameraObject( ODDLParser::DDLNode *node, aiScene *pS //------------------------------------------------------------------------------------------------ void OpenGEXImporter::handleLightObject( ODDLParser::DDLNode *node, aiScene *pScene ) { + aiLight *light( new aiLight ); + m_lightCache.push_back( light ); + std::string objName = node->getName(); + if ( !objName.empty() ) { + light->mName.Set( objName ); + } + m_currentLight = light; Property *prop( node->findPropertyByName( "type" ) ); if ( nullptr != prop ) { @@ -918,7 +933,7 @@ void OpenGEXImporter::handleIndexArrayNode( ODDLParser::DDLNode *node, aiScene * } //------------------------------------------------------------------------------------------------ -static void getColorRGB( aiColor3D *pColor, DataArrayList *colList ) { +static void getColorRGB3( aiColor3D *pColor, DataArrayList *colList ) { if( nullptr == pColor || nullptr == colList ) { return; } @@ -932,6 +947,23 @@ static void getColorRGB( aiColor3D *pColor, DataArrayList *colList ) { pColor->b = val->getFloat(); } +//------------------------------------------------------------------------------------------------ +static void getColorRGB4( aiColor4D *pColor, DataArrayList *colList ) { + if ( nullptr == pColor || nullptr == colList ) { + return; + } + + ai_assert( 4 == colList->m_numItems ); + Value *val( colList->m_dataList ); + pColor->r = val->getFloat(); + val = val->getNext(); + pColor->g = val->getFloat(); + val = val->getNext(); + pColor->b = val->getFloat(); + val = val->getNext(); + pColor->a = val->getFloat(); +} + //------------------------------------------------------------------------------------------------ enum ColorType { NoneColor = 0, @@ -982,7 +1014,17 @@ void OpenGEXImporter::handleColorNode( ODDLParser::DDLNode *node, aiScene *pScen return; } aiColor3D col; - getColorRGB( &col, colList ); + if ( 3 == colList->m_numItems ) { + aiColor3D col3; + getColorRGB3( &col3, colList ); + col = col3; + } else { + aiColor4D col4; + getColorRGB4( &col4, colList ); + col.r = col4.r; + col.g = col4.g; + col.b = col4.b; + } const ColorType colType( getColorType( prop->m_key ) ); if( DiffuseColor == colType ) { m_currentMaterial->AddProperty( &col, 1, AI_MATKEY_COLOR_DIFFUSE ); @@ -1014,7 +1056,6 @@ void OpenGEXImporter::handleTextureNode( ODDLParser::DDLNode *node, aiScene *pSc m_currentMaterial->AddProperty( &tex, AI_MATKEY_TEXTURE_DIFFUSE( 0 ) ); } else if( prop->m_value->getString() == Grammar::SpecularPowerTextureToken ) { m_currentMaterial->AddProperty( &tex, AI_MATKEY_TEXTURE_SPECULAR( 0 ) ); - } else if( prop->m_value->getString() == Grammar::EmissionTextureToken ) { m_currentMaterial->AddProperty( &tex, AI_MATKEY_TEXTURE_EMISSIVE( 0 ) ); } else if( prop->m_value->getString() == Grammar::OpacyTextureToken ) { @@ -1118,6 +1159,19 @@ void OpenGEXImporter::copyLights( aiScene *pScene ) { std::copy( m_lightCache.begin(), m_lightCache.end(), pScene->mLights ); } +//------------------------------------------------------------------------------------------------ +void OpenGEXImporter::copyMaterials( aiScene *pScene ) { + ai_assert( nullptr != pScene ); + + if ( m_materialCache.empty() ) { + return; + } + + pScene->mNumMaterials = static_cast(m_materialCache.size()); + pScene->mMaterials = new aiMaterial*[ pScene->mNumMaterials ]; + std::copy( m_materialCache.begin(), m_materialCache.end(), pScene->mMaterials ); +} + //------------------------------------------------------------------------------------------------ void OpenGEXImporter::resolveReferences() { if( m_unresolvedRefStack.empty() ) { @@ -1125,12 +1179,12 @@ void OpenGEXImporter::resolveReferences() { } RefInfo *currentRefInfo( nullptr ); - for( std::vector::iterator it = m_unresolvedRefStack.begin(); it != m_unresolvedRefStack.end(); ++it ) { - currentRefInfo = *it; + for( auto it = m_unresolvedRefStack.begin(); it != m_unresolvedRefStack.end(); ++it ) { + currentRefInfo = it->get(); if( nullptr != currentRefInfo ) { aiNode *node( currentRefInfo->m_node ); if( RefInfo::MeshRef == currentRefInfo->m_type ) { - for( size_t i = 0; i < currentRefInfo->m_Names.size(); i++ ) { + for( size_t i = 0; i < currentRefInfo->m_Names.size(); ++i ) { const std::string &name( currentRefInfo->m_Names[ i ] ); ReferenceMap::const_iterator it( m_mesh2refMap.find( name ) ); if( m_mesh2refMap.end() != it ) { @@ -1139,7 +1193,22 @@ void OpenGEXImporter::resolveReferences() { } } } else if( RefInfo::MaterialRef == currentRefInfo->m_type ) { - // ToDo! + for ( size_t i = 0; i < currentRefInfo->m_Names.size(); ++i ) { + const std::string name( currentRefInfo->m_Names[ i ] ); + ReferenceMap::const_iterator it( m_material2refMap.find( name ) ); + if ( m_material2refMap.end() != it ) { + if ( nullptr != m_currentMesh ) { + unsigned int matIdx = static_cast< unsigned int >( m_material2refMap[ name ] ); + if ( m_currentMesh->mMaterialIndex != 0 ) { + DefaultLogger::get()->warn( "Override of material reference in current mesh by material reference." ); + } + m_currentMesh->mMaterialIndex = matIdx; + } else { + DefaultLogger::get()->warn( "Cannot resolve material reference, because no current mesh is there." ); + + } + } + } } else { throw DeadlyImportError( "Unknown reference info to resolve." ); } @@ -1177,9 +1246,9 @@ void OpenGEXImporter::pushNode( aiNode *node, aiScene *pScene ) { if( m_nodeChildMap.end() == it ) { info = new ChildInfo; m_root = info; - m_nodeChildMap[ node->mParent ] = info; + m_nodeChildMap[ node->mParent ] = std::unique_ptr(info); } else { - info = it->second; + info = it->second.get(); } info->m_children.push_back( node ); } else { @@ -1189,9 +1258,9 @@ void OpenGEXImporter::pushNode( aiNode *node, aiScene *pScene ) { NodeChildMap::iterator it( m_nodeChildMap.find( node->mParent ) ); if( m_nodeChildMap.end() == it ) { info = new ChildInfo; - m_nodeChildMap[ node->mParent ] = info; + m_nodeChildMap[ node->mParent ] = std::unique_ptr(info); } else { - info = it->second; + info = it->second.get(); } info->m_children.push_back( node ); } diff --git a/code/OpenGEXImporter.h b/code/OpenGEXImporter.h index d33b0a804..c0cde579c 100644 --- a/code/OpenGEXImporter.h +++ b/code/OpenGEXImporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -48,6 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include namespace ODDLParser { class DDLNode; @@ -131,7 +133,7 @@ protected: void copyMeshes( aiScene *pScene ); void copyCameras( aiScene *pScene ); void copyLights( aiScene *pScene ); - + void copyMaterials( aiScene *pScene ); void resolveReferences(); void pushNode( aiNode *node, aiScene *pScene ); aiNode *popNode(); @@ -179,12 +181,13 @@ private: std::list m_children; }; ChildInfo *m_root; - typedef std::map NodeChildMap; + typedef std::map > NodeChildMap; NodeChildMap m_nodeChildMap; std::vector m_meshCache; typedef std::map ReferenceMap; std::map m_mesh2refMap; + std::map m_material2refMap; ODDLParser::Context *m_ctx; MetricInfo m_metrics[ MetricInfo::Max ]; @@ -199,7 +202,7 @@ private: std::vector m_cameraCache; std::vector m_lightCache; std::vector m_nodeStack; - std::vector m_unresolvedRefStack; + std::vector > m_unresolvedRefStack; }; } // Namespace OpenGEX diff --git a/code/OpenGEXStructs.h b/code/OpenGEXStructs.h index 910b03f60..6144a10c5 100644 --- a/code/OpenGEXStructs.h +++ b/code/OpenGEXStructs.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OptimizeGraph.cpp b/code/OptimizeGraph.cpp index 4d033ee31..04971af5e 100644 --- a/code/OptimizeGraph.cpp +++ b/code/OptimizeGraph.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -48,7 +49,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "OptimizeGraph.h" #include "ProcessHelper.h" -#include "SceneCombiner.h" +#include #include "Exceptional.h" #include diff --git a/code/OptimizeGraph.h b/code/OptimizeGraph.h index 7b3a1d0de..22d53afff 100644 --- a/code/OptimizeGraph.h +++ b/code/OptimizeGraph.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/OptimizeMeshes.cpp b/code/OptimizeMeshes.cpp index 2bb9c5717..f8183fc75 100644 --- a/code/OptimizeMeshes.cpp +++ b/code/OptimizeMeshes.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -49,7 +50,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "OptimizeMeshes.h" #include "ProcessHelper.h" -#include "SceneCombiner.h" +#include #include "Exceptional.h" using namespace Assimp; @@ -180,11 +181,8 @@ void OptimizeMeshesProcess::ProcessNode( aiNode* pNode) verts += mScene->mMeshes[am]->mNumVertices; faces += mScene->mMeshes[am]->mNumFaces; + pNode->mMeshes[a] = pNode->mMeshes[pNode->mNumMeshes - 1]; --pNode->mNumMeshes; - for( unsigned int n = a; n < pNode->mNumMeshes; ++n ) { - pNode->mMeshes[ n ] = pNode->mMeshes[ n + 1 ]; - } - --a; } } diff --git a/code/OptimizeMeshes.h b/code/OptimizeMeshes.h index fc8b6a10b..bcefe9247 100644 --- a/code/OptimizeMeshes.h +++ b/code/OptimizeMeshes.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ParsingUtils.h b/code/ParsingUtils.h index 2371ee606..7da664374 100644 --- a/code/ParsingUtils.h +++ b/code/ParsingUtils.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/PlyExporter.cpp b/code/PlyExporter.cpp index bd3c94830..eb0867046 100644 --- a/code/PlyExporter.cpp +++ b/code/PlyExporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/PlyExporter.h b/code/PlyExporter.h index be4fa466f..d1d4eafbb 100644 --- a/code/PlyExporter.h +++ b/code/PlyExporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -50,14 +51,12 @@ struct aiScene; struct aiNode; struct aiMesh; -namespace Assimp -{ +namespace Assimp { // ------------------------------------------------------------------------------------------------ /** Helper class to export a given scene to a Stanford Ply file. */ // ------------------------------------------------------------------------------------------------ -class PlyExporter -{ +class PlyExporter { public: /// The class constructor for a specific scene to export PlyExporter(const char* filename, const aiScene* pScene, bool binary = false); diff --git a/code/PlyLoader.cpp b/code/PlyLoader.cpp index 5dc83e7c6..c6e862bf1 100644 --- a/code/PlyLoader.cpp +++ b/code/PlyLoader.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team All rights reserved. @@ -12,18 +12,18 @@ 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. +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. +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. +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 @@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // internal headers #include "PlyLoader.h" +#include "IOStreamBuffer.h" #include "Macros.h" #include #include @@ -56,16 +57,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using namespace Assimp; static const aiImporterDesc desc = { - "Stanford Polygon Library (PLY) Importer", - "", - "", - "", - aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportTextFlavour, - 0, - 0, - 0, - 0, - "ply" + "Stanford Polygon Library (PLY) Importer", + "", + "", + "", + aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_SupportTextFlavour, + 0, + 0, + 0, + 0, + "ply" }; @@ -73,1040 +74,941 @@ static const aiImporterDesc desc = { // Internal stuff namespace { - // ------------------------------------------------------------------------------------------------ - // Checks that property index is within range - template - const T &GetProperty(const std::vector &props, int idx) - { - if( static_cast< size_t >( idx ) >= props.size() ) { - throw DeadlyImportError( "Invalid .ply file: Property index is out of range." ); - } - - return props[idx]; + // ------------------------------------------------------------------------------------------------ + // Checks that property index is within range + template + const T &GetProperty(const std::vector &props, int idx) + { + if (static_cast(idx) >= props.size()) { + throw DeadlyImportError("Invalid .ply file: Property index is out of range."); } + + return props[idx]; + } } // ------------------------------------------------------------------------------------------------ // Constructor to be privately used by Importer PLYImporter::PLYImporter() -: mBuffer() -, pcDOM(){ - // empty + : mBuffer() + , pcDOM() + , mGeneratedMesh(NULL){ + // empty } // ------------------------------------------------------------------------------------------------ // Destructor, private as well PLYImporter::~PLYImporter() { - // empty + // empty } // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool PLYImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const +bool PLYImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - const std::string extension = GetExtension(pFile); + const std::string extension = GetExtension(pFile); - if (extension == "ply") - return true; - else if (!extension.length() || checkSig) - { - if (!pIOHandler)return true; - const char* tokens[] = {"ply"}; - return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); - } - return false; + if (extension == "ply") + return true; + else if (!extension.length() || checkSig) + { + if (!pIOHandler)return true; + const char* tokens[] = { "ply" }; + return SearchFileHeaderForToken(pIOHandler, pFile, tokens, 1); + } + return false; } // ------------------------------------------------------------------------------------------------ -const aiImporterDesc* PLYImporter::GetInfo () const +const aiImporterDesc* PLYImporter::GetInfo() const { - return &desc; + return &desc; } // ------------------------------------------------------------------------------------------------ -static bool isBigEndian( const char* szMe ) { - ai_assert( NULL != szMe ); +static bool isBigEndian(const char* szMe) { + ai_assert(NULL != szMe); - // binary_little_endian - // binary_big_endian - bool isBigEndian( false ); + // binary_little_endian + // binary_big_endian + bool isBigEndian(false); #if (defined AI_BUILD_BIG_ENDIAN) - if ( 'l' == *szMe || 'L' == *szMe ) { - isBigEndian = true; -} + if ( 'l' == *szMe || 'L' == *szMe ) { + isBigEndian = true; + } #else - if ( 'b' == *szMe || 'B' == *szMe ) { - isBigEndian = true; - } + if ('b' == *szMe || 'B' == *szMe) { + isBigEndian = true; + } #endif // ! AI_BUILD_BIG_ENDIAN - return isBigEndian; + return isBigEndian; } // ------------------------------------------------------------------------------------------------ // Imports the given file into the given scene structure. -void PLYImporter::InternReadFile( const std::string& pFile, - aiScene* pScene, IOSystem* pIOHandler) +void PLYImporter::InternReadFile(const std::string& pFile, + aiScene* pScene, IOSystem* pIOHandler) { - std::unique_ptr file( pIOHandler->Open( pFile)); + static const std::string mode = "rb"; + std::unique_ptr fileStream(pIOHandler->Open(pFile, mode)); + if (!fileStream.get()) { + throw DeadlyImportError("Failed to open file " + pFile + "."); + } - // Check whether we can read from the file - if( file.get() == NULL) { - throw DeadlyImportError( "Failed to open PLY file " + pFile + "."); + // Get the file-size + size_t fileSize = fileStream->FileSize(); + if ( 0 == fileSize ) { + throw DeadlyImportError("File " + pFile + " is empty."); + } + + IOStreamBuffer streamedBuffer(1024 * 1024); + streamedBuffer.open(fileStream.get()); + + // the beginning of the file must be PLY - magic, magic + std::vector headerCheck; + streamedBuffer.getNextLine(headerCheck); + + if ((headerCheck.size() < 3) || + (headerCheck[0] != 'P' && headerCheck[0] != 'p') || + (headerCheck[1] != 'L' && headerCheck[1] != 'l') || + (headerCheck[2] != 'Y' && headerCheck[2] != 'y') ) + { + streamedBuffer.close(); + throw DeadlyImportError("Invalid .ply file: Magic number \'ply\' is no there"); + } + + std::vector mBuffer2; + streamedBuffer.getNextLine(mBuffer2); + mBuffer = (unsigned char*)&mBuffer2[0]; + + char* szMe = (char*)&this->mBuffer[0]; + SkipSpacesAndLineEnd(szMe, (const char**)&szMe); + + // determine the format of the file data and construct the aimesh + PLY::DOM sPlyDom; + this->pcDOM = &sPlyDom; + + if (TokenMatch(szMe, "format", 6)) { + if (TokenMatch(szMe, "ascii", 5)) { + SkipLine(szMe, (const char**)&szMe); + if (!PLY::DOM::ParseInstance(streamedBuffer, &sPlyDom, this)) + { + if (mGeneratedMesh != NULL) + delete(mGeneratedMesh); + + streamedBuffer.close(); + throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#1)"); + } } + else if (!::strncmp(szMe, "binary_", 7)) + { + szMe += 7; + const bool bIsBE(isBigEndian(szMe)); - // allocate storage and copy the contents of the file to a memory buffer - std::vector mBuffer2; - TextFileToBuffer(file.get(),mBuffer2); - mBuffer = (unsigned char*)&mBuffer2[0]; + // skip the line, parse the rest of the header and build the DOM + if (!PLY::DOM::ParseInstanceBinary(streamedBuffer, &sPlyDom, this, bIsBE)) + { + if (mGeneratedMesh != NULL) + delete(mGeneratedMesh); - // the beginning of the file must be PLY - magic, magic - if ((mBuffer[0] != 'P' && mBuffer[0] != 'p') || - (mBuffer[1] != 'L' && mBuffer[1] != 'l') || - (mBuffer[2] != 'Y' && mBuffer[2] != 'y')) { - throw DeadlyImportError( "Invalid .ply file: Magic number \'ply\' is no there"); - } - - char* szMe = (char*)&this->mBuffer[3]; - SkipSpacesAndLineEnd(szMe,(const char**)&szMe); - - // determine the format of the file data - PLY::DOM sPlyDom; - if (TokenMatch(szMe,"format",6)) { - if (TokenMatch(szMe,"ascii",5)) { - SkipLine(szMe,(const char**)&szMe); - if(!PLY::DOM::ParseInstance(szMe,&sPlyDom)) - throw DeadlyImportError( "Invalid .ply file: Unable to build DOM (#1)"); - } else if (!::strncmp(szMe,"binary_",7)) - { - szMe += 7; - const bool bIsBE( isBigEndian( szMe ) ); - - // skip the line, parse the rest of the header and build the DOM - SkipLine(szMe,(const char**)&szMe); - if ( !PLY::DOM::ParseInstanceBinary( szMe, &sPlyDom, bIsBE ) ) { - throw DeadlyImportError( "Invalid .ply file: Unable to build DOM (#2)" ); - } - } else { - throw DeadlyImportError( "Invalid .ply file: Unknown file format" ); - } + streamedBuffer.close(); + throw DeadlyImportError("Invalid .ply file: Unable to build DOM (#2)"); + } } else { - AI_DEBUG_INVALIDATE_PTR(this->mBuffer); - throw DeadlyImportError( "Invalid .ply file: Missing format specification"); + if (mGeneratedMesh != NULL) + delete(mGeneratedMesh); + + streamedBuffer.close(); + throw DeadlyImportError("Invalid .ply file: Unknown file format"); } - this->pcDOM = &sPlyDom; + } + else + { + AI_DEBUG_INVALIDATE_PTR(this->mBuffer); + if (mGeneratedMesh != NULL) + delete(mGeneratedMesh); - // now load a list of vertices. This must be successfully in order to procedure - std::vector avPositions; - this->LoadVertices(&avPositions,false); + streamedBuffer.close(); + throw DeadlyImportError("Invalid .ply file: Missing format specification"); + } - if ( avPositions.empty() ) { - throw DeadlyImportError( "Invalid .ply file: No vertices found. " - "Unable to parse the data format of the PLY file." ); - } + //free the file buffer + streamedBuffer.close(); - // now load a list of normals. - std::vector avNormals; - LoadVertices(&avNormals,true); + if (mGeneratedMesh == NULL) + { + throw DeadlyImportError("Invalid .ply file: Unable to extract mesh data "); + } - // load the face list - std::vector avFaces; - LoadFaces(&avFaces); - - // if no face list is existing we assume that the vertex - // list is containing a list of triangles - if (avFaces.empty()) + // if no face list is existing we assume that the vertex + // list is containing a list of points + bool pointsOnly = mGeneratedMesh->mFaces == NULL ? true : false; + if (pointsOnly) + { + if (mGeneratedMesh->mNumVertices < 3) { - if (avPositions.size() < 3) - { - throw DeadlyImportError( "Invalid .ply file: Not enough " - "vertices to build a proper face list. "); - } + if (mGeneratedMesh != NULL) + delete(mGeneratedMesh); - const unsigned int iNum = (unsigned int)avPositions.size() / 3; - for (unsigned int i = 0; i< iNum;++i) - { - PLY::Face sFace; - sFace.mIndices.push_back((iNum*3)); - sFace.mIndices.push_back((iNum*3)+1); - sFace.mIndices.push_back((iNum*3)+2); - avFaces.push_back(sFace); - } + streamedBuffer.close(); + throw DeadlyImportError("Invalid .ply file: Not enough " + "vertices to build a proper face list. "); } - // now load a list of all materials - std::vector avMaterials; - LoadMaterial(&avMaterials); + const unsigned int iNum = (unsigned int)mGeneratedMesh->mNumVertices / 3; + mGeneratedMesh->mNumFaces = iNum; + mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces]; - // now load a list of all vertex color channels - std::vector avColors; - avColors.reserve(avPositions.size()); - LoadVertexColor(&avColors); - - // now try to load texture coordinates - std::vector avTexCoords; - avTexCoords.reserve(avPositions.size()); - LoadTextureCoordinates(&avTexCoords); - - // now replace the default material in all faces and validate all material indices - ReplaceDefaultMaterial(&avFaces,&avMaterials); - - // now convert this to a list of aiMesh instances - std::vector avMeshes; - avMeshes.reserve(avMaterials.size()+1); - ConvertMeshes(&avFaces,&avPositions,&avNormals, - &avColors,&avTexCoords,&avMaterials,&avMeshes); - - if ( avMeshes.empty() ) { - throw DeadlyImportError( "Invalid .ply file: Unable to extract mesh data " ); + for (unsigned int i = 0; i < iNum; ++i) + { + mGeneratedMesh->mFaces[i].mNumIndices = 3; + mGeneratedMesh->mFaces[i].mIndices = new unsigned int[3]; + mGeneratedMesh->mFaces[i].mIndices[0] = (i * 3); + mGeneratedMesh->mFaces[i].mIndices[1] = (i * 3) + 1; + mGeneratedMesh->mFaces[i].mIndices[2] = (i * 3) + 2; } + } - // now generate the output scene object. Fill the material list - pScene->mNumMaterials = (unsigned int)avMaterials.size(); - pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; - for ( unsigned int i = 0; i < pScene->mNumMaterials; ++i ) { - pScene->mMaterials[ i ] = avMaterials[ i ]; - } + // now load a list of all materials + std::vector avMaterials; + std::string defaultTexture; + LoadMaterial(&avMaterials, defaultTexture, pointsOnly); - // fill the mesh list - pScene->mNumMeshes = (unsigned int)avMeshes.size(); - pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; - for ( unsigned int i = 0; i < pScene->mNumMeshes; ++i ) { - pScene->mMeshes[ i ] = avMeshes[ i ]; - } + // now generate the output scene object. Fill the material list + pScene->mNumMaterials = (unsigned int)avMaterials.size(); + pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; + for (unsigned int i = 0; i < pScene->mNumMaterials; ++i) { + pScene->mMaterials[i] = avMaterials[i]; + } - // generate a simple node structure - pScene->mRootNode = new aiNode(); - pScene->mRootNode->mNumMeshes = pScene->mNumMeshes; - pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes]; + // fill the mesh list + pScene->mNumMeshes = 1; + pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; + pScene->mMeshes[0] = mGeneratedMesh; - for ( unsigned int i = 0; i < pScene->mRootNode->mNumMeshes; ++i ) { - pScene->mRootNode->mMeshes[ i ] = i; - } + // generate a simple node structure + pScene->mRootNode = new aiNode(); + pScene->mRootNode->mNumMeshes = pScene->mNumMeshes; + pScene->mRootNode->mMeshes = new unsigned int[pScene->mNumMeshes]; + + for (unsigned int i = 0; i < pScene->mRootNode->mNumMeshes; ++i) { + pScene->mRootNode->mMeshes[i] = i; + } } -// ------------------------------------------------------------------------------------------------ -// Split meshes by material IDs -void PLYImporter::ConvertMeshes(std::vector* avFaces, - const std::vector* avPositions, - const std::vector* avNormals, - const std::vector* avColors, - const std::vector* avTexCoords, - const std::vector* avMaterials, - std::vector* avOut) -{ - ai_assert(NULL != avFaces); - ai_assert(NULL != avPositions); - ai_assert(NULL != avMaterials); +void PLYImporter::LoadVertex(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos) { + ai_assert(NULL != pcElement); + ai_assert(NULL != instElement); - // split by materials - std::vector* aiSplit = new std::vector[avMaterials->size()]; + ai_uint aiPositions[3] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + PLY::EDataType aiTypes[3] = { EDT_Char, EDT_Char, EDT_Char }; - unsigned int iNum = 0; - for (std::vector::const_iterator i = avFaces->begin();i != avFaces->end();++i,++iNum) - aiSplit[(*i).iMaterialIndex].push_back(iNum); + ai_uint aiNormal[3] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + PLY::EDataType aiNormalTypes[3] = { EDT_Char, EDT_Char, EDT_Char }; - // now generate sub-meshes - for (unsigned int p = 0; p < avMaterials->size();++p) - { - if (aiSplit[p].size() != 0) - { - // allocate the mesh object - aiMesh* p_pcOut = new aiMesh(); - p_pcOut->mMaterialIndex = p; + unsigned int aiColors[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }; + PLY::EDataType aiColorsTypes[4] = { EDT_Char, EDT_Char, EDT_Char, EDT_Char }; - p_pcOut->mNumFaces = (unsigned int)aiSplit[p].size(); - p_pcOut->mFaces = new aiFace[aiSplit[p].size()]; + unsigned int aiTexcoord[2] = { 0xFFFFFFFF, 0xFFFFFFFF }; + PLY::EDataType aiTexcoordTypes[2] = { EDT_Char, EDT_Char }; - // at first we need to determine the size of the output vector array - unsigned int iNum = 0; - for (unsigned int i = 0; i < aiSplit[p].size();++i) - { - iNum += (unsigned int)(*avFaces)[aiSplit[p][i]].mIndices.size(); - } - p_pcOut->mNumVertices = iNum; - if( 0 == iNum ) { // nothing to do - delete[] aiSplit; // cleanup - delete p_pcOut; - return; - } - p_pcOut->mVertices = new aiVector3D[iNum]; - - if (!avColors->empty()) - p_pcOut->mColors[0] = new aiColor4D[iNum]; - if (!avTexCoords->empty()) - { - p_pcOut->mNumUVComponents[0] = 2; - p_pcOut->mTextureCoords[0] = new aiVector3D[iNum]; - } - if (!avNormals->empty()) - p_pcOut->mNormals = new aiVector3D[iNum]; - - // add all faces - iNum = 0; - unsigned int iVertex = 0; - for (std::vector::const_iterator i = aiSplit[p].begin(); - i != aiSplit[p].end();++i,++iNum) - { - p_pcOut->mFaces[iNum].mNumIndices = (unsigned int)(*avFaces)[*i].mIndices.size(); - p_pcOut->mFaces[iNum].mIndices = new unsigned int[p_pcOut->mFaces[iNum].mNumIndices]; - - // build an unique set of vertices/colors for this face - for (unsigned int q = 0; q < p_pcOut->mFaces[iNum].mNumIndices;++q) - { - p_pcOut->mFaces[iNum].mIndices[q] = iVertex; - const size_t idx = ( *avFaces )[ *i ].mIndices[ q ]; - if( idx >= ( *avPositions ).size() ) { - // out of border - continue; - } - p_pcOut->mVertices[ iVertex ] = ( *avPositions )[ idx ]; - - if (!avColors->empty()) - p_pcOut->mColors[ 0 ][ iVertex ] = ( *avColors )[ idx ]; - - if (!avTexCoords->empty()) - { - const aiVector2D& vec = ( *avTexCoords )[ idx ]; - p_pcOut->mTextureCoords[0][iVertex].x = vec.x; - p_pcOut->mTextureCoords[0][iVertex].y = vec.y; - } - - if (!avNormals->empty()) - p_pcOut->mNormals[ iVertex ] = ( *avNormals )[ idx ]; - iVertex++; - } - - } - // add the mesh to the output list - avOut->push_back(p_pcOut); + // now check whether which normal components are available + unsigned int _a( 0 ), cnt( 0 ); + for ( std::vector::const_iterator a = pcElement->alProperties.begin(); + a != pcElement->alProperties.end(); ++a, ++_a) { + if ((*a).bIsList) { + continue; } - } - delete[] aiSplit; // cleanup -} -// ------------------------------------------------------------------------------------------------ -// Generate a default material if none was specified and apply it to all vanilla faces -void PLYImporter::ReplaceDefaultMaterial(std::vector* avFaces, - std::vector* avMaterials) -{ - bool bNeedDefaultMat = false; - - for (std::vector::iterator i = avFaces->begin();i != avFaces->end();++i) { - if (0xFFFFFFFF == (*i).iMaterialIndex) { - bNeedDefaultMat = true; - (*i).iMaterialIndex = (unsigned int)avMaterials->size(); - } - else if ((*i).iMaterialIndex >= avMaterials->size() ) { - // clamp the index - (*i).iMaterialIndex = (unsigned int)avMaterials->size()-1; + // Positions + if (PLY::EST_XCoord == (*a).Semantic) { + ++cnt; + aiPositions[0] = _a; + aiTypes[0] = (*a).eType; + } else if (PLY::EST_YCoord == (*a).Semantic) { + ++cnt; + aiPositions[1] = _a; + aiTypes[1] = (*a).eType; + } else if (PLY::EST_ZCoord == (*a).Semantic) { + ++cnt; + aiPositions[2] = _a; + aiTypes[2] = (*a).eType; + } else if (PLY::EST_XNormal == (*a).Semantic) { + // Normals + ++cnt; + aiNormal[0] = _a; + aiNormalTypes[0] = (*a).eType; + } else if (PLY::EST_YNormal == (*a).Semantic) { + ++cnt; + aiNormal[1] = _a; + aiNormalTypes[1] = (*a).eType; + } else if (PLY::EST_ZNormal == (*a).Semantic) { + ++cnt; + aiNormal[2] = _a; + aiNormalTypes[2] = (*a).eType; + } else if (PLY::EST_Red == (*a).Semantic) { + // Colors + ++cnt; + aiColors[0] = _a; + aiColorsTypes[0] = (*a).eType; + } else if (PLY::EST_Green == (*a).Semantic) { + ++cnt; + aiColors[1] = _a; + aiColorsTypes[1] = (*a).eType; + } else if (PLY::EST_Blue == (*a).Semantic) { + ++cnt; + aiColors[2] = _a; + aiColorsTypes[2] = (*a).eType; + } else if (PLY::EST_Alpha == (*a).Semantic) { + ++cnt; + aiColors[3] = _a; + aiColorsTypes[3] = (*a).eType; + } else if (PLY::EST_UTextureCoord == (*a).Semantic) { + // Texture coordinates + ++cnt; + aiTexcoord[0] = _a; + aiTexcoordTypes[0] = (*a).eType; + } else if (PLY::EST_VTextureCoord == (*a).Semantic) { + ++cnt; + aiTexcoord[1] = _a; + aiTexcoordTypes[1] = (*a).eType; } } - if (bNeedDefaultMat) { - // generate a default material - aiMaterial* pcHelper = new aiMaterial(); - - // fill in a default material - int iMode = (int)aiShadingMode_Gouraud; - pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); - - aiColor3D clr; - clr.b = clr.g = clr.r = 0.6f; - pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_DIFFUSE); - pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_SPECULAR); - - clr.b = clr.g = clr.r = 0.05f; - pcHelper->AddProperty(&clr, 1,AI_MATKEY_COLOR_AMBIENT); - - // The face order is absolutely undefined for PLY, so we have to - // use two-sided rendering to be sure it's ok. - const int two_sided = 1; - pcHelper->AddProperty(&two_sided,1,AI_MATKEY_TWOSIDED); - - avMaterials->push_back(pcHelper); - } -} - -// ------------------------------------------------------------------------------------------------ -void PLYImporter::LoadTextureCoordinates(std::vector* pvOut) -{ - ai_assert(NULL != pvOut); - - unsigned int aiPositions[2] = {0xFFFFFFFF,0xFFFFFFFF}; - PLY::EDataType aiTypes[2] = {EDT_Char,EDT_Char}; - PLY::ElementInstanceList* pcList = NULL; - unsigned int cnt = 0; - - // search in the DOM for a vertex entry - unsigned int _i = 0; - for (std::vector::const_iterator i = pcDOM->alElements.begin(); - i != pcDOM->alElements.end();++i,++_i) - { - if (PLY::EEST_Vertex == (*i).eSemantic) - { - pcList = &this->pcDOM->alElementData[_i]; - - // now check whether which normal components are available - unsigned int _a = 0; - for (std::vector::const_iterator a = (*i).alProperties.begin(); - a != (*i).alProperties.end();++a,++_a) - { - if ((*a).bIsList)continue; - if (PLY::EST_UTextureCoord == (*a).Semantic) - { - cnt++; - aiPositions[0] = _a; - aiTypes[0] = (*a).eType; - } - else if (PLY::EST_VTextureCoord == (*a).Semantic) - { - cnt++; - aiPositions[1] = _a; - aiTypes[1] = (*a).eType; - } - } - } - } - // check whether we have a valid source for the texture coordinates data - if (NULL != pcList && 0 != cnt) - { - pvOut->reserve(pcList->alInstances.size()); - for (std::vector::const_iterator i = pcList->alInstances.begin(); - i != pcList->alInstances.end();++i) - { - // convert the vertices to sp floats - aiVector2D vOut; - - if (0xFFFFFFFF != aiPositions[0]) - { - vOut.x = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, aiPositions[0]).avList.front(),aiTypes[0]); - } - - if (0xFFFFFFFF != aiPositions[1]) - { - vOut.y = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, aiPositions[1]).avList.front(),aiTypes[1]); - } - // and add them to our nice list - pvOut->push_back(vOut); - } - } -} - -// ------------------------------------------------------------------------------------------------ -// Try to extract vertices from the PLY DOM -void PLYImporter::LoadVertices(std::vector* pvOut, bool p_bNormals) -{ - ai_assert(NULL != pvOut); - - ai_uint aiPositions[3] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; - PLY::EDataType aiTypes[3] = {EDT_Char,EDT_Char,EDT_Char}; - PLY::ElementInstanceList* pcList = NULL; - unsigned int cnt = 0; - - // search in the DOM for a vertex entry - unsigned int _i = 0; - for (std::vector::const_iterator i = pcDOM->alElements.begin(); - i != pcDOM->alElements.end();++i,++_i) - { - if (PLY::EEST_Vertex == (*i).eSemantic) - { - pcList = &pcDOM->alElementData[_i]; - - // load normal vectors? - if (p_bNormals) - { - // now check whether which normal components are available - unsigned int _a = 0; - for (std::vector::const_iterator a = (*i).alProperties.begin(); - a != (*i).alProperties.end();++a,++_a) - { - if ((*a).bIsList)continue; - if (PLY::EST_XNormal == (*a).Semantic) - { - cnt++; - aiPositions[0] = _a; - aiTypes[0] = (*a).eType; - } - else if (PLY::EST_YNormal == (*a).Semantic) - { - cnt++; - aiPositions[1] = _a; - aiTypes[1] = (*a).eType; - } - else if (PLY::EST_ZNormal == (*a).Semantic) - { - cnt++; - aiPositions[2] = _a; - aiTypes[2] = (*a).eType; - } - } - } - // load vertex coordinates - else - { - // now check whether which coordinate sets are available - unsigned int _a = 0; - for (std::vector::const_iterator a = (*i).alProperties.begin(); - a != (*i).alProperties.end();++a,++_a) - { - if ((*a).bIsList)continue; - if (PLY::EST_XCoord == (*a).Semantic) - { - cnt++; - aiPositions[0] = _a; - aiTypes[0] = (*a).eType; - } - else if (PLY::EST_YCoord == (*a).Semantic) - { - cnt++; - aiPositions[1] = _a; - aiTypes[1] = (*a).eType; - } - else if (PLY::EST_ZCoord == (*a).Semantic) - { - cnt++; - aiPositions[2] = _a; - aiTypes[2] = (*a).eType; - } - if (3 == cnt)break; - } - } - break; - } - } // check whether we have a valid source for the vertex data - if (NULL != pcList && 0 != cnt) - { - pvOut->reserve(pcList->alInstances.size()); - for (std::vector::const_iterator - i = pcList->alInstances.begin(); - i != pcList->alInstances.end();++i) - { - // convert the vertices to sp floats - aiVector3D vOut; + if (0 != cnt) { + // Position + aiVector3D vOut; + if (0xFFFFFFFF != aiPositions[0]) { + vOut.x = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiPositions[0]).avList.front(), aiTypes[0]); + } - if (0xFFFFFFFF != aiPositions[0]) - { - vOut.x = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, aiPositions[0]).avList.front(),aiTypes[0]); + if (0xFFFFFFFF != aiPositions[1]) { + vOut.y = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiPositions[1]).avList.front(), aiTypes[1]); + } + + if (0xFFFFFFFF != aiPositions[2]) { + vOut.z = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiPositions[2]).avList.front(), aiTypes[2]); + } + + // Normals + aiVector3D nOut; + bool haveNormal = false; + if (0xFFFFFFFF != aiNormal[0]) { + nOut.x = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiNormal[0]).avList.front(), aiNormalTypes[0]); + haveNormal = true; + } + + if (0xFFFFFFFF != aiNormal[1]) { + nOut.y = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiNormal[1]).avList.front(), aiNormalTypes[1]); + haveNormal = true; + } + + if (0xFFFFFFFF != aiNormal[2]) { + nOut.z = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiNormal[2]).avList.front(), aiNormalTypes[2]); + haveNormal = true; + } + + //Colors + aiColor4D cOut; + bool haveColor = false; + if (0xFFFFFFFF != aiColors[0]) { + cOut.r = NormalizeColorValue(GetProperty(instElement->alProperties, + aiColors[0]).avList.front(), aiColorsTypes[0]); + haveColor = true; + } + + if (0xFFFFFFFF != aiColors[1]) { + cOut.g = NormalizeColorValue(GetProperty(instElement->alProperties, + aiColors[1]).avList.front(), aiColorsTypes[1]); + haveColor = true; + } + + if (0xFFFFFFFF != aiColors[2]) { + cOut.b = NormalizeColorValue(GetProperty(instElement->alProperties, + aiColors[2]).avList.front(), aiColorsTypes[2]); + haveColor = true; + } + + // assume 1.0 for the alpha channel ifit is not set + if (0xFFFFFFFF == aiColors[3]) { + cOut.a = 1.0; + } else { + cOut.a = NormalizeColorValue(GetProperty(instElement->alProperties, + aiColors[3]).avList.front(), aiColorsTypes[3]); + + haveColor = true; + } + + //Texture coordinates + aiVector3D tOut; + tOut.z = 0; + bool haveTextureCoords = false; + if (0xFFFFFFFF != aiTexcoord[0]) { + tOut.x = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiTexcoord[0]).avList.front(), aiTexcoordTypes[0]); + haveTextureCoords = true; + } + + if (0xFFFFFFFF != aiTexcoord[1]) { + tOut.y = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, aiTexcoord[1]).avList.front(), aiTexcoordTypes[1]); + haveTextureCoords = true; + } + + //create aiMesh if needed + if ( nullptr == mGeneratedMesh ) { + mGeneratedMesh = new aiMesh(); + mGeneratedMesh->mMaterialIndex = 0; + } + + if (nullptr == mGeneratedMesh->mVertices) { + mGeneratedMesh->mNumVertices = pcElement->NumOccur; + mGeneratedMesh->mVertices = new aiVector3D[mGeneratedMesh->mNumVertices]; + } + + mGeneratedMesh->mVertices[pos] = vOut; + + if (haveNormal) { + if (nullptr == mGeneratedMesh->mNormals) + mGeneratedMesh->mNormals = new aiVector3D[mGeneratedMesh->mNumVertices]; + mGeneratedMesh->mNormals[pos] = nOut; + } + + if (haveColor) { + if (nullptr == mGeneratedMesh->mColors[0]) + mGeneratedMesh->mColors[0] = new aiColor4D[mGeneratedMesh->mNumVertices]; + mGeneratedMesh->mColors[0][pos] = cOut; + } + + if (haveTextureCoords) { + if (nullptr == mGeneratedMesh->mTextureCoords[0]) { + mGeneratedMesh->mNumUVComponents[0] = 2; + mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices]; } - - if (0xFFFFFFFF != aiPositions[1]) - { - vOut.y = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, aiPositions[1]).avList.front(),aiTypes[1]); - } - - if (0xFFFFFFFF != aiPositions[2]) - { - vOut.z = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, aiPositions[2]).avList.front(),aiTypes[2]); - } - - // and add them to our nice list - pvOut->push_back(vOut); + mGeneratedMesh->mTextureCoords[0][pos] = tOut; } } } + // ------------------------------------------------------------------------------------------------ // Convert a color component to [0...1] -ai_real PLYImporter::NormalizeColorValue (PLY::PropertyInstance::ValueUnion val, - PLY::EDataType eType) +ai_real PLYImporter::NormalizeColorValue(PLY::PropertyInstance::ValueUnion val, + PLY::EDataType eType) { - switch (eType) - { - case EDT_Float: - return val.fFloat; - case EDT_Double: - return (ai_real)val.fDouble; + switch (eType) + { + case EDT_Float: + return val.fFloat; + case EDT_Double: + return (ai_real)val.fDouble; - case EDT_UChar: - return (ai_real)val.iUInt / (ai_real)0xFF; - case EDT_Char: - return (ai_real)(val.iInt+(0xFF/2)) / (ai_real)0xFF; - case EDT_UShort: - return (ai_real)val.iUInt / (ai_real)0xFFFF; - case EDT_Short: - return (ai_real)(val.iInt+(0xFFFF/2)) / (ai_real)0xFFFF; - case EDT_UInt: - return (ai_real)val.iUInt / (ai_real)0xFFFF; - case EDT_Int: - return ((ai_real)val.iInt / (ai_real)0xFF) + 0.5f; - default: ; - }; - return 0.0f; -} - -// ------------------------------------------------------------------------------------------------ -// Try to extract proper vertex colors from the PLY DOM -void PLYImporter::LoadVertexColor(std::vector* pvOut) -{ - ai_assert(NULL != pvOut); - - unsigned int aiPositions[4] = {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; - PLY::EDataType aiTypes[4] = {EDT_Char, EDT_Char, EDT_Char, EDT_Char}; // silencing gcc - unsigned int cnt = 0; - PLY::ElementInstanceList* pcList = NULL; - - // search in the DOM for a vertex entry - unsigned int _i = 0; - for (std::vector::const_iterator i = pcDOM->alElements.begin(); - i != pcDOM->alElements.end();++i,++_i) - { - if (PLY::EEST_Vertex == (*i).eSemantic) - { - pcList = &this->pcDOM->alElementData[_i]; - - // now check whether which coordinate sets are available - unsigned int _a = 0; - for (std::vector::const_iterator - a = (*i).alProperties.begin(); - a != (*i).alProperties.end();++a,++_a) - { - if ((*a).bIsList)continue; - if (PLY::EST_Red == (*a).Semantic) - { - cnt++; - aiPositions[0] = _a; - aiTypes[0] = (*a).eType; - } - else if (PLY::EST_Green == (*a).Semantic) - { - cnt++; - aiPositions[1] = _a; - aiTypes[1] = (*a).eType; - } - else if (PLY::EST_Blue == (*a).Semantic) - { - cnt++; - aiPositions[2] = _a; - aiTypes[2] = (*a).eType; - } - else if (PLY::EST_Alpha == (*a).Semantic) - { - cnt++; - aiPositions[3] = _a; - aiTypes[3] = (*a).eType; - } - if (4 == cnt)break; - } - break; - } - } - // check whether we have a valid source for the vertex data - if (NULL != pcList && 0 != cnt) - { - pvOut->reserve(pcList->alInstances.size()); - for (std::vector::const_iterator i = pcList->alInstances.begin(); - i != pcList->alInstances.end();++i) - { - // convert the vertices to sp floats - aiColor4D vOut; - - if (0xFFFFFFFF != aiPositions[0]) - { - vOut.r = NormalizeColorValue(GetProperty((*i).alProperties, - aiPositions[0]).avList.front(),aiTypes[0]); - } - - if (0xFFFFFFFF != aiPositions[1]) - { - vOut.g = NormalizeColorValue(GetProperty((*i).alProperties, - aiPositions[1]).avList.front(),aiTypes[1]); - } - - if (0xFFFFFFFF != aiPositions[2]) - { - vOut.b = NormalizeColorValue(GetProperty((*i).alProperties, - aiPositions[2]).avList.front(),aiTypes[2]); - } - - // assume 1.0 for the alpha channel ifit is not set - if (0xFFFFFFFF == aiPositions[3])vOut.a = 1.0; - else - { - vOut.a = NormalizeColorValue(GetProperty((*i).alProperties, - aiPositions[3]).avList.front(),aiTypes[3]); - } - - // and add them to our nice list - pvOut->push_back(vOut); - } - } + case EDT_UChar: + return (ai_real)val.iUInt / (ai_real)0xFF; + case EDT_Char: + return (ai_real)(val.iInt + (0xFF / 2)) / (ai_real)0xFF; + case EDT_UShort: + return (ai_real)val.iUInt / (ai_real)0xFFFF; + case EDT_Short: + return (ai_real)(val.iInt + (0xFFFF / 2)) / (ai_real)0xFFFF; + case EDT_UInt: + return (ai_real)val.iUInt / (ai_real)0xFFFF; + case EDT_Int: + return ((ai_real)val.iInt / (ai_real)0xFF) + 0.5f; + default:; + }; + return 0.0f; } // ------------------------------------------------------------------------------------------------ // Try to extract proper faces from the PLY DOM -void PLYImporter::LoadFaces(std::vector* pvOut) +void PLYImporter::LoadFace(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos) { - ai_assert(NULL != pvOut); + ai_assert(NULL != pcElement); + ai_assert(NULL != instElement); - PLY::ElementInstanceList* pcList = NULL; - bool bOne = false; + if (mGeneratedMesh == NULL) + throw DeadlyImportError("Invalid .ply file: Vertices should be declared before faces"); - // index of the vertex index list - unsigned int iProperty = 0xFFFFFFFF; - PLY::EDataType eType = EDT_Char; - bool bIsTriStrip = false; + bool bOne = false; - // index of the material index property - unsigned int iMaterialIndex = 0xFFFFFFFF; - PLY::EDataType eType2 = EDT_Char; + // index of the vertex index list + unsigned int iProperty = 0xFFFFFFFF; + PLY::EDataType eType = EDT_Char; + bool bIsTriStrip = false; - // search in the DOM for a face entry - unsigned int _i = 0; - for (std::vector::const_iterator i = pcDOM->alElements.begin(); - i != pcDOM->alElements.end();++i,++_i) + // index of the material index property + //unsigned int iMaterialIndex = 0xFFFFFFFF; + //PLY::EDataType eType2 = EDT_Char; + + // texture coordinates + unsigned int iTextureCoord = 0xFFFFFFFF; + PLY::EDataType eType3 = EDT_Char; + + // face = unique number of vertex indices + if (PLY::EEST_Face == pcElement->eSemantic) + { + unsigned int _a = 0; + for (std::vector::const_iterator a = pcElement->alProperties.begin(); + a != pcElement->alProperties.end(); ++a, ++_a) { - // face = unique number of vertex indices - if (PLY::EEST_Face == (*i).eSemantic) - { - pcList = &pcDOM->alElementData[_i]; - unsigned int _a = 0; - for (std::vector::const_iterator a = (*i).alProperties.begin(); - a != (*i).alProperties.end();++a,++_a) - { - if (PLY::EST_VertexIndex == (*a).Semantic) - { - // must be a dynamic list! - if (!(*a).bIsList)continue; - iProperty = _a; - bOne = true; - eType = (*a).eType; - } - else if (PLY::EST_MaterialIndex == (*a).Semantic) - { - if ((*a).bIsList)continue; - iMaterialIndex = _a; - bOne = true; - eType2 = (*a).eType; - } - } - break; - } - // triangle strip - // TODO: triangle strip and material index support??? - else if (PLY::EEST_TriStrip == (*i).eSemantic) - { - // find a list property in this ... - pcList = &this->pcDOM->alElementData[_i]; - unsigned int _a = 0; - for (std::vector::const_iterator a = (*i).alProperties.begin(); - a != (*i).alProperties.end();++a,++_a) - { - // must be a dynamic list! - if (!(*a).bIsList)continue; - iProperty = _a; - bOne = true; - bIsTriStrip = true; - eType = (*a).eType; - break; - } - break; - } + if (PLY::EST_VertexIndex == (*a).Semantic) + { + // must be a dynamic list! + if (!(*a).bIsList) + continue; + + iProperty = _a; + bOne = true; + eType = (*a).eType; + } + /*else if (PLY::EST_MaterialIndex == (*a).Semantic) + { + if ((*a).bIsList) + continue; + iMaterialIndex = _a; + bOne = true; + eType2 = (*a).eType; + }*/ + else if (PLY::EST_TextureCoordinates == (*a).Semantic) + { + // must be a dynamic list! + if (!(*a).bIsList) + continue; + iTextureCoord = _a; + bOne = true; + eType3 = (*a).eType; + } } - // check whether we have at least one per-face information set - if (pcList && bOne) + } + // triangle strip + // TODO: triangle strip and material index support??? + else if (PLY::EEST_TriStrip == pcElement->eSemantic) + { + unsigned int _a = 0; + for (std::vector::const_iterator a = pcElement->alProperties.begin(); + a != pcElement->alProperties.end(); ++a, ++_a) { - if (!bIsTriStrip) - { - pvOut->reserve(pcList->alInstances.size()); - for (std::vector::const_iterator i = pcList->alInstances.begin(); - i != pcList->alInstances.end();++i) - { - PLY::Face sFace; - - // parse the list of vertex indices - if (0xFFFFFFFF != iProperty) - { - const unsigned int iNum = (unsigned int)GetProperty((*i).alProperties, iProperty).avList.size(); - sFace.mIndices.resize(iNum); - - std::vector::const_iterator p = - GetProperty((*i).alProperties, iProperty).avList.begin(); - - for (unsigned int a = 0; a < iNum;++a,++p) - { - sFace.mIndices[a] = PLY::PropertyInstance::ConvertTo(*p,eType); - } - } - - // parse the material index - if (0xFFFFFFFF != iMaterialIndex) - { - sFace.iMaterialIndex = PLY::PropertyInstance::ConvertTo( - GetProperty((*i).alProperties, iMaterialIndex).avList.front(),eType2); - } - pvOut->push_back(sFace); - } - } - else // triangle strips - { - // normally we have only one triangle strip instance where - // a value of -1 indicates a restart of the strip - bool flip = false; - for (std::vector::const_iterator i = pcList->alInstances.begin();i != pcList->alInstances.end();++i) { - const std::vector& quak = GetProperty((*i).alProperties, iProperty).avList; - pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u)); - - int aiTable[2] = {-1,-1}; - for (std::vector::const_iterator a = quak.begin();a != quak.end();++a) { - const int p = PLY::PropertyInstance::ConvertTo(*a,eType); - - if (-1 == p) { - // restart the strip ... - aiTable[0] = aiTable[1] = -1; - flip = false; - continue; - } - if (-1 == aiTable[0]) { - aiTable[0] = p; - continue; - } - if (-1 == aiTable[1]) { - aiTable[1] = p; - continue; - } - - pvOut->push_back(PLY::Face()); - PLY::Face& sFace = pvOut->back(); - sFace.mIndices[0] = aiTable[0]; - sFace.mIndices[1] = aiTable[1]; - sFace.mIndices[2] = p; - if ((flip = !flip)) { - std::swap(sFace.mIndices[0],sFace.mIndices[1]); - } - - aiTable[0] = aiTable[1]; - aiTable[1] = p; - } - } - } + // must be a dynamic list! + if (!(*a).bIsList) + continue; + iProperty = _a; + bOne = true; + bIsTriStrip = true; + eType = (*a).eType; + break; } + } + + // check whether we have at least one per-face information set + if (bOne) + { + if (mGeneratedMesh->mFaces == NULL) + { + mGeneratedMesh->mNumFaces = pcElement->NumOccur; + mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces]; + } + + if (!bIsTriStrip) + { + // parse the list of vertex indices + if (0xFFFFFFFF != iProperty) + { + const unsigned int iNum = (unsigned int)GetProperty(instElement->alProperties, iProperty).avList.size(); + mGeneratedMesh->mFaces[pos].mNumIndices = iNum; + mGeneratedMesh->mFaces[pos].mIndices = new unsigned int[iNum]; + + std::vector::const_iterator p = + GetProperty(instElement->alProperties, iProperty).avList.begin(); + + for (unsigned int a = 0; a < iNum; ++a, ++p) + { + mGeneratedMesh->mFaces[pos].mIndices[a] = PLY::PropertyInstance::ConvertTo(*p, eType); + } + } + + // parse the material index + // cannot be handled without processing the whole file first + /*if (0xFFFFFFFF != iMaterialIndex) + { + mGeneratedMesh->mFaces[pos]. = PLY::PropertyInstance::ConvertTo( + GetProperty(instElement->alProperties, iMaterialIndex).avList.front(), eType2); + }*/ + + if (0xFFFFFFFF != iTextureCoord) + { + const unsigned int iNum = (unsigned int)GetProperty(instElement->alProperties, iTextureCoord).avList.size(); + + //should be 6 coords + std::vector::const_iterator p = + GetProperty(instElement->alProperties, iTextureCoord).avList.begin(); + + if ((iNum / 3) == 2) // X Y coord + { + for (unsigned int a = 0; a < iNum; ++a, ++p) + { + unsigned int vindex = mGeneratedMesh->mFaces[pos].mIndices[a / 2]; + if (vindex < mGeneratedMesh->mNumVertices) + { + if (mGeneratedMesh->mTextureCoords[0] == NULL) + { + mGeneratedMesh->mNumUVComponents[0] = 2; + mGeneratedMesh->mTextureCoords[0] = new aiVector3D[mGeneratedMesh->mNumVertices]; + } + + if (a % 2 == 0) + mGeneratedMesh->mTextureCoords[0][vindex].x = PLY::PropertyInstance::ConvertTo(*p, eType3); + else + mGeneratedMesh->mTextureCoords[0][vindex].y = PLY::PropertyInstance::ConvertTo(*p, eType3); + + mGeneratedMesh->mTextureCoords[0][vindex].z = 0; + } + } + } + } + } + else // triangle strips + { + // normally we have only one triangle strip instance where + // a value of -1 indicates a restart of the strip + bool flip = false; + const std::vector& quak = GetProperty(instElement->alProperties, iProperty).avList; + //pvOut->reserve(pvOut->size() + quak.size() + (quak.size()>>2u)); //Limits memory consumption + + int aiTable[2] = { -1, -1 }; + for (std::vector::const_iterator a = quak.begin(); a != quak.end(); ++a) { + const int p = PLY::PropertyInstance::ConvertTo(*a, eType); + + if (-1 == p) { + // restart the strip ... + aiTable[0] = aiTable[1] = -1; + flip = false; + continue; + } + if (-1 == aiTable[0]) { + aiTable[0] = p; + continue; + } + if (-1 == aiTable[1]) { + aiTable[1] = p; + continue; + } + + if (mGeneratedMesh->mFaces == NULL) + { + mGeneratedMesh->mNumFaces = pcElement->NumOccur; + mGeneratedMesh->mFaces = new aiFace[mGeneratedMesh->mNumFaces]; + } + + mGeneratedMesh->mFaces[pos].mNumIndices = 3; + mGeneratedMesh->mFaces[pos].mIndices = new unsigned int[3]; + mGeneratedMesh->mFaces[pos].mIndices[0] = aiTable[0]; + mGeneratedMesh->mFaces[pos].mIndices[1] = aiTable[1]; + mGeneratedMesh->mFaces[pos].mIndices[2] = p; + + if ((flip = !flip)) { + std::swap(mGeneratedMesh->mFaces[pos].mIndices[0], mGeneratedMesh->mFaces[pos].mIndices[1]); + } + + aiTable[0] = aiTable[1]; + aiTable[1] = p; + } + } + } } // ------------------------------------------------------------------------------------------------ // Get a RGBA color in [0...1] range void PLYImporter::GetMaterialColor(const std::vector& avList, - unsigned int aiPositions[4], - PLY::EDataType aiTypes[4], - aiColor4D* clrOut) + unsigned int aiPositions[4], + PLY::EDataType aiTypes[4], + aiColor4D* clrOut) { - ai_assert(NULL != clrOut); + ai_assert(NULL != clrOut); - if (0xFFFFFFFF == aiPositions[0])clrOut->r = 0.0f; - else - { - clrOut->r = NormalizeColorValue(GetProperty(avList, - aiPositions[0]).avList.front(),aiTypes[0]); - } + if (0xFFFFFFFF == aiPositions[0])clrOut->r = 0.0f; + else + { + clrOut->r = NormalizeColorValue(GetProperty(avList, + aiPositions[0]).avList.front(), aiTypes[0]); + } - if (0xFFFFFFFF == aiPositions[1])clrOut->g = 0.0f; - else - { - clrOut->g = NormalizeColorValue(GetProperty(avList, - aiPositions[1]).avList.front(),aiTypes[1]); - } + if (0xFFFFFFFF == aiPositions[1])clrOut->g = 0.0f; + else + { + clrOut->g = NormalizeColorValue(GetProperty(avList, + aiPositions[1]).avList.front(), aiTypes[1]); + } - if (0xFFFFFFFF == aiPositions[2])clrOut->b = 0.0f; - else - { - clrOut->b = NormalizeColorValue(GetProperty(avList, - aiPositions[2]).avList.front(),aiTypes[2]); - } + if (0xFFFFFFFF == aiPositions[2])clrOut->b = 0.0f; + else + { + clrOut->b = NormalizeColorValue(GetProperty(avList, + aiPositions[2]).avList.front(), aiTypes[2]); + } - // assume 1.0 for the alpha channel ifit is not set - if (0xFFFFFFFF == aiPositions[3])clrOut->a = 1.0f; - else - { - clrOut->a = NormalizeColorValue(GetProperty(avList, - aiPositions[3]).avList.front(),aiTypes[3]); - } + // assume 1.0 for the alpha channel ifit is not set + if (0xFFFFFFFF == aiPositions[3])clrOut->a = 1.0f; + else + { + clrOut->a = NormalizeColorValue(GetProperty(avList, + aiPositions[3]).avList.front(), aiTypes[3]); + } } // ------------------------------------------------------------------------------------------------ // Extract a material from the PLY DOM -void PLYImporter::LoadMaterial(std::vector* pvOut) +void PLYImporter::LoadMaterial(std::vector* pvOut, std::string &defaultTexture, const bool pointsOnly) { - ai_assert(NULL != pvOut); + ai_assert(NULL != pvOut); - // diffuse[4], specular[4], ambient[4] - // rgba order - unsigned int aaiPositions[3][4] = { + // diffuse[4], specular[4], ambient[4] + // rgba order + unsigned int aaiPositions[3][4] = { - {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}, - {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}, - {0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}, - }; + { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, + { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF }, + }; - PLY::EDataType aaiTypes[3][4] = { - {EDT_Char,EDT_Char,EDT_Char,EDT_Char}, - {EDT_Char,EDT_Char,EDT_Char,EDT_Char}, - {EDT_Char,EDT_Char,EDT_Char,EDT_Char} - }; - PLY::ElementInstanceList* pcList = NULL; + PLY::EDataType aaiTypes[3][4] = { + { EDT_Char, EDT_Char, EDT_Char, EDT_Char }, + { EDT_Char, EDT_Char, EDT_Char, EDT_Char }, + { EDT_Char, EDT_Char, EDT_Char, EDT_Char } + }; + PLY::ElementInstanceList* pcList = NULL; - unsigned int iPhong = 0xFFFFFFFF; - PLY::EDataType ePhong = EDT_Char; + unsigned int iPhong = 0xFFFFFFFF; + PLY::EDataType ePhong = EDT_Char; - unsigned int iOpacity = 0xFFFFFFFF; - PLY::EDataType eOpacity = EDT_Char; + unsigned int iOpacity = 0xFFFFFFFF; + PLY::EDataType eOpacity = EDT_Char; - // search in the DOM for a vertex entry - unsigned int _i = 0; - for (std::vector::const_iterator i = this->pcDOM->alElements.begin(); - i != this->pcDOM->alElements.end();++i,++_i) + // search in the DOM for a vertex entry + unsigned int _i = 0; + for (std::vector::const_iterator i = this->pcDOM->alElements.begin(); + i != this->pcDOM->alElements.end(); ++i, ++_i) + { + if (PLY::EEST_Material == (*i).eSemantic) { - if (PLY::EEST_Material == (*i).eSemantic) + pcList = &this->pcDOM->alElementData[_i]; + + // now check whether which coordinate sets are available + unsigned int _a = 0; + for (std::vector::const_iterator + a = (*i).alProperties.begin(); + a != (*i).alProperties.end(); ++a, ++_a) + { + if ((*a).bIsList)continue; + + // pohng specularity ----------------------------------- + if (PLY::EST_PhongPower == (*a).Semantic) { - pcList = &this->pcDOM->alElementData[_i]; - - // now check whether which coordinate sets are available - unsigned int _a = 0; - for (std::vector::const_iterator - a = (*i).alProperties.begin(); - a != (*i).alProperties.end();++a,++_a) - { - if ((*a).bIsList)continue; - - // pohng specularity ----------------------------------- - if (PLY::EST_PhongPower == (*a).Semantic) - { - iPhong = _a; - ePhong = (*a).eType; - } - - // general opacity ----------------------------------- - if (PLY::EST_Opacity == (*a).Semantic) - { - iOpacity = _a; - eOpacity = (*a).eType; - } - - // diffuse color channels ----------------------------------- - if (PLY::EST_DiffuseRed == (*a).Semantic) - { - aaiPositions[0][0] = _a; - aaiTypes[0][0] = (*a).eType; - } - else if (PLY::EST_DiffuseGreen == (*a).Semantic) - { - aaiPositions[0][1] = _a; - aaiTypes[0][1] = (*a).eType; - } - else if (PLY::EST_DiffuseBlue == (*a).Semantic) - { - aaiPositions[0][2] = _a; - aaiTypes[0][2] = (*a).eType; - } - else if (PLY::EST_DiffuseAlpha == (*a).Semantic) - { - aaiPositions[0][3] = _a; - aaiTypes[0][3] = (*a).eType; - } - // specular color channels ----------------------------------- - else if (PLY::EST_SpecularRed == (*a).Semantic) - { - aaiPositions[1][0] = _a; - aaiTypes[1][0] = (*a).eType; - } - else if (PLY::EST_SpecularGreen == (*a).Semantic) - { - aaiPositions[1][1] = _a; - aaiTypes[1][1] = (*a).eType; - } - else if (PLY::EST_SpecularBlue == (*a).Semantic) - { - aaiPositions[1][2] = _a; - aaiTypes[1][2] = (*a).eType; - } - else if (PLY::EST_SpecularAlpha == (*a).Semantic) - { - aaiPositions[1][3] = _a; - aaiTypes[1][3] = (*a).eType; - } - // ambient color channels ----------------------------------- - else if (PLY::EST_AmbientRed == (*a).Semantic) - { - aaiPositions[2][0] = _a; - aaiTypes[2][0] = (*a).eType; - } - else if (PLY::EST_AmbientGreen == (*a).Semantic) - { - aaiPositions[2][1] = _a; - aaiTypes[2][1] = (*a).eType; - } - else if (PLY::EST_AmbientBlue == (*a).Semantic) - { - aaiPositions[2][2] = _a; - aaiTypes[2][2] = (*a).eType; - } - else if (PLY::EST_AmbientAlpha == (*a).Semantic) - { - aaiPositions[2][3] = _a; - aaiTypes[2][3] = (*a).eType; - } - } - break; + iPhong = _a; + ePhong = (*a).eType; } - } - // check whether we have a valid source for the material data - if (NULL != pcList) { - for (std::vector::const_iterator i = pcList->alInstances.begin();i != pcList->alInstances.end();++i) { - aiColor4D clrOut; - aiMaterial* pcHelper = new aiMaterial(); - // build the diffuse material color - GetMaterialColor((*i).alProperties,aaiPositions[0],aaiTypes[0],&clrOut); - pcHelper->AddProperty(&clrOut,1,AI_MATKEY_COLOR_DIFFUSE); - - // build the specular material color - GetMaterialColor((*i).alProperties,aaiPositions[1],aaiTypes[1],&clrOut); - pcHelper->AddProperty(&clrOut,1,AI_MATKEY_COLOR_SPECULAR); - - // build the ambient material color - GetMaterialColor((*i).alProperties,aaiPositions[2],aaiTypes[2],&clrOut); - pcHelper->AddProperty(&clrOut,1,AI_MATKEY_COLOR_AMBIENT); - - // handle phong power and shading mode - int iMode = (int)aiShadingMode_Gouraud; - if (0xFFFFFFFF != iPhong) { - ai_real fSpec = PLY::PropertyInstance::ConvertTo(GetProperty((*i).alProperties, iPhong).avList.front(),ePhong); - - // if shininess is 0 (and the pow() calculation would therefore always - // become 1, not depending on the angle), use gouraud lighting - if (fSpec) { - // scale this with 15 ... hopefully this is correct - fSpec *= 15; - pcHelper->AddProperty(&fSpec, 1, AI_MATKEY_SHININESS); - - iMode = (int)aiShadingMode_Phong; - } - } - pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); - - // handle opacity - if (0xFFFFFFFF != iOpacity) { - ai_real fOpacity = PLY::PropertyInstance::ConvertTo(GetProperty((*i).alProperties, iPhong).avList.front(),eOpacity); - pcHelper->AddProperty(&fOpacity, 1, AI_MATKEY_OPACITY); - } - - // The face order is absolutely undefined for PLY, so we have to - // use two-sided rendering to be sure it's ok. - const int two_sided = 1; - pcHelper->AddProperty(&two_sided,1,AI_MATKEY_TWOSIDED); - - // add the newly created material instance to the list - pvOut->push_back(pcHelper); + // general opacity ----------------------------------- + if (PLY::EST_Opacity == (*a).Semantic) + { + iOpacity = _a; + eOpacity = (*a).eType; } + + // diffuse color channels ----------------------------------- + if (PLY::EST_DiffuseRed == (*a).Semantic) + { + aaiPositions[0][0] = _a; + aaiTypes[0][0] = (*a).eType; + } + else if (PLY::EST_DiffuseGreen == (*a).Semantic) + { + aaiPositions[0][1] = _a; + aaiTypes[0][1] = (*a).eType; + } + else if (PLY::EST_DiffuseBlue == (*a).Semantic) + { + aaiPositions[0][2] = _a; + aaiTypes[0][2] = (*a).eType; + } + else if (PLY::EST_DiffuseAlpha == (*a).Semantic) + { + aaiPositions[0][3] = _a; + aaiTypes[0][3] = (*a).eType; + } + // specular color channels ----------------------------------- + else if (PLY::EST_SpecularRed == (*a).Semantic) + { + aaiPositions[1][0] = _a; + aaiTypes[1][0] = (*a).eType; + } + else if (PLY::EST_SpecularGreen == (*a).Semantic) + { + aaiPositions[1][1] = _a; + aaiTypes[1][1] = (*a).eType; + } + else if (PLY::EST_SpecularBlue == (*a).Semantic) + { + aaiPositions[1][2] = _a; + aaiTypes[1][2] = (*a).eType; + } + else if (PLY::EST_SpecularAlpha == (*a).Semantic) + { + aaiPositions[1][3] = _a; + aaiTypes[1][3] = (*a).eType; + } + // ambient color channels ----------------------------------- + else if (PLY::EST_AmbientRed == (*a).Semantic) + { + aaiPositions[2][0] = _a; + aaiTypes[2][0] = (*a).eType; + } + else if (PLY::EST_AmbientGreen == (*a).Semantic) + { + aaiPositions[2][1] = _a; + aaiTypes[2][1] = (*a).eType; + } + else if (PLY::EST_AmbientBlue == (*a).Semantic) + { + aaiPositions[2][2] = _a; + aaiTypes[2][2] = (*a).eType; + } + else if (PLY::EST_AmbientAlpha == (*a).Semantic) + { + aaiPositions[2][3] = _a; + aaiTypes[2][3] = (*a).eType; + } + } + break; } + else if (PLY::EEST_TextureFile == (*i).eSemantic) + { + defaultTexture = (*i).szName; + } + } + // check whether we have a valid source for the material data + if (NULL != pcList) { + for (std::vector::const_iterator i = pcList->alInstances.begin(); i != pcList->alInstances.end(); ++i) { + aiColor4D clrOut; + aiMaterial* pcHelper = new aiMaterial(); + + // build the diffuse material color + GetMaterialColor((*i).alProperties, aaiPositions[0], aaiTypes[0], &clrOut); + pcHelper->AddProperty(&clrOut, 1, AI_MATKEY_COLOR_DIFFUSE); + + // build the specular material color + GetMaterialColor((*i).alProperties, aaiPositions[1], aaiTypes[1], &clrOut); + pcHelper->AddProperty(&clrOut, 1, AI_MATKEY_COLOR_SPECULAR); + + // build the ambient material color + GetMaterialColor((*i).alProperties, aaiPositions[2], aaiTypes[2], &clrOut); + pcHelper->AddProperty(&clrOut, 1, AI_MATKEY_COLOR_AMBIENT); + + // handle phong power and shading mode + int iMode = (int)aiShadingMode_Gouraud; + if (0xFFFFFFFF != iPhong) { + ai_real fSpec = PLY::PropertyInstance::ConvertTo(GetProperty((*i).alProperties, iPhong).avList.front(), ePhong); + + // if shininess is 0 (and the pow() calculation would therefore always + // become 1, not depending on the angle), use gouraud lighting + if (fSpec) { + // scale this with 15 ... hopefully this is correct + fSpec *= 15; + pcHelper->AddProperty(&fSpec, 1, AI_MATKEY_SHININESS); + + iMode = (int)aiShadingMode_Phong; + } + } + pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); + + // handle opacity + if (0xFFFFFFFF != iOpacity) { + ai_real fOpacity = PLY::PropertyInstance::ConvertTo(GetProperty((*i).alProperties, iPhong).avList.front(), eOpacity); + pcHelper->AddProperty(&fOpacity, 1, AI_MATKEY_OPACITY); + } + + // The face order is absolutely undefined for PLY, so we have to + // use two-sided rendering to be sure it's ok. + const int two_sided = 1; + pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED); + + //default texture + if (!defaultTexture.empty()) + { + const aiString name(defaultTexture.c_str()); + pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0); + } + + if (!pointsOnly) + { + const int two_sided = 1; + pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED); + } + + //set to wireframe, so when using this material info we can switch to points rendering + if (pointsOnly) + { + const int wireframe = 1; + pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME); + } + + // add the newly created material instance to the list + pvOut->push_back(pcHelper); + } + } + else + { + // generate a default material + aiMaterial* pcHelper = new aiMaterial(); + + // fill in a default material + int iMode = (int)aiShadingMode_Gouraud; + pcHelper->AddProperty(&iMode, 1, AI_MATKEY_SHADING_MODEL); + + //generate white material most 3D engine just multiply ambient / diffuse color with actual ambient / light color + aiColor3D clr; + clr.b = clr.g = clr.r = 1.0f; + pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_DIFFUSE); + pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_SPECULAR); + + clr.b = clr.g = clr.r = 1.0f; + pcHelper->AddProperty(&clr, 1, AI_MATKEY_COLOR_AMBIENT); + + // The face order is absolutely undefined for PLY, so we have to + // use two-sided rendering to be sure it's ok. + if (!pointsOnly) + { + const int two_sided = 1; + pcHelper->AddProperty(&two_sided, 1, AI_MATKEY_TWOSIDED); + } + + //default texture + if (!defaultTexture.empty()) + { + const aiString name(defaultTexture.c_str()); + pcHelper->AddProperty(&name, _AI_MATKEY_TEXTURE_BASE, aiTextureType_DIFFUSE, 0); + } + + //set to wireframe, so when using this material info we can switch to points rendering + if (pointsOnly) + { + const int wireframe = 1; + pcHelper->AddProperty(&wireframe, 1, AI_MATKEY_ENABLE_WIREFRAME); + } + + pvOut->push_back(pcHelper); + } } #endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER diff --git a/code/PlyLoader.h b/code/PlyLoader.h index 9fbcb67e1..eb64a9036 100644 --- a/code/PlyLoader.h +++ b/code/PlyLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -67,7 +68,6 @@ public: PLYImporter(); ~PLYImporter(); - public: // ------------------------------------------------------------------- @@ -77,6 +77,16 @@ public: bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; + // ------------------------------------------------------------------- + /** Extract a vertex from the DOM + */ + void LoadVertex(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos); + + // ------------------------------------------------------------------- + /** Extract a face from the DOM + */ + void LoadFace(const PLY::Element* pcElement, const PLY::ElementInstance* instElement, unsigned int pos); + protected: // ------------------------------------------------------------------- @@ -93,53 +103,10 @@ protected: IOSystem* pIOHandler); protected: - - - // ------------------------------------------------------------------- - /** Extract vertices from the DOM - */ - void LoadVertices(std::vector* pvOut, - bool p_bNormals = false); - - // ------------------------------------------------------------------- - /** Extract vertex color channels from the DOM - */ - void LoadVertexColor(std::vector* pvOut); - - // ------------------------------------------------------------------- - /** Extract texture coordinate channels from the DOM - */ - void LoadTextureCoordinates(std::vector* pvOut); - - // ------------------------------------------------------------------- - /** Extract a face list from the DOM - */ - void LoadFaces(std::vector* pvOut); - // ------------------------------------------------------------------- /** Extract a material list from the DOM */ - void LoadMaterial(std::vector* pvOut); - - - // ------------------------------------------------------------------- - /** Validate material indices, replace default material identifiers - */ - void ReplaceDefaultMaterial(std::vector* avFaces, - std::vector* avMaterials); - - - // ------------------------------------------------------------------- - /** Convert all meshes into our ourer representation - */ - void ConvertMeshes(std::vector* avFaces, - const std::vector* avPositions, - const std::vector* avNormals, - const std::vector* avColors, - const std::vector* avTexCoords, - const std::vector* avMaterials, - std::vector* avOut); - + void LoadMaterial(std::vector* pvOut, std::string &defaultTexture, const bool pointsOnly); // ------------------------------------------------------------------- /** Static helper to parse a color from four single channels in @@ -150,7 +117,6 @@ protected: PLY::EDataType aiTypes[4], aiColor4D* clrOut); - // ------------------------------------------------------------------- /** Static helper to parse a color channel value. The input value * is normalized to 0-1. @@ -159,12 +125,14 @@ protected: PLY::PropertyInstance::ValueUnion val, PLY::EDataType eType); - /** Buffer to hold the loaded file */ unsigned char* mBuffer; /** Document object model representation extracted from the file */ PLY::DOM* pcDOM; + + /** Mesh generated by loader */ + aiMesh* mGeneratedMesh; }; } // end of namespace Assimp diff --git a/code/PlyParser.cpp b/code/PlyParser.cpp index 9bb033842..f4b68a83f 100644 --- a/code/PlyParser.cpp +++ b/code/PlyParser.cpp @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team All rights reserved. @@ -12,18 +12,18 @@ 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. +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. +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. +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 @@ -44,916 +44,1074 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef ASSIMP_BUILD_NO_PLY_IMPORTER -#include "PlyLoader.h" #include "fast_atof.h" #include #include "ByteSwapper.h" - +#include "PlyLoader.h" using namespace Assimp; // ------------------------------------------------------------------------------------------------ -PLY::EDataType PLY::Property::ParseDataType(const char* pCur,const char** pCurOut) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); +PLY::EDataType PLY::Property::ParseDataType(std::vector &buffer) { + ai_assert(!buffer.empty()); - PLY::EDataType eOut = PLY::EDT_INVALID; + PLY::EDataType eOut = PLY::EDT_INVALID; - if (TokenMatch(pCur,"char",4) || - TokenMatch(pCur,"int8",4)) - { - eOut = PLY::EDT_Char; - } - else if (TokenMatch(pCur,"uchar",5) || - TokenMatch(pCur,"uint8",5)) - { - eOut = PLY::EDT_UChar; - } - else if (TokenMatch(pCur,"short",5) || - TokenMatch(pCur,"int16",5)) - { - eOut = PLY::EDT_Short; - } - else if (TokenMatch(pCur,"ushort",6) || - TokenMatch(pCur,"uint16",6)) - { - eOut = PLY::EDT_UShort; - } - else if (TokenMatch(pCur,"int32",5) || TokenMatch(pCur,"int",3)) - { - eOut = PLY::EDT_Int; - } - else if (TokenMatch(pCur,"uint32",6) || TokenMatch(pCur,"uint",4)) - { - eOut = PLY::EDT_UInt; - } - else if (TokenMatch(pCur,"float",5) || TokenMatch(pCur,"float32",7)) - { - eOut = PLY::EDT_Float; - } - else if (TokenMatch(pCur,"double64",8) || TokenMatch(pCur,"double",6) || - TokenMatch(pCur,"float64",7)) - { - eOut = PLY::EDT_Double; - } - if (PLY::EDT_INVALID == eOut) - { - DefaultLogger::get()->info("Found unknown data type in PLY file. This is OK"); - } - *pCurOut = pCur; + if (PLY::DOM::TokenMatch(buffer, "char", 4) || + PLY::DOM::TokenMatch(buffer, "int8", 4)) + { + eOut = PLY::EDT_Char; + } + else if (PLY::DOM::TokenMatch(buffer, "uchar", 5) || + PLY::DOM::TokenMatch(buffer, "uint8", 5)) + { + eOut = PLY::EDT_UChar; + } + else if (PLY::DOM::TokenMatch(buffer, "short", 5) || + PLY::DOM::TokenMatch(buffer, "int16", 5)) + { + eOut = PLY::EDT_Short; + } + else if (PLY::DOM::TokenMatch(buffer, "ushort", 6) || + PLY::DOM::TokenMatch(buffer, "uint16", 6)) + { + eOut = PLY::EDT_UShort; + } + else if (PLY::DOM::TokenMatch(buffer, "int32", 5) || PLY::DOM::TokenMatch(buffer, "int", 3)) + { + eOut = PLY::EDT_Int; + } + else if (PLY::DOM::TokenMatch(buffer, "uint32", 6) || PLY::DOM::TokenMatch(buffer, "uint", 4)) + { + eOut = PLY::EDT_UInt; + } + else if (PLY::DOM::TokenMatch(buffer, "float", 5) || PLY::DOM::TokenMatch(buffer, "float32", 7)) + { + eOut = PLY::EDT_Float; + } + else if (PLY::DOM::TokenMatch(buffer, "double64", 8) || PLY::DOM::TokenMatch(buffer, "double", 6) || + PLY::DOM::TokenMatch(buffer, "float64", 7)) + { + eOut = PLY::EDT_Double; + } + if (PLY::EDT_INVALID == eOut) + { + DefaultLogger::get()->info("Found unknown data type in PLY file. This is OK"); + } - return eOut; + return eOut; } // ------------------------------------------------------------------------------------------------ -PLY::ESemantic PLY::Property::ParseSemantic(const char* pCur,const char** pCurOut) { - ai_assert (NULL != pCur ); - ai_assert( NULL != pCurOut ); +PLY::ESemantic PLY::Property::ParseSemantic(std::vector &buffer) { + ai_assert(!buffer.empty()); - PLY::ESemantic eOut = PLY::EST_INVALID; - if (TokenMatch(pCur,"red",3)) { - eOut = PLY::EST_Red; - } else if (TokenMatch(pCur,"green",5)) { - eOut = PLY::EST_Green; - } else if (TokenMatch(pCur,"blue",4)) { - eOut = PLY::EST_Blue; - } else if (TokenMatch(pCur,"alpha",5)) { - eOut = PLY::EST_Alpha; - } else if (TokenMatch(pCur,"vertex_index",12) || TokenMatch(pCur,"vertex_indices",14)) { - eOut = PLY::EST_VertexIndex; - } - else if (TokenMatch(pCur,"material_index",14)) - { - eOut = PLY::EST_MaterialIndex; - } - else if (TokenMatch(pCur,"ambient_red",11)) - { - eOut = PLY::EST_AmbientRed; - } - else if (TokenMatch(pCur,"ambient_green",13)) - { - eOut = PLY::EST_AmbientGreen; - } - else if (TokenMatch(pCur,"ambient_blue",12)) - { - eOut = PLY::EST_AmbientBlue; - } - else if (TokenMatch(pCur,"ambient_alpha",13)) - { - eOut = PLY::EST_AmbientAlpha; - } - else if (TokenMatch(pCur,"diffuse_red",11)) - { - eOut = PLY::EST_DiffuseRed; - } - else if (TokenMatch(pCur,"diffuse_green",13)) - { - eOut = PLY::EST_DiffuseGreen; - } - else if (TokenMatch(pCur,"diffuse_blue",12)) - { - eOut = PLY::EST_DiffuseBlue; - } - else if (TokenMatch(pCur,"diffuse_alpha",13)) - { - eOut = PLY::EST_DiffuseAlpha; - } - else if (TokenMatch(pCur,"specular_red",12)) - { - eOut = PLY::EST_SpecularRed; - } - else if (TokenMatch(pCur,"specular_green",14)) - { - eOut = PLY::EST_SpecularGreen; - } - else if (TokenMatch(pCur,"specular_blue",13)) - { - eOut = PLY::EST_SpecularBlue; - } - else if (TokenMatch(pCur,"specular_alpha",14)) - { - eOut = PLY::EST_SpecularAlpha; - } - else if (TokenMatch(pCur,"opacity",7)) - { - eOut = PLY::EST_Opacity; - } - else if (TokenMatch(pCur,"specular_power",14)) - { - eOut = PLY::EST_PhongPower; - } - else if (TokenMatch(pCur,"r",1)) - { - eOut = PLY::EST_Red; - } - else if (TokenMatch(pCur,"g",1)) - { - eOut = PLY::EST_Green; - } - else if (TokenMatch(pCur,"b",1)) - { - eOut = PLY::EST_Blue; - } - // NOTE: Blender3D exports texture coordinates as s,t tuples - else if (TokenMatch(pCur,"u",1) || TokenMatch(pCur,"s",1) || TokenMatch(pCur,"tx",2)) - { - eOut = PLY::EST_UTextureCoord; - } - else if (TokenMatch(pCur,"v",1) || TokenMatch(pCur,"t",1) || TokenMatch(pCur,"ty",2)) - { - eOut = PLY::EST_VTextureCoord; - } - else if (TokenMatch(pCur,"x",1)) - { - eOut = PLY::EST_XCoord; - } else if (TokenMatch(pCur,"y",1)) { - eOut = PLY::EST_YCoord; - } else if (TokenMatch(pCur,"z",1)) { - eOut = PLY::EST_ZCoord; - } else if (TokenMatch(pCur,"nx",2)) { - eOut = PLY::EST_XNormal; - } else if (TokenMatch(pCur,"ny",2)) { - eOut = PLY::EST_YNormal; - } else if (TokenMatch(pCur,"nz",2)) { - eOut = PLY::EST_ZNormal; - } else { - DefaultLogger::get()->info("Found unknown property semantic in file. This is ok"); - SkipLine(&pCur); - } - *pCurOut = pCur; - return eOut; + PLY::ESemantic eOut = PLY::EST_INVALID; + if (PLY::DOM::TokenMatch(buffer, "red", 3)) { + eOut = PLY::EST_Red; + } + else if (PLY::DOM::TokenMatch(buffer, "green", 5)) { + eOut = PLY::EST_Green; + } + else if (PLY::DOM::TokenMatch(buffer, "blue", 4)) { + eOut = PLY::EST_Blue; + } + else if (PLY::DOM::TokenMatch(buffer, "alpha", 5)) { + eOut = PLY::EST_Alpha; + } + else if (PLY::DOM::TokenMatch(buffer, "vertex_index", 12) || PLY::DOM::TokenMatch(buffer, "vertex_indices", 14)) { + eOut = PLY::EST_VertexIndex; + } + else if (PLY::DOM::TokenMatch(buffer, "texcoord", 8)) // Manage uv coords on faces + { + eOut = PLY::EST_TextureCoordinates; + } + else if (PLY::DOM::TokenMatch(buffer, "material_index", 14)) + { + eOut = PLY::EST_MaterialIndex; + } + else if (PLY::DOM::TokenMatch(buffer, "ambient_red", 11)) + { + eOut = PLY::EST_AmbientRed; + } + else if (PLY::DOM::TokenMatch(buffer, "ambient_green", 13)) + { + eOut = PLY::EST_AmbientGreen; + } + else if (PLY::DOM::TokenMatch(buffer, "ambient_blue", 12)) + { + eOut = PLY::EST_AmbientBlue; + } + else if (PLY::DOM::TokenMatch(buffer, "ambient_alpha", 13)) + { + eOut = PLY::EST_AmbientAlpha; + } + else if (PLY::DOM::TokenMatch(buffer, "diffuse_red", 11)) + { + eOut = PLY::EST_DiffuseRed; + } + else if (PLY::DOM::TokenMatch(buffer, "diffuse_green", 13)) + { + eOut = PLY::EST_DiffuseGreen; + } + else if (PLY::DOM::TokenMatch(buffer, "diffuse_blue", 12)) + { + eOut = PLY::EST_DiffuseBlue; + } + else if (PLY::DOM::TokenMatch(buffer, "diffuse_alpha", 13)) + { + eOut = PLY::EST_DiffuseAlpha; + } + else if (PLY::DOM::TokenMatch(buffer, "specular_red", 12)) + { + eOut = PLY::EST_SpecularRed; + } + else if (PLY::DOM::TokenMatch(buffer, "specular_green", 14)) + { + eOut = PLY::EST_SpecularGreen; + } + else if (PLY::DOM::TokenMatch(buffer, "specular_blue", 13)) + { + eOut = PLY::EST_SpecularBlue; + } + else if (PLY::DOM::TokenMatch(buffer, "specular_alpha", 14)) + { + eOut = PLY::EST_SpecularAlpha; + } + else if (PLY::DOM::TokenMatch(buffer, "opacity", 7)) + { + eOut = PLY::EST_Opacity; + } + else if (PLY::DOM::TokenMatch(buffer, "specular_power", 14)) + { + eOut = PLY::EST_PhongPower; + } + else if (PLY::DOM::TokenMatch(buffer, "r", 1)) + { + eOut = PLY::EST_Red; + } + else if (PLY::DOM::TokenMatch(buffer, "g", 1)) + { + eOut = PLY::EST_Green; + } + else if (PLY::DOM::TokenMatch(buffer, "b", 1)) + { + eOut = PLY::EST_Blue; + } + + // NOTE: Blender3D exports texture coordinates as s,t tuples + else if (PLY::DOM::TokenMatch(buffer, "u", 1) || PLY::DOM::TokenMatch(buffer, "s", 1) || PLY::DOM::TokenMatch(buffer, "tx", 2) || PLY::DOM::TokenMatch(buffer, "texture_u", 9)) + { + eOut = PLY::EST_UTextureCoord; + } + else if (PLY::DOM::TokenMatch(buffer, "v", 1) || PLY::DOM::TokenMatch(buffer, "t", 1) || PLY::DOM::TokenMatch(buffer, "ty", 2) || PLY::DOM::TokenMatch(buffer, "texture_v", 9)) + { + eOut = PLY::EST_VTextureCoord; + } + else if (PLY::DOM::TokenMatch(buffer, "x", 1)) + { + eOut = PLY::EST_XCoord; + } + else if (PLY::DOM::TokenMatch(buffer, "y", 1)) { + eOut = PLY::EST_YCoord; + } + else if (PLY::DOM::TokenMatch(buffer, "z", 1)) { + eOut = PLY::EST_ZCoord; + } + else if (PLY::DOM::TokenMatch(buffer, "nx", 2)) { + eOut = PLY::EST_XNormal; + } + else if (PLY::DOM::TokenMatch(buffer, "ny", 2)) { + eOut = PLY::EST_YNormal; + } + else if (PLY::DOM::TokenMatch(buffer, "nz", 2)) { + eOut = PLY::EST_ZNormal; + } + else { + DefaultLogger::get()->info("Found unknown property semantic in file. This is ok"); + PLY::DOM::SkipLine(buffer); + } + return eOut; } // ------------------------------------------------------------------------------------------------ -bool PLY::Property::ParseProperty (const char* pCur, - const char** pCurOut, - PLY::Property* pOut) +bool PLY::Property::ParseProperty(std::vector &buffer, PLY::Property* pOut) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); + ai_assert(!buffer.empty()); - // Forms supported: - // "property float x" - // "property list uchar int vertex_index" - *pCurOut = pCur; - - // skip leading spaces - if (!SkipSpaces(pCur,&pCur)) { - return false; - } - - // skip the "property" string at the beginning - if (!TokenMatch(pCur,"property",8)) - { - // seems not to be a valid property entry - return false; - } - // get next word - if (!SkipSpaces(pCur,&pCur)) { - return false; - } - if (TokenMatch(pCur,"list",4)) - { - pOut->bIsList = true; - - // seems to be a list. - if(EDT_INVALID == (pOut->eFirstType = PLY::Property::ParseDataType(pCur, &pCur))) - { - // unable to parse list size data type - SkipLine(pCur,&pCur); - *pCurOut = pCur; - return false; - } - if (!SkipSpaces(pCur,&pCur))return false; - if(EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(pCur, &pCur))) - { - // unable to parse list data type - SkipLine(pCur,&pCur); - *pCurOut = pCur; - return false; - } - } - else - { - if(EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(pCur, &pCur))) - { - // unable to parse data type. Skip the property - SkipLine(pCur,&pCur); - *pCurOut = pCur; - return false; - } - } - - if (!SkipSpaces(pCur,&pCur))return false; - const char* szCur = pCur; - pOut->Semantic = PLY::Property::ParseSemantic(pCur, &pCur); - - if (PLY::EST_INVALID == pOut->Semantic) - { - // store the name of the semantic - uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; - - DefaultLogger::get()->info("Found unknown semantic in PLY file. This is OK"); - pOut->szName = std::string(szCur,iDiff); - } - - SkipSpacesAndLineEnd(pCur,&pCur); - *pCurOut = pCur; - - return true; -} - -// ------------------------------------------------------------------------------------------------ -PLY::EElementSemantic PLY::Element::ParseSemantic(const char* pCur, - const char** pCurOut) -{ - ai_assert(NULL != pCur && NULL != pCurOut); - PLY::EElementSemantic eOut = PLY::EEST_INVALID; - if (TokenMatch(pCur,"vertex",6)) - { - eOut = PLY::EEST_Vertex; - } - else if (TokenMatch(pCur,"face",4)) - { - eOut = PLY::EEST_Face; - } -#if 0 - // TODO: maybe implement this? - else if (TokenMatch(pCur,"range_grid",10)) - { - eOut = PLY::EEST_Face; - } -#endif - else if (TokenMatch(pCur,"tristrips",9)) - { - eOut = PLY::EEST_TriStrip; - } - else if (TokenMatch(pCur,"edge",4)) - { - eOut = PLY::EEST_Edge; - } - else if (TokenMatch(pCur,"material",8)) - { - eOut = PLY::EEST_Material; - } - *pCurOut = pCur; - - return eOut; -} - -// ------------------------------------------------------------------------------------------------ -bool PLY::Element::ParseElement (const char* pCur, - const char** pCurOut, - PLY::Element* pOut) -{ - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != pOut ); - - // Example format: "element vertex 8" - *pCurOut = pCur; - - // skip leading spaces - if (!SkipSpaces(&pCur)) { - return false; - } - - // skip the "element" string at the beginning - if (!TokenMatch(pCur,"element",7)) - { - // seems not to be a valid property entry - return false; - } - // get next word - if (!SkipSpaces(&pCur))return false; - - // parse the semantic of the element - const char* szCur = pCur; - pOut->eSemantic = PLY::Element::ParseSemantic(pCur,&pCur); - if (PLY::EEST_INVALID == pOut->eSemantic) - { - // if the exact semantic can't be determined, just store - // the original string identifier - uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; - pOut->szName = std::string(szCur,iDiff); - } - - if (!SkipSpaces(&pCur))return false; - - //parse the number of occurrences of this element - pOut->NumOccur = strtoul10(pCur,&pCur); - - // go to the next line - SkipSpacesAndLineEnd(pCur,&pCur); - - // now parse all properties of the element - while(true) - { - // skip all comments - PLY::DOM::SkipComments(pCur,&pCur); - - PLY::Property prop; - if(!PLY::Property::ParseProperty(pCur,&pCur,&prop))break; - pOut->alProperties.push_back(prop); - } - *pCurOut = pCur; - - return true; -} - -// ------------------------------------------------------------------------------------------------ -bool PLY::DOM::SkipComments (const char* pCur, - const char** pCurOut) -{ - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - *pCurOut = pCur; - - // skip spaces - if (!SkipSpaces(pCur,&pCur)) { - return false; - } - - if (TokenMatch(pCur,"comment",7)) - { - if ( !IsLineEnd(pCur[-1]) ) - { - SkipLine(pCur,&pCur); - } - SkipComments(pCur,&pCur); - *pCurOut = pCur; - return true; - } - *pCurOut = pCur; + // Forms supported: + // "property float x" + // "property list uchar int vertex_index" + // skip leading spaces + if (!PLY::DOM::SkipSpaces(buffer)) { return false; -} + } -// ------------------------------------------------------------------------------------------------ -bool PLY::DOM::ParseHeader (const char* pCur,const char** pCurOut,bool isBinary) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); + // skip the "property" string at the beginning + if (!PLY::DOM::TokenMatch(buffer, "property", 8)) + { + // seems not to be a valid property entry + return false; + } + // get next word + if (!PLY::DOM::SkipSpaces(buffer)) { + return false; + } + if (PLY::DOM::TokenMatch(buffer, "list", 4)) + { + pOut->bIsList = true; - DefaultLogger::get()->debug("PLY::DOM::ParseHeader() begin"); - - // after ply and format line - *pCurOut = pCur; - - // parse all elements - while ((*pCur) != '\0') + // seems to be a list. + if (EDT_INVALID == (pOut->eFirstType = PLY::Property::ParseDataType(buffer))) { - // skip all comments - PLY::DOM::SkipComments(pCur,&pCur); - - PLY::Element out; - if(PLY::Element::ParseElement(pCur,&pCur,&out)) - { - // add the element to the list of elements - alElements.push_back(out); - } - else if (TokenMatch(pCur,"end_header",10)) - { - // we have reached the end of the header - break; - } - else - { - // ignore unknown header elements - SkipLine(&pCur); - } + // unable to parse list size data type + PLY::DOM::SkipLine(buffer); + return false; } - if(!isBinary) - { // it would occur an error, if binary data start with values as space or line end. - SkipSpacesAndLineEnd(pCur,&pCur); + if (!PLY::DOM::SkipSpaces(buffer))return false; + if (EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(buffer))) + { + // unable to parse list data type + PLY::DOM::SkipLine(buffer); + return false; } - *pCurOut = pCur; + } + else + { + if (EDT_INVALID == (pOut->eType = PLY::Property::ParseDataType(buffer))) + { + // unable to parse data type. Skip the property + PLY::DOM::SkipLine(buffer); + return false; + } + } - DefaultLogger::get()->debug("PLY::DOM::ParseHeader() succeeded"); - return true; + if (!PLY::DOM::SkipSpaces(buffer)) + return false; + + pOut->Semantic = PLY::Property::ParseSemantic(buffer); + + if (PLY::EST_INVALID == pOut->Semantic) + { + DefaultLogger::get()->info("Found unknown semantic in PLY file. This is OK"); + std::string(&buffer[0], &buffer[0] + strlen(&buffer[0])); + } + + PLY::DOM::SkipSpacesAndLineEnd(buffer); + return true; } // ------------------------------------------------------------------------------------------------ -bool PLY::DOM::ParseElementInstanceLists ( - const char* pCur, - const char** pCurOut) +PLY::EElementSemantic PLY::Element::ParseSemantic(std::vector &buffer) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); + ai_assert(!buffer.empty()); - DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() begin"); - *pCurOut = pCur; + PLY::EElementSemantic eOut = PLY::EEST_INVALID; + if (PLY::DOM::TokenMatch(buffer, "vertex", 6)) + { + eOut = PLY::EEST_Vertex; + } + else if (PLY::DOM::TokenMatch(buffer, "face", 4)) + { + eOut = PLY::EEST_Face; + } + else if (PLY::DOM::TokenMatch(buffer, "tristrips", 9)) + { + eOut = PLY::EEST_TriStrip; + } +#if 0 + // TODO: maybe implement this? + else if (PLY::DOM::TokenMatch(buffer,"range_grid",10)) + { + eOut = PLY::EEST_Face; + } +#endif + else if (PLY::DOM::TokenMatch(buffer, "edge", 4)) + { + eOut = PLY::EEST_Edge; + } + else if (PLY::DOM::TokenMatch(buffer, "material", 8)) + { + eOut = PLY::EEST_Material; + } + else if (PLY::DOM::TokenMatch(buffer, "TextureFile", 11)) + { + eOut = PLY::EEST_TextureFile; + } - alElementData.resize(alElements.size()); - - std::vector::const_iterator i = alElements.begin(); - std::vector::iterator a = alElementData.begin(); - - // parse all element instances - for (;i != alElements.end();++i,++a) - { - (*a).alInstances.resize((*i).NumOccur); - PLY::ElementInstanceList::ParseInstanceList(pCur,&pCur,&(*i),&(*a)); - } - - DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() succeeded"); - *pCurOut = pCur; - return true; + return eOut; } // ------------------------------------------------------------------------------------------------ -bool PLY::DOM::ParseElementInstanceListsBinary ( - const char* pCur, - const char** pCurOut, +bool PLY::Element::ParseElement(IOStreamBuffer &streamBuffer, std::vector &buffer, PLY::Element* pOut) +{ + ai_assert(NULL != pOut); + // Example format: "element vertex 8" + + // skip leading spaces + if (!PLY::DOM::SkipSpaces(buffer)) + { + return false; + } + + // skip the "element" string at the beginning + if (!PLY::DOM::TokenMatch(buffer, "element", 7) && !PLY::DOM::TokenMatch(buffer, "comment", 7)) + { + // seems not to be a valid property entry + return false; + } + // get next word + if (!PLY::DOM::SkipSpaces(buffer)) + return false; + + // parse the semantic of the element + pOut->eSemantic = PLY::Element::ParseSemantic(buffer); + if (PLY::EEST_INVALID == pOut->eSemantic) + { + // if the exact semantic can't be determined, just store + // the original string identifier + pOut->szName = std::string(&buffer[0], &buffer[0] + strlen(&buffer[0])); + } + + if (!PLY::DOM::SkipSpaces(buffer)) + return false; + + if (PLY::EEST_TextureFile == pOut->eSemantic) + { + char* endPos = &buffer[0] + (strlen(&buffer[0]) - 1); + pOut->szName = std::string(&buffer[0], endPos); + } + + //parse the number of occurrences of this element + const char* pCur = (char*)&buffer[0]; + pOut->NumOccur = strtoul10(pCur, &pCur); + + // go to the next line + PLY::DOM::SkipSpacesAndLineEnd(buffer); + + // now parse all properties of the element + while (true) + { + streamBuffer.getNextLine(buffer); + pCur = (char*)&buffer[0]; + + // skip all comments + PLY::DOM::SkipComments(buffer); + + PLY::Property prop; + if (!PLY::Property::ParseProperty(buffer, &prop)) + break; + + pOut->alProperties.push_back(prop); + } + + return true; +} + +// ------------------------------------------------------------------------------------------------ +bool PLY::DOM::SkipSpaces(std::vector &buffer) +{ + const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0]; + bool ret = false; + if (pCur) + { + const char* szCur = pCur; + ret = Assimp::SkipSpaces(pCur, &pCur); + + uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; + buffer.erase(buffer.begin(), buffer.begin() + iDiff); + return ret; + } + + return ret; +} + +bool PLY::DOM::SkipLine(std::vector &buffer) +{ + const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0]; + bool ret = false; + if (pCur) + { + const char* szCur = pCur; + ret = Assimp::SkipLine(pCur, &pCur); + + uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; + buffer.erase(buffer.begin(), buffer.begin() + iDiff); + return ret; + } + + return ret; +} + +bool PLY::DOM::TokenMatch(std::vector &buffer, const char* token, unsigned int len) +{ + const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0]; + bool ret = false; + if (pCur) + { + const char* szCur = pCur; + ret = Assimp::TokenMatch(pCur, token, len); + + uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; + buffer.erase(buffer.begin(), buffer.begin() + iDiff); + return ret; + } + + return ret; +} + +bool PLY::DOM::SkipSpacesAndLineEnd(std::vector &buffer) +{ + const char* pCur = buffer.empty() ? NULL : (char*)&buffer[0]; + bool ret = false; + if (pCur) + { + const char* szCur = pCur; + ret = Assimp::SkipSpacesAndLineEnd(pCur, &pCur); + + uintptr_t iDiff = (uintptr_t)pCur - (uintptr_t)szCur; + buffer.erase(buffer.begin(), buffer.begin() + iDiff); + return ret; + } + + return ret; +} + +bool PLY::DOM::SkipComments(std::vector &buffer) +{ + ai_assert(!buffer.empty()); + + std::vector nbuffer = buffer; + // skip spaces + if (!SkipSpaces(nbuffer)) { + return false; + } + + if (TokenMatch(nbuffer, "comment", 7)) + { + if (!SkipSpaces(nbuffer)) + SkipLine(nbuffer); + + if (!TokenMatch(nbuffer, "TextureFile", 11)) + { + SkipLine(nbuffer); + buffer = nbuffer; + return true; + } + + return true; + } + + return false; +} + +// ------------------------------------------------------------------------------------------------ +bool PLY::DOM::ParseHeader(IOStreamBuffer &streamBuffer, std::vector &buffer, bool isBinary) { + DefaultLogger::get()->debug("PLY::DOM::ParseHeader() begin"); + + // parse all elements + while (!buffer.empty()) + { + // skip all comments + PLY::DOM::SkipComments(buffer); + + PLY::Element out; + if (PLY::Element::ParseElement(streamBuffer, buffer, &out)) + { + // add the element to the list of elements + alElements.push_back(out); + } + else if (TokenMatch(buffer, "end_header", 10)) + { + // we have reached the end of the header + break; + } + else + { + // ignore unknown header elements + streamBuffer.getNextLine(buffer); + } + } + + if (!isBinary) // it would occur an error, if binary data start with values as space or line end. + SkipSpacesAndLineEnd(buffer); + + DefaultLogger::get()->debug("PLY::DOM::ParseHeader() succeeded"); + return true; +} + +// ------------------------------------------------------------------------------------------------ +bool PLY::DOM::ParseElementInstanceLists(IOStreamBuffer &streamBuffer, std::vector &buffer, PLYImporter* loader) +{ + DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() begin"); + alElementData.resize(alElements.size()); + + std::vector::const_iterator i = alElements.begin(); + std::vector::iterator a = alElementData.begin(); + + // parse all element instances + //construct vertices and faces + for (; i != alElements.end(); ++i, ++a) + { + if ((*i).eSemantic == EEST_Vertex || (*i).eSemantic == EEST_Face || (*i).eSemantic == EEST_TriStrip) + { + PLY::ElementInstanceList::ParseInstanceList(streamBuffer, buffer, &(*i), NULL, loader); + } + else + { + (*a).alInstances.resize((*i).NumOccur); + PLY::ElementInstanceList::ParseInstanceList(streamBuffer, buffer, &(*i), &(*a), NULL); + } + } + + DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceLists() succeeded"); + return true; +} + +// ------------------------------------------------------------------------------------------------ +bool PLY::DOM::ParseElementInstanceListsBinary(IOStreamBuffer &streamBuffer, std::vector &buffer, + const char* &pCur, + unsigned int &bufferSize, + PLYImporter* loader, bool p_bBE) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut); + DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() begin"); + alElementData.resize(alElements.size()); - DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() begin"); - *pCurOut = pCur; + std::vector::const_iterator i = alElements.begin(); + std::vector::iterator a = alElementData.begin(); - alElementData.resize(alElements.size()); - - std::vector::const_iterator i = alElements.begin(); - std::vector::iterator a = alElementData.begin(); - - // parse all element instances - for (;i != alElements.end();++i,++a) + // parse all element instances + for (; i != alElements.end(); ++i, ++a) + { + if ((*i).eSemantic == EEST_Vertex || (*i).eSemantic == EEST_Face || (*i).eSemantic == EEST_TriStrip) { - (*a).alInstances.resize((*i).NumOccur); - PLY::ElementInstanceList::ParseInstanceListBinary(pCur,&pCur,&(*i),&(*a),p_bBE); - } - - DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() succeeded"); - *pCurOut = pCur; - return true; -} - -// ------------------------------------------------------------------------------------------------ -bool PLY::DOM::ParseInstanceBinary (const char* pCur,DOM* p_pcOut,bool p_bBE) -{ - ai_assert( NULL != pCur ); - ai_assert( NULL != p_pcOut ); - - DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() begin"); - - if(!p_pcOut->ParseHeader(pCur,&pCur,true)) - { - DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure"); - return false; - } - if(!p_pcOut->ParseElementInstanceListsBinary(pCur,&pCur,p_bBE)) - { - DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure"); - return false; - } - DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() succeeded"); - return true; -} - -// ------------------------------------------------------------------------------------------------ -bool PLY::DOM::ParseInstance (const char* pCur,DOM* p_pcOut) -{ - ai_assert(NULL != pCur); - ai_assert(NULL != p_pcOut); - - DefaultLogger::get()->debug("PLY::DOM::ParseInstance() begin"); - - - if(!p_pcOut->ParseHeader(pCur,&pCur,false)) - { - DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure"); - return false; - } - if(!p_pcOut->ParseElementInstanceLists(pCur,&pCur)) - { - DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure"); - return false; - } - DefaultLogger::get()->debug("PLY::DOM::ParseInstance() succeeded"); - return true; -} - -// ------------------------------------------------------------------------------------------------ -bool PLY::ElementInstanceList::ParseInstanceList ( - const char* pCur, - const char** pCurOut, - const PLY::Element* pcElement, - PLY::ElementInstanceList* p_pcOut) -{ - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != pcElement ); - ai_assert( NULL != p_pcOut ); - - if (EEST_INVALID == pcElement->eSemantic || pcElement->alProperties.empty()) - { - // if the element has an unknown semantic we can skip all lines - // However, there could be comments - for (unsigned int i = 0; i < pcElement->NumOccur;++i) - { - PLY::DOM::SkipComments(pCur,&pCur); - SkipLine(pCur,&pCur); - } + PLY::ElementInstanceList::ParseInstanceListBinary(streamBuffer, buffer, pCur, bufferSize, &(*i), NULL, loader, p_bBE); } else { - // be sure to have enough storage - for (unsigned int i = 0; i < pcElement->NumOccur;++i) - { - PLY::DOM::SkipComments(pCur,&pCur); - PLY::ElementInstance::ParseInstance(pCur, &pCur,pcElement, - &p_pcOut->alInstances[i]); - } + (*a).alInstances.resize((*i).NumOccur); + PLY::ElementInstanceList::ParseInstanceListBinary(streamBuffer, buffer, pCur, bufferSize, &(*i), &(*a), NULL, p_bBE); } - *pCurOut = pCur; - return true; + } + + DefaultLogger::get()->debug("PLY::DOM::ParseElementInstanceListsBinary() succeeded"); + return true; } // ------------------------------------------------------------------------------------------------ -bool PLY::ElementInstanceList::ParseInstanceListBinary ( - const char* pCur, - const char** pCurOut, - const PLY::Element* pcElement, - PLY::ElementInstanceList* p_pcOut, - bool p_bBE /* = false */) +bool PLY::DOM::ParseInstanceBinary(IOStreamBuffer &streamBuffer, DOM* p_pcOut, PLYImporter* loader, bool p_bBE) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != pcElement ); - ai_assert( NULL != p_pcOut ); + ai_assert(NULL != p_pcOut); + ai_assert(NULL != loader); - // we can add special handling code for unknown element semantics since - // we can't skip it as a whole block (we don't know its exact size - // due to the fact that lists could be contained in the property list - // of the unknown element) - for (unsigned int i = 0; i < pcElement->NumOccur;++i) - { - PLY::ElementInstance::ParseInstanceBinary(pCur, &pCur,pcElement, - &p_pcOut->alInstances[i], p_bBE); - } - *pCurOut = pCur; - return true; + std::vector buffer; + streamBuffer.getNextLine(buffer); + + DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() begin"); + + if (!p_pcOut->ParseHeader(streamBuffer, buffer, true)) + { + DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure"); + return false; + } + + streamBuffer.getNextBlock(buffer); + unsigned int bufferSize = static_cast(buffer.size()); + const char* pCur = (char*)&buffer[0]; + if (!p_pcOut->ParseElementInstanceListsBinary(streamBuffer, buffer, pCur, bufferSize, loader, p_bBE)) + { + DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() failure"); + return false; + } + DefaultLogger::get()->debug("PLY::DOM::ParseInstanceBinary() succeeded"); + return true; } // ------------------------------------------------------------------------------------------------ -bool PLY::ElementInstance::ParseInstance ( - const char* pCur, - const char** pCurOut, - const PLY::Element* pcElement, - PLY::ElementInstance* p_pcOut) +bool PLY::DOM::ParseInstance(IOStreamBuffer &streamBuffer, DOM* p_pcOut, PLYImporter* loader) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != pcElement ); - ai_assert( NULL != p_pcOut ); + ai_assert(NULL != p_pcOut); + ai_assert(NULL != loader); - if (!SkipSpaces(pCur, &pCur)) { - return false; - } + std::vector buffer; + streamBuffer.getNextLine(buffer); - // allocate enough storage - p_pcOut->alProperties.resize(pcElement->alProperties.size()); + DefaultLogger::get()->debug("PLY::DOM::ParseInstance() begin"); - std::vector::iterator i = p_pcOut->alProperties.begin(); - std::vector::const_iterator a = pcElement->alProperties.begin(); - for (;i != p_pcOut->alProperties.end();++i,++a) - { - if(!(PLY::PropertyInstance::ParseInstance(pCur, &pCur,&(*a),&(*i)))) - { - DefaultLogger::get()->warn("Unable to parse property instance. " - "Skipping this element instance"); + if (!p_pcOut->ParseHeader(streamBuffer, buffer, false)) + { + DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure"); + return false; + } - // skip the rest of the instance - SkipLine(pCur, &pCur); - - PLY::PropertyInstance::ValueUnion v = PLY::PropertyInstance::DefaultValue((*a).eType); - (*i).avList.push_back(v); - } - } - *pCurOut = pCur; - return true; + //get next line after header + streamBuffer.getNextLine(buffer); + if (!p_pcOut->ParseElementInstanceLists(streamBuffer, buffer, loader)) + { + DefaultLogger::get()->debug("PLY::DOM::ParseInstance() failure"); + return false; + } + DefaultLogger::get()->debug("PLY::DOM::ParseInstance() succeeded"); + return true; } // ------------------------------------------------------------------------------------------------ -bool PLY::ElementInstance::ParseInstanceBinary ( - const char* pCur, - const char** pCurOut, - const PLY::Element* pcElement, - PLY::ElementInstance* p_pcOut, - bool p_bBE /* = false */) +bool PLY::ElementInstanceList::ParseInstanceList( + IOStreamBuffer &streamBuffer, + std::vector &buffer, + const PLY::Element* pcElement, + PLY::ElementInstanceList* p_pcOut, + PLYImporter* loader) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != pcElement ); - ai_assert( NULL != p_pcOut ); + ai_assert(NULL != pcElement); + const char* pCur = (const char*)&buffer[0]; - // allocate enough storage - p_pcOut->alProperties.resize(pcElement->alProperties.size()); - - std::vector::iterator i = p_pcOut->alProperties.begin(); - std::vector::const_iterator a = pcElement->alProperties.begin(); - for (;i != p_pcOut->alProperties.end();++i,++a) + // parse all elements + if (EEST_INVALID == pcElement->eSemantic || pcElement->alProperties.empty()) + { + // if the element has an unknown semantic we can skip all lines + // However, there could be comments + for (unsigned int i = 0; i < pcElement->NumOccur; ++i) { - if(!(PLY::PropertyInstance::ParseInstanceBinary(pCur, &pCur,&(*a),&(*i),p_bBE))) - { - DefaultLogger::get()->warn("Unable to parse binary property instance. " - "Skipping this element instance"); - - (*i).avList.push_back(PLY::PropertyInstance::DefaultValue((*a).eType)); - } + PLY::DOM::SkipComments(buffer); + PLY::DOM::SkipLine(buffer); + streamBuffer.getNextLine(buffer); + pCur = (buffer.empty()) ? NULL : (const char*)&buffer[0]; } - *pCurOut = pCur; - return true; + } + else + { + // be sure to have enough storage + for (unsigned int i = 0; i < pcElement->NumOccur; ++i) + { + if (p_pcOut) + PLY::ElementInstance::ParseInstance(pCur, pcElement, &p_pcOut->alInstances[i]); + else + { + ElementInstance elt; + PLY::ElementInstance::ParseInstance(pCur, pcElement, &elt); + + // Create vertex or face + if (pcElement->eSemantic == EEST_Vertex) + { + //call loader instance from here + loader->LoadVertex(pcElement, &elt, i); + } + else if (pcElement->eSemantic == EEST_Face) + { + //call loader instance from here + loader->LoadFace(pcElement, &elt, i); + } + else if (pcElement->eSemantic == EEST_TriStrip) + { + //call loader instance from here + loader->LoadFace(pcElement, &elt, i); + } + } + + streamBuffer.getNextLine(buffer); + pCur = (buffer.empty()) ? NULL : (const char*)&buffer[0]; + } + } + return true; } // ------------------------------------------------------------------------------------------------ -bool PLY::PropertyInstance::ParseInstance (const char* pCur,const char** pCurOut, - const PLY::Property* prop, PLY::PropertyInstance* p_pcOut) +bool PLY::ElementInstanceList::ParseInstanceListBinary( + IOStreamBuffer &streamBuffer, + std::vector &buffer, + const char* &pCur, + unsigned int &bufferSize, + const PLY::Element* pcElement, + PLY::ElementInstanceList* p_pcOut, + PLYImporter* loader, + bool p_bBE /* = false */) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != prop ); - ai_assert( NULL != p_pcOut ); + ai_assert(NULL != pcElement); - *pCurOut = pCur; - - // skip spaces at the beginning - if (!SkipSpaces(pCur, &pCur)) { - return false; - } - - if (prop->bIsList) - { - // parse the number of elements in the list - PLY::PropertyInstance::ValueUnion v; - PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eFirstType,&v); - - // convert to unsigned int - unsigned int iNum = PLY::PropertyInstance::ConvertTo(v,prop->eFirstType); - - // parse all list elements - p_pcOut->avList.resize(iNum); - for (unsigned int i = 0; i < iNum;++i) - { - if (!SkipSpaces(pCur, &pCur))return false; - PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eType,&p_pcOut->avList[i]); - } - } + // we can add special handling code for unknown element semantics since + // we can't skip it as a whole block (we don't know its exact size + // due to the fact that lists could be contained in the property list + // of the unknown element) + for (unsigned int i = 0; i < pcElement->NumOccur; ++i) + { + if (p_pcOut) + PLY::ElementInstance::ParseInstanceBinary(streamBuffer, buffer, pCur, bufferSize, pcElement, &p_pcOut->alInstances[i], p_bBE); else { - // parse the property - PLY::PropertyInstance::ValueUnion v; + ElementInstance elt; + PLY::ElementInstance::ParseInstanceBinary(streamBuffer, buffer, pCur, bufferSize, pcElement, &elt, p_bBE); - PLY::PropertyInstance::ParseValue(pCur, &pCur,prop->eType,&v); - p_pcOut->avList.push_back(v); + // Create vertex or face + if (pcElement->eSemantic == EEST_Vertex) + { + //call loader instance from here + loader->LoadVertex(pcElement, &elt, i); + } + else if (pcElement->eSemantic == EEST_Face) + { + //call loader instance from here + loader->LoadFace(pcElement, &elt, i); + } + else if (pcElement->eSemantic == EEST_TriStrip) + { + //call loader instance from here + loader->LoadFace(pcElement, &elt, i); + } } - SkipSpacesAndLineEnd(pCur, &pCur); - *pCurOut = pCur; - return true; + } + return true; } // ------------------------------------------------------------------------------------------------ -bool PLY::PropertyInstance::ParseInstanceBinary ( - const char* pCur, - const char** pCurOut, - const PLY::Property* prop, - PLY::PropertyInstance* p_pcOut, - bool p_bBE) +bool PLY::ElementInstance::ParseInstance(const char* &pCur, + const PLY::Element* pcElement, + PLY::ElementInstance* p_pcOut) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != prop ); - ai_assert( NULL != p_pcOut ); + ai_assert(NULL != pcElement); + ai_assert(NULL != p_pcOut); - if (prop->bIsList) + // allocate enough storage + p_pcOut->alProperties.resize(pcElement->alProperties.size()); + + std::vector::iterator i = p_pcOut->alProperties.begin(); + std::vector::const_iterator a = pcElement->alProperties.begin(); + for (; i != p_pcOut->alProperties.end(); ++i, ++a) + { + if (!(PLY::PropertyInstance::ParseInstance(pCur, &(*a), &(*i)))) { - // parse the number of elements in the list - PLY::PropertyInstance::ValueUnion v; - PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eFirstType,&v,p_bBE); + DefaultLogger::get()->warn("Unable to parse property instance. " + "Skipping this element instance"); - // convert to unsigned int - unsigned int iNum = PLY::PropertyInstance::ConvertTo(v,prop->eFirstType); - - // parse all list elements - p_pcOut->avList.resize(iNum); - for (unsigned int i = 0; i < iNum;++i){ - PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eType,&p_pcOut->avList[i],p_bBE); - } + PLY::PropertyInstance::ValueUnion v = PLY::PropertyInstance::DefaultValue((*a).eType); + (*i).avList.push_back(v); } - else - { - // parse the property - PLY::PropertyInstance::ValueUnion v; - PLY::PropertyInstance::ParseValueBinary(pCur, &pCur,prop->eType,&v,p_bBE); - p_pcOut->avList.push_back(v); - } - *pCurOut = pCur; - return true; + } + return true; } // ------------------------------------------------------------------------------------------------ -PLY::PropertyInstance::ValueUnion PLY::PropertyInstance::DefaultValue( PLY::EDataType eType ) +bool PLY::ElementInstance::ParseInstanceBinary( + IOStreamBuffer &streamBuffer, + std::vector &buffer, + const char* &pCur, + unsigned int &bufferSize, + const PLY::Element* pcElement, + PLY::ElementInstance* p_pcOut, + bool p_bBE /* = false */) { - PLY::PropertyInstance::ValueUnion out; + ai_assert(NULL != pcElement); + ai_assert(NULL != p_pcOut); - switch (eType) + // allocate enough storage + p_pcOut->alProperties.resize(pcElement->alProperties.size()); + + std::vector::iterator i = p_pcOut->alProperties.begin(); + std::vector::const_iterator a = pcElement->alProperties.begin(); + for (; i != p_pcOut->alProperties.end(); ++i, ++a) + { + if (!(PLY::PropertyInstance::ParseInstanceBinary(streamBuffer, buffer, pCur, bufferSize, &(*a), &(*i), p_bBE))) { - case EDT_Float: - out.fFloat = 0.f; - return out; + DefaultLogger::get()->warn("Unable to parse binary property instance. " + "Skipping this element instance"); - case EDT_Double: - out.fDouble = 0.; - return out; + (*i).avList.push_back(PLY::PropertyInstance::DefaultValue((*a).eType)); + } + } + return true; +} - default: ; - }; - out.iUInt = 0; +// ------------------------------------------------------------------------------------------------ +bool PLY::PropertyInstance::ParseInstance(const char* &pCur, + const PLY::Property* prop, PLY::PropertyInstance* p_pcOut) +{ + ai_assert(NULL != prop); + ai_assert(NULL != p_pcOut); + + // skip spaces at the beginning + if (!SkipSpaces(&pCur)) + { + return false; + } + + if (prop->bIsList) + { + // parse the number of elements in the list + PLY::PropertyInstance::ValueUnion v; + PLY::PropertyInstance::ParseValue(pCur, prop->eFirstType, &v); + + // convert to unsigned int + unsigned int iNum = PLY::PropertyInstance::ConvertTo(v, prop->eFirstType); + + // parse all list elements + p_pcOut->avList.resize(iNum); + for (unsigned int i = 0; i < iNum; ++i) + { + if (!SkipSpaces(&pCur)) + return false; + + PLY::PropertyInstance::ParseValue(pCur, prop->eType, &p_pcOut->avList[i]); + } + } + else + { + // parse the property + PLY::PropertyInstance::ValueUnion v; + + PLY::PropertyInstance::ParseValue(pCur, prop->eType, &v); + p_pcOut->avList.push_back(v); + } + SkipSpacesAndLineEnd(&pCur); + return true; +} + +// ------------------------------------------------------------------------------------------------ +bool PLY::PropertyInstance::ParseInstanceBinary(IOStreamBuffer &streamBuffer, std::vector &buffer, + const char* &pCur, + unsigned int &bufferSize, + const PLY::Property* prop, + PLY::PropertyInstance* p_pcOut, + bool p_bBE) +{ + ai_assert(NULL != prop); + ai_assert(NULL != p_pcOut); + + // parse all elements + if (prop->bIsList) + { + // parse the number of elements in the list + PLY::PropertyInstance::ValueUnion v; + PLY::PropertyInstance::ParseValueBinary(streamBuffer, buffer, pCur, bufferSize, prop->eFirstType, &v, p_bBE); + + // convert to unsigned int + unsigned int iNum = PLY::PropertyInstance::ConvertTo(v, prop->eFirstType); + + // parse all list elements + p_pcOut->avList.resize(iNum); + for (unsigned int i = 0; i < iNum; ++i) + { + PLY::PropertyInstance::ParseValueBinary(streamBuffer, buffer, pCur, bufferSize, prop->eType, &p_pcOut->avList[i], p_bBE); + } + } + else + { + // parse the property + PLY::PropertyInstance::ValueUnion v; + PLY::PropertyInstance::ParseValueBinary(streamBuffer, buffer, pCur, bufferSize, prop->eType, &v, p_bBE); + p_pcOut->avList.push_back(v); + } + return true; +} + +// ------------------------------------------------------------------------------------------------ +PLY::PropertyInstance::ValueUnion PLY::PropertyInstance::DefaultValue(PLY::EDataType eType) +{ + PLY::PropertyInstance::ValueUnion out; + + switch (eType) + { + case EDT_Float: + out.fFloat = 0.f; return out; + + case EDT_Double: + out.fDouble = 0.; + return out; + + default:; + }; + out.iUInt = 0; + return out; } // ------------------------------------------------------------------------------------------------ -bool PLY::PropertyInstance::ParseValue( - const char* pCur, - const char** pCurOut, - PLY::EDataType eType, - PLY::PropertyInstance::ValueUnion* out) +bool PLY::PropertyInstance::ParseValue(const char* &pCur, + PLY::EDataType eType, + PLY::PropertyInstance::ValueUnion* out) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != out ); + ai_assert(NULL != pCur); + ai_assert(NULL != out); + + //calc element size + bool ret = true; + switch (eType) + { + case EDT_UInt: + case EDT_UShort: + case EDT_UChar: - bool ret = true; - *pCurOut = pCur; - switch (eType) - { - case EDT_UInt: - case EDT_UShort: - case EDT_UChar: + out->iUInt = (uint32_t)strtoul10(pCur, &pCur); + break; - out->iUInt = (uint32_t)strtoul10(pCur, &pCur); - break; + case EDT_Int: + case EDT_Short: + case EDT_Char: - case EDT_Int: - case EDT_Short: - case EDT_Char: + out->iInt = (int32_t)strtol10(pCur, &pCur); + break; - out->iInt = (int32_t)strtol10(pCur, &pCur); - break; + case EDT_Float: + // technically this should cast to float, but people tend to use float descriptors for double data + // this is the best way to not risk losing precision on import and it doesn't hurt to do this + ai_real f; + pCur = fast_atoreal_move(pCur, f); + out->fFloat = (ai_real)f; + break; - case EDT_Float: - // technically this should cast to float, but people tend to use float descriptors for double data - // this is the best way to not risk losing precision on import and it doesn't hurt to do this - ai_real f; - pCur = fast_atoreal_move(pCur,f); - out->fFloat = (ai_real)f; - break; + case EDT_Double: + double d; + pCur = fast_atoreal_move(pCur, d); + out->fDouble = (double)d; + break; - case EDT_Double: - double d; - pCur = fast_atoreal_move(pCur,d); - out->fDouble = (double)d; - break; + case EDT_INVALID: + default: + ret = false; + break; + } - default: - ret = false; - break; - } - *pCurOut = pCur; - - return ret; + return ret; } // ------------------------------------------------------------------------------------------------ -bool PLY::PropertyInstance::ParseValueBinary( - const char* pCur, - const char** pCurOut, - PLY::EDataType eType, - PLY::PropertyInstance::ValueUnion* out, - bool p_bBE) +bool PLY::PropertyInstance::ParseValueBinary(IOStreamBuffer &streamBuffer, + std::vector &buffer, + const char* &pCur, + unsigned int &bufferSize, + PLY::EDataType eType, + PLY::PropertyInstance::ValueUnion* out, + bool p_bBE) { - ai_assert( NULL != pCur ); - ai_assert( NULL != pCurOut ); - ai_assert( NULL != out ); + ai_assert(NULL != out); - bool ret = true; - switch (eType) + //calc element size + unsigned int lsize = 0; + switch (eType) + { + case EDT_Char: + case EDT_UChar: + lsize = 1; + break; + + case EDT_UShort: + case EDT_Short: + lsize = 2; + break; + + case EDT_UInt: + case EDT_Int: + case EDT_Float: + lsize = 4; + break; + + case EDT_Double: + lsize = 8; + break; + + case EDT_INVALID: + default: + break; + } + + //read the next file block if needed + if (bufferSize < lsize) + { + std::vector nbuffer; + if (streamBuffer.getNextBlock(nbuffer)) { - case EDT_UInt: - out->iUInt = (uint32_t)*((uint32_t*)pCur); - pCur += 4; - - // Swap endianness - if (p_bBE)ByteSwap::Swap((int32_t*)&out->iUInt); - break; - - case EDT_UShort: - { - uint16_t i = *((uint16_t*)pCur); - - // Swap endianness - if (p_bBE)ByteSwap::Swap(&i); - out->iUInt = (uint32_t)i; - pCur += 2; - break; - } - - case EDT_UChar: - { - out->iUInt = (uint32_t)(*((uint8_t*)pCur)); - pCur ++; - break; - } - - case EDT_Int: - out->iInt = *((int32_t*)pCur); - pCur += 4; - - // Swap endianness - if (p_bBE)ByteSwap::Swap(&out->iInt); - break; - - case EDT_Short: - { - int16_t i = *((int16_t*)pCur); - - // Swap endianness - if (p_bBE)ByteSwap::Swap(&i); - out->iInt = (int32_t)i; - pCur += 2; - break; - } - - case EDT_Char: - out->iInt = (int32_t)*((int8_t*)pCur); - pCur ++; - break; - - case EDT_Float: - { - out->fFloat = *((float*)pCur); - - // Swap endianness - if (p_bBE)ByteSwap::Swap((int32_t*)&out->fFloat); - pCur += 4; - break; - } - case EDT_Double: - { - out->fDouble = *((double*)pCur); - - // Swap endianness - if (p_bBE)ByteSwap::Swap((int64_t*)&out->fDouble); - pCur += 8; - break; - } - default: - ret = false; + //concat buffer contents + buffer = std::vector(buffer.end() - bufferSize, buffer.end()); + buffer.insert(buffer.end(), nbuffer.begin(), nbuffer.end()); + nbuffer.clear(); + bufferSize = static_cast(buffer.size()); + pCur = (char*)&buffer[0]; } - *pCurOut = pCur; + else + { + throw DeadlyImportError("Invalid .ply file: File corrupted"); + } + } - return ret; + bool ret = true; + switch (eType) + { + case EDT_UInt: + out->iUInt = (uint32_t)*((uint32_t*)pCur); + pCur += 4; + + // Swap endianness + if (p_bBE)ByteSwap::Swap((int32_t*)&out->iUInt); + break; + + case EDT_UShort: + { + uint16_t i = *((uint16_t*)pCur); + + // Swap endianness + if (p_bBE)ByteSwap::Swap(&i); + out->iUInt = (uint32_t)i; + pCur += 2; + break; + } + + case EDT_UChar: + { + out->iUInt = (uint32_t)(*((uint8_t*)pCur)); + pCur++; + break; + } + + case EDT_Int: + out->iInt = *((int32_t*)pCur); + pCur += 4; + + // Swap endianness + if (p_bBE)ByteSwap::Swap(&out->iInt); + break; + + case EDT_Short: + { + int16_t i = *((int16_t*)pCur); + + // Swap endianness + if (p_bBE)ByteSwap::Swap(&i); + out->iInt = (int32_t)i; + pCur += 2; + break; + } + + case EDT_Char: + out->iInt = (int32_t)*((int8_t*)pCur); + pCur++; + break; + + case EDT_Float: + { + out->fFloat = *((float*)pCur); + + // Swap endianness + if (p_bBE)ByteSwap::Swap((int32_t*)&out->fFloat); + pCur += 4; + break; + } + case EDT_Double: + { + out->fDouble = *((double*)pCur); + + // Swap endianness + if (p_bBE)ByteSwap::Swap((int64_t*)&out->fDouble); + pCur += 8; + break; + } + default: + ret = false; + } + + bufferSize -= lsize; + + return ret; } #endif // !! ASSIMP_BUILD_NO_PLY_IMPORTER diff --git a/code/PlyParser.h b/code/PlyParser.h index 30791e22b..b17b07341 100644 --- a/code/PlyParser.h +++ b/code/PlyParser.h @@ -2,7 +2,7 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team All rights reserved. Redistribution and use of this software in source and binary forms, @@ -45,19 +45,21 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ParsingUtils.h" +#include "IOStreamBuffer.h" #include - namespace Assimp { +//pre-declaration +class PLYImporter; + // http://local.wasp.uwa.edu.au/~pbourke/dataformats/ply/ // http://w3.impa.br/~lvelho/outgoing/sossai/old/ViHAP_D4.4.2_PLY_format_v1.1.pdf // http://www.okino.com/conv/exp_ply.htm namespace PLY { - // --------------------------------------------------------------------------------- /* name type number of bytes @@ -196,6 +198,9 @@ enum EElementSemantic //! The element is a material description EEST_Material, + //! texture path + EEST_TextureFile, + //! Marks invalid entries EEST_INVALID }; @@ -237,16 +242,15 @@ public: //! string is either '\n', '\r' or '\0'. Return value is false //! if the input string is NOT a valid property (E.g. does //! not start with the "property" keyword) - static bool ParseProperty (const char* pCur, const char** pCurOut, - Property* pOut); + static bool ParseProperty(std::vector &buffer, Property* pOut); // ------------------------------------------------------------------- //! Parse a data type from a string - static EDataType ParseDataType(const char* pCur,const char** pCurOut); + static EDataType ParseDataType(std::vector &buffer); // ------------------------------------------------------------------- //! Parse a semantic from a string - static ESemantic ParseSemantic(const char* pCur,const char** pCurOut); + static ESemantic ParseSemantic(std::vector &buffer); }; // --------------------------------------------------------------------------------- @@ -284,13 +288,11 @@ public: //! Parse an element from a string. //! The function will parse all properties contained in the //! element, too. - static bool ParseElement (const char* pCur, const char** pCurOut, - Element* pOut); + static bool ParseElement(IOStreamBuffer &streamBuffer, std::vector &buffer, Element* pOut); // ------------------------------------------------------------------- //! Parse a semantic from a string - static EElementSemantic ParseSemantic(const char* pCur, - const char** pCurOut); + static EElementSemantic ParseSemantic(std::vector &buffer); }; // --------------------------------------------------------------------------------- @@ -330,13 +332,13 @@ public: // ------------------------------------------------------------------- //! Parse a property instance - static bool ParseInstance (const char* pCur,const char** pCurOut, + static bool ParseInstance(const char* &pCur, const Property* prop, PropertyInstance* p_pcOut); // ------------------------------------------------------------------- //! Parse a property instance in binary format - static bool ParseInstanceBinary (const char* pCur,const char** pCurOut, - const Property* prop, PropertyInstance* p_pcOut,bool p_bBE); + static bool ParseInstanceBinary(IOStreamBuffer &streamBuffer, std::vector &buffer, + const char* &pCur, unsigned int &bufferSize, const Property* prop, PropertyInstance* p_pcOut, bool p_bBE); // ------------------------------------------------------------------- //! Get the default value for a given data type @@ -344,13 +346,12 @@ public: // ------------------------------------------------------------------- //! Parse a value - static bool ParseValue(const char* pCur,const char** pCurOut, - EDataType eType,ValueUnion* out); + static bool ParseValue(const char* &pCur, EDataType eType, ValueUnion* out); // ------------------------------------------------------------------- //! Parse a binary value - static bool ParseValueBinary(const char* pCur,const char** pCurOut, - EDataType eType,ValueUnion* out,bool p_bBE); + static bool ParseValueBinary(IOStreamBuffer &streamBuffer, std::vector &buffer, + const char* &pCur, unsigned int &bufferSize, EDataType eType, ValueUnion* out, bool p_bBE); // ------------------------------------------------------------------- //! Convert a property value to a given type TYPE @@ -374,13 +375,13 @@ public: // ------------------------------------------------------------------- //! Parse an element instance - static bool ParseInstance (const char* pCur,const char** pCurOut, + static bool ParseInstance(const char* &pCur, const Element* pcElement, ElementInstance* p_pcOut); // ------------------------------------------------------------------- //! Parse a binary element instance - static bool ParseInstanceBinary (const char* pCur,const char** pCurOut, - const Element* pcElement, ElementInstance* p_pcOut,bool p_bBE); + static bool ParseInstanceBinary(IOStreamBuffer &streamBuffer, std::vector &buffer, + const char* &pCur, unsigned int &bufferSize, const Element* pcElement, ElementInstance* p_pcOut, bool p_bBE); }; // --------------------------------------------------------------------------------- @@ -399,13 +400,13 @@ public: // ------------------------------------------------------------------- //! Parse an element instance list - static bool ParseInstanceList (const char* pCur,const char** pCurOut, - const Element* pcElement, ElementInstanceList* p_pcOut); + static bool ParseInstanceList(IOStreamBuffer &streamBuffer, std::vector &buffer, + const Element* pcElement, ElementInstanceList* p_pcOut, PLYImporter* loader); // ------------------------------------------------------------------- //! Parse a binary element instance list - static bool ParseInstanceListBinary (const char* pCur,const char** pCurOut, - const Element* pcElement, ElementInstanceList* p_pcOut,bool p_bBE); + static bool ParseInstanceListBinary(IOStreamBuffer &streamBuffer, std::vector &buffer, + const char* &pCur, unsigned int &bufferSize, const Element* pcElement, ElementInstanceList* p_pcOut, PLYImporter* loader, bool p_bBE); }; // --------------------------------------------------------------------------------- /** \brief Class to represent the document object model of an ASCII or binary @@ -427,50 +428,33 @@ public: //! Parse the DOM for a PLY file. The input string is assumed //! to be terminated with zero - static bool ParseInstance (const char* pCur,DOM* p_pcOut); - static bool ParseInstanceBinary (const char* pCur, - DOM* p_pcOut,bool p_bBE); + static bool ParseInstance(IOStreamBuffer &streamBuffer, DOM* p_pcOut, PLYImporter* loader); + static bool ParseInstanceBinary(IOStreamBuffer &streamBuffer, DOM* p_pcOut, PLYImporter* loader, bool p_bBE); //! Skip all comment lines after this - static bool SkipComments (const char* pCur,const char** pCurOut); + static bool SkipComments(std::vector &buffer); + + static bool SkipSpaces(std::vector &buffer); + + static bool SkipLine(std::vector &buffer); + + static bool TokenMatch(std::vector &buffer, const char* token, unsigned int len); + + static bool SkipSpacesAndLineEnd(std::vector &buffer); private: // ------------------------------------------------------------------- //! Handle the file header and read all element descriptions - bool ParseHeader (const char* pCur,const char** pCurOut, bool p_bBE); + bool ParseHeader(IOStreamBuffer &streamBuffer, std::vector &buffer, bool p_bBE); // ------------------------------------------------------------------- //! Read in all element instance lists - bool ParseElementInstanceLists (const char* pCur,const char** pCurOut); + bool ParseElementInstanceLists(IOStreamBuffer &streamBuffer, std::vector &buffer, PLYImporter* loader); // ------------------------------------------------------------------- //! Read in all element instance lists for a binary file format - bool ParseElementInstanceListsBinary (const char* pCur, - const char** pCurOut,bool p_bBE); -}; - -// --------------------------------------------------------------------------------- -/** \brief Helper class to represent a loaded PLY face - */ -class Face -{ -public: - - Face() - : iMaterialIndex(0xFFFFFFFF) - { - // set all indices to zero by default - mIndices.resize(3,0); - } - -public: - - //! List of vertex indices - std::vector mIndices; - - //! Material index - unsigned int iMaterialIndex; + bool ParseElementInstanceListsBinary(IOStreamBuffer &streamBuffer, std::vector &buffer, const char* &pCur, unsigned int &bufferSize, PLYImporter* loader, bool p_bBE); }; // --------------------------------------------------------------------------------- diff --git a/code/PolyTools.h b/code/PolyTools.h index 80e1dd173..1089327ae 100644 --- a/code/PolyTools.h +++ b/code/PolyTools.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/PostStepRegistry.cpp b/code/PostStepRegistry.cpp index 31518c132..c80c373e5 100644 --- a/code/PostStepRegistry.cpp +++ b/code/PostStepRegistry.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/PretransformVertices.cpp b/code/PretransformVertices.cpp index bcb3913c3..5fc294618 100644 --- a/code/PretransformVertices.cpp +++ b/code/PretransformVertices.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -46,7 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "PretransformVertices.h" #include "ProcessHelper.h" -#include "SceneCombiner.h" +#include #include "Exceptional.h" using namespace Assimp; @@ -159,6 +160,11 @@ void PretransformVertices::CollectData( aiScene* pcScene, aiNode* pcNode, unsign unsigned int& num_ref = num_refs[pcNode->mMeshes[i]]; ai_assert(0 != num_ref); --num_ref; + // Save the name of the last mesh + if (num_ref==0) + { + pcMeshOut->mName = pcMesh->mName; + } if (identity) { // copy positions without modifying them @@ -625,9 +631,10 @@ void PretransformVertices::Execute( aiScene* pScene) // now delete all nodes in the scene and build a new // flat node graph with a root node and some level 1 children + aiNode* newRoot = new aiNode(); + newRoot->mName = pScene->mRootNode->mName; delete pScene->mRootNode; - pScene->mRootNode = new aiNode(); - pScene->mRootNode->mName.Set(""); + pScene->mRootNode = newRoot; if (1 == pScene->mNumMeshes && !pScene->mNumLights && !pScene->mNumCameras) { @@ -645,7 +652,7 @@ void PretransformVertices::Execute( aiScene* pScene) { aiNode* pcNode = *nodes = new aiNode(); pcNode->mParent = pScene->mRootNode; - pcNode->mName.length = ::ai_snprintf(pcNode->mName.data,MAXLEN,"mesh_%u",i); + pcNode->mName = pScene->mMeshes[i]->mName; // setup mesh indices pcNode->mNumMeshes = 1; diff --git a/code/PretransformVertices.h b/code/PretransformVertices.h index 28bd95a67..65b4938b0 100644 --- a/code/PretransformVertices.h +++ b/code/PretransformVertices.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ProcessHelper.cpp b/code/ProcessHelper.cpp index 501d44484..c255979bd 100644 --- a/code/ProcessHelper.cpp +++ b/code/ProcessHelper.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ProcessHelper.h b/code/ProcessHelper.h index c70e23f5f..a49115936 100644 --- a/code/ProcessHelper.h +++ b/code/ProcessHelper.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Profiler.h b/code/Profiler.h index 9354339a2..1c9ca60b5 100644 --- a/code/Profiler.h +++ b/code/Profiler.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -51,21 +52,19 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include namespace Assimp { - namespace Profiling { - - using namespace Formatter; +namespace Profiling { +using namespace Formatter; // ------------------------------------------------------------------------------------------------ /** Simple wrapper around boost::timer to simplify reporting. Timings are automatically * dumped to the log file. */ -class Profiler -{ - +class Profiler { public: - - Profiler() {} + Profiler() { + // empty + } public: @@ -83,17 +82,17 @@ public: return; } - auto elapsedSeconds = std::chrono::system_clock::now() - regions[region]; + std::chrono::duration elapsedSeconds = std::chrono::system_clock::now() - regions[region]; DefaultLogger::get()->debug((format("END `"),region,"`, dt= ", elapsedSeconds.count()," s")); } private: - typedef std::map> RegionMap; RegionMap regions; }; - } +} } #endif + diff --git a/code/Q3BSPFileData.h b/code/Q3BSPFileData.h index ab46db24f..b836795f8 100644 --- a/code/Q3BSPFileData.h +++ b/code/Q3BSPFileData.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Q3BSPFileImporter.cpp b/code/Q3BSPFileImporter.cpp index 287f08cf7..9d6d8e870 100644 --- a/code/Q3BSPFileImporter.cpp +++ b/code/Q3BSPFileImporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Q3BSPFileImporter.h b/code/Q3BSPFileImporter.h index bac370411..cf53d4db0 100644 --- a/code/Q3BSPFileImporter.h +++ b/code/Q3BSPFileImporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Q3BSPFileParser.cpp b/code/Q3BSPFileParser.cpp index b32f15000..69721fc2d 100644 --- a/code/Q3BSPFileParser.cpp +++ b/code/Q3BSPFileParser.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Q3BSPFileParser.h b/code/Q3BSPFileParser.h index 8363d31c0..1ee6d4aef 100644 --- a/code/Q3BSPFileParser.h +++ b/code/Q3BSPFileParser.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Q3BSPZipArchive.cpp b/code/Q3BSPZipArchive.cpp index 16455c10a..7428c04c3 100644 --- a/code/Q3BSPZipArchive.cpp +++ b/code/Q3BSPZipArchive.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -38,14 +39,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ---------------------------------------------------------------------- */ - - #ifndef ASSIMP_BUILD_NO_Q3BSP_IMPORTER #include "Q3BSPZipArchive.h" -#include #include -#include #include namespace Assimp { @@ -136,7 +133,6 @@ zlib_filefunc_def IOSystem2Unzip::get(IOSystem* pIOHandler) { return mapping; } -// ------------------------------------------------------------------------------------------------ ZipFile::ZipFile(size_t size) : m_Size(size) { ai_assert(m_Size != 0); diff --git a/code/Q3BSPZipArchive.h b/code/Q3BSPZipArchive.h index 4dcd7a849..5430bac6f 100644 --- a/code/Q3BSPZipArchive.h +++ b/code/Q3BSPZipArchive.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -43,7 +44,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #include #include #include diff --git a/code/Q3DLoader.cpp b/code/Q3DLoader.cpp index 0debb2d05..5aa639d09 100644 --- a/code/Q3DLoader.cpp +++ b/code/Q3DLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/Q3DLoader.h b/code/Q3DLoader.h index fb1dd1818..97184a5ff 100644 --- a/code/Q3DLoader.h +++ b/code/Q3DLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/RawLoader.cpp b/code/RawLoader.cpp index ae10ba8b4..e14b5140d 100644 --- a/code/RawLoader.cpp +++ b/code/RawLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/RawLoader.h b/code/RawLoader.h index 984141a04..0a1a35815 100644 --- a/code/RawLoader.h +++ b/code/RawLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/RemoveComments.cpp b/code/RemoveComments.cpp index 8290d2217..37d74124d 100644 --- a/code/RemoveComments.cpp +++ b/code/RemoveComments.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/RemoveComments.h b/code/RemoveComments.h index 35f7774a3..0a00a8f0f 100644 --- a/code/RemoveComments.h +++ b/code/RemoveComments.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/RemoveRedundantMaterials.cpp b/code/RemoveRedundantMaterials.cpp index a9954b946..154bf63ca 100644 --- a/code/RemoveRedundantMaterials.cpp +++ b/code/RemoveRedundantMaterials.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/RemoveRedundantMaterials.h b/code/RemoveRedundantMaterials.h index 60efad9a4..cb4ec02bb 100644 --- a/code/RemoveRedundantMaterials.h +++ b/code/RemoveRedundantMaterials.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/RemoveVCProcess.cpp b/code/RemoveVCProcess.cpp index 473460452..016757dbb 100644 --- a/code/RemoveVCProcess.cpp +++ b/code/RemoveVCProcess.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -305,7 +306,7 @@ bool RemoveVCProcess::ProcessMesh(aiMesh* pMesh) if (!pMesh->mColors[i])break; if (configDeleteFlags & aiComponent_COLORSn(i) || b) { - delete pMesh->mColors[i]; + delete [] pMesh->mColors[i]; pMesh->mColors[i] = NULL; ret = true; diff --git a/code/RemoveVCProcess.h b/code/RemoveVCProcess.h index a9173a815..5735bf419 100644 --- a/code/RemoveVCProcess.h +++ b/code/RemoveVCProcess.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SGSpatialSort.cpp b/code/SGSpatialSort.cpp index 84061888e..7a80381e2 100644 --- a/code/SGSpatialSort.cpp +++ b/code/SGSpatialSort.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -47,7 +48,6 @@ the 3ds loader handling smooth groups correctly */ using namespace Assimp; - // ------------------------------------------------------------------------------------------------ SGSpatialSort::SGSpatialSort() { @@ -88,12 +88,11 @@ void SGSpatialSort::FindPositions( const aiVector3D& pPosition, float dist = pPosition * mPlaneNormal; float minDist = dist - pRadius, maxDist = dist + pRadius; - // clear the array in this strange fashion because a simple clear() would also deallocate - // the array which we want to avoid - poResults.erase( poResults.begin(), poResults.end()); + // clear the array + poResults.clear(); // quick check for positions outside the range - if( mPositions.size() == 0) + if( mPositions.empty() ) return; if( maxDist < mPositions.front().mDistance) return; diff --git a/code/SGSpatialSort.h b/code/SGSpatialSort.h index 59a5c37d6..e7cd38724 100644 --- a/code/SGSpatialSort.h +++ b/code/SGSpatialSort.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SIBImporter.cpp b/code/SIBImporter.cpp index 0a4df61a3..bdda3c677 100644 --- a/code/SIBImporter.cpp +++ b/code/SIBImporter.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -57,7 +58,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ByteSwapper.h" #include "StreamReader.h" #include "TinyFormatter.h" -#include "../contrib/ConvertUTF/ConvertUTF.h" +//#include "../contrib/ConvertUTF/ConvertUTF.h" +#include "../contrib/utf8cpp/source/utf8.h" #include #include #include @@ -65,7 +67,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include - using namespace Assimp; static const aiImporterDesc desc = { @@ -79,25 +80,26 @@ static const aiImporterDesc desc = { "sib" }; -struct SIBChunk -{ +struct SIBChunk { uint32_t Tag; uint32_t Size; } PACK_STRUCT; -enum { POS, NRM, UV, N }; +enum { + POS, + NRM, + UV, + N +}; typedef std::pair SIBPair; -static SIBPair makePair(uint32_t a, uint32_t b) { return (a pos, nrm, uv; @@ -108,15 +110,13 @@ struct SIBMesh std::map edgeMap; }; -struct SIBObject -{ +struct SIBObject { aiString name; aiMatrix4x4 axis; size_t meshIdx, meshCount; }; -struct SIB -{ +struct SIB { std::vector mtls; std::vector meshes; std::vector lights; @@ -124,8 +124,7 @@ struct SIB }; // ------------------------------------------------------------------------------------------------ -static SIBEdge& GetEdge(SIBMesh* mesh, uint32_t posA, uint32_t posB) -{ +static SIBEdge& GetEdge(SIBMesh* mesh, uint32_t posA, uint32_t posB) { SIBPair pair = (posA < posB) ? SIBPair(posA, posB) : SIBPair(posB, posA); std::map::iterator it = mesh->edgeMap.find(pair); if (it != mesh->edgeMap.end()) @@ -177,24 +176,29 @@ static void UnknownChunk(StreamReaderLE* stream, const SIBChunk& chunk) } // Reads a UTF-16LE string and returns it at UTF-8. -static aiString ReadString(StreamReaderLE* stream, uint32_t numWChars) -{ +static aiString ReadString(StreamReaderLE *stream, uint32_t numWChars) { + if ( nullptr == stream || 0 == numWChars ) { + static const aiString empty; + return empty; + } + // Allocate buffers (max expansion is 1 byte -> 4 bytes for UTF-8) - UTF16* temp = new UTF16[numWChars]; - UTF8* str = new UTF8[numWChars * 4 + 1]; - for (uint32_t n=0;nGetU2(); + std::vector str; + str.reserve( numWChars * 4 + 1 ); + uint16_t *temp = new uint16_t[ numWChars ]; + for ( uint32_t n = 0; n < numWChars; ++n ) { + temp[ n ] = stream->GetU2(); + } // Convert it and NUL-terminate. - const UTF16 *start = temp, *end = temp + numWChars; - UTF8 *dest = str, *limit = str + numWChars*4; - ConvertUTF16toUTF8(&start, end, &dest, limit, lenientConversion); - *dest = '\0'; + const uint16_t *start( temp ), *end( temp + numWChars ); + utf8::utf16to8( start, end, back_inserter( str ) ); + str[ str.size() - 1 ] = '\0'; // Return the final string. - aiString result = aiString((const char *)str); - delete[] str; + aiString result = aiString((const char *)&str[0]); delete[] temp; + return result; } @@ -212,26 +216,26 @@ SIBImporter::~SIBImporter() { // ------------------------------------------------------------------------------------------------ // Returns whether the class can handle the format of the given file. -bool SIBImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const -{ +bool SIBImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const { return SimpleExtensionCheck(pFile, "sib"); } // ------------------------------------------------------------------------------------------------ -const aiImporterDesc* SIBImporter::GetInfo () const -{ +const aiImporterDesc* SIBImporter::GetInfo () const { return &desc; } // ------------------------------------------------------------------------------------------------ -static void ReadVerts(SIBMesh* mesh, StreamReaderLE* stream, uint32_t count) -{ - mesh->pos.resize(count); +static void ReadVerts(SIBMesh* mesh, StreamReaderLE* stream, uint32_t count) { + if ( nullptr == mesh || nullptr == stream ) { + return; + } - for (uint32_t n=0;npos[n].x = stream->GetF4(); - mesh->pos[n].y = stream->GetF4(); - mesh->pos[n].z = stream->GetF4(); + mesh->pos.resize(count); + for ( uint32_t n=0; npos[ n ].x = stream->GetF4(); + mesh->pos[ n ].y = stream->GetF4(); + mesh->pos[ n ].z = stream->GetF4(); } } @@ -816,7 +820,7 @@ static void ReadInstance(SIB* sib, StreamReaderLE* stream) static void CheckVersion(StreamReaderLE* stream) { uint32_t version = stream->GetU4(); - if ( version != 1 ) { + if ( version < 1 || version > 2 ) { throw DeadlyImportError( "SIB: Unsupported file version." ); } } diff --git a/code/SIBImporter.h b/code/SIBImporter.h index bd71104c6..e7e2ec0b9 100644 --- a/code/SIBImporter.h +++ b/code/SIBImporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SMDLoader.cpp b/code/SMDLoader.cpp index 37968d030..60e3f63c8 100644 --- a/code/SMDLoader.cpp +++ b/code/SMDLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -449,7 +450,9 @@ void SMDImporter::CreateOutputMeshes() // add bone child nodes void SMDImporter::AddBoneChildren(aiNode* pcNode, uint32_t iParent) { - ai_assert(NULL != pcNode && 0 == pcNode->mNumChildren && NULL == pcNode->mChildren); + ai_assert( NULL != pcNode ); + ai_assert( 0 == pcNode->mNumChildren ); + ai_assert( NULL == pcNode->mChildren); // first count ... for (unsigned int i = 0; i < asBones.size();++i) @@ -647,12 +650,14 @@ void SMDImporter::ComputeAbsoluteBoneTransformations() // create output materials void SMDImporter::CreateOutputMaterials() { + ai_assert( nullptr != pScene ); + pScene->mNumMaterials = (unsigned int)aszTextures.size(); pScene->mMaterials = new aiMaterial*[std::max(1u, pScene->mNumMaterials)]; - for (unsigned int iMat = 0; iMat < pScene->mNumMaterials;++iMat) - { + for (unsigned int iMat = 0; iMat < pScene->mNumMaterials; ++iMat) { aiMaterial* pcMat = new aiMaterial(); + ai_assert( nullptr != pcMat ); pScene->mMaterials[iMat] = pcMat; aiString szName; diff --git a/code/SMDLoader.h b/code/SMDLoader.h index f45c49a7e..c50b327e3 100644 --- a/code/SMDLoader.h +++ b/code/SMDLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/STEPFile.h b/code/STEPFile.h index 9a830c068..529d4edbd 100644 --- a/code/STEPFile.h +++ b/code/STEPFile.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -438,13 +439,17 @@ namespace STEP { // ------------------------------------------------------------------------------ /** Base class for all concrete object instances */ // ------------------------------------------------------------------------------ - class Object - { + class Object { public: - - virtual ~Object() {} Object(const char* classname = "unknown") - : classname(classname) {} + : id( 0 ) + , classname(classname) { + // empty + } + + virtual ~Object() { + // empty + } public: @@ -459,7 +464,6 @@ namespace STEP { return dynamic_cast(*this); } - template const T* ToPtr() const { return dynamic_cast(this); @@ -471,7 +475,6 @@ namespace STEP { } public: - uint64_t GetID() const { return id; } @@ -489,7 +492,6 @@ namespace STEP { const char* const classname; }; - template size_t GenericFill(const STEP::DB& db, const EXPRESS::LIST& params, T* in); // (intentionally undefined) diff --git a/code/STEPFileEncoding.cpp b/code/STEPFileEncoding.cpp index aff0b618d..f9a9dd1ce 100644 --- a/code/STEPFileEncoding.cpp +++ b/code/STEPFileEncoding.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -39,18 +40,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file STEPFileEncoding.cpp - * @brief STEP character handling, string unescaping + * @brief STEP character handling, string un-escaping */ #include "STEPFileEncoding.h" #include "fast_atof.h" +#include -#include "../contrib/ConvertUTF/ConvertUTF.h" #include using namespace Assimp; // roman1 to utf16 table -static const UTF16 mac_codetable[] = { +static const uint16_t mac_codetable[] = { // 0x20 unassig./nonprint. slots 0x0020 , 0x0021 , @@ -308,14 +309,12 @@ bool STEP::StringToUTF8(std::string& s) ai_assert(sizeof(mac_codetable) / sizeof(mac_codetable[0]) == 0x100-0x20); - const UTF32 unival = mac_codetable[macval - 0x20], *univalp = &unival; + const uint32_t unival = mac_codetable[macval - 0x20], *univalp = &unival; - UTF8 temp[5], *tempp = temp; - ai_assert(sizeof(UTF8) == 1); + unsigned char temp[5], *tempp = temp; + ai_assert(sizeof( unsigned char ) == 1); - if(ConvertUTF32toUTF8(&univalp, univalp+1, &tempp, tempp+sizeof(temp), lenientConversion) != conversionOK) { - return false; - } + utf8::utf32to8( univalp, univalp + 1, tempp ); const size_t outcount = static_cast(tempp-temp); @@ -354,28 +353,26 @@ bool STEP::StringToUTF8(std::string& s) } const size_t count = (j-basei)/4; - std::unique_ptr src(new UTF16[count]); + std::unique_ptr src(new uint16_t[count]); const char* cur = s.c_str() + basei; for (size_t k = 0; k < count; ++k, cur += 4) { - src[k] = (static_cast(HexOctetToDecimal(cur)) << 8u) | - static_cast(HexOctetToDecimal(cur+2)); + src[k] = (static_cast(HexOctetToDecimal(cur)) << 8u) | + static_cast(HexOctetToDecimal(cur+2)); } const size_t dcount = count * 3; // this is enough to hold all possible outputs - std::unique_ptr dest(new UTF8[dcount]); + std::unique_ptr dest(new unsigned char[dcount]); - const UTF16* srct = src.get(); - UTF8* destt = dest.get(); - if(ConvertUTF16toUTF8(&srct, srct+count, &destt, destt+dcount, lenientConversion) != conversionOK) { - return false; - } + const uint16_t* srct = src.get(); + unsigned char* destt = dest.get(); + utf8::utf16to8( srct, srct + count, destt ); const size_t outcount = static_cast(destt-dest.get()); s.erase(i,(j+4-i)); - ai_assert(sizeof(UTF8) == 1); + ai_assert(sizeof(unsigned char) == 1); s.insert(i, reinterpret_cast(dest.get()), outcount); i += outcount; @@ -387,37 +384,34 @@ bool STEP::StringToUTF8(std::string& s) } const size_t count = (j-basei)/8; - std::unique_ptr src(new UTF32[count]); + std::unique_ptr src(new uint32_t[count]); const char* cur = s.c_str() + basei; for (size_t k = 0; k < count; ++k, cur += 8) { - src[k] = (static_cast(HexOctetToDecimal(cur )) << 24u) | - (static_cast(HexOctetToDecimal(cur+2)) << 16u) | - (static_cast(HexOctetToDecimal(cur+4)) << 8u) | - (static_cast(HexOctetToDecimal(cur+6))); + src[k] = (static_cast(HexOctetToDecimal(cur )) << 24u) | + (static_cast(HexOctetToDecimal(cur+2)) << 16u) | + (static_cast(HexOctetToDecimal(cur+4)) << 8u) | + (static_cast(HexOctetToDecimal(cur+6))); } const size_t dcount = count * 5; // this is enough to hold all possible outputs - std::unique_ptr dest(new UTF8[dcount]); + std::unique_ptr dest(new unsigned char[dcount]); - const UTF32* srct = src.get(); - UTF8* destt = dest.get(); - if(ConvertUTF32toUTF8(&srct, srct+count, &destt, destt+dcount, lenientConversion) != conversionOK) { - return false; - } + const uint32_t* srct = src.get(); + unsigned char* destt = dest.get(); + utf8::utf32to8( srct, srct + count, destt ); const size_t outcount = static_cast(destt-dest.get()); s.erase(i,(j+4-i)); - ai_assert(sizeof(UTF8) == 1); + ai_assert(sizeof(unsigned char) == 1); s.insert(i, reinterpret_cast(dest.get()), outcount); i += outcount; continue; } } - break; // TODO: other encoding patterns? diff --git a/code/STEPFileEncoding.h b/code/STEPFileEncoding.h index 3aec83056..56615c8f6 100644 --- a/code/STEPFileEncoding.h +++ b/code/STEPFileEncoding.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/STEPFileReader.cpp b/code/STEPFileReader.cpp index afaa53a45..d014c1a5d 100644 --- a/code/STEPFileReader.cpp +++ b/code/STEPFileReader.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/STEPFileReader.h b/code/STEPFileReader.h index c5bc88a5e..fb8c86f59 100644 --- a/code/STEPFileReader.h +++ b/code/STEPFileReader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/STLExporter.cpp b/code/STLExporter.cpp index c9d554655..f94debfc9 100644 --- a/code/STLExporter.cpp +++ b/code/STLExporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/STLExporter.h b/code/STLExporter.h index 44b12344f..7fb6a3e75 100644 --- a/code/STLExporter.h +++ b/code/STLExporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/STLLoader.cpp b/code/STLLoader.cpp index 61d8d33b5..f4d6ddda7 100644 --- a/code/STLLoader.cpp +++ b/code/STLLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -210,20 +211,20 @@ void STLImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOS for (unsigned int i = 0; i < pScene->mNumMeshes; i++) pScene->mRootNode->mMeshes[i] = i; - // create a single default material, using a light gray diffuse color for consistency with + // create a single default material, using a white diffuse color for consistency with // other geometric types (e.g., PLY). aiMaterial* pcMat = new aiMaterial(); aiString s; s.Set(AI_DEFAULT_MATERIAL_NAME); pcMat->AddProperty(&s, AI_MATKEY_NAME); - aiColor4D clrDiffuse(ai_real(0.6),ai_real(0.6),ai_real(0.6),ai_real(1.0)); + aiColor4D clrDiffuse(ai_real(1.0),ai_real(1.0),ai_real(1.0),ai_real(1.0)); if (bMatClr) { clrDiffuse = clrColorDefault; } pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_DIFFUSE); pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_SPECULAR); - clrDiffuse = aiColor4D( ai_real( 0.05), ai_real( 0.05), ai_real( 0.05), ai_real( 1.0)); + clrDiffuse = aiColor4D( ai_real(1.0), ai_real(1.0), ai_real(1.0), ai_real(1.0)); pcMat->AddProperty(&clrDiffuse,1,AI_MATKEY_COLOR_AMBIENT); pScene->mNumMaterials = 1; diff --git a/code/STLLoader.h b/code/STLLoader.h index a0d82dbe8..87ed3288d 100644 --- a/code/STLLoader.h +++ b/code/STLLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SceneCombiner.cpp b/code/SceneCombiner.cpp index a4f832e8f..6fb120325 100644 --- a/code/SceneCombiner.cpp +++ b/code/SceneCombiner.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -50,13 +51,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * OptimizeGraph step. */ // ---------------------------------------------------------------------------- -#include "SceneCombiner.h" +#include #include "StringUtils.h" #include "fast_atof.h" #include "Hash.h" #include "time.h" #include #include +#include #include #include "ScenePrivate.h" @@ -756,7 +758,7 @@ void SceneCombiner::MergeBones(aiMesh* out,std::vector::const_iterator // ------------------------------------------------------------------------------------------------ // Merge a list of meshes -void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int /*flags*/, +void SceneCombiner::MergeMeshes(aiMesh** _out, unsigned int /*flags*/, std::vector::const_iterator begin, std::vector::const_iterator end) { @@ -771,8 +773,14 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int /*flags*/, aiMesh* out = *_out = new aiMesh(); out->mMaterialIndex = (*begin)->mMaterialIndex; + std::string name; // Find out how much output storage we'll need - for (std::vector::const_iterator it = begin; it != end;++it) { + for (std::vector::const_iterator it = begin; it != end; ++it) { + const char *meshName( (*it)->mName.C_Str() ); + name += std::string( meshName ); + if ( it != end - 1 ) { + name += "."; + } out->mNumVertices += (*it)->mNumVertices; out->mNumFaces += (*it)->mNumFaces; out->mNumBones += (*it)->mNumBones; @@ -780,6 +788,7 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int /*flags*/, // combine primitive type flags out->mPrimitiveTypes |= (*it)->mPrimitiveTypes; } + out->mName.Set( name.c_str() ); if (out->mNumVertices) { aiVector3D* pv2; @@ -788,7 +797,7 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int /*flags*/, if ((**begin).HasPositions()) { pv2 = out->mVertices = new aiVector3D[out->mNumVertices]; - for (std::vector::const_iterator it = begin; it != end;++it) { + for (std::vector::const_iterator it = begin; it != end; ++it) { if ((*it)->mVertices) { ::memcpy(pv2,(*it)->mVertices,(*it)->mNumVertices*sizeof(aiVector3D)); } @@ -808,7 +817,7 @@ void SceneCombiner::MergeMeshes(aiMesh** _out,unsigned int /*flags*/, pv2 += (*it)->mNumVertices; } } - // copy tangents and bitangents + // copy tangents and bi-tangents if ((**begin).HasTangentsAndBitangents()) { pv2 = out->mTangents = new aiVector3D[out->mNumVertices]; diff --git a/code/ScenePreprocessor.cpp b/code/ScenePreprocessor.cpp index 327da0b35..0a6366b7d 100644 --- a/code/ScenePreprocessor.cpp +++ b/code/ScenePreprocessor.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ScenePreprocessor.h b/code/ScenePreprocessor.h index 9c4b422a2..3311036c3 100644 --- a/code/ScenePreprocessor.h +++ b/code/ScenePreprocessor.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ScenePrivate.h b/code/ScenePrivate.h index dd4d0a5e1..90d34bade 100644 --- a/code/ScenePrivate.h +++ b/code/ScenePrivate.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SkeletonMeshBuilder.cpp b/code/SkeletonMeshBuilder.cpp index c01b575da..e9f427113 100644 --- a/code/SkeletonMeshBuilder.cpp +++ b/code/SkeletonMeshBuilder.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SkeletonMeshBuilder.h b/code/SkeletonMeshBuilder.h index 3c518e8cd..7a7e7b8ff 100644 --- a/code/SkeletonMeshBuilder.h +++ b/code/SkeletonMeshBuilder.h @@ -4,7 +4,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SmoothingGroups.h b/code/SmoothingGroups.h index 75c59d1cb..7a7e2e429 100644 --- a/code/SmoothingGroups.h +++ b/code/SmoothingGroups.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SortByPTypeProcess.cpp b/code/SortByPTypeProcess.cpp index 74867184a..e4b314e02 100644 --- a/code/SortByPTypeProcess.cpp +++ b/code/SortByPTypeProcess.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/SortByPTypeProcess.h b/code/SortByPTypeProcess.h index f96985cb3..0be7925ff 100644 --- a/code/SortByPTypeProcess.h +++ b/code/SortByPTypeProcess.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SpatialSort.cpp b/code/SpatialSort.cpp index 3825dc33a..35724c2cd 100644 --- a/code/SpatialSort.cpp +++ b/code/SpatialSort.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -125,9 +126,8 @@ void SpatialSort::FindPositions( const aiVector3D& pPosition, const ai_real dist = pPosition * mPlaneNormal; const ai_real minDist = dist - pRadius, maxDist = dist + pRadius; - // clear the array in this strange fashion because a simple clear() would also deallocate - // the array which we want to avoid - poResults.erase( poResults.begin(), poResults.end()); + // clear the array + poResults.clear(); // quick check for positions outside the range if( mPositions.size() == 0) @@ -269,7 +269,7 @@ void SpatialSort::FindIdenticalPositions( const aiVector3D& pPosition, // clear the array in this strange fashion because a simple clear() would also deallocate // the array which we want to avoid - poResults.erase( poResults.begin(), poResults.end()); + poResults.resize( 0 ); // do a binary search for the minimal distance to start the iteration there unsigned int index = (unsigned int)mPositions.size() / 2; diff --git a/code/SpatialSort.h b/code/SpatialSort.h index 367e0f6a6..36b7a2767 100644 --- a/code/SpatialSort.h +++ b/code/SpatialSort.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SplitByBoneCountProcess.cpp b/code/SplitByBoneCountProcess.cpp index 4d01bf0ee..a73dfe81e 100644 --- a/code/SplitByBoneCountProcess.cpp +++ b/code/SplitByBoneCountProcess.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SplitByBoneCountProcess.h b/code/SplitByBoneCountProcess.h index 816d18357..434ef9866 100644 --- a/code/SplitByBoneCountProcess.h +++ b/code/SplitByBoneCountProcess.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SplitLargeMeshes.cpp b/code/SplitLargeMeshes.cpp index 5e21ec6b8..2066f7989 100644 --- a/code/SplitLargeMeshes.cpp +++ b/code/SplitLargeMeshes.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SplitLargeMeshes.h b/code/SplitLargeMeshes.h index 9be27a8f1..7556e9fe8 100644 --- a/code/SplitLargeMeshes.h +++ b/code/SplitLargeMeshes.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/StandardShapes.cpp b/code/StandardShapes.cpp index 26c84217a..4346a8d76 100644 --- a/code/StandardShapes.cpp +++ b/code/StandardShapes.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/StandardShapes.h b/code/StandardShapes.h index faa250a2e..a31de566c 100644 --- a/code/StandardShapes.h +++ b/code/StandardShapes.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/StdOStreamLogStream.h b/code/StdOStreamLogStream.h index 249e30458..d9993b246 100644 --- a/code/StdOStreamLogStream.h +++ b/code/StdOStreamLogStream.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/StepExporter.cpp b/code/StepExporter.cpp index aa7086cee..acf1b6dad 100644 --- a/code/StepExporter.cpp +++ b/code/StepExporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -42,12 +43,13 @@ 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 "Bitmap.h" #include "BaseImporter.h" #include "fast_atof.h" -#include "SceneCombiner.h" +#include #include #include #include diff --git a/code/StepExporter.h b/code/StepExporter.h index b51280c6c..e5cdda7a1 100644 --- a/code/StepExporter.h +++ b/code/StepExporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/StreamReader.h b/code/StreamReader.h index 698ba2b39..6220de9a8 100644 --- a/code/StreamReader.h +++ b/code/StreamReader.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -290,15 +291,11 @@ private: throw DeadlyImportError("End of file or stream limit was reached"); } -///*#ifdef __arm__ T f; ::memcpy (&f, current, sizeof(T)); -//#else*/ -// T f = *((const T*)current); -//#endif - Intern :: Getter() (&f,le); - + Intern::Getter() (&f,le); current += sizeof(T); + return f; } diff --git a/code/StreamWriter.h b/code/StreamWriter.h index 12239bf7f..26873fb5b 100644 --- a/code/StreamWriter.h +++ b/code/StreamWriter.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/StringComparison.h b/code/StringComparison.h index d3130e1cb..ed5f4bd6a 100644 --- a/code/StringComparison.h +++ b/code/StringComparison.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/StringUtils.h b/code/StringUtils.h index 434ab4520..64f66e6b9 100644 --- a/code/StringUtils.h +++ b/code/StringUtils.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -42,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include /// @fn ai_snprintf /// @brief The portable version of the function snprintf ( C99 standard ), which works on visual studio compilers 2013 and earlier. diff --git a/code/Subdivision.cpp b/code/Subdivision.cpp index 7bc30c53a..bc5292dbe 100644 --- a/code/Subdivision.cpp +++ b/code/Subdivision.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -39,7 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "Subdivision.h" -#include "SceneCombiner.h" +#include #include "SpatialSort.h" #include "ProcessHelper.h" #include "Vertex.h" diff --git a/code/Subdivision.h b/code/Subdivision.h index 658640f55..b8ce228d2 100644 --- a/code/Subdivision.h +++ b/code/Subdivision.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/TargetAnimation.cpp b/code/TargetAnimation.cpp index ecf6f0dcf..ab6b3d12f 100644 --- a/code/TargetAnimation.cpp +++ b/code/TargetAnimation.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/TargetAnimation.h b/code/TargetAnimation.h index 79cef599e..21b66e591 100644 --- a/code/TargetAnimation.h +++ b/code/TargetAnimation.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/TerragenLoader.cpp b/code/TerragenLoader.cpp index dcb19b9ca..ecf33aae9 100644 --- a/code/TerragenLoader.cpp +++ b/code/TerragenLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/TerragenLoader.h b/code/TerragenLoader.h index c216a2186..a95bd6bff 100644 --- a/code/TerragenLoader.h +++ b/code/TerragenLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/TextureTransform.cpp b/code/TextureTransform.cpp index 948ec013b..76f0ce58c 100644 --- a/code/TextureTransform.cpp +++ b/code/TextureTransform.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/TextureTransform.h b/code/TextureTransform.h index ccad3bdd9..7f1e4572f 100644 --- a/code/TextureTransform.h +++ b/code/TextureTransform.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/TinyFormatter.h b/code/TinyFormatter.h index 1182e3a5a..1612282fb 100644 --- a/code/TinyFormatter.h +++ b/code/TinyFormatter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/TriangulateProcess.cpp b/code/TriangulateProcess.cpp index 883a45e3d..e2d77a80f 100644 --- a/code/TriangulateProcess.cpp +++ b/code/TriangulateProcess.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/TriangulateProcess.h b/code/TriangulateProcess.h index 97b5004e1..6775eca7c 100644 --- a/code/TriangulateProcess.h +++ b/code/TriangulateProcess.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/UnrealLoader.cpp b/code/UnrealLoader.cpp index 59be4bed1..a79a2a5c5 100644 --- a/code/UnrealLoader.cpp +++ b/code/UnrealLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -156,7 +157,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile, DefaultLogger::get()->debug("UNREAL: uc file is " + uc_path); // and open the files ... we can't live without them - IOStream* p = pIOHandler->Open(d_path); + std::unique_ptr p(pIOHandler->Open(d_path)); if (!p) throw DeadlyImportError("UNREAL: Unable to open _d file"); StreamReaderLE d_reader(pIOHandler->Open(d_path)); @@ -202,7 +203,7 @@ void UnrealImporter::InternReadFile( const std::string& pFile, d_reader.IncPtr(1); } - p = pIOHandler->Open(a_path); + p.reset(pIOHandler->Open(a_path)); if (!p) throw DeadlyImportError("UNREAL: Unable to open _a file"); StreamReaderLE a_reader(pIOHandler->Open(a_path)); diff --git a/code/UnrealLoader.h b/code/UnrealLoader.h index 93648ca82..a2ceb3d54 100644 --- a/code/UnrealLoader.h +++ b/code/UnrealLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/ValidateDataStructure.cpp b/code/ValidateDataStructure.cpp index 44e361f71..ae1e0d342 100644 --- a/code/ValidateDataStructure.cpp +++ b/code/ValidateDataStructure.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -408,12 +409,12 @@ void ValidateDSProcess::Validate( const aiMesh* pMesh) // the MSB flag is temporarily used by the extra verbose // mode to tell us that the JoinVerticesProcess might have // been executed already. - if ( !(this->mScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT ) && !(this->mScene->mFlags & AI_SCENE_FLAGS_ALLOW_SHARED) && + /*if ( !(this->mScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT ) && !(this->mScene->mFlags & AI_SCENE_FLAGS_ALLOW_SHARED) && abRefList[face.mIndices[a]]) { ReportError("aiMesh::mVertices[%i] is referenced twice - second " "time by aiMesh::mFaces[%i]::mIndices[%i]",face.mIndices[a],i,a); - } + }*/ abRefList[face.mIndices[a]] = true; } } diff --git a/code/ValidateDataStructure.h b/code/ValidateDataStructure.h index 87f158b37..6daf9b87d 100644 --- a/code/ValidateDataStructure.h +++ b/code/ValidateDataStructure.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Version.cpp b/code/Version.cpp index fd8ed622c..2cd759817 100644 --- a/code/Version.cpp +++ b/code/Version.cpp @@ -45,8 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "ScenePrivate.h" -static const unsigned int MajorVersion = 3; -static const unsigned int MinorVersion = 3; +static const unsigned int MajorVersion = 4; +static const unsigned int MinorVersion = 0; // -------------------------------------------------------------------------------- // Legal information string - dont't remove this. @@ -107,34 +107,32 @@ ASSIMP_API unsigned int aiGetCompileFlags () { #include "revision.h" // ------------------------------------------------------------------------------------------------ -ASSIMP_API unsigned int aiGetVersionRevision () -{ +ASSIMP_API unsigned int aiGetVersionRevision() { return GitVersion; } // ------------------------------------------------------------------------------------------------ ASSIMP_API aiScene::aiScene() - : mFlags(0) - , mRootNode(NULL) - , mNumMeshes(0) - , mMeshes(NULL) - , mNumMaterials(0) - , mMaterials(NULL) - , mNumAnimations(0) - , mAnimations(NULL) - , mNumTextures(0) - , mTextures(NULL) - , mNumLights(0) - , mLights(NULL) - , mNumCameras(0) - , mCameras(NULL) - , mPrivate(new Assimp::ScenePrivateData()) - { - } +: mFlags(0) +, mRootNode(NULL) +, mNumMeshes(0) +, mMeshes(NULL) +, mNumMaterials(0) +, mMaterials(NULL) +, mNumAnimations(0) +, mAnimations(NULL) +, mNumTextures(0) +, mTextures(NULL) +, mNumLights(0) +, mLights(NULL) +, mNumCameras(0) +, mCameras(NULL) +, mPrivate(new Assimp::ScenePrivateData()) { + // empty +} // ------------------------------------------------------------------------------------------------ -ASSIMP_API aiScene::~aiScene() -{ +ASSIMP_API aiScene::~aiScene() { // delete all sub-objects recursively delete mRootNode; diff --git a/code/Vertex.h b/code/Vertex.h index 88840eab7..1f1685ae9 100644 --- a/code/Vertex.h +++ b/code/Vertex.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/VertexTriangleAdjacency.cpp b/code/VertexTriangleAdjacency.cpp index 6de55ab34..09c0a51a7 100644 --- a/code/VertexTriangleAdjacency.cpp +++ b/code/VertexTriangleAdjacency.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/VertexTriangleAdjacency.h b/code/VertexTriangleAdjacency.h index 218607508..ed7b83a6b 100644 --- a/code/VertexTriangleAdjacency.h +++ b/code/VertexTriangleAdjacency.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/Win32DebugLogStream.h b/code/Win32DebugLogStream.h index de8606ebc..0833712f9 100644 --- a/code/Win32DebugLogStream.h +++ b/code/Win32DebugLogStream.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/X3DExporter.cpp b/code/X3DExporter.cpp index 9e89b5b9e..31a391c47 100644 --- a/code/X3DExporter.cpp +++ b/code/X3DExporter.cpp @@ -140,7 +140,7 @@ void X3DExporter::AttrHelper_Col3DArrToString(const aiColor3D* pArray, const siz AttrHelper_CommaToPoint(pTargetString); } -void X3DExporter::AttrHelper_Color3ToAttrList(std::list pList, const std::string& pName, const aiColor3D& pValue, const aiColor3D& pDefaultValue) +void X3DExporter::AttrHelper_Color3ToAttrList(std::list& pList, const std::string& pName, const aiColor3D& pValue, const aiColor3D& pDefaultValue) { string tstr; @@ -150,7 +150,7 @@ string tstr; pList.push_back({pName, tstr}); } -void X3DExporter::AttrHelper_FloatToAttrList(std::list pList, const string& pName, const float pValue, const float pDefaultValue) +void X3DExporter::AttrHelper_FloatToAttrList(std::list& pList, const string& pName, const float pValue, const float pDefaultValue) { string tstr; diff --git a/code/X3DExporter.hpp b/code/X3DExporter.hpp index 20aec951b..bf1e72218 100644 --- a/code/X3DExporter.hpp +++ b/code/X3DExporter.hpp @@ -134,7 +134,7 @@ private: /// \fn void AttrHelper_FloatToAttrList(std::list pList, const std::string& pName, const float pValue, const float pDefaultValue) /// \overload void AttrHelper_Col3DArrToString(const aiColor3D* pArray, const size_t pArray_Size, std::string& pTargetString) - void AttrHelper_FloatToAttrList(std::list pList, const std::string& pName, const float pValue, const float pDefaultValue); + void AttrHelper_FloatToAttrList(std::list &pList, const std::string& pName, const float pValue, const float pDefaultValue); /// \fn void AttrHelper_Color3ToAttrList(std::list pList, const std::string& pName, const aiColor3D& pValue, const aiColor3D& pDefaultValue) /// Add attribute to list if value not equal to default. @@ -142,7 +142,7 @@ private: /// \param [in] pName - name of new attribute. /// \param [in] pValue - value of the new attribute. /// \param [in] pDefaultValue - default value for checking: if pValue is equal to pDefaultValue then attribute will not be added. - void AttrHelper_Color3ToAttrList(std::list pList, const std::string& pName, const aiColor3D& pValue, const aiColor3D& pDefaultValue); + void AttrHelper_Color3ToAttrList(std::list &pList, const std::string& pName, const aiColor3D& pValue, const aiColor3D& pDefaultValue); /// \fn void NodeHelper_OpenNode(const std::string& pNodeName, const size_t pTabLevel, const bool pEmptyElement, const std::list& pAttrList) /// Begin new XML-node element. diff --git a/code/X3DImporter.cpp b/code/X3DImporter.cpp index b1ed85380..aaf99b309 100644 --- a/code/X3DImporter.cpp +++ b/code/X3DImporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -51,10 +52,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Header files, Assimp. #include #include "fast_atof.h" +#include "FIReader.hpp" // Header files, stdlib. #include #include +#include namespace Assimp { @@ -65,14 +68,53 @@ const aiImporterDesc X3DImporter::Description = { "smalcom", "", "See documentation in source code. Chapter: Limitations.", - aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental, + aiImporterFlags_SupportTextFlavour | aiImporterFlags_SupportBinaryFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental, 0, 0, 0, 0, - "x3d" + "x3d x3db" }; +//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 { + static const char *whitespace; + const char *start_, *end_; + WordIterator(const char *start, const char *end): start_(start), end_(end) { + start_ = start + strspn(start, whitespace); + if (start_ >= end_) { + start_ = 0; + } + } + WordIterator(): start_(0), end_(0) {} + WordIterator(const WordIterator &other): start_(other.start_), end_(other.end_) {} + WordIterator &operator=(const WordIterator &other) { + start_ = other.start_; + end_ = other.end_; + return *this; + } + bool operator==(const WordIterator &other) const { return start_ == other.start_; } + bool operator!=(const WordIterator &other) const { return start_ != other.start_; } + WordIterator &operator++() { + start_ += strcspn(start_, whitespace); + start_ += strspn(start_, whitespace); + if (start_ >= end_) { + start_ = 0; + } + return *this; + } + WordIterator operator++(int) { + WordIterator result(*this); + ++(*this); + return result; + } + const char *operator*() const { return start_; } +}; + +const char *WordIterator::whitespace = ", \t\r\n"; + X3DImporter::X3DImporter() : NodeElement_Cur( nullptr ) , mReader( nullptr ) { @@ -80,7 +122,6 @@ X3DImporter::X3DImporter() } X3DImporter::~X3DImporter() { - delete mReader; // Clear() is accounting if data already is deleted. So, just check again if all data is deleted. Clear(); } @@ -240,7 +281,7 @@ void X3DImporter::XML_CheckNode_MustBeEmpty() void X3DImporter::XML_CheckNode_SkipUnsupported(const std::string& pParentNodeName) { - const size_t Uns_Skip_Len = 189; + static const size_t Uns_Skip_Len = 192; const char* Uns_Skip[ Uns_Skip_Len ] = { // CAD geometry component "CADAssembly", "CADFace", "CADLayer", "CADPart", "IndexedQuadSet", "QuadSet", @@ -267,7 +308,7 @@ void X3DImporter::XML_CheckNode_SkipUnsupported(const std::string& pParentNodeNa "PositionInterpolator", "PositionInterpolator2D", "ScalarInterpolator", "SplinePositionInterpolator", "SplinePositionInterpolator2D", "SplineScalarInterpolator", "SquadOrientationInterpolator", // Key device sensor component - "KeySensor", "StringSensor" + "KeySensor", "StringSensor", // Layering component "Layer", "LayerSet", "Viewport", // Layout component @@ -275,7 +316,7 @@ void X3DImporter::XML_CheckNode_SkipUnsupported(const std::string& pParentNodeNa // Navigation component "Billboard", "Collision", "LOD", "NavigationInfo", "OrthoViewpoint", "Viewpoint", "ViewpointGroup", // Networking component - "Anchor", "LoadSensor", + "EXPORT", "IMPORT", "Anchor", "LoadSensor", // NURBS component "Contour2D", "ContourPolyline2D", "CoordinateDouble", "NurbsCurve", "NurbsCurve2D", "NurbsOrientationInterpolator", "NurbsPatchSurface", "NurbsPositionInterpolator", "NurbsSet", "NurbsSurfaceInterpolator", "NurbsSweptSurface", "NurbsSwungSurface", "NurbsTextureCoordinate", @@ -367,38 +408,65 @@ bool X3DImporter::XML_SearchNode(const std::string& pNodeName) bool X3DImporter::XML_ReadNode_GetAttrVal_AsBool(const int pAttrIdx) { -std::string val(mReader->getAttributeValue(pAttrIdx)); + auto boolValue = std::dynamic_pointer_cast(mReader->getAttributeEncodedValue(pAttrIdx)); + if (boolValue) { + if (boolValue->value.size() == 1) { + return boolValue->value.front(); + } + throw DeadlyImportError("Invalid bool value"); + } + else { + std::string val(mReader->getAttributeValue(pAttrIdx)); - if(val == "false") - return false; - else if(val == "true") - return true; - else - throw DeadlyImportError("Bool attribute value can contain \"false\" or \"true\" not the \"" + val + "\""); + if(val == "false") + return false; + else if(val == "true") + return true; + else + throw DeadlyImportError("Bool attribute value can contain \"false\" or \"true\" not the \"" + val + "\""); + } } float X3DImporter::XML_ReadNode_GetAttrVal_AsFloat(const int pAttrIdx) { - std::string val; - float tvalf; + auto floatValue = std::dynamic_pointer_cast(mReader->getAttributeEncodedValue(pAttrIdx)); + if (floatValue) { + if (floatValue->value.size() == 1) { + return floatValue->value.front(); + } + throw DeadlyImportError("Invalid float value"); + } + else { + std::string val; + float tvalf; - ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), val); - fast_atoreal_move(val.c_str(), tvalf, false); + ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), val); + fast_atoreal_move(val.c_str(), tvalf, false); - return tvalf; + return tvalf; + } } int32_t X3DImporter::XML_ReadNode_GetAttrVal_AsI32(const int pAttrIdx) { - return strtol10(mReader->getAttributeValue(pAttrIdx)); + auto intValue = std::dynamic_pointer_cast(mReader->getAttributeEncodedValue(pAttrIdx)); + if (intValue) { + if (intValue->value.size() == 1) { + return intValue->value.front(); + } + throw DeadlyImportError("Invalid int value"); + } + else { + return strtol10(mReader->getAttributeValue(pAttrIdx)); + } } void X3DImporter::XML_ReadNode_GetAttrVal_AsCol3f(const int pAttrIdx, aiColor3D& pValue) { - std::list tlist; - std::list::iterator it; + std::vector tlist; + std::vector::iterator it; - XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist); + XML_ReadNode_GetAttrVal_AsArrF(pAttrIdx, tlist); if(tlist.size() != 3) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx)); it = tlist.begin(); @@ -409,10 +477,10 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsCol3f(const int pAttrIdx, aiColor3D& void X3DImporter::XML_ReadNode_GetAttrVal_AsVec2f(const int pAttrIdx, aiVector2D& pValue) { - std::list tlist; - std::list::iterator it; + std::vector tlist; + std::vector::iterator it; - XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist); + XML_ReadNode_GetAttrVal_AsArrF(pAttrIdx, tlist); if(tlist.size() != 2) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx)); it = tlist.begin(); @@ -422,10 +490,10 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsVec2f(const int pAttrIdx, aiVector2D void X3DImporter::XML_ReadNode_GetAttrVal_AsVec3f(const int pAttrIdx, aiVector3D& pValue) { - std::list tlist; - std::list::iterator it; + std::vector tlist; + std::vector::iterator it; - XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist); + XML_ReadNode_GetAttrVal_AsArrF(pAttrIdx, tlist); if(tlist.size() != 3) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx)); it = tlist.begin(); @@ -434,181 +502,95 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsVec3f(const int pAttrIdx, aiVector3D pValue.z = *it; } -void X3DImporter::XML_ReadNode_GetAttrVal_AsListB(const int pAttrIdx, std::list& pValue) -{ - // make copy of attribute value - string with list of bool values. Also all bool values is strings. - size_t tok_str_len = strlen(mReader->getAttributeValue(pAttrIdx)); - if ( 0 == tok_str_len ) { - Throw_IncorrectAttrValue( mReader->getAttributeName( pAttrIdx ) ); - } - - tok_str_len++;// take in account terminating '\0'. - char *tok_str = new char[tok_str_len]; - - strcpy(tok_str, mReader->getAttributeValue(pAttrIdx)); - // change all spacebars to symbol '\0'. That is needed for parsing. - for(size_t i = 0; i < tok_str_len; i++) - { - if(tok_str[i] == ' ') tok_str[i] = 0; - } - - // at now check what current token is - for(char *tok_cur = tok_str, *tok_end = (tok_str + tok_str_len); tok_cur < tok_end;) - { - if(strncmp(tok_cur, "true", 4) == 0) - { - pValue.push_back(true); - tok_cur += 5;// five, not four. Because '\0' must be skipped too. - } - else if(strncmp(tok_cur, "false", 5) == 0) - { - pValue.push_back(true); - tok_cur += 6;// six, not five. Because '\0' must be skipped too. - } - else - { - Throw_IncorrectAttrValue(mReader->getAttributeName(pAttrIdx)); - } - }// for(char* tok_cur = tok_str, tok_end = (tok_str + tok_str_len); tok_cur < tok_end;) - - // delete temporary string - delete [] tok_str; -} - void X3DImporter::XML_ReadNode_GetAttrVal_AsArrB(const int pAttrIdx, std::vector& pValue) { - std::list tlist; + auto boolValue = std::dynamic_pointer_cast(mReader->getAttributeEncodedValue(pAttrIdx)); + if (boolValue) { + pValue = boolValue->value; + } + else { + const char *val = mReader->getAttributeValue(pAttrIdx); + pValue.clear(); - XML_ReadNode_GetAttrVal_AsListB(pAttrIdx, tlist);// read as list - // and copy to array - if(tlist.size() > 0) - { - pValue.reserve(tlist.size()); - for(std::list::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it); - } -} + //std::cregex_iterator wordItBegin(val, val + strlen(val), pattern_nws); + //const std::cregex_iterator wordItEnd; + //std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const std::cmatch &match) { return std::regex_match(match.str(), pattern_true); }); -void X3DImporter::XML_ReadNode_GetAttrVal_AsListI32(const int pAttrIdx, std::list& pValue) -{ - const char* tstr = mReader->getAttributeValue(pAttrIdx); - const char* tstr_end = tstr + strlen(tstr); - - do - { - const char* ostr; - - int32_t tval32; - - tval32 = strtol10(tstr, &ostr); - if(ostr == tstr) break; - - while((ostr < tstr_end) && (*ostr == ' ')) ostr++;// skip spaces between values. - - tstr = ostr; - pValue.push_back(tval32); - } while(tstr < tstr_end); + WordIterator wordItBegin(val, val + strlen(val)); + WordIterator wordItEnd; + std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const char *match) { return (::tolower(match[0]) == 't') || (match[0] == '1'); }); + } } void X3DImporter::XML_ReadNode_GetAttrVal_AsArrI32(const int pAttrIdx, std::vector& pValue) { - std::list tlist; + auto intValue = std::dynamic_pointer_cast(mReader->getAttributeEncodedValue(pAttrIdx)); + if (intValue) { + pValue = intValue->value; + } + else { + const char *val = mReader->getAttributeValue(pAttrIdx); + pValue.clear(); - XML_ReadNode_GetAttrVal_AsListI32(pAttrIdx, tlist);// read as list - // and copy to array - if(tlist.size() > 0) - { - pValue.reserve(tlist.size()); - for(std::list::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it); - } -} + //std::cregex_iterator wordItBegin(val, val + strlen(val), pattern_nws); + //const std::cregex_iterator wordItEnd; + //std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const std::cmatch &match) { return std::stoi(match.str()); }); -void X3DImporter::XML_ReadNode_GetAttrVal_AsListF(const int pAttrIdx, std::list& pValue) -{ - std::string str_fixed; - - // at first check string values like '.xxx'. - ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), str_fixed); - if(!str_fixed.size()) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx)); - - // and convert all values and place it in list. - const char* pstr = str_fixed.c_str(); - const char* pstr_end = pstr + str_fixed.size(); - - do - { - float tvalf; - - while((*pstr == ' ') && (pstr < pstr_end)) pstr++;// skip spaces between values. - - if(pstr < pstr_end)// additional check, because attribute value can be ended with spaces. - { - pstr = fast_atoreal_move(pstr, tvalf, false); - pValue.push_back(tvalf); - } - } while(pstr < pstr_end); + WordIterator wordItBegin(val, val + strlen(val)); + WordIterator wordItEnd; + std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const char *match) { return atoi(match); }); + } } void X3DImporter::XML_ReadNode_GetAttrVal_AsArrF(const int pAttrIdx, std::vector& pValue) { - std::list tlist; + auto floatValue = std::dynamic_pointer_cast(mReader->getAttributeEncodedValue(pAttrIdx)); + if (floatValue) { + pValue = floatValue->value; + } + else { + const char *val = mReader->getAttributeValue(pAttrIdx); + pValue.clear(); - XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list - // and copy to array - if(tlist.size() > 0) - { - pValue.reserve(tlist.size()); - for(std::list::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it); - } -} + //std::cregex_iterator wordItBegin(val, val + strlen(val), pattern_nws); + //const std::cregex_iterator wordItEnd; + //std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const std::cmatch &match) { return std::stof(match.str()); }); -void X3DImporter::XML_ReadNode_GetAttrVal_AsListD(const int pAttrIdx, std::list& pValue) -{ - std::string str_fixed; - - // at first check string values like '.xxx'. - ParseHelper_FixTruncatedFloatString(mReader->getAttributeValue(pAttrIdx), str_fixed); - if(!str_fixed.size()) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx)); - - // and convert all values and place it in list. - const char* pstr = str_fixed.c_str(); - const char* pstr_end = pstr + str_fixed.size(); - - do - { - double tvald; - - while((*pstr == ' ') && (pstr < pstr_end)) pstr++;// skip spaces between values. - - if(pstr < pstr_end)// additional check, because attribute value can be ended with spaces. - { - pstr = fast_atoreal_move(pstr, tvald, false); - pValue.push_back(tvald); - } - } while(pstr < pstr_end); + WordIterator wordItBegin(val, val + strlen(val)); + WordIterator wordItEnd; + std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const char *match) { return static_cast(atof(match)); }); + } } void X3DImporter::XML_ReadNode_GetAttrVal_AsArrD(const int pAttrIdx, std::vector& pValue) { - std::list tlist; + auto doubleValue = std::dynamic_pointer_cast(mReader->getAttributeEncodedValue(pAttrIdx)); + if (doubleValue) { + pValue = doubleValue->value; + } + else { + const char *val = mReader->getAttributeValue(pAttrIdx); + pValue.clear(); - XML_ReadNode_GetAttrVal_AsListD(pAttrIdx, tlist);// read as list - // and copy to array - if(tlist.size() > 0) - { - pValue.reserve(tlist.size()); - for(std::list::iterator it = tlist.begin(); it != tlist.end(); it++) pValue.push_back(*it); - } + //std::cregex_iterator wordItBegin(val, val + strlen(val), pattern_nws); + //const std::cregex_iterator wordItEnd; + //std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const std::cmatch &match) { return std::stod(match.str()); }); + + WordIterator wordItBegin(val, val + strlen(val)); + WordIterator wordItEnd; + std::transform(wordItBegin, wordItEnd, std::back_inserter(pValue), [](const char *match) { return atof(match); }); + } } void X3DImporter::XML_ReadNode_GetAttrVal_AsListCol3f(const int pAttrIdx, std::list& pValue) { - std::list tlist; + std::vector tlist; - XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list + XML_ReadNode_GetAttrVal_AsArrF(pAttrIdx, tlist);// read as list if(tlist.size() % 3) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx)); // copy data to array - for(std::list::iterator it = tlist.begin(); it != tlist.end();) + for(std::vector::iterator it = tlist.begin(); it != tlist.end();) { aiColor3D tcol; @@ -634,13 +616,13 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrCol3f(const int pAttrIdx, std::ve void X3DImporter::XML_ReadNode_GetAttrVal_AsListCol4f(const int pAttrIdx, std::list& pValue) { - std::list tlist; + std::vector tlist; - XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list + XML_ReadNode_GetAttrVal_AsArrF(pAttrIdx, tlist);// read as list if(tlist.size() % 4) Throw_ConvertFail_Str2ArrF(mReader->getAttributeValue(pAttrIdx)); // copy data to array - for(std::list::iterator it = tlist.begin(); it != tlist.end();) + for(std::vector::iterator it = tlist.begin(); it != tlist.end();) { aiColor4D tcol; @@ -670,16 +652,16 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrCol4f(const int pAttrIdx, std::ve void X3DImporter::XML_ReadNode_GetAttrVal_AsListVec2f(const int pAttrIdx, std::list& pValue) { - std::list tlist; + std::vector tlist; - XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list + XML_ReadNode_GetAttrVal_AsArrF(pAttrIdx, tlist);// read as list if ( tlist.size() % 2 ) { Throw_ConvertFail_Str2ArrF( mReader->getAttributeValue( pAttrIdx ) ); } // copy data to array - for(std::list::iterator it = tlist.begin(); it != tlist.end();) + for(std::vector::iterator it = tlist.begin(); it != tlist.end();) { aiVector2D tvec; @@ -707,16 +689,16 @@ void X3DImporter::XML_ReadNode_GetAttrVal_AsArrVec2f(const int pAttrIdx, std::ve void X3DImporter::XML_ReadNode_GetAttrVal_AsListVec3f(const int pAttrIdx, std::list& pValue) { - std::list tlist; + std::vector tlist; - XML_ReadNode_GetAttrVal_AsListF(pAttrIdx, tlist);// read as list + XML_ReadNode_GetAttrVal_AsArrF(pAttrIdx, tlist);// read as list if ( tlist.size() % 3 ) { Throw_ConvertFail_Str2ArrF( mReader->getAttributeValue( pAttrIdx ) ); } // copy data to array - for(std::list::iterator it = tlist.begin(); it != tlist.end();) + for(std::vector::iterator it = tlist.begin(); it != tlist.end();) { aiVector3D tvec; @@ -906,9 +888,9 @@ void X3DImporter::GeometryHelper_MakeQL_RectParallelepiped(const aiVector3D& pSi #undef MESH_RectParallelepiped_CREATE_VERT -void X3DImporter::GeometryHelper_CoordIdxStr2FacesArr(const std::list& pCoordIdx, std::vector& pFaces, unsigned int& pPrimitiveTypes) const +void X3DImporter::GeometryHelper_CoordIdxStr2FacesArr(const std::vector& pCoordIdx, std::vector& pFaces, unsigned int& pPrimitiveTypes) const { - std::list f_data(pCoordIdx); + std::vector f_data(pCoordIdx); std::vector inds; unsigned int prim_type = 0; @@ -921,7 +903,7 @@ void X3DImporter::GeometryHelper_CoordIdxStr2FacesArr(const std::list& pFaces.reserve(f_data.size() / 3); inds.reserve(4); //PrintVectorSet("build. ci", pCoordIdx); - for(std::list::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)) @@ -1013,7 +995,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pColorIdx, +void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::vector& pCoordIdx, const std::vector& pColorIdx, const std::list& pColors, const bool pColorPerVertex) const { std::list tcol; @@ -1028,7 +1010,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list& MeshGeometry_AddColor(pMesh, pCoordIdx, pColorIdx, tcol, pColorPerVertex); } -void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pColorIdx, +void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::vector& pCoordIdx, const std::vector& pColorIdx, const std::list& pColors, const bool pColorPerVertex) const { std::vector col_tgt_arr; @@ -1059,7 +1041,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list& } // create list with colors for every vertex. col_tgt_arr.resize(pMesh.mNumVertices); - for(std::list::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 ) ) { @@ -1107,7 +1089,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list& // create list with colors for every vertex using faces indices. col_tgt_arr.resize(pMesh.mNumFaces); - std::list::const_iterator colidx_it = pColorIdx.begin(); + std::vector::const_iterator colidx_it = pColorIdx.begin(); for(size_t fi = 0; fi < pMesh.mNumFaces; fi++) { if((unsigned int)*colidx_it > pMesh.mNumFaces) throw DeadlyImportError("MeshGeometry_AddColor2. Face idx is out of range."); @@ -1137,7 +1119,7 @@ void X3DImporter::MeshGeometry_AddColor(aiMesh& pMesh, const std::list& MeshGeometry_AddColor(pMesh, col_tgt_list, pColorPerVertex); } -void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pNormalIdx, +void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::vector& pCoordIdx, const std::vector& pNormalIdx, const std::list& pNormals, const bool pNormalPerVertex) const { std::vector tind; @@ -1152,35 +1134,36 @@ void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::list if(pNormalPerVertex) { - const std::list* srcidx; - if(pNormalIdx.size() > 0) { // check indices array count. if(pNormalIdx.size() != pCoordIdx.size()) throw DeadlyImportError("Normals and Coords inidces count must be equal."); - srcidx = &pNormalIdx; + tind.reserve(pNormalIdx.size()); + for(std::vector::const_iterator it = pNormalIdx.begin(); it != pNormalIdx.end(); it++) + { + if(*it != (-1)) tind.push_back(*it); + } + + // copy normals to mesh + pMesh.mNormals = new aiVector3D[pMesh.mNumVertices]; + for(size_t i = 0; (i < pMesh.mNumVertices) && (i < tind.size()); i++) + { + if(tind[i] >= norm_arr_copy.size()) + throw DeadlyImportError("MeshGeometry_AddNormal. Normal index(" + to_string(tind[i]) + + ") is out of range. Normals count: " + to_string(norm_arr_copy.size()) + "."); + + pMesh.mNormals[i] = norm_arr_copy[tind[i]]; + } } else { - srcidx = &pCoordIdx; - } + if(pNormals.size() != pMesh.mNumVertices) throw DeadlyImportError("MeshGeometry_AddNormal. Normals and vertices count must be equal."); - tind.reserve(srcidx->size()); - for(std::list::const_iterator it = srcidx->begin(); it != srcidx->end(); it++) - { - if(*it != (-1)) tind.push_back(*it); - } - - // copy normals to mesh - pMesh.mNormals = new aiVector3D[pMesh.mNumVertices]; - for(size_t i = 0; (i < pMesh.mNumVertices) && (i < tind.size()); i++) - { - if(tind[i] >= norm_arr_copy.size()) - throw DeadlyImportError("MeshGeometry_AddNormal. Normal index(" + to_string(tind[i]) + - ") is out of range. Normals count: " + to_string(norm_arr_copy.size()) + "."); - - pMesh.mNormals[i] = norm_arr_copy[tind[i]]; + // copy normals to mesh + pMesh.mNormals = new aiVector3D[pMesh.mNumVertices]; + std::list::const_iterator norm_it = pNormals.begin(); + for(size_t i = 0; i < pMesh.mNumVertices; i++) pMesh.mNormals[i] = *norm_it++; } }// if(pNormalPerVertex) else @@ -1189,7 +1172,7 @@ void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::list { if(pMesh.mNumFaces != pNormalIdx.size()) throw DeadlyImportError("Normals faces count must be equal to mesh faces count."); - std::list::const_iterator normidx_it = pNormalIdx.begin(); + std::vector::const_iterator normidx_it = pNormalIdx.begin(); tind.reserve(pNormalIdx.size()); for(size_t i = 0, i_e = pNormalIdx.size(); i < i_e; i++) tind.push_back(*normidx_it++); @@ -1242,7 +1225,7 @@ void X3DImporter::MeshGeometry_AddNormal(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pTexCoordIdx, +void X3DImporter::MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::vector& pCoordIdx, const std::vector& pTexCoordIdx, const std::list& pTexCoords) const { std::vector texcoord_arr_copy; @@ -1315,7 +1298,7 @@ void X3DImporter::MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pVertices) const +aiMesh* X3DImporter::GeometryHelper_MakeMesh(const std::vector& pCoordIdx, const std::list& pVertices) const { std::vector faces; unsigned int prim_type = 0; @@ -1418,9 +1401,12 @@ void X3DImporter::ParseHelper_FixTruncatedFloatString(const char* pInStr, std::s } } +extern FIVocabulary X3D_vocabulary_3_2; +extern FIVocabulary X3D_vocabulary_3_3; + void X3DImporter::ParseFile(const std::string& pFile, IOSystem* pIOHandler) { - irr::io::IrrXMLReader* OldReader = mReader;// store current XMLreader. + std::unique_ptr OldReader = std::move(mReader);// store current XMLreader. std::unique_ptr file(pIOHandler->Open(pFile, "rb")); // Check whether we can read from the file @@ -1428,19 +1414,18 @@ void X3DImporter::ParseFile(const std::string& pFile, IOSystem* pIOHandler) { throw DeadlyImportError( "Failed to open X3D file " + pFile + "." ); } - // generate a XML reader for it - std::unique_ptr mIOWrapper(new CIrrXML_IOStreamReader(file.get())); - mReader = irr::io::createIrrXMLReader(mIOWrapper.get()); + mReader = FIReader::create(file.get()); if ( !mReader ) { throw DeadlyImportError( "Failed to create XML reader for file" + pFile + "." ); } + mReader->registerVocabulary("urn:web3d:x3d:fi-vocabulary-3.2", &X3D_vocabulary_3_2); + mReader->registerVocabulary("urn:web3d:x3d:fi-vocabulary-3.3", &X3D_vocabulary_3_3); // start reading ParseNode_Root(); - delete mReader; // restore old XMLreader - mReader = OldReader; + mReader = std::move(OldReader); } void X3DImporter::ParseNode_Root() @@ -1654,7 +1639,7 @@ bool X3DImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool p { const std::string extension = GetExtension(pFile); - if(extension == "x3d") return true; + if((extension == "x3d") || (extension == "x3db")) return true; if(!extension.length() || pCheckSig) { @@ -1669,6 +1654,7 @@ bool X3DImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool p void X3DImporter::GetExtensionList(std::set& pExtensionList) { pExtensionList.insert("x3d"); + pExtensionList.insert("x3db"); } const aiImporterDesc* X3DImporter::GetInfo () const @@ -1678,9 +1664,13 @@ const aiImporterDesc* X3DImporter::GetInfo () const void X3DImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { + mpIOHandler = pIOHandler; + Clear();// delete old graph. - mFileDir = DefaultIOSystem::absolutePath(pFile); + std::string::size_type slashPos = pFile.find_last_of("\\/"); + pIOHandler->PushDirectory(slashPos == std::string::npos ? std::string() : pFile.substr(0, slashPos + 1)); ParseFile(pFile, pIOHandler); + pIOHandler->PopDirectory(); // // Assimp use static arrays of objects for fast speed of rendering. That's good, but need some additional operations/ // We know that geometry objects(meshes) are stored in , also in -> materials(in Assimp logical view) diff --git a/code/X3DImporter.hpp b/code/X3DImporter.hpp index 447a3f1e4..2d2d41fdb 100644 --- a/code/X3DImporter.hpp +++ b/code/X3DImporter.hpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -55,6 +56,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include "BaseImporter.h" #include "irrXMLWrapper.h" +#include "FIReader.hpp" +//#include namespace Assimp { @@ -100,7 +103,7 @@ namespace Assimp { /// Navigation component: /// "Billboard", "Collision", "LOD", "NavigationInfo", "OrthoViewpoint", "Viewpoint", "ViewpointGroup" /// Networking component: -/// "Anchor", "LoadSensor" +/// "EXPORT", "IMPORT", "Anchor", "LoadSensor" /// NURBS component: /// "Contour2D", "ContourPolyline2D", "CoordinateDouble", "NurbsCurve", "NurbsCurve2D", "NurbsOrientationInterpolator", "NurbsPatchSurface", /// "NurbsPositionInterpolator", "NurbsSet", "NurbsSurfaceInterpolator", "NurbsSweptSurface", "NurbsSwungSurface", "NurbsTextureCoordinate", @@ -448,33 +451,21 @@ private: /// Read attribute value. /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). /// \param [out] pValue - read data. - void XML_ReadNode_GetAttrVal_AsListB(const int pAttrIdx, std::list& pValue); - - /// \overload void XML_ReadNode_GetAttrVal_AsListBool(const int pAttrIdx, std::list& pValue) void XML_ReadNode_GetAttrVal_AsArrB(const int pAttrIdx, std::vector& pValue); /// Read attribute value. /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). /// \param [out] pValue - read data. - void XML_ReadNode_GetAttrVal_AsListI32(const int pAttrIdx, std::list& pValue); - - /// \overload void XML_ReadNode_GetAttrVal_AsListI32(const int pAttrIdx, std::list& pValue) void XML_ReadNode_GetAttrVal_AsArrI32(const int pAttrIdx, std::vector& pValue); /// Read attribute value. /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). /// \param [out] pValue - read data. - void XML_ReadNode_GetAttrVal_AsListF(const int pAttrIdx, std::list& pValue); - - /// \overload void XML_ReadNode_GetAttrVal_AsListF(const int pAttrIdx, std::list& pValue) void XML_ReadNode_GetAttrVal_AsArrF(const int pAttrIdx, std::vector& pValue); /// Read attribute value. /// \param [in] pAttrIdx - attribute index (\ref mReader->getAttribute* set). /// \param [out] pValue - read data. - void XML_ReadNode_GetAttrVal_AsListD(const int pAttrIdx, std::list& pValue); - - /// \overload void XML_ReadNode_GetAttrVal_AsListD(const int pAttrIdx, std::list& pValue) void XML_ReadNode_GetAttrVal_AsArrD(const int pAttrIdx, std::vector& pValue); /// Read attribute value. @@ -553,7 +544,7 @@ private: /// \param [in] pCoordIdx - vertices indices divided by delimiter "-1". /// \param [in] pFaces - created faces array. /// \param [in] pPrimitiveTypes - type of primitives in faces. - void GeometryHelper_CoordIdxStr2FacesArr(const std::list& pCoordIdx, std::vector& pFaces, unsigned int& pPrimitiveTypes) const; + void GeometryHelper_CoordIdxStr2FacesArr(const std::vector& pCoordIdx, std::vector& pFaces, unsigned int& pPrimitiveTypes) const; /// Add colors to mesh. /// a. If colorPerVertex is FALSE, colours are applied to each face, as follows: @@ -572,11 +563,11 @@ private: /// then pColorIdx contain color indices for every faces and must not contain delimiter "-1". /// \param [in] pColors - defined colors. /// \param [in] pColorPerVertex - if \ref pColorPerVertex is true then color in \ref pColors defined for every vertex, if false - for every face. - void MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pColorIdx, + void MeshGeometry_AddColor(aiMesh& pMesh, const std::vector& pCoordIdx, const std::vector& pColorIdx, const std::list& pColors, const bool pColorPerVertex) const; /// \overload void MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pColorIdx, const std::list& pColors, const bool pColorPerVertex) const; - void MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pColorIdx, + void MeshGeometry_AddColor(aiMesh& pMesh, const std::vector& pCoordIdx, const std::vector& pColorIdx, const std::list& pColors, const bool pColorPerVertex) const; /// Add colors to mesh. @@ -589,14 +580,14 @@ private: void MeshGeometry_AddColor(aiMesh& pMesh, const std::list& pColors, const bool pColorPerVertex) const; /// Add normals to mesh. Function work similar to \ref MeshGeometry_AddColor; - void MeshGeometry_AddNormal(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pNormalIdx, + void MeshGeometry_AddNormal(aiMesh& pMesh, const std::vector& pCoordIdx, const std::vector& pNormalIdx, const std::list& pNormals, const bool pNormalPerVertex) const; /// Add normals to mesh. Function work similar to \ref MeshGeometry_AddColor; void MeshGeometry_AddNormal(aiMesh& pMesh, const std::list& pNormals, const bool pNormalPerVertex) const; /// Add texture coordinates to mesh. Function work similar to \ref MeshGeometry_AddColor; - void MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::list& pCoordIdx, const std::list& pTexCoordIdx, + void MeshGeometry_AddTexCoord(aiMesh& pMesh, const std::vector& pCoordIdx, const std::vector& pTexCoordIdx, const std::list& pTexCoords) const; /// Add texture coordinates to mesh. Function work similar to \ref MeshGeometry_AddColor; @@ -606,7 +597,7 @@ private: /// \param [in] pCoordIdx - vertices indices divided by delimiter "-1". /// \param [in] pVertices - vertices of mesh. /// \return created mesh. - aiMesh* GeometryHelper_MakeMesh(const std::list& pCoordIdx, const std::list& pVertices) const; + aiMesh* GeometryHelper_MakeMesh(const std::vector& pCoordIdx, const std::list& pVertices) const; /***********************************************/ /******** Functions: parse set private *********/ @@ -825,13 +816,16 @@ private: /****************** Constants ******************/ /***********************************************/ static const aiImporterDesc Description; + //static const std::regex pattern_nws; + //static const std::regex pattern_true; + /***********************************************/ /****************** Variables ******************/ /***********************************************/ CX3DImporter_NodeElement* NodeElement_Cur;///< Current element. - irr::io::IrrXMLReader* mReader;///< Pointer to XML-reader object - std::string mFileDir; + std::unique_ptr mReader;///< Pointer to XML-reader object + IOSystem *mpIOHandler; };// class X3DImporter }// namespace Assimp diff --git a/code/X3DImporter_Geometry2D.cpp b/code/X3DImporter_Geometry2D.cpp index bfa1834ec..895ba8798 100644 --- a/code/X3DImporter_Geometry2D.cpp +++ b/code/X3DImporter_Geometry2D.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/X3DImporter_Geometry3D.cpp b/code/X3DImporter_Geometry3D.cpp index 614f202cc..b2e9a28f8 100644 --- a/code/X3DImporter_Geometry3D.cpp +++ b/code/X3DImporter_Geometry3D.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -284,7 +285,7 @@ void X3DImporter::ParseNode_Geometry3D_ElevationGrid() bool ccw = true; bool colorPerVertex = true; float creaseAngle = 0; - std::list height; + std::vector height; bool normalPerVertex = true; bool solid = true; int32_t xDimension = 0; @@ -300,7 +301,7 @@ void X3DImporter::ParseNode_Geometry3D_ElevationGrid() MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_CHECK_RET("creaseAngle", creaseAngle, XML_ReadNode_GetAttrVal_AsFloat); - MACRO_ATTRREAD_CHECK_REF("height", height, XML_ReadNode_GetAttrVal_AsListF); + MACRO_ATTRREAD_CHECK_REF("height", height, XML_ReadNode_GetAttrVal_AsArrF); MACRO_ATTRREAD_CHECK_RET("xDimension", xDimension, XML_ReadNode_GetAttrVal_AsI32); MACRO_ATTRREAD_CHECK_RET("xSpacing", xSpacing, XML_ReadNode_GetAttrVal_AsFloat); MACRO_ATTRREAD_CHECK_RET("zDimension", zDimension, XML_ReadNode_GetAttrVal_AsI32); @@ -325,7 +326,7 @@ void X3DImporter::ParseNode_Geometry3D_ElevationGrid() CX3DImporter_NodeElement_ElevationGrid& grid_alias = *((CX3DImporter_NodeElement_ElevationGrid*)ne);// create alias for conveience {// create grid vertices list - std::list::const_iterator he_it = height.begin(); + std::vector::const_iterator he_it = height.begin(); for(int32_t zi = 0; zi < zDimension; zi++)// rows { @@ -862,29 +863,29 @@ void X3DImporter::ParseNode_Geometry3D_IndexedFaceSet() { std::string use, def; bool ccw = true; - std::list colorIndex; + std::vector colorIndex; bool colorPerVertex = true; bool convex = true; - std::list coordIndex; + std::vector coordIndex; float creaseAngle = 0; - std::list normalIndex; + std::vector normalIndex; bool normalPerVertex = true; bool solid = true; - std::list texCoordIndex; + std::vector texCoordIndex; CX3DImporter_NodeElement* ne( nullptr ); MACRO_ATTRREAD_LOOPBEG; MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool); - MACRO_ATTRREAD_CHECK_REF("colorIndex", colorIndex, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_REF("colorIndex", colorIndex, XML_ReadNode_GetAttrVal_AsArrI32); MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_CHECK_RET("convex", convex, XML_ReadNode_GetAttrVal_AsBool); - MACRO_ATTRREAD_CHECK_REF("coordIndex", coordIndex, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_REF("coordIndex", coordIndex, XML_ReadNode_GetAttrVal_AsArrI32); MACRO_ATTRREAD_CHECK_RET("creaseAngle", creaseAngle, XML_ReadNode_GetAttrVal_AsFloat); - MACRO_ATTRREAD_CHECK_REF("normalIndex", normalIndex, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_REF("normalIndex", normalIndex, XML_ReadNode_GetAttrVal_AsArrI32); MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); - MACRO_ATTRREAD_CHECK_REF("texCoordIndex", texCoordIndex, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_REF("texCoordIndex", texCoordIndex, XML_ReadNode_GetAttrVal_AsArrI32); MACRO_ATTRREAD_LOOPEND; // if "USE" defined then find already defined element. @@ -948,7 +949,7 @@ void X3DImporter::ParseNode_Geometry3D_IndexedFaceSet() void X3DImporter::ParseNode_Geometry3D_Sphere() { std::string use, def; - float radius = 1; + ai_real radius = 1; bool solid = true; CX3DImporter_NodeElement* ne( nullptr ); diff --git a/code/X3DImporter_Group.cpp b/code/X3DImporter_Group.cpp index e476ba58b..e7df97b4b 100644 --- a/code/X3DImporter_Group.cpp +++ b/code/X3DImporter_Group.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/X3DImporter_Light.cpp b/code/X3DImporter_Light.cpp index 54f56e76e..ff450f7a9 100644 --- a/code/X3DImporter_Light.cpp +++ b/code/X3DImporter_Light.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/X3DImporter_Macro.hpp b/code/X3DImporter_Macro.hpp index 445edfe91..6281efcd5 100644 --- a/code/X3DImporter_Macro.hpp +++ b/code/X3DImporter_Macro.hpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/X3DImporter_Metadata.cpp b/code/X3DImporter_Metadata.cpp index 1f57d9f63..9d7147aea 100644 --- a/code/X3DImporter_Metadata.cpp +++ b/code/X3DImporter_Metadata.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -122,14 +123,14 @@ void X3DImporter::ParseNode_MetadataBoolean() { std::string def, use; std::string name, reference; - std::list value; + std::vector value; CX3DImporter_NodeElement* ne( nullptr ); MACRO_ATTRREAD_LOOPBEG; MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue); MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue); - MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsListB); + MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsArrB); MACRO_ATTRREAD_LOOPEND; MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, CX3DImporter_NodeElement_MetaBoolean, "MetadataBoolean", ENET_MetaBoolean); @@ -146,14 +147,14 @@ void X3DImporter::ParseNode_MetadataDouble() { std::string def, use; std::string name, reference; - std::list value; + std::vector value; CX3DImporter_NodeElement* ne( nullptr ); MACRO_ATTRREAD_LOOPBEG; MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue); MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue); - MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsListD); + MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsArrD); MACRO_ATTRREAD_LOOPEND; MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, CX3DImporter_NodeElement_MetaDouble, "MetadataDouble", ENET_MetaDouble); @@ -170,14 +171,14 @@ void X3DImporter::ParseNode_MetadataFloat() { std::string def, use; std::string name, reference; - std::list value; + std::vector value; CX3DImporter_NodeElement* ne( nullptr ); MACRO_ATTRREAD_LOOPBEG; MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue); MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue); - MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsListF); + MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsArrF); MACRO_ATTRREAD_LOOPEND; MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, CX3DImporter_NodeElement_MetaFloat, "MetadataFloat", ENET_MetaFloat); @@ -194,14 +195,14 @@ void X3DImporter::ParseNode_MetadataInteger() { std::string def, use; std::string name, reference; - std::list value; + std::vector value; CX3DImporter_NodeElement* ne( nullptr ); MACRO_ATTRREAD_LOOPBEG; MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); MACRO_ATTRREAD_CHECK_RET("name", name, mReader->getAttributeValue); MACRO_ATTRREAD_CHECK_RET("reference", reference, mReader->getAttributeValue); - MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_REF("value", value, XML_ReadNode_GetAttrVal_AsArrI32); MACRO_ATTRREAD_LOOPEND; MACRO_METADATA_FINDCREATE(def, use, reference, value, ne, CX3DImporter_NodeElement_MetaInteger, "MetadataInteger", ENET_MetaInteger); diff --git a/code/X3DImporter_Networking.cpp b/code/X3DImporter_Networking.cpp index d862cd7ef..269c58ba3 100644 --- a/code/X3DImporter_Networking.cpp +++ b/code/X3DImporter_Networking.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -50,9 +51,14 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Header files, Assimp. #include +//#include + namespace Assimp { +//static std::regex pattern_parentDir(R"((^|/)[^/]+/../)"); +static std::string parentDir("/../"); + // 0)) { - DefaultIOSystem io_handler; - std::string full_path; + std::string full_path = mpIOHandler->CurrentDirectory() + url.front(); - full_path = mFileDir + "/" + url.front(); + //full_path = std::regex_replace(full_path, pattern_parentDir, "$1"); + for (std::string::size_type pos = full_path.find(parentDir); pos != std::string::npos; pos = full_path.find(parentDir, pos)) { + if (pos > 0) { + std::string::size_type pos2 = full_path.rfind('/', pos - 1); + if (pos2 != std::string::npos) { + full_path.erase(pos2, pos - pos2 + 3); + pos = pos2; + } + else { + full_path.erase(0, pos + 4); + pos = 0; + } + } + else { + pos += 3; + } + } // Attribute "url" can contain list of strings. But we need only one - first. - ParseFile(full_path, &io_handler); + std::string::size_type slashPos = full_path.find_last_of("\\/"); + mpIOHandler->PushDirectory(slashPos == std::string::npos ? std::string() : full_path.substr(0, slashPos + 1)); + ParseFile(full_path, mpIOHandler); + mpIOHandler->PopDirectory(); } // check for X3DMetadataObject childs. diff --git a/code/X3DImporter_Node.hpp b/code/X3DImporter_Node.hpp index 5d258dfef..6ed96c2f9 100644 --- a/code/X3DImporter_Node.hpp +++ b/code/X3DImporter_Node.hpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -51,6 +52,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // Header files, stdlib. #include +#include #include /// \class CX3DImporter_NodeElement @@ -263,7 +265,7 @@ public: /// This struct describe metavalue of type boolean. struct CX3DImporter_NodeElement_MetaBoolean : public CX3DImporter_NodeElement_Meta { - std::list Value;///< Stored value. + std::vector Value;///< Stored value. /// \fn CX3DImporter_NodeElement_MetaBoolean(CX3DImporter_NodeElement* pParent) /// Constructor @@ -278,7 +280,7 @@ struct CX3DImporter_NodeElement_MetaBoolean : public CX3DImporter_NodeElement_Me /// This struct describe metavalue of type double. struct CX3DImporter_NodeElement_MetaDouble : public CX3DImporter_NodeElement_Meta { - std::list Value;///< Stored value. + std::vector Value;///< Stored value. /// \fn CX3DImporter_NodeElement_MetaDouble(CX3DImporter_NodeElement* pParent) /// Constructor @@ -293,7 +295,7 @@ struct CX3DImporter_NodeElement_MetaDouble : public CX3DImporter_NodeElement_Met /// This struct describe metavalue of type float. struct CX3DImporter_NodeElement_MetaFloat : public CX3DImporter_NodeElement_Meta { - std::list Value;///< Stored value. + std::vector Value;///< Stored value. /// \fn CX3DImporter_NodeElement_MetaFloat(CX3DImporter_NodeElement* pParent) /// Constructor @@ -308,7 +310,7 @@ struct CX3DImporter_NodeElement_MetaFloat : public CX3DImporter_NodeElement_Meta /// This struct describe metavalue of type integer. struct CX3DImporter_NodeElement_MetaInteger : public CX3DImporter_NodeElement_Meta { - std::list Value;///< Stored value. + std::vector Value;///< Stored value. /// \fn CX3DImporter_NodeElement_MetaInteger(CX3DImporter_NodeElement* pParent) /// Constructor @@ -466,42 +468,29 @@ public: /// \class CX3DImporter_NodeElement_Geometry3D /// Three-dimensional body. -class CX3DImporter_NodeElement_Geometry3D : public CX3DImporter_NodeElement -{ - /***********************************************/ - /****************** Variables ******************/ - /***********************************************/ - +class CX3DImporter_NodeElement_Geometry3D : public CX3DImporter_NodeElement { public: + std::list Vertices; ///< Vertices list. + size_t NumIndices;///< Number of indices in one face. + bool Solid; ///< Flag: if true then render must use back-face culling, else render must draw both sides of object. - std::list Vertices;///< Vertices list. - size_t NumIndices;///< Number of indices in one face. - bool Solid;///< Flag: if true then render must use back-face culling, else render must draw both sides of object. - - /***********************************************/ - /****************** Functions ******************/ - /***********************************************/ - -private: - - /// \fn CX3DImporter_NodeElement_Geometry3D(const CX3DImporter_NodeElement_Geometry3D& pNode) - /// Disabled copy constructor. - CX3DImporter_NodeElement_Geometry3D(const CX3DImporter_NodeElement_Geometry3D& pNode); - - /// \fn CX3DImporter_NodeElement_Geometry3D& operator=(const CX3DImporter_NodeElement_Geometry3D& pNode) - /// Disabled assign operator. - CX3DImporter_NodeElement_Geometry3D& operator=(const CX3DImporter_NodeElement_Geometry3D& pNode); - -public: - - /// \fn CX3DImporter_NodeElement_Geometry3D(const EType pType, CX3DImporter_NodeElement* pParent) /// Constructor. /// \param [in] pParent - pointer to parent node. /// \param [in] pType - type of geometry object. CX3DImporter_NodeElement_Geometry3D(const EType pType, CX3DImporter_NodeElement* pParent) - : CX3DImporter_NodeElement(pType, pParent), Solid(true) - {} + : CX3DImporter_NodeElement(pType, pParent) + , Vertices() + , NumIndices( 0 ) + , Solid(true) { + // empty + } +private: + /// Disabled copy constructor. + CX3DImporter_NodeElement_Geometry3D(const CX3DImporter_NodeElement_Geometry3D& pNode); + + /// Disabled assign operator. + CX3DImporter_NodeElement_Geometry3D& operator=(const CX3DImporter_NodeElement_Geometry3D& pNode); };// class CX3DImporter_NodeElement_Geometry3D /// \class CX3DImporter_NodeElement_ElevationGrid @@ -520,7 +509,7 @@ public: /// If the angle between the geometric normals of two adjacent faces is less than the crease angle, normals shall be calculated so that the faces are /// shaded smoothly across the edge; otherwise, normals shall be calculated so that a lighting discontinuity across the edge is produced. float CreaseAngle; - std::list CoordIdx;///< Coordinates list by faces. In X3D format: "-1" - delimiter for faces. + std::vector CoordIdx;///< Coordinates list by faces. In X3D format: "-1" - delimiter for faces. /***********************************************/ /****************** Functions ******************/ @@ -566,21 +555,21 @@ public: /// direction. If normals are not generated but are supplied using a Normal node, and the orientation of the normals does not match the setting of the /// ccw field, results are undefined. bool CCW; - std::list ColorIndex;///< Field to specify the polygonal faces by indexing into the or . + std::vector ColorIndex;///< Field to specify the polygonal faces by indexing into the or . bool ColorPerVertex;///< If true then colors are defined for every vertex, else for every face(line). /// \var Convex /// The convex field indicates whether all polygons in the shape are convex (TRUE). A polygon is convex if it is planar, does not intersect itself, /// and all of the interior angles at its vertices are less than 180 degrees. Non planar and self intersecting polygons may produce undefined results /// even if the convex field is FALSE. bool Convex; - std::list CoordIndex;///< Field to specify the polygonal faces by indexing into the . + std::vector CoordIndex;///< Field to specify the polygonal faces by indexing into the . /// \var CreaseAngle /// If the angle between the geometric normals of two adjacent faces is less than the crease angle, normals shall be calculated so that the faces are /// shaded smoothly across the edge; otherwise, normals shall be calculated so that a lighting discontinuity across the edge is produced. float CreaseAngle; - std::list NormalIndex;///< Field to specify the polygonal faces by indexing into the . + std::vector NormalIndex;///< Field to specify the polygonal faces by indexing into the . bool NormalPerVertex;///< If true then normals are defined for every vertex, else for every face(line). - std::list TexCoordIndex;///< Field to specify the polygonal faces by indexing into the . + std::vector TexCoordIndex;///< Field to specify the polygonal faces by indexing into the . /***********************************************/ /****************** Functions ******************/ @@ -628,10 +617,10 @@ public: bool CCW; bool ColorPerVertex;///< If true then colors are defined for every vertex, else for every face(line). bool NormalPerVertex;///< If true then normals are defined for every vertex, else for every face(line). - std::list CoordIndex;///< Field to specify the polygonal faces by indexing into the . - std::list NormalIndex;///< Field to specify the polygonal faces by indexing into the . - std::list TexCoordIndex;///< Field to specify the polygonal faces by indexing into the . - std::list VertexCount;///< Field describes how many vertices are to be used in each polyline(polygon) from the field. + std::vector CoordIndex;///< Field to specify the polygonal faces by indexing into the . + std::vector NormalIndex;///< Field to specify the polygonal faces by indexing into the . + std::vector TexCoordIndex;///< Field to specify the polygonal faces by indexing into the . + std::vector VertexCount;///< Field describes how many vertices are to be used in each polyline(polygon) from the field. /***********************************************/ /****************** Functions ******************/ @@ -687,45 +676,35 @@ struct CX3DImporter_NodeElement_Appearance : public CX3DImporter_NodeElement /// \class CX3DImporter_NodeElement_Material /// Material. -class CX3DImporter_NodeElement_Material : public CX3DImporter_NodeElement -{ - /***********************************************/ - /****************** Variables ******************/ - /***********************************************/ - +class CX3DImporter_NodeElement_Material : public CX3DImporter_NodeElement { public: + float AmbientIntensity;///< Specifies how much ambient light from light sources this surface shall reflect. + aiColor3D DiffuseColor; ///< Reflects all X3D light sources depending on the angle of the surface with respect to the light source. + aiColor3D EmissiveColor; ///< Models "glowing" objects. This can be useful for displaying pre-lit models. + float Shininess; ///< Lower shininess values produce soft glows, while higher values result in sharper, smaller highlights. + aiColor3D SpecularColor; ///< The specularColor and shininess fields determine the specular highlights. + float Transparency; ///< Specifies how "clear" an object is, with 1.0 being completely transparent, and 0.0 completely opaque. - float AmbientIntensity;///< Specifies how much ambient light from light sources this surface shall reflect. - aiColor3D DiffuseColor;///< Reflects all X3D light sources depending on the angle of the surface with respect to the light source. - aiColor3D EmissiveColor;///< Models "glowing" objects. This can be useful for displaying pre-lit models. - float Shininess;///< Lower shininess values produce soft glows, while higher values result in sharper, smaller highlights. - aiColor3D SpecularColor;///< The specularColor and shininess fields determine the specular highlights. - float Transparency;///< Specifies how "clear" an object is, with 1.0 being completely transparent, and 0.0 completely opaque. - - /***********************************************/ - /****************** Functions ******************/ - /***********************************************/ - -private: - - /// \fn CX3DImporter_NodeElement_Material(const CX3DImporter_NodeElement_Material& pNode) - /// Disabled copy constructor. - CX3DImporter_NodeElement_Material(const CX3DImporter_NodeElement_Material& pNode); - - /// \fn CX3DImporter_NodeElement_Material& operator=(const CX3DImporter_NodeElement_Material& pNode) - /// Disabled assign operator. - CX3DImporter_NodeElement_Material& operator=(const CX3DImporter_NodeElement_Material& pNode); - -public: - - /// \fn CX3DImporter_NodeElement_Material(const EType pType, CX3DImporter_NodeElement* pParent) /// Constructor. /// \param [in] pParent - pointer to parent node. /// \param [in] pType - type of geometry object. CX3DImporter_NodeElement_Material(CX3DImporter_NodeElement* pParent) - : CX3DImporter_NodeElement(ENET_Material, pParent) - {} + : CX3DImporter_NodeElement(ENET_Material, pParent) + , AmbientIntensity( 0.0f ) + , DiffuseColor() + , EmissiveColor() + , Shininess( 0.0f ) + , SpecularColor() + , Transparency( 1.0f ) { + // empty + } +private: + /// Disabled copy constructor. + CX3DImporter_NodeElement_Material(const CX3DImporter_NodeElement_Material& pNode); + + /// Disabled assign operator. + CX3DImporter_NodeElement_Material& operator=(const CX3DImporter_NodeElement_Material& pNode); };// class CX3DImporter_NodeElement_Material /// \struct CX3DImporter_NodeElement_ImageTexture diff --git a/code/X3DImporter_Postprocess.cpp b/code/X3DImporter_Postprocess.cpp index eb297e654..0e3f3a8ae 100644 --- a/code/X3DImporter_Postprocess.cpp +++ b/code/X3DImporter_Postprocess.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -503,6 +504,9 @@ 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++) { + if ( nullptr == *pMesh ) { + break; + } if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_Color) MeshGeometry_AddColor(**pMesh, ((CX3DImporter_NodeElement_Color*)*ch_it)->Value,tnemesh.ColorPerVertex); else if((*ch_it)->Type == CX3DImporter_NodeElement::ENET_ColorRGBA) diff --git a/code/X3DImporter_Rendering.cpp b/code/X3DImporter_Rendering.cpp index 29dc28765..1d4632f32 100644 --- a/code/X3DImporter_Rendering.cpp +++ b/code/X3DImporter_Rendering.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -179,16 +180,16 @@ void X3DImporter::ParseNode_Rendering_Coordinate() void X3DImporter::ParseNode_Rendering_IndexedLineSet() { std::string use, def; - std::list colorIndex; + std::vector colorIndex; bool colorPerVertex = true; - std::list coordIndex; + std::vector coordIndex; CX3DImporter_NodeElement* ne( nullptr ); MACRO_ATTRREAD_LOOPBEG; MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); - MACRO_ATTRREAD_CHECK_REF("colorIndex", colorIndex, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_REF("colorIndex", colorIndex, XML_ReadNode_GetAttrVal_AsArrI32); MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); - MACRO_ATTRREAD_CHECK_REF("coordIndex", coordIndex, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_REF("coordIndex", coordIndex, XML_ReadNode_GetAttrVal_AsArrI32); MACRO_ATTRREAD_LOOPEND; // if "USE" defined then find already defined element. @@ -255,7 +256,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleFanSet() std::string use, def; bool ccw = true; bool colorPerVertex = true; - std::list index; + std::vector index; bool normalPerVertex = true; bool solid = true; CX3DImporter_NodeElement* ne( nullptr ); @@ -264,7 +265,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleFanSet() MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); - MACRO_ATTRREAD_CHECK_REF("index", index, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_REF("index", index, XML_ReadNode_GetAttrVal_AsArrI32); MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_LOOPEND; @@ -287,9 +288,46 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleFanSet() ne_alias.CCW = ccw; ne_alias.ColorPerVertex = colorPerVertex; - ne_alias.CoordIndex = index; ne_alias.NormalPerVertex = normalPerVertex; ne_alias.Solid = solid; + + 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++) + { + idx[2] = *idx_it; + if (idx[2] < 0) + { + counter = 0; + } + else + { + if (counter >= 2) + { + if(ccw) + { + ne_alias.CoordIndex.push_back(idx[0]); + ne_alias.CoordIndex.push_back(idx[1]); + ne_alias.CoordIndex.push_back(idx[2]); + } + else + { + ne_alias.CoordIndex.push_back(idx[0]); + ne_alias.CoordIndex.push_back(idx[2]); + ne_alias.CoordIndex.push_back(idx[1]); + } + ne_alias.CoordIndex.push_back(-1); + idx[1] = idx[2]; + } + else + { + idx[counter] = idx[2]; + } + ++counter; + } + }// for(std::list::const_iterator idx_it = index.begin(); idx_it != ne_alias.index.end(); idx_it++) + // check for child nodes if(!mReader->isEmptyElement()) { @@ -336,7 +374,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleSet() std::string use, def; bool ccw = true; bool colorPerVertex = true; - std::list index; + std::vector index; bool normalPerVertex = true; bool solid = true; CX3DImporter_NodeElement* ne( nullptr ); @@ -345,7 +383,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleSet() MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); - MACRO_ATTRREAD_CHECK_REF("index", index, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_REF("index", index, XML_ReadNode_GetAttrVal_AsArrI32); MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_LOOPEND; @@ -368,9 +406,34 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleSet() ne_alias.CCW = ccw; ne_alias.ColorPerVertex = colorPerVertex; - ne_alias.CoordIndex = index; ne_alias.NormalPerVertex = normalPerVertex; ne_alias.Solid = solid; + + 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++) + { + idx[counter++] = *idx_it; + if (counter > 2) + { + counter = 0; + if(ccw) + { + ne_alias.CoordIndex.push_back(idx[0]); + ne_alias.CoordIndex.push_back(idx[1]); + ne_alias.CoordIndex.push_back(idx[2]); + } + else + { + ne_alias.CoordIndex.push_back(idx[0]); + ne_alias.CoordIndex.push_back(idx[2]); + ne_alias.CoordIndex.push_back(idx[1]); + } + ne_alias.CoordIndex.push_back(-1); + } + }// for(std::list::const_iterator idx_it = index.begin(); idx_it != ne_alias.index.end(); idx_it++) + // check for child nodes if(!mReader->isEmptyElement()) { @@ -417,7 +480,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleStripSet() std::string use, def; bool ccw = true; bool colorPerVertex = true; - std::list index; + std::vector index; bool normalPerVertex = true; bool solid = true; CX3DImporter_NodeElement* ne( nullptr ); @@ -426,7 +489,7 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleStripSet() MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); - MACRO_ATTRREAD_CHECK_REF("index", index, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_REF("index", index, XML_ReadNode_GetAttrVal_AsArrI32); MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_LOOPEND; @@ -449,9 +512,42 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleStripSet() ne_alias.CCW = ccw; ne_alias.ColorPerVertex = colorPerVertex; - ne_alias.CoordIndex = index; ne_alias.NormalPerVertex = normalPerVertex; ne_alias.Solid = solid; + + 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++) + { + idx[2] = *idx_it; + if (idx[2] < 0) + { + counter = 0; + } + else + { + if (counter >= 2) + { + if(ccw) + { + ne_alias.CoordIndex.push_back(idx[0]); + ne_alias.CoordIndex.push_back(idx[1]); + ne_alias.CoordIndex.push_back(idx[2]); + } + else + { + ne_alias.CoordIndex.push_back(idx[0]); + ne_alias.CoordIndex.push_back(idx[2]); + ne_alias.CoordIndex.push_back(idx[1]); + } + ne_alias.CoordIndex.push_back(-1); + } + idx[counter & 1] = idx[2]; + ++counter; + } + }// for(std::list::const_iterator idx_it = index.begin(); idx_it != ne_alias.index.end(); idx_it++) + // check for child nodes if(!mReader->isEmptyElement()) { @@ -491,12 +587,12 @@ void X3DImporter::ParseNode_Rendering_IndexedTriangleStripSet() void X3DImporter::ParseNode_Rendering_LineSet() { std::string use, def; - std::list vertexCount; + std::vector vertexCount; CX3DImporter_NodeElement* ne( nullptr ); MACRO_ATTRREAD_LOOPBEG; MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); - MACRO_ATTRREAD_CHECK_REF("vertexCount", vertexCount, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_REF("vertexCount", vertexCount, XML_ReadNode_GetAttrVal_AsArrI32); MACRO_ATTRREAD_LOOPEND; // if "USE" defined then find already defined element. @@ -520,7 +616,7 @@ void X3DImporter::ParseNode_Rendering_LineSet() size_t coord_num = 0; ne_alias.CoordIndex.clear(); - for(std::list::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."); @@ -626,7 +722,7 @@ void X3DImporter::ParseNode_Rendering_TriangleFanSet() std::string use, def; bool ccw = true; bool colorPerVertex = true; - std::list fanCount; + std::vector fanCount; bool normalPerVertex = true; bool solid = true; CX3DImporter_NodeElement* ne( nullptr ); @@ -635,7 +731,7 @@ void X3DImporter::ParseNode_Rendering_TriangleFanSet() MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); - MACRO_ATTRREAD_CHECK_REF("fanCount", fanCount, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_REF("fanCount", fanCount, XML_ReadNode_GetAttrVal_AsArrI32); MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_LOOPEND; @@ -668,7 +764,7 @@ void X3DImporter::ParseNode_Rendering_TriangleFanSet() // assign indices for first triangle coord_num_first = 0; coord_num_prev = 1; - for(std::list::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."); @@ -817,7 +913,7 @@ void X3DImporter::ParseNode_Rendering_TriangleStripSet() std::string use, def; bool ccw = true; bool colorPerVertex = true; - std::list stripCount; + std::vector stripCount; bool normalPerVertex = true; bool solid = true; CX3DImporter_NodeElement* ne( nullptr ); @@ -826,7 +922,7 @@ void X3DImporter::ParseNode_Rendering_TriangleStripSet() MACRO_ATTRREAD_CHECKUSEDEF_RET(def, use); MACRO_ATTRREAD_CHECK_RET("ccw", ccw, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_CHECK_RET("colorPerVertex", colorPerVertex, XML_ReadNode_GetAttrVal_AsBool); - MACRO_ATTRREAD_CHECK_REF("stripCount", stripCount, XML_ReadNode_GetAttrVal_AsListI32); + MACRO_ATTRREAD_CHECK_REF("stripCount", stripCount, XML_ReadNode_GetAttrVal_AsArrI32); MACRO_ATTRREAD_CHECK_RET("normalPerVertex", normalPerVertex, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_CHECK_RET("solid", solid, XML_ReadNode_GetAttrVal_AsBool); MACRO_ATTRREAD_LOOPEND; @@ -859,7 +955,7 @@ void X3DImporter::ParseNode_Rendering_TriangleStripSet() ne_alias.CoordIndex.clear(); coord_num_sb = 0; - for(std::list::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/X3DImporter_Shape.cpp index 7b3c7da77..55ce7fa99 100644 --- a/code/X3DImporter_Shape.cpp +++ b/code/X3DImporter_Shape.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/X3DImporter_Texturing.cpp b/code/X3DImporter_Texturing.cpp index 8372a231b..40ea47797 100644 --- a/code/X3DImporter_Texturing.cpp +++ b/code/X3DImporter_Texturing.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/X3DVocabulary.cpp b/code/X3DVocabulary.cpp new file mode 100644 index 000000000..780c4ffc2 --- /dev/null +++ b/code/X3DVocabulary.cpp @@ -0,0 +1,1675 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 X3DVocabulary.cpp +/// \brief Vocabulary for Fast Infoset encoded binary X3D files. +/// \date 2017 +/// \author Patrick Daehne + +#ifndef ASSIMP_BUILD_NO_X3D_IMPORTER + +#include "FIReader.hpp" + +namespace Assimp { + +static const char *encodingAlgorithmTable_3_2[] = { + "encoder://web3d.org/QuantizedFloatArrayEncoder", + "encoder://web3d.org/DeltazlibIntArrayEncoder", + "encoder://web3d.org/QuantizedzlibFloatArrayEncoder", + "encoder://web3d.org/zlibFloatArrayEncoder", + "encoder://web3d.org/QuantizedDoubleArrayEncoder", + "encoder://web3d.org/zlibDoubleArrayEncoder", + "encoder://web3d.org/QuantizedzlibDoubleArrayEncoder", + "encoder://web3d.org/RangeIntArrayEncoder" +}; + +static const std::shared_ptr attributeValueTable_3_2[] = { + FIStringValue::create("false"), + FIStringValue::create("true") +}; + +static const FIQName elementNameTable_3_2[] = { + { "Shape", nullptr, nullptr }, + { "Appearance", nullptr, nullptr }, + { "Material", nullptr, nullptr }, + { "IndexedFaceSet", nullptr, nullptr }, + { "ProtoInstance", nullptr, nullptr }, + { "Transform", nullptr, nullptr }, + { "ImageTexture", nullptr, nullptr }, + { "TextureTransform", nullptr, nullptr }, + { "Coordinate", nullptr, nullptr }, + { "Normal", nullptr, nullptr }, + { "Color", nullptr, nullptr }, + { "ColorRGBA", nullptr, nullptr }, + { "TextureCoordinate", nullptr, nullptr }, + { "ROUTE", nullptr, nullptr }, + { "fieldValue", nullptr, nullptr }, + { "Group", nullptr, nullptr }, + { "LOD", nullptr, nullptr }, + { "Switch", nullptr, nullptr }, + { "Script", nullptr, nullptr }, + { "IndexedTriangleFanSet", nullptr, nullptr }, + { "IndexedTriangleSet", nullptr, nullptr }, + { "IndexedTriangleStripSet", nullptr, nullptr }, + { "MultiTexture", nullptr, nullptr }, + { "MultiTextureCoordinate", nullptr, nullptr }, + { "MultiTextureTransform", nullptr, nullptr }, + { "IndexedLineSet", nullptr, nullptr }, + { "PointSet", nullptr, nullptr }, + { "StaticGroup", nullptr, nullptr }, + { "Sphere", nullptr, nullptr }, + { "Box", nullptr, nullptr }, + { "Cone", nullptr, nullptr }, + { "Anchor", nullptr, nullptr }, + { "Arc2D", nullptr, nullptr }, + { "ArcClose2D", nullptr, nullptr }, + { "AudioClip", nullptr, nullptr }, + { "Background", nullptr, nullptr }, + { "Billboard", nullptr, nullptr }, + { "BooleanFilter", nullptr, nullptr }, + { "BooleanSequencer", nullptr, nullptr }, + { "BooleanToggle", nullptr, nullptr }, + { "BooleanTrigger", nullptr, nullptr }, + { "Circle2D", nullptr, nullptr }, + { "Collision", nullptr, nullptr }, + { "ColorInterpolator", nullptr, nullptr }, + { "Contour2D", nullptr, nullptr }, + { "ContourPolyline2D", nullptr, nullptr }, + { "CoordinateDouble", nullptr, nullptr }, + { "CoordinateInterpolator", nullptr, nullptr }, + { "CoordinateInterpolator2D", nullptr, nullptr }, + { "Cylinder", nullptr, nullptr }, + { "CylinderSensor", nullptr, nullptr }, + { "DirectionalLight", nullptr, nullptr }, + { "Disk2D", nullptr, nullptr }, + { "EXPORT", nullptr, nullptr }, + { "ElevationGrid", nullptr, nullptr }, + { "EspduTransform", nullptr, nullptr }, + { "ExternProtoDeclare", nullptr, nullptr }, + { "Extrusion", nullptr, nullptr }, + { "FillProperties", nullptr, nullptr }, + { "Fog", nullptr, nullptr }, + { "FontStyle", nullptr, nullptr }, + { "GeoCoordinate", nullptr, nullptr }, + { "GeoElevationGrid", nullptr, nullptr }, + { "GeoLOD", nullptr, nullptr }, + { "GeoLocation", nullptr, nullptr }, + { "GeoMetadata", nullptr, nullptr }, + { "GeoOrigin", nullptr, nullptr }, + { "GeoPositionInterpolator", nullptr, nullptr }, + { "GeoTouchSensor", nullptr, nullptr }, + { "GeoViewpoint", nullptr, nullptr }, + { "HAnimDisplacer", nullptr, nullptr }, + { "HAnimHumanoid", nullptr, nullptr }, + { "HAnimJoint", nullptr, nullptr }, + { "HAnimSegment", nullptr, nullptr }, + { "HAnimSite", nullptr, nullptr }, + { "IMPORT", nullptr, nullptr }, + { "IS", nullptr, nullptr }, + { "Inline", nullptr, nullptr }, + { "IntegerSequencer", nullptr, nullptr }, + { "IntegerTrigger", nullptr, nullptr }, + { "KeySensor", nullptr, nullptr }, + { "LineProperties", nullptr, nullptr }, + { "LineSet", nullptr, nullptr }, + { "LoadSensor", nullptr, nullptr }, + { "MetadataDouble", nullptr, nullptr }, + { "MetadataFloat", nullptr, nullptr }, + { "MetadataInteger", nullptr, nullptr }, + { "MetadataSet", nullptr, nullptr }, + { "MetadataString", nullptr, nullptr }, + { "MovieTexture", nullptr, nullptr }, + { "NavigationInfo", nullptr, nullptr }, + { "NormalInterpolator", nullptr, nullptr }, + { "NurbsCurve", nullptr, nullptr }, + { "NurbsCurve2D", nullptr, nullptr }, + { "NurbsOrientationInterpolator", nullptr, nullptr }, + { "NurbsPatchSurface", nullptr, nullptr }, + { "NurbsPositionInterpolator", nullptr, nullptr }, + { "NurbsSet", nullptr, nullptr }, + { "NurbsSurfaceInterpolator", nullptr, nullptr }, + { "NurbsSweptSurface", nullptr, nullptr }, + { "NurbsSwungSurface", nullptr, nullptr }, + { "NurbsTextureCoordinate", nullptr, nullptr }, + { "NurbsTrimmedSurface", nullptr, nullptr }, + { "OrientationInterpolator", nullptr, nullptr }, + { "PixelTexture", nullptr, nullptr }, + { "PlaneSensor", nullptr, nullptr }, + { "PointLight", nullptr, nullptr }, + { "Polyline2D", nullptr, nullptr }, + { "Polypoint2D", nullptr, nullptr }, + { "PositionInterpolator", nullptr, nullptr }, + { "PositionInterpolator2D", nullptr, nullptr }, + { "ProtoBody", nullptr, nullptr }, + { "ProtoDeclare", nullptr, nullptr }, + { "ProtoInterface", nullptr, nullptr }, + { "ProximitySensor", nullptr, nullptr }, + { "ReceiverPdu", nullptr, nullptr }, + { "Rectangle2D", nullptr, nullptr }, + { "ScalarInterpolator", nullptr, nullptr }, + { "Scene", nullptr, nullptr }, + { "SignalPdu", nullptr, nullptr }, + { "Sound", nullptr, nullptr }, + { "SphereSensor", nullptr, nullptr }, + { "SpotLight", nullptr, nullptr }, + { "StringSensor", nullptr, nullptr }, + { "Text", nullptr, nullptr }, + { "TextureBackground", nullptr, nullptr }, + { "TextureCoordinateGenerator", nullptr, nullptr }, + { "TimeSensor", nullptr, nullptr }, + { "TimeTrigger", nullptr, nullptr }, + { "TouchSensor", nullptr, nullptr }, + { "TransmitterPdu", nullptr, nullptr }, + { "TriangleFanSet", nullptr, nullptr }, + { "TriangleSet", nullptr, nullptr }, + { "TriangleSet2D", nullptr, nullptr }, + { "TriangleStripSet", nullptr, nullptr }, + { "Viewpoint", nullptr, nullptr }, + { "VisibilitySensor", nullptr, nullptr }, + { "WorldInfo", nullptr, nullptr }, + { "X3D", nullptr, nullptr }, + { "component", nullptr, nullptr }, + { "connect", nullptr, nullptr }, + { "field", nullptr, nullptr }, + { "head", nullptr, nullptr }, + { "humanoidBodyType", nullptr, nullptr }, + { "meta", nullptr, nullptr }, + { "CADAssembly", nullptr, nullptr }, + { "CADFace", nullptr, nullptr }, + { "CADLayer", nullptr, nullptr }, + { "CADPart", nullptr, nullptr }, + { "ComposedCubeMapTexture", nullptr, nullptr }, + { "ComposedShader", nullptr, nullptr }, + { "ComposedTexture3D", nullptr, nullptr }, + { "FloatVertexAttribute", nullptr, nullptr }, + { "FogCoordinate", nullptr, nullptr }, + { "GeneratedCubeMapTexture", nullptr, nullptr }, + { "ImageCubeMapTexture", nullptr, nullptr }, + { "ImageTexture3D", nullptr, nullptr }, + { "IndexedQuadSet", nullptr, nullptr }, + { "LocalFog", nullptr, nullptr }, + { "Matrix3VertexAttribute", nullptr, nullptr }, + { "Matrix4VertexAttribute", nullptr, nullptr }, + { "PackagedShader", nullptr, nullptr }, + { "PixelTexture3D", nullptr, nullptr }, + { "ProgramShader", nullptr, nullptr }, + { "QuadSet", nullptr, nullptr }, + { "ShaderPart", nullptr, nullptr }, + { "ShaderProgram", nullptr, nullptr }, + { "TextureCoordinate3D", nullptr, nullptr }, + { "TextureCoordinate4D", nullptr, nullptr }, + { "TextureTransform3D", nullptr, nullptr }, + { "TextureTransformMatrix3D", nullptr, nullptr }, + { "BallJoint", nullptr, nullptr }, + { "BoundedPhysicsModel", nullptr, nullptr }, + { "ClipPlane", nullptr, nullptr }, + { "CollidableOffset", nullptr, nullptr }, + { "CollidableShape", nullptr, nullptr }, + { "CollisionCollection", nullptr, nullptr }, + { "CollisionSensor", nullptr, nullptr }, + { "CollisionSpace", nullptr, nullptr }, + { "ColorDamper", nullptr, nullptr }, + { "ConeEmitter", nullptr, nullptr }, + { "Contact", nullptr, nullptr }, + { "CoordinateDamper", nullptr, nullptr }, + { "DISEntityManager", nullptr, nullptr }, + { "DISEntityTypeMapping", nullptr, nullptr }, + { "DoubleAxisHingeJoint", nullptr, nullptr }, + { "EaseInEaseOut", nullptr, nullptr }, + { "ExplosionEmitter", nullptr, nullptr }, + { "ForcePhysicsModel", nullptr, nullptr }, + { "GeoProximitySensor", nullptr, nullptr }, + { "GeoTransform", nullptr, nullptr }, + { "Layer", nullptr, nullptr }, + { "LayerSet", nullptr, nullptr }, + { "Layout", nullptr, nullptr }, + { "LayoutGroup", nullptr, nullptr }, + { "LayoutLayer", nullptr, nullptr }, + { "LinePickSensor", nullptr, nullptr }, + { "MotorJoint", nullptr, nullptr }, + { "OrientationChaser", nullptr, nullptr }, + { "OrientationDamper", nullptr, nullptr }, + { "OrthoViewpoint", nullptr, nullptr }, + { "ParticleSystem", nullptr, nullptr }, + { "PickableGroup", nullptr, nullptr }, + { "PointEmitter", nullptr, nullptr }, + { "PointPickSensor", nullptr, nullptr }, + { "PolylineEmitter", nullptr, nullptr }, + { "PositionChaser", nullptr, nullptr }, + { "PositionChaser2D", nullptr, nullptr }, + { "PositionDamper", nullptr, nullptr }, + { "PositionDamper2D", nullptr, nullptr }, + { "PrimitivePickSensor", nullptr, nullptr }, + { "RigidBody", nullptr, nullptr }, + { "RigidBodyCollection", nullptr, nullptr }, + { "ScalarChaser", nullptr, nullptr }, + { "ScreenFontStyle", nullptr, nullptr }, + { "ScreenGroup", nullptr, nullptr }, + { "SingleAxisHingeJoint", nullptr, nullptr }, + { "SliderJoint", nullptr, nullptr }, + { "SplinePositionInterpolator", nullptr, nullptr }, + { "SplinePositionInterpolator2D", nullptr, nullptr }, + { "SplineScalarInterpolator", nullptr, nullptr }, + { "SquadOrientationInterpolator", nullptr, nullptr }, + { "SurfaceEmitter", nullptr, nullptr }, + { "TexCoordDamper", nullptr, nullptr }, + { "TextureProperties", nullptr, nullptr }, + { "TransformSensor", nullptr, nullptr }, + { "TwoSidedMaterial", nullptr, nullptr }, + { "UniversalJoint", nullptr, nullptr }, + { "ViewpointGroup", nullptr, nullptr }, + { "Viewport", nullptr, nullptr }, + { "VolumeEmitter", nullptr, nullptr }, + { "VolumePickSensor", nullptr, nullptr }, + { "WindPhysicsModel", nullptr, nullptr } +}; + +static const FIQName attributeNameTable_3_2[] = { + { "DEF", nullptr, nullptr }, + { "USE", nullptr, nullptr }, + { "containerField", nullptr, nullptr }, + { "fromNode", nullptr, nullptr }, + { "fromField", nullptr, nullptr }, + { "toNode", nullptr, nullptr }, + { "toField", nullptr, nullptr }, + { "name", nullptr, nullptr }, + { "value", nullptr, nullptr }, + { "color", nullptr, nullptr }, + { "colorIndex", nullptr, nullptr }, + { "coordIndex", nullptr, nullptr }, + { "texCoordIndex", nullptr, nullptr }, + { "normalIndex", nullptr, nullptr }, + { "colorPerVertex", nullptr, nullptr }, + { "normalPerVertex", nullptr, nullptr }, + { "rotation", nullptr, nullptr }, + { "scale", nullptr, nullptr }, + { "center", nullptr, nullptr }, + { "scaleOrientation", nullptr, nullptr }, + { "translation", nullptr, nullptr }, + { "url", nullptr, nullptr }, + { "repeatS", nullptr, nullptr }, + { "repeatT", nullptr, nullptr }, + { "point", nullptr, nullptr }, + { "vector", nullptr, nullptr }, + { "range", nullptr, nullptr }, + { "ambientIntensity", nullptr, nullptr }, + { "diffuseColor", nullptr, nullptr }, + { "emissiveColor", nullptr, nullptr }, + { "shininess", nullptr, nullptr }, + { "specularColor", nullptr, nullptr }, + { "transparency", nullptr, nullptr }, + { "whichChoice", nullptr, nullptr }, + { "index", nullptr, nullptr }, + { "mode", nullptr, nullptr }, + { "source", nullptr, nullptr }, + { "function", nullptr, nullptr }, + { "alpha", nullptr, nullptr }, + { "vertexCount", nullptr, nullptr }, + { "radius", nullptr, nullptr }, + { "size", nullptr, nullptr }, + { "height", nullptr, nullptr }, + { "solid", nullptr, nullptr }, + { "ccw", nullptr, nullptr }, + { "key", nullptr, nullptr }, + { "keyValue", nullptr, nullptr }, + { "enabled", nullptr, nullptr }, + { "direction", nullptr, nullptr }, + { "position", nullptr, nullptr }, + { "orientation", nullptr, nullptr }, + { "bboxCenter", nullptr, nullptr }, + { "bboxSize", nullptr, nullptr }, + { "AS", nullptr, nullptr }, + { "InlineDEF", nullptr, nullptr }, + { "accessType", nullptr, nullptr }, + { "actionKeyPress", nullptr, nullptr }, + { "actionKeyRelease", nullptr, nullptr }, + { "address", nullptr, nullptr }, + { "altKey", nullptr, nullptr }, + { "antennaLocation", nullptr, nullptr }, + { "antennaPatternLength", nullptr, nullptr }, + { "antennaPatternType", nullptr, nullptr }, + { "applicationID", nullptr, nullptr }, + { "articulationParameterArray", nullptr, nullptr }, + { "articulationParameterChangeIndicatorArray", nullptr, nullptr }, + { "articulationParameterCount", nullptr, nullptr }, + { "articulationParameterDesignatorArray", nullptr, nullptr }, + { "articulationParameterIdPartAttachedArray", nullptr, nullptr }, + { "articulationParameterTypeArray", nullptr, nullptr }, + { "attenuation", nullptr, nullptr }, + { "autoOffset", nullptr, nullptr }, + { "avatarSize", nullptr, nullptr }, + { "axisOfRotation", nullptr, nullptr }, + { "backUrl", nullptr, nullptr }, + { "beamWidth", nullptr, nullptr }, + { "beginCap", nullptr, nullptr }, + { "bindTime", nullptr, nullptr }, + { "bottom", nullptr, nullptr }, + { "bottomRadius", nullptr, nullptr }, + { "bottomUrl", nullptr, nullptr }, + { "centerOfMass", nullptr, nullptr }, + { "centerOfRotation", nullptr, nullptr }, + { "child1Url", nullptr, nullptr }, + { "child2Url", nullptr, nullptr }, + { "child3Url", nullptr, nullptr }, + { "child4Url", nullptr, nullptr }, + { "class", nullptr, nullptr }, + { "closureType", nullptr, nullptr }, + { "collideTime", nullptr, nullptr }, + { "content", nullptr, nullptr }, + { "controlKey", nullptr, nullptr }, + { "controlPoint", nullptr, nullptr }, + { "convex", nullptr, nullptr }, + { "coordinateSystem", nullptr, nullptr }, + { "copyright", nullptr, nullptr }, + { "creaseAngle", nullptr, nullptr }, + { "crossSection", nullptr, nullptr }, + { "cryptoKeyID", nullptr, nullptr }, + { "cryptoSystem", nullptr, nullptr }, + { "cutOffAngle", nullptr, nullptr }, + { "cycleInterval", nullptr, nullptr }, + { "cycleTime", nullptr, nullptr }, + { "data", nullptr, nullptr }, + { "dataFormat", nullptr, nullptr }, + { "dataLength", nullptr, nullptr }, + { "dataUrl", nullptr, nullptr }, + { "date", nullptr, nullptr }, + { "deadReckoning", nullptr, nullptr }, + { "deletionAllowed", nullptr, nullptr }, + { "description", nullptr, nullptr }, + { "detonateTime", nullptr, nullptr }, + { "dir", nullptr, nullptr }, + { "directOutput", nullptr, nullptr }, + { "diskAngle", nullptr, nullptr }, + { "displacements", nullptr, nullptr }, + { "documentation", nullptr, nullptr }, + { "elapsedTime", nullptr, nullptr }, + { "ellipsoid", nullptr, nullptr }, + { "encodingScheme", nullptr, nullptr }, + { "endAngle", nullptr, nullptr }, + { "endCap", nullptr, nullptr }, + { "enterTime", nullptr, nullptr }, + { "enteredText", nullptr, nullptr }, + { "entityCategory", nullptr, nullptr }, + { "entityCountry", nullptr, nullptr }, + { "entityDomain", nullptr, nullptr }, + { "entityExtra", nullptr, nullptr }, + { "entityID", nullptr, nullptr }, + { "entityKind", nullptr, nullptr }, + { "entitySpecific", nullptr, nullptr }, + { "entitySubCategory", nullptr, nullptr }, + { "exitTime", nullptr, nullptr }, + { "extent", nullptr, nullptr }, + { "family", nullptr, nullptr }, + { "fanCount", nullptr, nullptr }, + { "fieldOfView", nullptr, nullptr }, + { "filled", nullptr, nullptr }, + { "finalText", nullptr, nullptr }, + { "fireMissionIndex", nullptr, nullptr }, + { "fired1", nullptr, nullptr }, + { "fired2", nullptr, nullptr }, + { "firedTime", nullptr, nullptr }, + { "firingRange", nullptr, nullptr }, + { "firingRate", nullptr, nullptr }, + { "fogType", nullptr, nullptr }, + { "forceID", nullptr, nullptr }, + { "frequency", nullptr, nullptr }, + { "frontUrl", nullptr, nullptr }, + { "fuse", nullptr, nullptr }, + { "geoCoords", nullptr, nullptr }, + { "geoGridOrigin", nullptr, nullptr }, + { "geoSystem", nullptr, nullptr }, + { "groundAngle", nullptr, nullptr }, + { "groundColor", nullptr, nullptr }, + { "hatchColor", nullptr, nullptr }, + { "hatchStyle", nullptr, nullptr }, + { "hatched", nullptr, nullptr }, + { "headlight", nullptr, nullptr }, + { "horizontal", nullptr, nullptr }, + { "horizontalDatum", nullptr, nullptr }, + { "http-equiv", nullptr, nullptr }, + { "image", nullptr, nullptr }, + { "importedDEF", nullptr, nullptr }, + { "info", nullptr, nullptr }, + { "innerRadius", nullptr, nullptr }, + { "inputFalse", nullptr, nullptr }, + { "inputNegate", nullptr, nullptr }, + { "inputSource", nullptr, nullptr }, + { "inputTrue", nullptr, nullptr }, + { "integerKey", nullptr, nullptr }, + { "intensity", nullptr, nullptr }, + { "jump", nullptr, nullptr }, + { "justify", nullptr, nullptr }, + { "keyPress", nullptr, nullptr }, + { "keyRelease", nullptr, nullptr }, + { "knot", nullptr, nullptr }, + { "lang", nullptr, nullptr }, + { "language", nullptr, nullptr }, + { "leftToRight", nullptr, nullptr }, + { "leftUrl", nullptr, nullptr }, + { "length", nullptr, nullptr }, + { "lengthOfModulationParameters", nullptr, nullptr }, + { "level", nullptr, nullptr }, + { "limitOrientation", nullptr, nullptr }, + { "lineSegments", nullptr, nullptr }, + { "linearAcceleration", nullptr, nullptr }, + { "linearVelocity", nullptr, nullptr }, + { "linetype", nullptr, nullptr }, + { "linewidthScaleFactor", nullptr, nullptr }, + { "llimit", nullptr, nullptr }, + { "load", nullptr, nullptr }, + { "loadTime", nullptr, nullptr }, + { "localDEF", nullptr, nullptr }, + { "location", nullptr, nullptr }, + { "loop", nullptr, nullptr }, + { "marking", nullptr, nullptr }, + { "mass", nullptr, nullptr }, + { "maxAngle", nullptr, nullptr }, + { "maxBack", nullptr, nullptr }, + { "maxExtent", nullptr, nullptr }, + { "maxFront", nullptr, nullptr }, + { "maxPosition", nullptr, nullptr }, + { "metadataFormat", nullptr, nullptr }, + { "minAngle", nullptr, nullptr }, + { "minBack", nullptr, nullptr }, + { "minFront", nullptr, nullptr }, + { "minPosition", nullptr, nullptr }, + { "modulationTypeDetail", nullptr, nullptr }, + { "modulationTypeMajor", nullptr, nullptr }, + { "modulationTypeSpreadSpectrum", nullptr, nullptr }, + { "modulationTypeSystem", nullptr, nullptr }, + { "momentsOfInertia", nullptr, nullptr }, + { "multicastRelayHost", nullptr, nullptr }, + { "multicastRelayPort", nullptr, nullptr }, + { "munitionApplicationID", nullptr, nullptr }, + { "munitionEndPoint", nullptr, nullptr }, + { "munitionEntityID", nullptr, nullptr }, + { "munitionQuantity", nullptr, nullptr }, + { "munitionSiteID", nullptr, nullptr }, + { "munitionStartPoint", nullptr, nullptr }, + { "mustEvaluate", nullptr, nullptr }, + { "navType", nullptr, nullptr }, + { "networkMode", nullptr, nullptr }, + { "next", nullptr, nullptr }, + { "nodeField", nullptr, nullptr }, + { "offset", nullptr, nullptr }, + { "on", nullptr, nullptr }, + { "order", nullptr, nullptr }, + { "originator", nullptr, nullptr }, + { "outerRadius", nullptr, nullptr }, + { "parameter", nullptr, nullptr }, + { "pauseTime", nullptr, nullptr }, + { "pitch", nullptr, nullptr }, + { "points", nullptr, nullptr }, + { "port", nullptr, nullptr }, + { "power", nullptr, nullptr }, + { "previous", nullptr, nullptr }, + { "priority", nullptr, nullptr }, + { "profile", nullptr, nullptr }, + { "progress", nullptr, nullptr }, + { "protoField", nullptr, nullptr }, + { "radioEntityTypeCategory", nullptr, nullptr }, + { "radioEntityTypeCountry", nullptr, nullptr }, + { "radioEntityTypeDomain", nullptr, nullptr }, + { "radioEntityTypeKind", nullptr, nullptr }, + { "radioEntityTypeNomenclature", nullptr, nullptr }, + { "radioEntityTypeNomenclatureVersion", nullptr, nullptr }, + { "radioID", nullptr, nullptr }, + { "readInterval", nullptr, nullptr }, + { "receivedPower", nullptr, nullptr }, + { "receiverState", nullptr, nullptr }, + { "reference", nullptr, nullptr }, + { "relativeAntennaLocation", nullptr, nullptr }, + { "resolution", nullptr, nullptr }, + { "resumeTime", nullptr, nullptr }, + { "rightUrl", nullptr, nullptr }, + { "rootUrl", nullptr, nullptr }, + { "rotateYUp", nullptr, nullptr }, + { "rtpHeaderExpected", nullptr, nullptr }, + { "sampleRate", nullptr, nullptr }, + { "samples", nullptr, nullptr }, + { "shiftKey", nullptr, nullptr }, + { "side", nullptr, nullptr }, + { "siteID", nullptr, nullptr }, + { "skinCoordIndex", nullptr, nullptr }, + { "skinCoordWeight", nullptr, nullptr }, + { "skyAngle", nullptr, nullptr }, + { "skyColor", nullptr, nullptr }, + { "spacing", nullptr, nullptr }, + { "spatialize", nullptr, nullptr }, + { "speed", nullptr, nullptr }, + { "speedFactor", nullptr, nullptr }, + { "spine", nullptr, nullptr }, + { "startAngle", nullptr, nullptr }, + { "startTime", nullptr, nullptr }, + { "stiffness", nullptr, nullptr }, + { "stopTime", nullptr, nullptr }, + { "string", nullptr, nullptr }, + { "stripCount", nullptr, nullptr }, + { "style", nullptr, nullptr }, + { "summary", nullptr, nullptr }, + { "tdlType", nullptr, nullptr }, + { "tessellation", nullptr, nullptr }, + { "tessellationScale", nullptr, nullptr }, + { "time", nullptr, nullptr }, + { "timeOut", nullptr, nullptr }, + { "timestamp", nullptr, nullptr }, + { "title", nullptr, nullptr }, + { "toggle", nullptr, nullptr }, + { "top", nullptr, nullptr }, + { "topToBottom", nullptr, nullptr }, + { "topUrl", nullptr, nullptr }, + { "touchTime", nullptr, nullptr }, + { "transmitFrequencyBandwidth", nullptr, nullptr }, + { "transmitState", nullptr, nullptr }, + { "transmitterApplicationID", nullptr, nullptr }, + { "transmitterEntityID", nullptr, nullptr }, + { "transmitterRadioID", nullptr, nullptr }, + { "transmitterSiteID", nullptr, nullptr }, + { "transparent", nullptr, nullptr }, + { "triggerTime", nullptr, nullptr }, + { "triggerTrue", nullptr, nullptr }, + { "triggerValue", nullptr, nullptr }, + { "type", nullptr, nullptr }, + { "uDimension", nullptr, nullptr }, + { "uKnot", nullptr, nullptr }, + { "uOrder", nullptr, nullptr }, + { "uTessellation", nullptr, nullptr }, + { "ulimit", nullptr, nullptr }, + { "vDimension", nullptr, nullptr }, + { "vKnot", nullptr, nullptr }, + { "vOrder", nullptr, nullptr }, + { "vTessellation", nullptr, nullptr }, + { "version", nullptr, nullptr }, + { "verticalDatum", nullptr, nullptr }, + { "vertices", nullptr, nullptr }, + { "visibilityLimit", nullptr, nullptr }, + { "visibilityRange", nullptr, nullptr }, + { "warhead", nullptr, nullptr }, + { "weight", nullptr, nullptr }, + { "whichGeometry", nullptr, nullptr }, + { "writeInterval", nullptr, nullptr }, + { "xDimension", nullptr, nullptr }, + { "xSpacing", nullptr, nullptr }, + { "yScale", nullptr, nullptr }, + { "zDimension", nullptr, nullptr }, + { "zSpacing", nullptr, nullptr }, + { "visible", nullptr, nullptr }, + { "repeatR", nullptr, nullptr }, + { "texture", nullptr, nullptr }, + { "back", nullptr, nullptr }, + { "front", nullptr, nullptr }, + { "left", nullptr, nullptr }, + { "right", nullptr, nullptr }, + { "parts", nullptr, nullptr }, + { "isSelected", nullptr, nullptr }, + { "isValid", nullptr, nullptr }, + { "numComponents", nullptr, nullptr }, + { "depth", nullptr, nullptr }, + { "update", nullptr, nullptr }, + { "fogCoord", nullptr, nullptr }, + { "texCoord", nullptr, nullptr }, + { "activate", nullptr, nullptr }, + { "programs", nullptr, nullptr }, + { "matrix", nullptr, nullptr }, + { "anchorPoint", nullptr, nullptr }, + { "body1", nullptr, nullptr }, + { "body2", nullptr, nullptr }, + { "mustOutput", nullptr, nullptr }, + { "body1AnchorPoint", nullptr, nullptr }, + { "body2AnchorPoint", nullptr, nullptr }, + { "plane", nullptr, nullptr }, + { "appliedParameters", nullptr, nullptr }, + { "bounce", nullptr, nullptr }, + { "frictionCoefficients", nullptr, nullptr }, + { "minBounceSpeed", nullptr, nullptr }, + { "slipFactors", nullptr, nullptr }, + { "softnessConstantForceMix", nullptr, nullptr }, + { "softnessErrorCorrection", nullptr, nullptr }, + { "surfaceSpeed", nullptr, nullptr }, + { "isActive", nullptr, nullptr }, + { "useGeometry", nullptr, nullptr }, + { "set_destination", nullptr, nullptr }, + { "set_value", nullptr, nullptr }, + { "tau", nullptr, nullptr }, + { "tolerance", nullptr, nullptr }, + { "value_changed", nullptr, nullptr }, + { "initialDestination", nullptr, nullptr }, + { "initialValue", nullptr, nullptr }, + { "angle", nullptr, nullptr }, + { "variation", nullptr, nullptr }, + { "surfaceArea", nullptr, nullptr }, + { "frictionDirection", nullptr, nullptr }, + { "slipCoefficients", nullptr, nullptr }, + { "category", nullptr, nullptr }, + { "country", nullptr, nullptr }, + { "domain", nullptr, nullptr }, + { "extra", nullptr, nullptr }, + { "kind", nullptr, nullptr }, + { "specific", nullptr, nullptr }, + { "subcategory", nullptr, nullptr }, + { "axis1", nullptr, nullptr }, + { "axis2", nullptr, nullptr }, + { "desiredAngularVelocity1", nullptr, nullptr }, + { "desiredAngularVelocity2", nullptr, nullptr }, + { "maxAngle1", nullptr, nullptr }, + { "maxTorque1", nullptr, nullptr }, + { "maxTorque2", nullptr, nullptr }, + { "minAngle1", nullptr, nullptr }, + { "stopBounce1", nullptr, nullptr }, + { "stopConstantForceMix1", nullptr, nullptr }, + { "stopErrorCorrection1", nullptr, nullptr }, + { "suspensionErrorCorrection", nullptr, nullptr }, + { "suspensionForce", nullptr, nullptr }, + { "body1Axis", nullptr, nullptr }, + { "body2Axis", nullptr, nullptr }, + { "hinge1Angle", nullptr, nullptr }, + { "hinge1AngleRate", nullptr, nullptr }, + { "hinge2Angle", nullptr, nullptr }, + { "hinge2AngleRate", nullptr, nullptr }, + { "set_fraction", nullptr, nullptr }, + { "easeInEaseOut", nullptr, nullptr }, + { "modifiedFraction_changed", nullptr, nullptr }, + { "force", nullptr, nullptr }, + { "geoCenter", nullptr, nullptr }, + { "centerOfRotation_changed", nullptr, nullptr }, + { "geoCoord_changed", nullptr, nullptr }, + { "orientation_changed", nullptr, nullptr }, + { "position_changed", nullptr, nullptr }, + { "isPickable", nullptr, nullptr }, + { "viewport", nullptr, nullptr }, + { "activeLayer", nullptr, nullptr }, + { "align", nullptr, nullptr }, + { "offsetUnits", nullptr, nullptr }, + { "scaleMode", nullptr, nullptr }, + { "sizeUnits", nullptr, nullptr }, + { "layout", nullptr, nullptr }, + { "objectType", nullptr, nullptr }, + { "pickedNormal", nullptr, nullptr }, + { "pickedPoint", nullptr, nullptr }, + { "pickedTextureCoordinate", nullptr, nullptr }, + { "intersectionType", nullptr, nullptr }, + { "sortOrder", nullptr, nullptr }, + { "axis1Angle", nullptr, nullptr }, + { "axis1Torque", nullptr, nullptr }, + { "axis2Angle", nullptr, nullptr }, + { "axis2Torque", nullptr, nullptr }, + { "axis3Angle", nullptr, nullptr }, + { "axis3Torque", nullptr, nullptr }, + { "enabledAxies", nullptr, nullptr }, + { "motor1Axis", nullptr, nullptr }, + { "motor2Axis", nullptr, nullptr }, + { "motor3Axis", nullptr, nullptr }, + { "stop1Bounce", nullptr, nullptr }, + { "stop1ErrorCorrection", nullptr, nullptr }, + { "stop2Bounce", nullptr, nullptr }, + { "stop2ErrorCorrection", nullptr, nullptr }, + { "stop3Bounce", nullptr, nullptr }, + { "stop3ErrorCorrection", nullptr, nullptr }, + { "motor1Angle", nullptr, nullptr }, + { "motor1AngleRate", nullptr, nullptr }, + { "motor2Angle", nullptr, nullptr }, + { "motor2AngleRate", nullptr, nullptr }, + { "motor3Angle", nullptr, nullptr }, + { "motor3AngleRate", nullptr, nullptr }, + { "autoCalc", nullptr, nullptr }, + { "duration", nullptr, nullptr }, + { "retainUserOffsets", nullptr, nullptr }, + { "isBound", nullptr, nullptr }, + { "appearance", nullptr, nullptr }, + { "createParticles", nullptr, nullptr }, + { "lifetimeVariation", nullptr, nullptr }, + { "maxParticles", nullptr, nullptr }, + { "particleLifetime", nullptr, nullptr }, + { "particleSize", nullptr, nullptr }, + { "colorKey", nullptr, nullptr }, + { "geometryType", nullptr, nullptr }, + { "texCoordKey", nullptr, nullptr }, + { "pickable", nullptr, nullptr }, + { "angularDampingFactor", nullptr, nullptr }, + { "angularVelocity", nullptr, nullptr }, + { "autoDamp", nullptr, nullptr }, + { "autoDisable", nullptr, nullptr }, + { "disableAngularSpeed", nullptr, nullptr }, + { "disableLinearSpeed", nullptr, nullptr }, + { "disableTime", nullptr, nullptr }, + { "finiteRotationAxis", nullptr, nullptr }, + { "fixed", nullptr, nullptr }, + { "forces", nullptr, nullptr }, + { "inertia", nullptr, nullptr }, + { "linearDampingFactor", nullptr, nullptr }, + { "torques", nullptr, nullptr }, + { "useFiniteRotation", nullptr, nullptr }, + { "useGlobalForce", nullptr, nullptr }, + { "constantForceMix", nullptr, nullptr }, + { "constantSurfaceThickness", nullptr, nullptr }, + { "errorCorrection", nullptr, nullptr }, + { "iterations", nullptr, nullptr }, + { "maxCorrectionSpeed", nullptr, nullptr }, + { "preferAccuracy", nullptr, nullptr }, + { "pointSize", nullptr, nullptr }, + { "stopBounce", nullptr, nullptr }, + { "stopErrorCorrection", nullptr, nullptr }, + { "angleRate", nullptr, nullptr }, + { "maxSeparation", nullptr, nullptr }, + { "minSeparation", nullptr, nullptr }, + { "separation", nullptr, nullptr }, + { "separationRate", nullptr, nullptr }, + { "closed", nullptr, nullptr }, + { "keyVelocity", nullptr, nullptr }, + { "normalizeVelocity", nullptr, nullptr }, + { "surface", nullptr, nullptr }, + { "anisotropicDegree", nullptr, nullptr }, + { "borderColor", nullptr, nullptr }, + { "borderWidth", nullptr, nullptr }, + { "boundaryModeS", nullptr, nullptr }, + { "boundaryModeT", nullptr, nullptr }, + { "boundaryModeR", nullptr, nullptr }, + { "magnificationFilter", nullptr, nullptr }, + { "minificationFilter", nullptr, nullptr }, + { "textureCompression", nullptr, nullptr }, + { "texturePriority", nullptr, nullptr }, + { "generateMipMaps", nullptr, nullptr }, + { "targetObject", nullptr, nullptr }, + { "backAmbientIntensity", nullptr, nullptr }, + { "backDiffuseColor", nullptr, nullptr }, + { "backEmissiveColor", nullptr, nullptr }, + { "backShininess", nullptr, nullptr }, + { "backSpecularColor", nullptr, nullptr }, + { "separateBackColor", nullptr, nullptr }, + { "displayed", nullptr, nullptr }, + { "clipBoundary", nullptr, nullptr }, + { "internal", nullptr, nullptr }, + { "gustiness", nullptr, nullptr }, + { "turbulence", nullptr, nullptr } +}; + +FIVocabulary X3D_vocabulary_3_2 = { + nullptr, 0, + encodingAlgorithmTable_3_2, 8, + nullptr, 0, + nullptr, 0, + nullptr, 0, + nullptr, 0, + nullptr, 0, + attributeValueTable_3_2, 2, + nullptr, 0, + nullptr, 0, + elementNameTable_3_2, 233, + attributeNameTable_3_2, 516 +}; + +static const char *encodingAlgorithmTable_3_3[] = { + "encoder://web3d.org/QuantizedFloatArrayEncoder", + "encoder://web3d.org/DeltazlibIntArrayEncoder", + "encoder://web3d.org/QuantizedzlibFloatArrayEncoder", + "encoder://web3d.org/zlibFloatArrayEncoder", + "encoder://web3d.org/QuantizedDoubleArrayEncoder", + "encoder://web3d.org/zlibDoubleArrayEncoder", + "encoder://web3d.org/QuantizedzlibDoubleArrayEncoder", + "encoder://web3d.org/RangeIntArrayEncoder" +}; + +static const std::shared_ptr attributeValueTable_3_3[] = { + FIStringValue::create("false"), + FIStringValue::create("true") +}; + +static const FIQName elementNameTable_3_3[] = { + { "Shape", nullptr, nullptr }, + { "Appearance", nullptr, nullptr }, + { "Material", nullptr, nullptr }, + { "IndexedFaceSet", nullptr, nullptr }, + { "ProtoInstance", nullptr, nullptr }, + { "Transform", nullptr, nullptr }, + { "ImageTexture", nullptr, nullptr }, + { "TextureTransform", nullptr, nullptr }, + { "Coordinate", nullptr, nullptr }, + { "Normal", nullptr, nullptr }, + { "Color", nullptr, nullptr }, + { "ColorRGBA", nullptr, nullptr }, + { "TextureCoordinate", nullptr, nullptr }, + { "ROUTE", nullptr, nullptr }, + { "fieldValue", nullptr, nullptr }, + { "Group", nullptr, nullptr }, + { "LOD", nullptr, nullptr }, + { "Switch", nullptr, nullptr }, + { "Script", nullptr, nullptr }, + { "IndexedTriangleFanSet", nullptr, nullptr }, + { "IndexedTriangleSet", nullptr, nullptr }, + { "IndexedTriangleStripSet", nullptr, nullptr }, + { "MultiTexture", nullptr, nullptr }, + { "MultiTextureCoordinate", nullptr, nullptr }, + { "MultiTextureTransform", nullptr, nullptr }, + { "IndexedLineSet", nullptr, nullptr }, + { "PointSet", nullptr, nullptr }, + { "StaticGroup", nullptr, nullptr }, + { "Sphere", nullptr, nullptr }, + { "Box", nullptr, nullptr }, + { "Cone", nullptr, nullptr }, + { "Anchor", nullptr, nullptr }, + { "Arc2D", nullptr, nullptr }, + { "ArcClose2D", nullptr, nullptr }, + { "AudioClip", nullptr, nullptr }, + { "Background", nullptr, nullptr }, + { "Billboard", nullptr, nullptr }, + { "BooleanFilter", nullptr, nullptr }, + { "BooleanSequencer", nullptr, nullptr }, + { "BooleanToggle", nullptr, nullptr }, + { "BooleanTrigger", nullptr, nullptr }, + { "Circle2D", nullptr, nullptr }, + { "Collision", nullptr, nullptr }, + { "ColorInterpolator", nullptr, nullptr }, + { "Contour2D", nullptr, nullptr }, + { "ContourPolyline2D", nullptr, nullptr }, + { "CoordinateDouble", nullptr, nullptr }, + { "CoordinateInterpolator", nullptr, nullptr }, + { "CoordinateInterpolator2D", nullptr, nullptr }, + { "Cylinder", nullptr, nullptr }, + { "CylinderSensor", nullptr, nullptr }, + { "DirectionalLight", nullptr, nullptr }, + { "Disk2D", nullptr, nullptr }, + { "EXPORT", nullptr, nullptr }, + { "ElevationGrid", nullptr, nullptr }, + { "EspduTransform", nullptr, nullptr }, + { "ExternProtoDeclare", nullptr, nullptr }, + { "Extrusion", nullptr, nullptr }, + { "FillProperties", nullptr, nullptr }, + { "Fog", nullptr, nullptr }, + { "FontStyle", nullptr, nullptr }, + { "GeoCoordinate", nullptr, nullptr }, + { "GeoElevationGrid", nullptr, nullptr }, + { "GeoLOD", nullptr, nullptr }, + { "GeoLocation", nullptr, nullptr }, + { "GeoMetadata", nullptr, nullptr }, + { "GeoOrigin", nullptr, nullptr }, + { "GeoPositionInterpolator", nullptr, nullptr }, + { "GeoTouchSensor", nullptr, nullptr }, + { "GeoViewpoint", nullptr, nullptr }, + { "HAnimDisplacer", nullptr, nullptr }, + { "HAnimHumanoid", nullptr, nullptr }, + { "HAnimJoint", nullptr, nullptr }, + { "HAnimSegment", nullptr, nullptr }, + { "HAnimSite", nullptr, nullptr }, + { "IMPORT", nullptr, nullptr }, + { "IS", nullptr, nullptr }, + { "Inline", nullptr, nullptr }, + { "IntegerSequencer", nullptr, nullptr }, + { "IntegerTrigger", nullptr, nullptr }, + { "KeySensor", nullptr, nullptr }, + { "LineProperties", nullptr, nullptr }, + { "LineSet", nullptr, nullptr }, + { "LoadSensor", nullptr, nullptr }, + { "MetadataDouble", nullptr, nullptr }, + { "MetadataFloat", nullptr, nullptr }, + { "MetadataInteger", nullptr, nullptr }, + { "MetadataSet", nullptr, nullptr }, + { "MetadataString", nullptr, nullptr }, + { "MovieTexture", nullptr, nullptr }, + { "NavigationInfo", nullptr, nullptr }, + { "NormalInterpolator", nullptr, nullptr }, + { "NurbsCurve", nullptr, nullptr }, + { "NurbsCurve2D", nullptr, nullptr }, + { "NurbsOrientationInterpolator", nullptr, nullptr }, + { "NurbsPatchSurface", nullptr, nullptr }, + { "NurbsPositionInterpolator", nullptr, nullptr }, + { "NurbsSet", nullptr, nullptr }, + { "NurbsSurfaceInterpolator", nullptr, nullptr }, + { "NurbsSweptSurface", nullptr, nullptr }, + { "NurbsSwungSurface", nullptr, nullptr }, + { "NurbsTextureCoordinate", nullptr, nullptr }, + { "NurbsTrimmedSurface", nullptr, nullptr }, + { "OrientationInterpolator", nullptr, nullptr }, + { "PixelTexture", nullptr, nullptr }, + { "PlaneSensor", nullptr, nullptr }, + { "PointLight", nullptr, nullptr }, + { "Polyline2D", nullptr, nullptr }, + { "Polypoint2D", nullptr, nullptr }, + { "PositionInterpolator", nullptr, nullptr }, + { "PositionInterpolator2D", nullptr, nullptr }, + { "ProtoBody", nullptr, nullptr }, + { "ProtoDeclare", nullptr, nullptr }, + { "ProtoInterface", nullptr, nullptr }, + { "ProximitySensor", nullptr, nullptr }, + { "ReceiverPdu", nullptr, nullptr }, + { "Rectangle2D", nullptr, nullptr }, + { "ScalarInterpolator", nullptr, nullptr }, + { "Scene", nullptr, nullptr }, + { "SignalPdu", nullptr, nullptr }, + { "Sound", nullptr, nullptr }, + { "SphereSensor", nullptr, nullptr }, + { "SpotLight", nullptr, nullptr }, + { "StringSensor", nullptr, nullptr }, + { "Text", nullptr, nullptr }, + { "TextureBackground", nullptr, nullptr }, + { "TextureCoordinateGenerator", nullptr, nullptr }, + { "TimeSensor", nullptr, nullptr }, + { "TimeTrigger", nullptr, nullptr }, + { "TouchSensor", nullptr, nullptr }, + { "TransmitterPdu", nullptr, nullptr }, + { "TriangleFanSet", nullptr, nullptr }, + { "TriangleSet", nullptr, nullptr }, + { "TriangleSet2D", nullptr, nullptr }, + { "TriangleStripSet", nullptr, nullptr }, + { "Viewpoint", nullptr, nullptr }, + { "VisibilitySensor", nullptr, nullptr }, + { "WorldInfo", nullptr, nullptr }, + { "X3D", nullptr, nullptr }, + { "component", nullptr, nullptr }, + { "connect", nullptr, nullptr }, + { "field", nullptr, nullptr }, + { "head", nullptr, nullptr }, + { "humanoidBodyType", nullptr, nullptr }, + { "meta", nullptr, nullptr }, + { "CADAssembly", nullptr, nullptr }, + { "CADFace", nullptr, nullptr }, + { "CADLayer", nullptr, nullptr }, + { "CADPart", nullptr, nullptr }, + { "ComposedCubeMapTexture", nullptr, nullptr }, + { "ComposedShader", nullptr, nullptr }, + { "ComposedTexture3D", nullptr, nullptr }, + { "FloatVertexAttribute", nullptr, nullptr }, + { "FogCoordinate", nullptr, nullptr }, + { "GeneratedCubeMapTexture", nullptr, nullptr }, + { "ImageCubeMapTexture", nullptr, nullptr }, + { "ImageTexture3D", nullptr, nullptr }, + { "IndexedQuadSet", nullptr, nullptr }, + { "LocalFog", nullptr, nullptr }, + { "Matrix3VertexAttribute", nullptr, nullptr }, + { "Matrix4VertexAttribute", nullptr, nullptr }, + { "PackagedShader", nullptr, nullptr }, + { "PixelTexture3D", nullptr, nullptr }, + { "ProgramShader", nullptr, nullptr }, + { "QuadSet", nullptr, nullptr }, + { "ShaderPart", nullptr, nullptr }, + { "ShaderProgram", nullptr, nullptr }, + { "TextureCoordinate3D", nullptr, nullptr }, + { "TextureCoordinate4D", nullptr, nullptr }, + { "TextureTransform3D", nullptr, nullptr }, + { "TextureTransformMatrix3D", nullptr, nullptr }, + { "BallJoint", nullptr, nullptr }, + { "BoundedPhysicsModel", nullptr, nullptr }, + { "ClipPlane", nullptr, nullptr }, + { "CollidableOffset", nullptr, nullptr }, + { "CollidableShape", nullptr, nullptr }, + { "CollisionCollection", nullptr, nullptr }, + { "CollisionSensor", nullptr, nullptr }, + { "CollisionSpace", nullptr, nullptr }, + { "ColorDamper", nullptr, nullptr }, + { "ConeEmitter", nullptr, nullptr }, + { "Contact", nullptr, nullptr }, + { "CoordinateDamper", nullptr, nullptr }, + { "DISEntityManager", nullptr, nullptr }, + { "DISEntityTypeMapping", nullptr, nullptr }, + { "DoubleAxisHingeJoint", nullptr, nullptr }, + { "EaseInEaseOut", nullptr, nullptr }, + { "ExplosionEmitter", nullptr, nullptr }, + { "ForcePhysicsModel", nullptr, nullptr }, + { "GeoProximitySensor", nullptr, nullptr }, + { "GeoTransform", nullptr, nullptr }, + { "Layer", nullptr, nullptr }, + { "LayerSet", nullptr, nullptr }, + { "Layout", nullptr, nullptr }, + { "LayoutGroup", nullptr, nullptr }, + { "LayoutLayer", nullptr, nullptr }, + { "LinePickSensor", nullptr, nullptr }, + { "MotorJoint", nullptr, nullptr }, + { "OrientationChaser", nullptr, nullptr }, + { "OrientationDamper", nullptr, nullptr }, + { "OrthoViewpoint", nullptr, nullptr }, + { "ParticleSystem", nullptr, nullptr }, + { "PickableGroup", nullptr, nullptr }, + { "PointEmitter", nullptr, nullptr }, + { "PointPickSensor", nullptr, nullptr }, + { "PolylineEmitter", nullptr, nullptr }, + { "PositionChaser", nullptr, nullptr }, + { "PositionChaser2D", nullptr, nullptr }, + { "PositionDamper", nullptr, nullptr }, + { "PositionDamper2D", nullptr, nullptr }, + { "PrimitivePickSensor", nullptr, nullptr }, + { "RigidBody", nullptr, nullptr }, + { "RigidBodyCollection", nullptr, nullptr }, + { "ScalarChaser", nullptr, nullptr }, + { "ScreenFontStyle", nullptr, nullptr }, + { "ScreenGroup", nullptr, nullptr }, + { "SingleAxisHingeJoint", nullptr, nullptr }, + { "SliderJoint", nullptr, nullptr }, + { "SplinePositionInterpolator", nullptr, nullptr }, + { "SplinePositionInterpolator2D", nullptr, nullptr }, + { "SplineScalarInterpolator", nullptr, nullptr }, + { "SquadOrientationInterpolator", nullptr, nullptr }, + { "SurfaceEmitter", nullptr, nullptr }, + { "TexCoordDamper2D", nullptr, nullptr }, + { "TextureProperties", nullptr, nullptr }, + { "TransformSensor", nullptr, nullptr }, + { "TwoSidedMaterial", nullptr, nullptr }, + { "UniversalJoint", nullptr, nullptr }, + { "ViewpointGroup", nullptr, nullptr }, + { "Viewport", nullptr, nullptr }, + { "VolumeEmitter", nullptr, nullptr }, + { "VolumePickSensor", nullptr, nullptr }, + { "WindPhysicsModel", nullptr, nullptr }, + { "BlendedVolumeStyle", nullptr, nullptr }, + { "BoundaryEnhancementVolumeStyle", nullptr, nullptr }, + { "CartoonVolumeStyle", nullptr, nullptr }, + { "ComposedVolumeStyle", nullptr, nullptr }, + { "EdgeEnhancementVolumeStyle", nullptr, nullptr }, + { "IsoSurfaceVolumeData", nullptr, nullptr }, + { "MetadataBoolean", nullptr, nullptr }, + { "OpacityMapVolumeStyle", nullptr, nullptr }, + { "ProjectionVolumeStyle", nullptr, nullptr }, + { "SegmentedVolumeData", nullptr, nullptr }, + { "ShadedVolumeStyle", nullptr, nullptr }, + { "SilhouetteEnhancementVolumeStyle", nullptr, nullptr }, + { "ToneMappedVolumeStyle", nullptr, nullptr }, + { "VolumeData", nullptr, nullptr }, + { "ColorChaser", nullptr, nullptr }, + { "CoordinateChaser", nullptr, nullptr }, + { "ScalarDamper", nullptr, nullptr }, + { "TexCoordChaser2D", nullptr, nullptr }, + { "unit", nullptr, nullptr } +}; + +static const FIQName attributeNameTable_3_3[] = { + { "DEF", nullptr, nullptr }, + { "USE", nullptr, nullptr }, + { "containerField", nullptr, nullptr }, + { "fromNode", nullptr, nullptr }, + { "fromField", nullptr, nullptr }, + { "toNode", nullptr, nullptr }, + { "toField", nullptr, nullptr }, + { "name", nullptr, nullptr }, + { "value", nullptr, nullptr }, + { "color", nullptr, nullptr }, + { "colorIndex", nullptr, nullptr }, + { "coordIndex", nullptr, nullptr }, + { "texCoordIndex", nullptr, nullptr }, + { "normalIndex", nullptr, nullptr }, + { "colorPerVertex", nullptr, nullptr }, + { "normalPerVertex", nullptr, nullptr }, + { "rotation", nullptr, nullptr }, + { "scale", nullptr, nullptr }, + { "center", nullptr, nullptr }, + { "scaleOrientation", nullptr, nullptr }, + { "translation", nullptr, nullptr }, + { "url", nullptr, nullptr }, + { "repeatS", nullptr, nullptr }, + { "repeatT", nullptr, nullptr }, + { "point", nullptr, nullptr }, + { "vector", nullptr, nullptr }, + { "range", nullptr, nullptr }, + { "ambientIntensity", nullptr, nullptr }, + { "diffuseColor", nullptr, nullptr }, + { "emissiveColor", nullptr, nullptr }, + { "shininess", nullptr, nullptr }, + { "specularColor", nullptr, nullptr }, + { "transparency", nullptr, nullptr }, + { "whichChoice", nullptr, nullptr }, + { "index", nullptr, nullptr }, + { "mode", nullptr, nullptr }, + { "source", nullptr, nullptr }, + { "function", nullptr, nullptr }, + { "alpha", nullptr, nullptr }, + { "vertexCount", nullptr, nullptr }, + { "radius", nullptr, nullptr }, + { "size", nullptr, nullptr }, + { "height", nullptr, nullptr }, + { "solid", nullptr, nullptr }, + { "ccw", nullptr, nullptr }, + { "key", nullptr, nullptr }, + { "keyValue", nullptr, nullptr }, + { "enabled", nullptr, nullptr }, + { "direction", nullptr, nullptr }, + { "position", nullptr, nullptr }, + { "orientation", nullptr, nullptr }, + { "bboxCenter", nullptr, nullptr }, + { "bboxSize", nullptr, nullptr }, + { "AS", nullptr, nullptr }, + { "InlineDEF", nullptr, nullptr }, + { "accessType", nullptr, nullptr }, + { "actionKeyPress", nullptr, nullptr }, + { "actionKeyRelease", nullptr, nullptr }, + { "address", nullptr, nullptr }, + { "altKey", nullptr, nullptr }, + { "antennaLocation", nullptr, nullptr }, + { "antennaPatternLength", nullptr, nullptr }, + { "antennaPatternType", nullptr, nullptr }, + { "applicationID", nullptr, nullptr }, + { "articulationParameterArray", nullptr, nullptr }, + { "articulationParameterChangeIndicatorArray", nullptr, nullptr }, + { "articulationParameterCount", nullptr, nullptr }, + { "articulationParameterDesignatorArray", nullptr, nullptr }, + { "articulationParameterIdPartAttachedArray", nullptr, nullptr }, + { "articulationParameterTypeArray", nullptr, nullptr }, + { "attenuation", nullptr, nullptr }, + { "autoOffset", nullptr, nullptr }, + { "avatarSize", nullptr, nullptr }, + { "axisOfRotation", nullptr, nullptr }, + { "backUrl", nullptr, nullptr }, + { "beamWidth", nullptr, nullptr }, + { "beginCap", nullptr, nullptr }, + { "bindTime", nullptr, nullptr }, + { "bottom", nullptr, nullptr }, + { "bottomRadius", nullptr, nullptr }, + { "bottomUrl", nullptr, nullptr }, + { "centerOfMass", nullptr, nullptr }, + { "centerOfRotation", nullptr, nullptr }, + { "child1Url", nullptr, nullptr }, + { "child2Url", nullptr, nullptr }, + { "child3Url", nullptr, nullptr }, + { "child4Url", nullptr, nullptr }, + { "class", nullptr, nullptr }, + { "closureType", nullptr, nullptr }, + { "collideTime", nullptr, nullptr }, + { "content", nullptr, nullptr }, + { "controlKey", nullptr, nullptr }, + { "controlPoint", nullptr, nullptr }, + { "convex", nullptr, nullptr }, + { "coordinateSystem", nullptr, nullptr }, + { "copyright", nullptr, nullptr }, + { "creaseAngle", nullptr, nullptr }, + { "crossSection", nullptr, nullptr }, + { "cryptoKeyID", nullptr, nullptr }, + { "cryptoSystem", nullptr, nullptr }, + { "cutOffAngle", nullptr, nullptr }, + { "cycleInterval", nullptr, nullptr }, + { "cycleTime", nullptr, nullptr }, + { "data", nullptr, nullptr }, + { "dataFormat", nullptr, nullptr }, + { "dataLength", nullptr, nullptr }, + { "dataUrl", nullptr, nullptr }, + { "date", nullptr, nullptr }, + { "deadReckoning", nullptr, nullptr }, + { "deletionAllowed", nullptr, nullptr }, + { "description", nullptr, nullptr }, + { "detonateTime", nullptr, nullptr }, + { "dir", nullptr, nullptr }, + { "directOutput", nullptr, nullptr }, + { "diskAngle", nullptr, nullptr }, + { "displacements", nullptr, nullptr }, + { "documentation", nullptr, nullptr }, + { "elapsedTime", nullptr, nullptr }, + { "ellipsoid", nullptr, nullptr }, + { "encodingScheme", nullptr, nullptr }, + { "endAngle", nullptr, nullptr }, + { "endCap", nullptr, nullptr }, + { "enterTime", nullptr, nullptr }, + { "enteredText", nullptr, nullptr }, + { "entityCategory", nullptr, nullptr }, + { "entityCountry", nullptr, nullptr }, + { "entityDomain", nullptr, nullptr }, + { "entityExtra", nullptr, nullptr }, + { "entityID", nullptr, nullptr }, + { "entityKind", nullptr, nullptr }, + { "entitySpecific", nullptr, nullptr }, + { "entitySubCategory", nullptr, nullptr }, + { "exitTime", nullptr, nullptr }, + { "extent", nullptr, nullptr }, + { "family", nullptr, nullptr }, + { "fanCount", nullptr, nullptr }, + { "fieldOfView", nullptr, nullptr }, + { "filled", nullptr, nullptr }, + { "finalText", nullptr, nullptr }, + { "fireMissionIndex", nullptr, nullptr }, + { "fired1", nullptr, nullptr }, + { "fired2", nullptr, nullptr }, + { "firedTime", nullptr, nullptr }, + { "firingRange", nullptr, nullptr }, + { "firingRate", nullptr, nullptr }, + { "fogType", nullptr, nullptr }, + { "forceID", nullptr, nullptr }, + { "frequency", nullptr, nullptr }, + { "frontUrl", nullptr, nullptr }, + { "fuse", nullptr, nullptr }, + { "geoCoords", nullptr, nullptr }, + { "geoGridOrigin", nullptr, nullptr }, + { "geoSystem", nullptr, nullptr }, + { "groundAngle", nullptr, nullptr }, + { "groundColor", nullptr, nullptr }, + { "hatchColor", nullptr, nullptr }, + { "hatchStyle", nullptr, nullptr }, + { "hatched", nullptr, nullptr }, + { "headlight", nullptr, nullptr }, + { "horizontal", nullptr, nullptr }, + { "horizontalDatum", nullptr, nullptr }, + { "http-equiv", nullptr, nullptr }, + { "image", nullptr, nullptr }, + { "importedDEF", nullptr, nullptr }, + { "info", nullptr, nullptr }, + { "innerRadius", nullptr, nullptr }, + { "inputFalse", nullptr, nullptr }, + { "inputNegate", nullptr, nullptr }, + { "inputSource", nullptr, nullptr }, + { "inputTrue", nullptr, nullptr }, + { "integerKey", nullptr, nullptr }, + { "intensity", nullptr, nullptr }, + { "jump", nullptr, nullptr }, + { "justify", nullptr, nullptr }, + { "keyPress", nullptr, nullptr }, + { "keyRelease", nullptr, nullptr }, + { "knot", nullptr, nullptr }, + { "lang", nullptr, nullptr }, + { "language", nullptr, nullptr }, + { "leftToRight", nullptr, nullptr }, + { "leftUrl", nullptr, nullptr }, + { "length", nullptr, nullptr }, + { "lengthOfModulationParameters", nullptr, nullptr }, + { "level", nullptr, nullptr }, + { "limitOrientation", nullptr, nullptr }, + { "lineSegments", nullptr, nullptr }, + { "linearAcceleration", nullptr, nullptr }, + { "linearVelocity", nullptr, nullptr }, + { "linetype", nullptr, nullptr }, + { "linewidthScaleFactor", nullptr, nullptr }, + { "llimit", nullptr, nullptr }, + { "load", nullptr, nullptr }, + { "loadTime", nullptr, nullptr }, + { "localDEF", nullptr, nullptr }, + { "location", nullptr, nullptr }, + { "loop", nullptr, nullptr }, + { "marking", nullptr, nullptr }, + { "mass", nullptr, nullptr }, + { "maxAngle", nullptr, nullptr }, + { "maxBack", nullptr, nullptr }, + { "maxExtent", nullptr, nullptr }, + { "maxFront", nullptr, nullptr }, + { "maxPosition", nullptr, nullptr }, + { "metadataFormat", nullptr, nullptr }, + { "minAngle", nullptr, nullptr }, + { "minBack", nullptr, nullptr }, + { "minFront", nullptr, nullptr }, + { "minPosition", nullptr, nullptr }, + { "modulationTypeDetail", nullptr, nullptr }, + { "modulationTypeMajor", nullptr, nullptr }, + { "modulationTypeSpreadSpectrum", nullptr, nullptr }, + { "modulationTypeSystem", nullptr, nullptr }, + { "momentsOfInertia", nullptr, nullptr }, + { "multicastRelayHost", nullptr, nullptr }, + { "multicastRelayPort", nullptr, nullptr }, + { "munitionApplicationID", nullptr, nullptr }, + { "munitionEndPoint", nullptr, nullptr }, + { "munitionEntityID", nullptr, nullptr }, + { "munitionQuantity", nullptr, nullptr }, + { "munitionSiteID", nullptr, nullptr }, + { "munitionStartPoint", nullptr, nullptr }, + { "mustEvaluate", nullptr, nullptr }, + { "navType", nullptr, nullptr }, + { "networkMode", nullptr, nullptr }, + { "next", nullptr, nullptr }, + { "nodeField", nullptr, nullptr }, + { "offset", nullptr, nullptr }, + { "on", nullptr, nullptr }, + { "order", nullptr, nullptr }, + { "originator", nullptr, nullptr }, + { "outerRadius", nullptr, nullptr }, + { "parameter", nullptr, nullptr }, + { "pauseTime", nullptr, nullptr }, + { "pitch", nullptr, nullptr }, + { "points", nullptr, nullptr }, + { "port", nullptr, nullptr }, + { "power", nullptr, nullptr }, + { "previous", nullptr, nullptr }, + { "priority", nullptr, nullptr }, + { "profile", nullptr, nullptr }, + { "progress", nullptr, nullptr }, + { "protoField", nullptr, nullptr }, + { "radioEntityTypeCategory", nullptr, nullptr }, + { "radioEntityTypeCountry", nullptr, nullptr }, + { "radioEntityTypeDomain", nullptr, nullptr }, + { "radioEntityTypeKind", nullptr, nullptr }, + { "radioEntityTypeNomenclature", nullptr, nullptr }, + { "radioEntityTypeNomenclatureVersion", nullptr, nullptr }, + { "radioID", nullptr, nullptr }, + { "readInterval", nullptr, nullptr }, + { "receivedPower", nullptr, nullptr }, + { "receiverState", nullptr, nullptr }, + { "reference", nullptr, nullptr }, + { "relativeAntennaLocation", nullptr, nullptr }, + { "resolution", nullptr, nullptr }, + { "resumeTime", nullptr, nullptr }, + { "rightUrl", nullptr, nullptr }, + { "rootUrl", nullptr, nullptr }, + { "rotateYUp", nullptr, nullptr }, + { "rtpHeaderExpected", nullptr, nullptr }, + { "sampleRate", nullptr, nullptr }, + { "samples", nullptr, nullptr }, + { "shiftKey", nullptr, nullptr }, + { "side", nullptr, nullptr }, + { "siteID", nullptr, nullptr }, + { "skinCoordIndex", nullptr, nullptr }, + { "skinCoordWeight", nullptr, nullptr }, + { "skyAngle", nullptr, nullptr }, + { "skyColor", nullptr, nullptr }, + { "spacing", nullptr, nullptr }, + { "spatialize", nullptr, nullptr }, + { "speed", nullptr, nullptr }, + { "speedFactor", nullptr, nullptr }, + { "spine", nullptr, nullptr }, + { "startAngle", nullptr, nullptr }, + { "startTime", nullptr, nullptr }, + { "stiffness", nullptr, nullptr }, + { "stopTime", nullptr, nullptr }, + { "string", nullptr, nullptr }, + { "stripCount", nullptr, nullptr }, + { "style", nullptr, nullptr }, + { "summary", nullptr, nullptr }, + { "tdlType", nullptr, nullptr }, + { "tessellation", nullptr, nullptr }, + { "tessellationScale", nullptr, nullptr }, + { "time", nullptr, nullptr }, + { "timeOut", nullptr, nullptr }, + { "timestamp", nullptr, nullptr }, + { "title", nullptr, nullptr }, + { "toggle", nullptr, nullptr }, + { "top", nullptr, nullptr }, + { "topToBottom", nullptr, nullptr }, + { "topUrl", nullptr, nullptr }, + { "touchTime", nullptr, nullptr }, + { "transmitFrequencyBandwidth", nullptr, nullptr }, + { "transmitState", nullptr, nullptr }, + { "transmitterApplicationID", nullptr, nullptr }, + { "transmitterEntityID", nullptr, nullptr }, + { "transmitterRadioID", nullptr, nullptr }, + { "transmitterSiteID", nullptr, nullptr }, + { "transparent", nullptr, nullptr }, + { "triggerTime", nullptr, nullptr }, + { "triggerTrue", nullptr, nullptr }, + { "triggerValue", nullptr, nullptr }, + { "type", nullptr, nullptr }, + { "uDimension", nullptr, nullptr }, + { "uKnot", nullptr, nullptr }, + { "uOrder", nullptr, nullptr }, + { "uTessellation", nullptr, nullptr }, + { "ulimit", nullptr, nullptr }, + { "vDimension", nullptr, nullptr }, + { "vKnot", nullptr, nullptr }, + { "vOrder", nullptr, nullptr }, + { "vTessellation", nullptr, nullptr }, + { "version", nullptr, nullptr }, + { "verticalDatum", nullptr, nullptr }, + { "vertices", nullptr, nullptr }, + { "visibilityLimit", nullptr, nullptr }, + { "visibilityRange", nullptr, nullptr }, + { "warhead", nullptr, nullptr }, + { "weight", nullptr, nullptr }, + { "whichGeometry", nullptr, nullptr }, + { "writeInterval", nullptr, nullptr }, + { "xDimension", nullptr, nullptr }, + { "xSpacing", nullptr, nullptr }, + { "yScale", nullptr, nullptr }, + { "zDimension", nullptr, nullptr }, + { "zSpacing", nullptr, nullptr }, + { "visible", nullptr, nullptr }, + { "repeatR", nullptr, nullptr }, + { "texture", nullptr, nullptr }, + { "back", nullptr, nullptr }, + { "front", nullptr, nullptr }, + { "left", nullptr, nullptr }, + { "right", nullptr, nullptr }, + { "parts", nullptr, nullptr }, + { "isSelected", nullptr, nullptr }, + { "isValid", nullptr, nullptr }, + { "numComponents", nullptr, nullptr }, + { "depth", nullptr, nullptr }, + { "update", nullptr, nullptr }, + { "fogCoord", nullptr, nullptr }, + { "texCoord", nullptr, nullptr }, + { "activate", nullptr, nullptr }, + { "programs", nullptr, nullptr }, + { "matrix", nullptr, nullptr }, + { "anchorPoint", nullptr, nullptr }, + { "body1", nullptr, nullptr }, + { "body2", nullptr, nullptr }, + { "forceOutput", nullptr, nullptr }, + { "body1AnchorPoint", nullptr, nullptr }, + { "body2AnchorPoint", nullptr, nullptr }, + { "plane", nullptr, nullptr }, + { "appliedParameters", nullptr, nullptr }, + { "bounce", nullptr, nullptr }, + { "frictionCoefficients", nullptr, nullptr }, + { "minBounceSpeed", nullptr, nullptr }, + { "slipFactors", nullptr, nullptr }, + { "softnessConstantForceMix", nullptr, nullptr }, + { "softnessErrorCorrection", nullptr, nullptr }, + { "surfaceSpeed", nullptr, nullptr }, + { "isActive", nullptr, nullptr }, + { "useGeometry", nullptr, nullptr }, + { "set_destination", nullptr, nullptr }, + { "set_value", nullptr, nullptr }, + { "tau", nullptr, nullptr }, + { "tolerance", nullptr, nullptr }, + { "value_changed", nullptr, nullptr }, + { "initialDestination", nullptr, nullptr }, + { "initialValue", nullptr, nullptr }, + { "angle", nullptr, nullptr }, + { "variation", nullptr, nullptr }, + { "surfaceArea", nullptr, nullptr }, + { "frictionDirection", nullptr, nullptr }, + { "slipCoefficients", nullptr, nullptr }, + { "category", nullptr, nullptr }, + { "country", nullptr, nullptr }, + { "domain", nullptr, nullptr }, + { "extra", nullptr, nullptr }, + { "kind", nullptr, nullptr }, + { "specific", nullptr, nullptr }, + { "subcategory", nullptr, nullptr }, + { "axis1", nullptr, nullptr }, + { "axis2", nullptr, nullptr }, + { "desiredAngularVelocity1", nullptr, nullptr }, + { "desiredAngularVelocity2", nullptr, nullptr }, + { "maxAngle1", nullptr, nullptr }, + { "maxTorque1", nullptr, nullptr }, + { "maxTorque2", nullptr, nullptr }, + { "minAngle1", nullptr, nullptr }, + { "stopBounce1", nullptr, nullptr }, + { "stopConstantForceMix1", nullptr, nullptr }, + { "stopErrorCorrection1", nullptr, nullptr }, + { "suspensionErrorCorrection", nullptr, nullptr }, + { "suspensionForce", nullptr, nullptr }, + { "body1Axis", nullptr, nullptr }, + { "body2Axis", nullptr, nullptr }, + { "hinge1Angle", nullptr, nullptr }, + { "hinge1AngleRate", nullptr, nullptr }, + { "hinge2Angle", nullptr, nullptr }, + { "hinge2AngleRate", nullptr, nullptr }, + { "set_fraction", nullptr, nullptr }, + { "easeInEaseOut", nullptr, nullptr }, + { "modifiedFraction_changed", nullptr, nullptr }, + { "force", nullptr, nullptr }, + { "geoCenter", nullptr, nullptr }, + { "centerOfRotation_changed", nullptr, nullptr }, + { "geoCoord_changed", nullptr, nullptr }, + { "orientation_changed", nullptr, nullptr }, + { "position_changed", nullptr, nullptr }, + { "isPickable", nullptr, nullptr }, + { "viewport", nullptr, nullptr }, + { "activeLayer", nullptr, nullptr }, + { "align", nullptr, nullptr }, + { "offsetUnits", nullptr, nullptr }, + { "scaleMode", nullptr, nullptr }, + { "sizeUnits", nullptr, nullptr }, + { "layout", nullptr, nullptr }, + { "objectType", nullptr, nullptr }, + { "pickedNormal", nullptr, nullptr }, + { "pickedPoint", nullptr, nullptr }, + { "pickedTextureCoordinate", nullptr, nullptr }, + { "intersectionType", nullptr, nullptr }, + { "sortOrder", nullptr, nullptr }, + { "axis1Angle", nullptr, nullptr }, + { "axis1Torque", nullptr, nullptr }, + { "axis2Angle", nullptr, nullptr }, + { "axis2Torque", nullptr, nullptr }, + { "axis3Angle", nullptr, nullptr }, + { "axis3Torque", nullptr, nullptr }, + { "enabledAxies", nullptr, nullptr }, + { "motor1Axis", nullptr, nullptr }, + { "motor2Axis", nullptr, nullptr }, + { "motor3Axis", nullptr, nullptr }, + { "stop1Bounce", nullptr, nullptr }, + { "stop1ErrorCorrection", nullptr, nullptr }, + { "stop2Bounce", nullptr, nullptr }, + { "stop2ErrorCorrection", nullptr, nullptr }, + { "stop3Bounce", nullptr, nullptr }, + { "stop3ErrorCorrection", nullptr, nullptr }, + { "motor1Angle", nullptr, nullptr }, + { "motor1AngleRate", nullptr, nullptr }, + { "motor2Angle", nullptr, nullptr }, + { "motor2AngleRate", nullptr, nullptr }, + { "motor3Angle", nullptr, nullptr }, + { "motor3AngleRate", nullptr, nullptr }, + { "autoCalc", nullptr, nullptr }, + { "duration", nullptr, nullptr }, + { "retainUserOffsets", nullptr, nullptr }, + { "isBound", nullptr, nullptr }, + { "appearance", nullptr, nullptr }, + { "createParticles", nullptr, nullptr }, + { "lifetimeVariation", nullptr, nullptr }, + { "maxParticles", nullptr, nullptr }, + { "particleLifetime", nullptr, nullptr }, + { "particleSize", nullptr, nullptr }, + { "colorKey", nullptr, nullptr }, + { "geometryType", nullptr, nullptr }, + { "texCoordKey", nullptr, nullptr }, + { "pickable", nullptr, nullptr }, + { "angularDampingFactor", nullptr, nullptr }, + { "angularVelocity", nullptr, nullptr }, + { "autoDamp", nullptr, nullptr }, + { "autoDisable", nullptr, nullptr }, + { "disableAngularSpeed", nullptr, nullptr }, + { "disableLinearSpeed", nullptr, nullptr }, + { "disableTime", nullptr, nullptr }, + { "finiteRotationAxis", nullptr, nullptr }, + { "fixed", nullptr, nullptr }, + { "forces", nullptr, nullptr }, + { "inertia", nullptr, nullptr }, + { "linearDampingFactor", nullptr, nullptr }, + { "torques", nullptr, nullptr }, + { "useFiniteRotation", nullptr, nullptr }, + { "useGlobalForce", nullptr, nullptr }, + { "constantForceMix", nullptr, nullptr }, + { "constantSurfaceThickness", nullptr, nullptr }, + { "errorCorrection", nullptr, nullptr }, + { "iterations", nullptr, nullptr }, + { "maxCorrectionSpeed", nullptr, nullptr }, + { "preferAccuracy", nullptr, nullptr }, + { "pointSize", nullptr, nullptr }, + { "stopBounce", nullptr, nullptr }, + { "stopErrorCorrection", nullptr, nullptr }, + { "angleRate", nullptr, nullptr }, + { "maxSeparation", nullptr, nullptr }, + { "minSeparation", nullptr, nullptr }, + { "separation", nullptr, nullptr }, + { "separationRate", nullptr, nullptr }, + { "closed", nullptr, nullptr }, + { "keyVelocity", nullptr, nullptr }, + { "normalizeVelocity", nullptr, nullptr }, + { "surface", nullptr, nullptr }, + { "anisotropicDegree", nullptr, nullptr }, + { "borderColor", nullptr, nullptr }, + { "borderWidth", nullptr, nullptr }, + { "boundaryModeS", nullptr, nullptr }, + { "boundaryModeT", nullptr, nullptr }, + { "boundaryModeR", nullptr, nullptr }, + { "magnificationFilter", nullptr, nullptr }, + { "minificationFilter", nullptr, nullptr }, + { "textureCompression", nullptr, nullptr }, + { "texturePriority", nullptr, nullptr }, + { "generateMipMaps", nullptr, nullptr }, + { "targetObject", nullptr, nullptr }, + { "backAmbientIntensity", nullptr, nullptr }, + { "backDiffuseColor", nullptr, nullptr }, + { "backEmissiveColor", nullptr, nullptr }, + { "backShininess", nullptr, nullptr }, + { "backSpecularColor", nullptr, nullptr }, + { "separateBackColor", nullptr, nullptr }, + { "displayed", nullptr, nullptr }, + { "clipBoundary", nullptr, nullptr }, + { "internal", nullptr, nullptr }, + { "gustiness", nullptr, nullptr }, + { "turbulence", nullptr, nullptr }, + { "unitCategory", nullptr, nullptr }, + { "unitName", nullptr, nullptr }, + { "unitConversionFactor", nullptr, nullptr }, + { "weightConstant1", nullptr, nullptr }, + { "weightConstant2", nullptr, nullptr }, + { "weightFunction1", nullptr, nullptr }, + { "weightFunction2", nullptr, nullptr }, + { "boundaryOpacity", nullptr, nullptr }, + { "opacityFactor", nullptr, nullptr }, + { "retainedOpacity", nullptr, nullptr }, + { "colorSteps", nullptr, nullptr }, + { "orthogonalColor", nullptr, nullptr }, + { "parallelColor", nullptr, nullptr }, + { "ordered", nullptr, nullptr }, + { "edgeColor", nullptr, nullptr }, + { "gradientThreshold", nullptr, nullptr }, + { "contourStepSize", nullptr, nullptr }, + { "dimensions", nullptr, nullptr }, + { "surfaceTolerance", nullptr, nullptr }, + { "surfaceValues", nullptr, nullptr }, + { "intensityThreshold", nullptr, nullptr }, + { "segmentEnabled", nullptr, nullptr }, + { "lighting", nullptr, nullptr }, + { "shadows", nullptr, nullptr }, + { "phaseFunction", nullptr, nullptr }, + { "silhouetteBoundaryOpacity", nullptr, nullptr }, + { "silhouetteRetainedOpacity", nullptr, nullptr }, + { "silhouetteSharpness", nullptr, nullptr }, + { "coolColor", nullptr, nullptr }, + { "warmColor", nullptr, nullptr } +}; + +FIVocabulary X3D_vocabulary_3_3 = { + nullptr, 0, + encodingAlgorithmTable_3_3, 8, + nullptr, 0, + nullptr, 0, + nullptr, 0, + nullptr, 0, + nullptr, 0, + attributeValueTable_3_3, 2, + nullptr, 0, + nullptr, 0, + elementNameTable_3_3, 252, + attributeNameTable_3_3, 546 +}; + +}// namespace Assimp + +#endif // !ASSIMP_BUILD_NO_X3D_IMPORTER diff --git a/code/XFileExporter.cpp b/code/XFileExporter.cpp index 1e77c8b81..6407bf738 100644 --- a/code/XFileExporter.cpp +++ b/code/XFileExporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -42,12 +43,13 @@ 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 "Bitmap.h" #include "BaseImporter.h" #include "fast_atof.h" -#include "SceneCombiner.h" +#include #include #include #include diff --git a/code/XFileExporter.h b/code/XFileExporter.h index 389c7010c..e45fd7983 100644 --- a/code/XFileExporter.h +++ b/code/XFileExporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -92,7 +93,10 @@ protected: void PushTag() { startstr.append( " "); } /// Leaves an element, decreasing the indentation - void PopTag() { ai_assert( startstr.length() > 1); startstr.erase( startstr.length() - 2); } + void PopTag() { + ai_assert( startstr.length() > 1); + startstr.erase( startstr.length() - 2); + } public: /// Stringstream to write all output into diff --git a/code/XFileHelper.h b/code/XFileHelper.h index 49a41d153..e7c02c7c6 100644 --- a/code/XFileHelper.h +++ b/code/XFileHelper.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/XFileImporter.cpp b/code/XFileImporter.cpp index 436195c2c..00c32dcc2 100644 --- a/code/XFileImporter.cpp +++ b/code/XFileImporter.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -236,8 +237,9 @@ aiNode* XFileImporter::CreateNodes( aiScene* pScene, aiNode* pParent, const XFil // Creates the meshes for the given node. void XFileImporter::CreateMeshes( aiScene* pScene, aiNode* pNode, const std::vector& pMeshes) { - if( pMeshes.size() == 0) + if (pMeshes.empty()) { return; + } // create a mesh for each mesh-material combination in the source node std::vector meshes; diff --git a/code/XFileImporter.h b/code/XFileImporter.h index 1de56cbc5..528dcb851 100644 --- a/code/XFileImporter.h +++ b/code/XFileImporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/XFileParser.cpp b/code/XFileParser.cpp index 83d017d92..1f8b8cbd3 100644 --- a/code/XFileParser.cpp +++ b/code/XFileParser.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -465,15 +466,12 @@ void XFileParser::ParseDataObjectMesh( Mesh* pMesh) pMesh->mPosFaces.resize( numPosFaces); for( unsigned int a = 0; a < numPosFaces; a++) { - unsigned int numIndices = ReadInt(); - if( numIndices < 3) { - ThrowException( format() << "Invalid index count " << numIndices << " for face " << a << "." ); - } - // read indices + unsigned int numIndices = ReadInt(); Face& face = pMesh->mPosFaces[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(); } diff --git a/code/XFileParser.h b/code/XFileParser.h index b0c874627..ec823bac0 100644 --- a/code/XFileParser.h +++ b/code/XFileParser.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/XGLLoader.cpp b/code/XGLLoader.cpp index 6c9db1f89..df33229a6 100644 --- a/code/XGLLoader.cpp +++ b/code/XGLLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -82,8 +83,11 @@ struct free_it }; namespace Assimp { // this has to be in here because LogFunctions is in ::Assimp -template<> const std::string LogFunctions::log_prefix = "XGL: "; - + template<> const char* LogFunctions::Prefix() + { + static auto prefix = "XGL: "; + return prefix; + } } static const aiImporterDesc desc = { diff --git a/code/XGLLoader.h b/code/XGLLoader.h index a7f0d7208..97ae5f8a3 100644 --- a/code/XGLLoader.h +++ b/code/XGLLoader.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/XMLTools.h b/code/XMLTools.h index 7339a2fc8..5d31f885e 100644 --- a/code/XMLTools.h +++ b/code/XMLTools.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/fast_atof.h b/code/fast_atof.h index 965ff0717..be1e59221 100644 --- a/code/fast_atof.h +++ b/code/fast_atof.h @@ -1,3 +1,5 @@ +#pragma once + // Copyright (C) 2002-2007 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine" and the "irrXML" project. // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h @@ -22,6 +24,7 @@ #include #include "StringComparison.h" +#include #ifdef _MSC_VER @@ -192,7 +195,7 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* uint64_t value = 0; if ( *in < '0' || *in > '9' ) - throw std::invalid_argument(std::string("The string \"") + in + "\" cannot be converted into a value."); + throw std::invalid_argument(std::string("The string \"") + in + "\" cannot be converted into a value."); bool running = true; while ( running ) @@ -202,8 +205,12 @@ inline uint64_t strtoul10_64( const char* in, const char** out=0, unsigned int* const uint64_t new_value = ( value * 10 ) + ( *in - '0' ); - if (new_value < value) /* numeric overflow, we rely on you */ - throw std::overflow_error(std::string("Converting the string \"") + in + "\" into a value resulted in overflow."); + // numeric overflow, we rely on you + if ( new_value < value ) { + DefaultLogger::get()->warn( std::string( "Converting the string \"" ) + in + "\" into a value resulted in overflow." ); + return 0; + } + //throw std::overflow_error(); value = new_value; diff --git a/code/glTF2Asset.h b/code/glTF2Asset.h new file mode 100644 index 000000000..63282dc6e --- /dev/null +++ b/code/glTF2Asset.h @@ -0,0 +1,1108 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 glTFAsset.h + * Declares a glTF class to handle gltf/glb files + * + * glTF Extensions Support: + * KHR_materials_pbrSpecularGlossiness full + */ +#ifndef GLTF2ASSET_H_INC +#define GLTF2ASSET_H_INC + +#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER + +#include +#include +#include +#include +#include +#include + +#define RAPIDJSON_HAS_STDSTRING 1 +#include +#include +#include + +#ifdef ASSIMP_API +# include +# include +# include "ByteSwapper.h" +#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 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 rapidjson::Value; + using rapidjson::Document; + + class Asset; + class AssetWriter; + + struct BufferView; // here due to cross-reference + 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); + } + + + //! Magic number for GLB files + #define AI_GLB_MAGIC_NUMBER "glTF" + + #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 + #define AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE aiTextureType_UNKNOWN, 0 + #define AI_MATKEY_GLTF_ALPHAMODE "$mat.gltf.alphaMode", 0, 0 + #define AI_MATKEY_GLTF_ALPHACUTOFF "$mat.gltf.alphaCutoff", 0, 0 + #define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS "$mat.gltf.pbrSpecularGlossiness", 0, 0 + #define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_FACTOR "$clr.diffuse", 0, 1 + #define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULAR_FACTOR "$clr.specular", 0, 1 + #define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR "$mat.gltf.pbrMetallicRoughness.glossinessFactor", 0, 0 + #define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_TEXTURE aiTextureType_DIFFUSE, 1 + #define AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULARGLOSSINESS_TEXTURE aiTextureType_UNKNOWN, 1 + + #define _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE "$tex.file.texCoord" + #define _AI_MATKEY_GLTF_MAPPINGNAME_BASE "$tex.mappingname" + #define _AI_MATKEY_GLTF_MAPPINGID_BASE "$tex.mappingid" + #define _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE "$tex.mappingfiltermag" + #define _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE "$tex.mappingfiltermin" + + #define AI_MATKEY_GLTF_TEXTURE_TEXCOORD _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, type, N + #define AI_MATKEY_GLTF_MAPPINGNAME(type, N) _AI_MATKEY_GLTF_MAPPINGNAME_BASE, type, N + #define AI_MATKEY_GLTF_MAPPINGID(type, N) _AI_MATKEY_GLTF_MAPPINGID_BASE, type, N + #define AI_MATKEY_GLTF_MAPPINGFILTER_MAG(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MAG_BASE, type, N + #define AI_MATKEY_GLTF_MAPPINGFILTER_MIN(type, N) _AI_MATKEY_GLTF_MAPPINGFILTER_MIN_BASE, type, N + + #ifdef ASSIMP_API + #include "./../include/assimp/Compiler/pushpack1.h" + #endif + + #ifdef ASSIMP_API + #include "./../include/assimp/Compiler/poppack1.h" + #endif + + + //! Values for the GLB_Header::sceneFormat field + enum SceneFormat + { + SceneFormat_JSON = 0 + }; + + //! Values for the mesh primitive modes + enum PrimitiveMode + { + PrimitiveMode_POINTS = 0, + PrimitiveMode_LINES = 1, + PrimitiveMode_LINE_LOOP = 2, + PrimitiveMode_LINE_STRIP = 3, + PrimitiveMode_TRIANGLES = 4, + PrimitiveMode_TRIANGLE_STRIP = 5, + PrimitiveMode_TRIANGLE_FAN = 6 + }; + + //! Values for the Accessor::componentType field + enum ComponentType + { + ComponentType_BYTE = 5120, + ComponentType_UNSIGNED_BYTE = 5121, + ComponentType_SHORT = 5122, + ComponentType_UNSIGNED_SHORT = 5123, + ComponentType_UNSIGNED_INT = 5125, + ComponentType_FLOAT = 5126 + }; + + inline unsigned int ComponentTypeSize(ComponentType t) + { + switch (t) { + case ComponentType_SHORT: + case ComponentType_UNSIGNED_SHORT: + return 2; + + case ComponentType_UNSIGNED_INT: + case ComponentType_FLOAT: + return 4; + + case ComponentType_BYTE: + case ComponentType_UNSIGNED_BYTE: + return 1; + default: + throw DeadlyImportError("GLTF: Unsupported Component Type " + std::to_string(t)); + } + } + + //! Values for the BufferView::target field + enum BufferViewTarget + { + BufferViewTarget_ARRAY_BUFFER = 34962, + BufferViewTarget_ELEMENT_ARRAY_BUFFER = 34963 + }; + + //! Values for the Sampler::magFilter field + enum class SamplerMagFilter: unsigned int + { + UNSET = 0, + SamplerMagFilter_Nearest = 9728, + SamplerMagFilter_Linear = 9729 + }; + + //! Values for the Sampler::minFilter field + enum class SamplerMinFilter: unsigned int + { + UNSET = 0, + SamplerMinFilter_Nearest = 9728, + SamplerMinFilter_Linear = 9729, + SamplerMinFilter_Nearest_Mipmap_Nearest = 9984, + SamplerMinFilter_Linear_Mipmap_Nearest = 9985, + SamplerMinFilter_Nearest_Mipmap_Linear = 9986, + SamplerMinFilter_Linear_Mipmap_Linear = 9987 + }; + + //! Values for the Sampler::wrapS and Sampler::wrapT field + enum class SamplerWrap: unsigned int + { + UNSET = 0, + Clamp_To_Edge = 33071, + Mirrored_Repeat = 33648, + Repeat = 10497 + }; + + //! Values for the Texture::format and Texture::internalFormat fields + enum TextureFormat + { + TextureFormat_ALPHA = 6406, + TextureFormat_RGB = 6407, + TextureFormat_RGBA = 6408, + TextureFormat_LUMINANCE = 6409, + TextureFormat_LUMINANCE_ALPHA = 6410 + }; + + //! Values for the Texture::target field + enum TextureTarget + { + TextureTarget_TEXTURE_2D = 3553 + }; + + //! Values for the Texture::type field + enum TextureType + { + TextureType_UNSIGNED_BYTE = 5121, + TextureType_UNSIGNED_SHORT_5_6_5 = 33635, + TextureType_UNSIGNED_SHORT_4_4_4_4 = 32819, + TextureType_UNSIGNED_SHORT_5_5_5_1 = 32820 + }; + + + //! Values for the Accessor::type field (helper class) + class AttribType + { + public: + enum Value + { SCALAR, VEC2, VEC3, VEC4, MAT2, MAT3, MAT4 }; + + private: + static const size_t NUM_VALUES = static_cast(MAT4)+1; + + struct Info + { const char* name; unsigned int numComponents; }; + + template struct data + { static const Info infos[NUM_VALUES]; }; + + public: + inline static Value FromString(const char* str) + { + for (size_t i = 0; i < NUM_VALUES; ++i) { + if (strcmp(data<0>::infos[i].name, str) == 0) { + return static_cast(i); + } + } + return SCALAR; + } + + inline static const char* ToString(Value type) + { + return data<0>::infos[static_cast(type)].name; + } + + inline static unsigned int GetNumComponents(Value type) + { + return data<0>::infos[static_cast(type)].numComponents; + } + }; + + // must match the order of the AttribTypeTraits::Value enum! + template const AttribType::Info + AttribType::data::infos[AttribType::NUM_VALUES] = { + { "SCALAR", 1 }, { "VEC2", 2 }, { "VEC3", 3 }, { "VEC4", 4 }, { "MAT2", 4 }, { "MAT3", 9 }, { "MAT4", 16 } + }; + + + + //! A reference to one top-level object, which is valid + //! until the Asset instance is destroyed + template + class Ref + { + std::vector* vector; + unsigned int index; + + public: + Ref() : vector(0), index(0) {} + Ref(std::vector& vec, unsigned int idx) : vector(&vec), index(idx) {} + + inline unsigned int GetIndex() const + { return index; } + + operator bool() const + { return vector != 0; } + + T* operator->() + { return (*vector)[index]; } + + T& operator*() + { return *((*vector)[index]); } + }; + + //! Helper struct to represent values that might not be present + template + struct Nullable + { + T value; + bool isPresent; + + Nullable() : isPresent(false) {} + Nullable(T& val) : value(val), isPresent(true) {} + }; + + + //! Base classe for all glTF top-level objects + struct Object + { + int index; //!< The index of this object within its property container + int oIndex; //!< The original index of this object defined in the JSON + std::string id; //!< The globally unique ID used to reference this object + std::string name; //!< The user-defined name of this object + + //! Objects marked as special are not exported (used to emulate the binary body buffer) + virtual bool IsSpecial() const + { return false; } + + virtual ~Object() {} + + //! Maps special IDs to another ID, where needed. Subclasses may override it (statically) + static const char* TranslateId(Asset& r, const char* id) + { return id; } + }; + + // + // Classes for each glTF top-level object type + // + + //! A typed view into a BufferView. A BufferView contains raw binary data. + //! An accessor provides a typed view into a BufferView or a subset of a BufferView + //! similar to how WebGL's vertexAttribPointer() defines an attribute in a buffer. + 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) + unsigned int byteStride; //!< The stride, in bytes, between attributes referenced by this accessor. (default: 0) + ComponentType componentType; //!< The datatype of components in the attribute. (required) + unsigned int 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. + + unsigned int GetNumComponents(); + unsigned int GetBytesPerComponent(); + unsigned int GetElementSize(); + + inline uint8_t* GetPointer(); + + template + bool ExtractData(T*& outData); + + void WriteData(size_t count, const void* src_buffer, size_t src_stride); + + //! Helper class to iterate the data + class Indexer + { + friend struct Accessor; + + Accessor& accessor; + uint8_t* data; + size_t elemSize, stride; + + Indexer(Accessor& acc); + + public: + + //! Accesses the i-th value as defined by the accessor + template + T GetValue(int i); + + //! Accesses the i-th value as defined by the accessor + inline unsigned int GetUInt(int i) + { + return GetValue(i); + } + + inline bool IsValid() const + { + return data != 0; + } + }; + + inline Indexer GetIndexer() + { + return Indexer(*this); + } + + Accessor() {} + void Read(Value& obj, Asset& r); + }; + + //! A buffer points to binary geometry, animation, or skins. + struct Buffer : public Object + { + /********************* Types *********************/ + public: + + enum Type + { + Type_arraybuffer, + Type_text + }; + + /// \struct SEncodedRegion + /// Descriptor of encoded region in "bufferView". + struct SEncodedRegion + { + const size_t Offset;///< Offset from begin of "bufferView" to encoded region, in bytes. + const size_t EncodedData_Length;///< Size of encoded region, in bytes. + uint8_t* const DecodedData;///< Cached encoded data. + const size_t DecodedData_Length;///< Size of decoded region, in bytes. + const std::string ID;///< ID of the region. + + /// \fn SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID) + /// Constructor. + /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes. + /// \param [in] pEncodedData_Length - size of encoded region, in bytes. + /// \param [in] pDecodedData - pointer to decoded data array. + /// \param [in] pDecodedData_Length - size of encoded region, in bytes. + /// \param [in] pID - ID of the region. + SEncodedRegion(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string pID) + : Offset(pOffset), EncodedData_Length(pEncodedData_Length), DecodedData(pDecodedData), DecodedData_Length(pDecodedData_Length), ID(pID) + {} + + /// \fn ~SEncodedRegion() + /// Destructor. + ~SEncodedRegion() { delete[] DecodedData; } + }; + + /******************* Variables *******************/ + + //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") + + Type type; + + /// \var EncodedRegion_Current + /// Pointer to currently active encoded region. + /// Why not decoding all regions at once and not to set one buffer with decoded data? + /// Yes, why not? Even "accessor" point to decoded data. I mean that fields "byteOffset", "byteStride" and "count" has values which describes decoded + /// data array. But only in range of mesh while is active parameters from "compressedData". For another mesh accessors point to decoded data too. But + /// offset is counted for another regions is encoded. + /// Example. You have two meshes. For every of it you have 4 bytes of data. That data compressed to 2 bytes. So, you have buffer with encoded data: + /// M1_E0, M1_E1, M2_E0, M2_E1. + /// After decoding you'll get: + /// M1_D0, M1_D1, M1_D2, M1_D3, M2_D0, M2_D1, M2_D2, M2_D3. + /// "accessors" must to use values that point to decoded data - obviously. So, you'll expect "accessors" like + /// "accessor_0" : { byteOffset: 0, byteLength: 4}, "accessor_1" : { byteOffset: 4, byteLength: 4} + /// 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 + /// 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 + /// exporter and importer. And, thanks to such way, there is no need to load whole file into memory. + SEncodedRegion* EncodedRegion_Current; + + private: + + shared_ptr mData; //!< Pointer to the data + bool mIsSpecial; //!< Set to true for special cases (e.g. the body buffer) + + /// \var EncodedRegion_List + /// List of encoded regions. + std::list EncodedRegion_List; + + /******************* Functions *******************/ + + public: + + Buffer(); + ~Buffer(); + + void Read(Value& obj, Asset& r); + + bool LoadFromStream(IOStream& stream, size_t length = 0, size_t baseOffset = 0); + + /// \fn void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID) + /// Mark region of "bufferView" as encoded. When data is request from such region then "bufferView" use decoded data. + /// \param [in] pOffset - offset from begin of "bufferView" to encoded region, in bytes. + /// \param [in] pEncodedData_Length - size of encoded region, in bytes. + /// \param [in] pDecodedData - pointer to decoded data array. + /// \param [in] pDecodedData_Length - size of encoded region, in bytes. + /// \param [in] pID - ID of the region. + void EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID); + + /// \fn void EncodedRegion_SetCurrent(const std::string& pID) + /// Select current encoded region by ID. \sa EncodedRegion_Current. + /// \param [in] pID - ID of the region. + void EncodedRegion_SetCurrent(const std::string& pID); + + /// \fn bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count) + /// Replace part of buffer data. Pay attention that function work with original array of data (\ref mData) not with encoded regions. + /// \param [in] pBufferData_Offset - index of first element in buffer from which new data will be placed. + /// \param [in] pBufferData_Count - count of bytes in buffer which will be replaced. + /// \param [in] pReplace_Data - pointer to array with new data for buffer. + /// \param [in] pReplace_Count - count of bytes in new data. + /// \return true - if successfully replaced, false if input arguments is out of range. + bool ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count); + + size_t AppendData(uint8_t* data, size_t length); + void Grow(size_t amount); + + uint8_t* GetPointer() + { return mData.get(); } + + void MarkAsSpecial() + { mIsSpecial = true; } + + bool IsSpecial() const + { return mIsSpecial; } + + std::string GetURI() + { return std::string(this->id) + ".bin"; } + + static const char* TranslateId(Asset& r, const char* id); + }; + + //! A view into a buffer generally representing a subset of the buffer. + struct BufferView : public Object + { + Ref buffer; //! The ID of the buffer. (required) + size_t byteOffset; //! The offset into the buffer in bytes. (required) + size_t byteLength; //! The length of the bufferView in bytes. (default: 0) + + BufferViewTarget target; //! The target that the WebGL buffer should be bound to. + + void Read(Value& obj, Asset& r); + }; + + struct Camera : public Object + { + enum Type + { + Perspective, + Orthographic + }; + + Type type; + + union + { + struct { + float aspectRatio; //! bufferView; + + std::string mimeType; + + int width, height; + + private: + uint8_t* mData; + size_t mDataLength; + + public: + + Image(); + void Read(Value& obj, Asset& r); + + inline bool HasData() const + { return mDataLength > 0; } + + inline size_t GetDataLength() const + { return mDataLength; } + + inline const uint8_t* GetData() const + { return mData; } + + inline uint8_t* StealData(); + + inline void SetData(uint8_t* data, size_t length, Asset& r); + }; + + const vec4 defaultBaseColor = {1, 1, 1, 1}; + const vec3 defaultEmissiveFactor = {0, 0, 0}; + const vec4 defaultDiffuseFactor = {1, 1, 1, 1}; + const vec3 defaultSpecularFactor = {1, 1, 1}; + + struct TextureInfo + { + Ref texture; + unsigned int index; + unsigned int texCoord = 0; + }; + + struct NormalTextureInfo : TextureInfo + { + float scale = 1; + }; + + struct OcclusionTextureInfo : TextureInfo + { + float strength = 1; + }; + + struct PbrMetallicRoughness + { + vec4 baseColorFactor; + TextureInfo baseColorTexture; + TextureInfo metallicRoughnessTexture; + float metallicFactor; + float roughnessFactor; + }; + + struct PbrSpecularGlossiness + { + vec4 diffuseFactor; + vec3 specularFactor; + float glossinessFactor; + TextureInfo diffuseTexture; + TextureInfo specularGlossinessTexture; + + PbrSpecularGlossiness() { SetDefaults(); } + void SetDefaults(); + }; + + //! The material appearance of a primitive. + struct Material : public Object + { + //PBR metallic roughness properties + PbrMetallicRoughness pbrMetallicRoughness; + + //other basic material properties + NormalTextureInfo normalTexture; + OcclusionTextureInfo occlusionTexture; + TextureInfo emissiveTexture; + vec3 emissiveFactor; + std::string alphaMode; + float alphaCutoff; + bool doubleSided; + + //extension: KHR_materials_pbrSpecularGlossiness + Nullable pbrSpecularGlossiness; + + Material() { SetDefaults(); } + void Read(Value& obj, Asset& r); + void SetDefaults(); + }; + + //! A set of primitives to be rendered. A node can contain one or more meshes. A node's transform places the mesh in the scene. + struct Mesh : public Object + { + typedef std::vector< Ref > AccessorList; + + struct Primitive + { + PrimitiveMode mode; + + struct Attributes { + AccessorList position, normal, texcoord, color, joint, jointmatrix, weight; + } attributes; + + Ref indices; + + Ref material; + }; + + std::vector primitives; + + Mesh() {} + + /// \fn void Read(Value& pJSON_Object, Asset& pAsset_Root) + /// Get mesh data from JSON-object and place them to root asset. + /// \param [in] pJSON_Object - reference to pJSON-object from which data are read. + /// \param [out] pAsset_Root - reference to root assed where data will be stored. + void Read(Value& pJSON_Object, Asset& pAsset_Root); + }; + + struct Node : public Object + { + std::vector< Ref > children; + std::vector< Ref > meshes; + + Nullable matrix; + Nullable translation; + Nullable rotation; + Nullable scale; + + Ref camera; + + 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. + std::string jointName; //!< Name used when this node is a joint in a skin. + + Ref parent; //!< This is not part of the glTF specification. Used as a helper. + + Node() {} + void Read(Value& obj, Asset& r); + }; + + struct Program : public Object + { + Program() {} + void Read(Value& obj, Asset& r); + }; + + + struct Sampler : public Object + { + SamplerMagFilter magFilter; //!< The texture magnification filter. + SamplerMinFilter minFilter; //!< The texture minification filter. + SamplerWrap wrapS; //!< The texture wrapping in the S direction. + SamplerWrap wrapT; //!< The texture wrapping in the T direction. + + Sampler() { SetDefaults(); } + void Read(Value& obj, Asset& r); + void SetDefaults(); + }; + + struct Scene : public Object + { + std::vector< Ref > nodes; + + Scene() {} + void Read(Value& obj, Asset& r); + }; + + struct Shader : public Object + { + Shader() {} + void Read(Value& obj, Asset& r); + }; + + struct Skin : public Object + { + Nullable bindShapeMatrix; //!< Floating-point 4x4 transformation matrix stored in column-major order. + Ref inverseBindMatrices; //!< The ID of the accessor containing the floating-point 4x4 inverse-bind matrices. + std::vector> jointNames; //!< Joint names of the joints (nodes with a jointName property) in this skin. + std::string name; //!< The user-defined name of this object. + + Skin() {} + void Read(Value& obj, Asset& r); + }; + + //! A texture and its sampler. + struct Texture : public Object + { + Ref sampler; //!< The ID of the sampler used by this texture. (required) + Ref source; //!< The ID of the image used by this texture. (required) + + //TextureFormat format; //!< The texture's format. (default: TextureFormat_RGBA) + //TextureFormat internalFormat; //!< The texture's internal format. (default: TextureFormat_RGBA) + + //TextureTarget target; //!< The target that the WebGL texture should be bound to. (default: TextureTarget_TEXTURE_2D) + //TextureType type; //!< Texel datatype. (default: TextureType_UNSIGNED_BYTE) + + Texture() {} + void Read(Value& obj, Asset& r); + }; + + struct Animation : public Object + { + struct AnimSampler { + std::string id; //!< The ID of this sampler. + std::string input; //!< The ID of a parameter in this animation to use as key-frame input. + std::string interpolation; //!< Type of interpolation algorithm to use between key-frames. + std::string output; //!< The ID of a parameter in this animation to use as key-frame output. + }; + + struct AnimChannel { + int sampler; //!< The index of a sampler in the containing animation's samplers property. + + struct AnimTarget { + Ref node; //!< The node to animate. + std::string path; //!< The name of property of the node to animate ("translation", "rotation", or "scale"). + } target; + }; + + struct AnimParameters { + Ref TIME; //!< Accessor reference to a buffer storing a array of floating point scalar values. + Ref rotation; //!< Accessor reference to a buffer storing a array of four-component floating-point vectors. + Ref scale; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors. + Ref translation; //!< Accessor reference to a buffer storing a array of three-component floating-point vectors. + }; + + // AnimChannel Channels[3]; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy. + // AnimParameters Parameters; //!< The samplers that interpolate between the key-frames. + // AnimSampler Samplers[3]; //!< The parameterized inputs representing the key-frame data. + + std::vector Channels; //!< Connect the output values of the key-frame animation to a specific node in the hierarchy. + AnimParameters Parameters; //!< The samplers that interpolate between the key-frames. + std::vector Samplers; //!< The parameterized inputs representing the key-frame data. + + Animation() {} + void Read(Value& obj, Asset& r); + + //! Get accessor given an animation parameter name. + Ref GetAccessor(std::string name) { + if (name == "TIME") { + return Parameters.TIME; + } else if (name == "rotation") { + return Parameters.rotation; + } else if (name == "scale") { + return Parameters.scale; + } else if (name == "translation") { + return Parameters.translation; + } + return Ref(); + } + }; + + + //! Base class for LazyDict that acts as an interface + class LazyDictBase + { + public: + virtual ~LazyDictBase() {} + + virtual void AttachToDocument(Document& doc) = 0; + virtual void DetachFromDocument() = 0; + + virtual void WriteObjects(AssetWriter& writer) = 0; + }; + + + template + class LazyDict; + + //! (Implemented in glTFAssetWriter.h) + template + void WriteLazyDict(LazyDict& d, AssetWriter& w); + + + //! Manages lazy loading of the glTF top-level objects, and keeps a reference to them by ID + //! It is the owner the loaded objects, so when it is destroyed it also deletes them + template + class LazyDict : public LazyDictBase + { + friend class Asset; + friend class AssetWriter; + + typedef typename std::gltf_unordered_map< unsigned int, unsigned int > Dict; + typedef typename std::gltf_unordered_map< std::string, unsigned int > IdDict; + + std::vector mObjs; //! The read objects + Dict mObjsByOIndex; //! The read objects accessible by original index + IdDict mObjsById; //! The read objects accessible by id + const char* mDictId; //! ID of the dictionary object + const char* mExtId; //! ID of the extension defining the dictionary + Value* mDict; //! JSON dictionary object + Asset& mAsset; //! The asset instance + + void AttachToDocument(Document& doc); + void DetachFromDocument(); + + void WriteObjects(AssetWriter& writer) + { WriteLazyDict(*this, writer); } + + Ref Add(T* obj); + + public: + LazyDict(Asset& asset, const char* dictId, const char* extId = 0); + ~LazyDict(); + + Ref Retrieve(unsigned int i); + + Ref Get(unsigned int i); + Ref Get(const char* id); + + Ref Create(const char* id); + Ref Create(const std::string& id) + { return Create(id.c_str()); } + + inline unsigned int Size() const + { return unsigned(mObjs.size()); } + + inline T& operator[](size_t i) + { return *mObjs[i]; } + + }; + + + struct AssetMetadata + { + std::string copyright; //!< A copyright message suitable for display to credit the content creator. + std::string generator; //!< Tool that generated this glTF model.Useful for debugging. + + struct { + std::string api; //!< Specifies the target rendering API (default: "WebGL") + std::string version; //!< Specifies the target rendering API (default: "1.0.3") + } profile; //!< Specifies the target rendering API and version, e.g., WebGL 1.0.3. (default: {}) + + std::string version; //!< The glTF format version + + void Read(Document& doc); + + AssetMetadata() : version("") {} + }; + + // + // glTF Asset class + // + + //! Root object for a glTF asset + class Asset + { + typedef std::gltf_unordered_map IdMap; + + template + friend class LazyDict; + + friend struct Buffer; // To access OpenFile + + friend class AssetWriter; + + private: + IOSystem* mIOSystem; + + std::string mCurrentAssetDir; + + size_t mSceneLength; + size_t mBodyOffset, mBodyLength; + + std::vector mDicts; + + IdMap mUsedIds; + + Ref mBodyBuffer; + + Asset(Asset&); + Asset& operator=(const Asset&); + + public: + + //! Keeps info about the enabled extensions + struct Extensions + { + bool KHR_materials_pbrSpecularGlossiness; + + } extensionsUsed; + + AssetMetadata asset; + + + // Dictionaries for each type of object + + LazyDict accessors; + LazyDict animations; + LazyDict buffers; + LazyDict bufferViews; + LazyDict cameras; + LazyDict images; + LazyDict materials; + LazyDict meshes; + LazyDict nodes; + LazyDict samplers; + LazyDict scenes; + LazyDict skins; + LazyDict textures; + + Ref scene; + + public: + Asset(IOSystem* io = 0) + : mIOSystem(io) + , asset() + , accessors (*this, "accessors") + , animations (*this, "animations") + , buffers (*this, "buffers") + , bufferViews (*this, "bufferViews") + , cameras (*this, "cameras") + , images (*this, "images") + , materials (*this, "materials") + , meshes (*this, "meshes") + , nodes (*this, "nodes") + , samplers (*this, "samplers") + , scenes (*this, "scenes") + , skins (*this, "skins") + , textures (*this, "textures") + { + memset(&extensionsUsed, 0, sizeof(extensionsUsed)); + } + + //! Main function + void Load(const std::string& file); + + //! Search for an available name, starting from the given strings + std::string FindUniqueID(const std::string& str, const char* suffix); + + Ref GetBodyBuffer() + { return mBodyBuffer; } + + private: + void ReadExtensionsUsed(Document& doc); + + IOStream* OpenFile(std::string path, const char* mode, bool absolute = false); + }; + +} + +// Include the implementation of the methods +#include "glTF2Asset.inl" + +#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER + +#endif // GLTF2ASSET_H_INC diff --git a/code/glTF2Asset.inl b/code/glTF2Asset.inl new file mode 100644 index 000000000..8b50fa1d3 --- /dev/null +++ b/code/glTF2Asset.inl @@ -0,0 +1,1319 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 "StringUtils.h" + +// Header files, Assimp +#include + +using namespace Assimp; + +namespace glTF2 { + +namespace { + + // + // JSON Value reading helpers + // + + template + struct ReadHelper { static bool Read(Value& val, T& out) { + return val.IsInt() ? out = static_cast(val.GetInt()), true : false; + }}; + + template<> struct ReadHelper { static bool Read(Value& val, bool& out) { + return val.IsBool() ? out = val.GetBool(), true : false; + }}; + + template<> struct ReadHelper { static bool Read(Value& val, float& out) { + return val.IsNumber() ? out = static_cast(val.GetDouble()), true : false; + }}; + + template struct ReadHelper { static bool Read(Value& val, float (&out)[N]) { + if (!val.IsArray() || val.Size() != N) return false; + for (unsigned int i = 0; i < N; ++i) { + if (val[i].IsNumber()) + out[i] = static_cast(val[i].GetDouble()); + } + return true; + }}; + + template<> struct ReadHelper { static bool Read(Value& val, const char*& out) { + return val.IsString() ? (out = val.GetString(), true) : false; + }}; + + template<> struct ReadHelper { static bool Read(Value& val, std::string& out) { + return val.IsString() ? (out = std::string(val.GetString(), val.GetStringLength()), true) : false; + }}; + + template struct ReadHelper< Nullable > { static bool Read(Value& val, Nullable& out) { + return out.isPresent = ReadHelper::Read(val, out.value); + }}; + + template + inline static bool ReadValue(Value& val, T& out) + { + return ReadHelper::Read(val, out); + } + + template + inline static bool ReadMember(Value& obj, const char* id, T& out) + { + Value::MemberIterator it = obj.FindMember(id); + if (it != obj.MemberEnd()) { + return ReadHelper::Read(it->value, out); + } + return false; + } + + template + inline static T MemberOrDefault(Value& obj, const char* id, T defaultValue) + { + T out; + return ReadMember(obj, id, out) ? out : defaultValue; + } + + inline Value* FindMember(Value& val, const char* id) + { + Value::MemberIterator it = val.FindMember(id); + return (it != val.MemberEnd()) ? &it->value : 0; + } + + inline Value* FindString(Value& val, const char* id) + { + Value::MemberIterator it = val.FindMember(id); + return (it != val.MemberEnd() && it->value.IsString()) ? &it->value : 0; + } + + inline Value* FindNumber(Value& val, const char* id) + { + Value::MemberIterator it = val.FindMember(id); + return (it != val.MemberEnd() && it->value.IsNumber()) ? &it->value : 0; + } + + inline Value* FindUInt(Value& val, const char* id) + { + Value::MemberIterator it = val.FindMember(id); + return (it != val.MemberEnd() && it->value.IsUint()) ? &it->value : 0; + } + + inline Value* FindArray(Value& val, const char* id) + { + Value::MemberIterator it = val.FindMember(id); + return (it != val.MemberEnd() && it->value.IsArray()) ? &it->value : 0; + } + + inline Value* FindObject(Value& val, const char* id) + { + Value::MemberIterator it = val.FindMember(id); + return (it != val.MemberEnd() && it->value.IsObject()) ? &it->value : 0; + } +} + +// +// LazyDict methods +// + +template +inline LazyDict::LazyDict(Asset& asset, const char* dictId, const char* extId) + : mDictId(dictId), mExtId(extId), mDict(0), mAsset(asset) +{ + asset.mDicts.push_back(this); // register to the list of dictionaries +} + +template +inline LazyDict::~LazyDict() +{ + for (size_t i = 0; i < mObjs.size(); ++i) { + delete mObjs[i]; + } +} + + +template +inline void LazyDict::AttachToDocument(Document& doc) +{ + Value* container = 0; + + if (mExtId) { + if (Value* exts = FindObject(doc, "extensions")) { + container = FindObject(*exts, mExtId); + } + } + else { + container = &doc; + } + + if (container) { + mDict = FindArray(*container, mDictId); + } +} + +template +inline void LazyDict::DetachFromDocument() +{ + mDict = 0; +} + +template +Ref LazyDict::Retrieve(unsigned int i) +{ + + typename Dict::iterator it = mObjsByOIndex.find(i); + if (it != mObjsByOIndex.end()) {// already created? + return Ref(mObjs, it->second); + } + + // read it from the JSON object + if (!mDict) { + throw DeadlyImportError("GLTF: Missing section \"" + std::string(mDictId) + "\""); + } + + if (!mDict->IsArray()) { + throw DeadlyImportError("GLTF: Field is not an array \"" + std::string(mDictId) + "\""); + } + + Value &obj = (*mDict)[i]; + + if (!obj.IsObject()) { + throw DeadlyImportError("GLTF: Object at index \"" + std::to_string(i) + "\" is not a JSON object"); + } + + T* inst = new T(); + inst->id = std::string(mDictId) + "_" + std::to_string(i); + inst->oIndex = i; + ReadMember(obj, "name", inst->name); + inst->Read(obj, mAsset); + + return Add(inst); +} + +template +Ref LazyDict::Get(unsigned int i) +{ + + return Ref(mObjs, i); + +} + +template +Ref LazyDict::Get(const char* id) +{ + id = T::TranslateId(mAsset, id); + + typename IdDict::iterator it = mObjsById.find(id); + if (it != mObjsById.end()) { // already created? + return Ref(mObjs, it->second); + } + + return Ref(); +} + +template +Ref LazyDict::Add(T* obj) +{ + unsigned int idx = unsigned(mObjs.size()); + mObjs.push_back(obj); + mObjsByOIndex[obj->oIndex] = idx; + mObjsById[obj->id] = idx; + mAsset.mUsedIds[obj->id] = true; + return Ref(mObjs, idx); +} + +template +Ref LazyDict::Create(const char* id) +{ + Asset::IdMap::iterator it = mAsset.mUsedIds.find(id); + if (it != mAsset.mUsedIds.end()) { + throw DeadlyImportError("GLTF: two objects with the same ID exist"); + } + T* inst = new T(); + unsigned int idx = unsigned(mObjs.size()); + inst->id = id; + inst->index = idx; + inst->oIndex = idx; + return Add(inst); +} + + +// +// glTF dictionary objects methods +// + + +inline Buffer::Buffer() + : byteLength(0), type(Type_arraybuffer), EncodedRegion_Current(nullptr), mIsSpecial(false) +{ } + +inline Buffer::~Buffer() +{ + for(SEncodedRegion* reg : EncodedRegion_List) delete reg; +} + +inline const char* Buffer::TranslateId(Asset& r, const char* id) +{ + return id; +} + +inline void Buffer::Read(Value& obj, Asset& r) +{ + size_t statedLength = MemberOrDefault(obj, "byteLength", 0); + byteLength = statedLength; + + Value* it = FindString(obj, "uri"); + if (!it) { + if (statedLength > 0) { + throw DeadlyImportError("GLTF: buffer with non-zero length missing the \"uri\" attribute"); + } + return; + } + + const char* uri = it->GetString(); + + 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->mData.reset(data, std::default_delete()); + + if (statedLength > 0 && this->byteLength != statedLength) { + throw DeadlyImportError("GLTF: buffer \"" + id + "\", expected " + to_string(statedLength) + + " bytes, but found " + to_string(dataURI.dataLength)); + } + } + else { // assume raw data + if (statedLength != dataURI.dataLength) { + throw DeadlyImportError("GLTF: buffer \"" + id + "\", expected " + to_string(statedLength) + + " bytes, but found " + to_string(dataURI.dataLength)); + } + + this->mData.reset(new uint8_t[dataURI.dataLength], std::default_delete()); + memcpy( this->mData.get(), dataURI.data, dataURI.dataLength ); + } + } + else { // Local file + if (byteLength > 0) { + std::string dir = !r.mCurrentAssetDir.empty() ? (r.mCurrentAssetDir + "/") : ""; + + IOStream* file = r.OpenFile(dir + uri, "rb"); + if (file) { + bool ok = LoadFromStream(*file, byteLength); + delete file; + + if (!ok) + throw DeadlyImportError("GLTF: error while reading referenced file \"" + std::string(uri) + "\"" ); + } + else { + throw DeadlyImportError("GLTF: could not open referenced file \"" + std::string(uri) + "\""); + } + } + } +} + +inline bool Buffer::LoadFromStream(IOStream& stream, size_t length, size_t baseOffset) +{ + byteLength = length ? length : stream.FileSize(); + + if (baseOffset) { + stream.Seek(baseOffset, aiOrigin_SET); + } + + mData.reset(new uint8_t[byteLength], std::default_delete()); + + if (stream.Read(mData.get(), byteLength, 1) != 1) { + return false; + } + return true; +} + +inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncodedData_Length, uint8_t* pDecodedData, const size_t pDecodedData_Length, const std::string& pID) +{ + // Check pointer to data + if(pDecodedData == nullptr) throw DeadlyImportError("GLTF: for marking encoded region pointer to decoded data must be provided."); + + // Check offset + if(pOffset > byteLength) + { + const uint8_t val_size = 32; + + char val[val_size]; + + ai_snprintf(val, val_size, "%llu", (long long)pOffset); + throw DeadlyImportError(std::string("GLTF: incorrect offset value (") + val + ") for marking encoded region."); + } + + // Check length + if((pOffset + pEncodedData_Length) > byteLength) + { + const uint8_t val_size = 64; + + char val[val_size]; + + ai_snprintf(val, val_size, "%llu, %llu", (long long)pOffset, (long long)pEncodedData_Length); + throw DeadlyImportError(std::string("GLTF: encoded region with offset/length (") + val + ") is out of range."); + } + + // Add new region + EncodedRegion_List.push_back(new SEncodedRegion(pOffset, pEncodedData_Length, pDecodedData, pDecodedData_Length, pID)); + // And set new value for "byteLength" + byteLength += (pDecodedData_Length - pEncodedData_Length); +} + +inline void Buffer::EncodedRegion_SetCurrent(const std::string& pID) +{ + if((EncodedRegion_Current != nullptr) && (EncodedRegion_Current->ID == pID)) return; + + for(SEncodedRegion* reg : EncodedRegion_List) + { + if(reg->ID == pID) + { + EncodedRegion_Current = reg; + + return; + } + + } + + throw DeadlyImportError("GLTF: EncodedRegion with ID: \"" + pID + "\" not found."); +} + +inline bool Buffer::ReplaceData(const size_t pBufferData_Offset, const size_t pBufferData_Count, const uint8_t* pReplace_Data, const size_t pReplace_Count) +{ +const size_t new_data_size = byteLength + pReplace_Count - pBufferData_Count; + +uint8_t* new_data; + + if((pBufferData_Count == 0) || (pReplace_Count == 0) || (pReplace_Data == nullptr)) return false; + + new_data = new uint8_t[new_data_size]; + // Copy data which place before replacing part. + memcpy(new_data, mData.get(), pBufferData_Offset); + // Copy new data. + memcpy(&new_data[pBufferData_Offset], pReplace_Data, pReplace_Count); + // 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, std::default_delete()); + byteLength = new_data_size; + + return true; +} + +inline size_t Buffer::AppendData(uint8_t* data, size_t length) +{ + size_t offset = this->byteLength; + Grow(length); + memcpy(mData.get() + offset, data, length); + return offset; +} + +inline void Buffer::Grow(size_t amount) +{ + if (amount <= 0) return; + uint8_t* b = new uint8_t[byteLength + amount]; + if (mData) memcpy(b, mData.get(), byteLength); + mData.reset(b, std::default_delete()); + byteLength += amount; +} + +// +// struct BufferView +// + +inline void BufferView::Read(Value& obj, Asset& r) +{ + + if (Value* bufferVal = FindUInt(obj, "buffer")) { + buffer = r.buffers.Retrieve(bufferVal->GetUint()); + } + + byteOffset = MemberOrDefault(obj, "byteOffset", 0u); + byteLength = MemberOrDefault(obj, "byteLength", 0u); +} + +// +// struct Accessor +// + +inline void Accessor::Read(Value& obj, Asset& r) +{ + + if (Value* bufferViewVal = FindUInt(obj, "bufferView")) { + bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint()); + } + + byteOffset = MemberOrDefault(obj, "byteOffset", 0u); + byteStride = MemberOrDefault(obj, "byteStride", 0u); + componentType = MemberOrDefault(obj, "componentType", ComponentType_BYTE); + count = MemberOrDefault(obj, "count", 0u); + + const char* typestr; + type = ReadMember(obj, "type", typestr) ? AttribType::FromString(typestr) : AttribType::SCALAR; +} + +inline unsigned int Accessor::GetNumComponents() +{ + return AttribType::GetNumComponents(type); +} + +inline unsigned int Accessor::GetBytesPerComponent() +{ + return int(ComponentTypeSize(componentType)); +} + +inline unsigned int Accessor::GetElementSize() +{ + return GetNumComponents() * GetBytesPerComponent(); +} + +inline uint8_t* Accessor::GetPointer() +{ + if (!bufferView || !bufferView->buffer) return 0; + uint8_t* basePtr = bufferView->buffer->GetPointer(); + if (!basePtr) return 0; + + size_t offset = byteOffset + bufferView->byteOffset; + + // Check if region is encoded. + if(bufferView->buffer->EncodedRegion_Current != nullptr) + { + const size_t begin = bufferView->buffer->EncodedRegion_Current->Offset; + const size_t end = begin + bufferView->buffer->EncodedRegion_Current->DecodedData_Length; + + if((offset >= begin) && (offset < end)) + return &bufferView->buffer->EncodedRegion_Current->DecodedData[offset - begin]; + } + + return basePtr + offset; +} + +namespace { + inline void CopyData(size_t count, + const uint8_t* src, size_t src_stride, + uint8_t* dst, size_t dst_stride) + { + if (src_stride == dst_stride) { + memcpy(dst, src, count * src_stride); + } + else { + size_t sz = std::min(src_stride, dst_stride); + for (size_t i = 0; i < count; ++i) { + memcpy(dst, src, sz); + if (sz < dst_stride) { + memset(dst + sz, 0, dst_stride - sz); + } + src += src_stride; + dst += dst_stride; + } + } + } +} + +template +bool Accessor::ExtractData(T*& outData) +{ + uint8_t* data = GetPointer(); + if (!data) return false; + + const size_t elemSize = GetElementSize(); + const size_t totalSize = elemSize * count; + + const size_t stride = byteStride ? byteStride : elemSize; + + const size_t targetElemSize = sizeof(T); + ai_assert(elemSize <= targetElemSize); + + ai_assert(count*stride <= bufferView->byteLength); + + outData = new T[count]; + if (stride == elemSize && targetElemSize == elemSize) { + memcpy(outData, data, totalSize); + } + else { + for (size_t i = 0; i < count; ++i) { + memcpy(outData + i, data + i*stride, elemSize); + } + } + + return true; +} + +inline void Accessor::WriteData(size_t count, const void* src_buffer, size_t src_stride) +{ + uint8_t* buffer_ptr = bufferView->buffer->GetPointer(); + size_t offset = byteOffset + bufferView->byteOffset; + + size_t dst_stride = GetNumComponents() * GetBytesPerComponent(); + + const uint8_t* src = reinterpret_cast(src_buffer); + uint8_t* dst = reinterpret_cast< uint8_t*>(buffer_ptr + offset); + + ai_assert(dst + count*dst_stride <= buffer_ptr + bufferView->buffer->byteLength); + CopyData(count, src, src_stride, dst, dst_stride); +} + + + +inline Accessor::Indexer::Indexer(Accessor& acc) + : accessor(acc) + , data(acc.GetPointer()) + , elemSize(acc.GetElementSize()) + , stride(acc.byteStride ? acc.byteStride : elemSize) +{ + +} + +//! Accesses the i-th value as defined by the accessor +template +T Accessor::Indexer::GetValue(int i) +{ + ai_assert(data); + ai_assert(i*stride < accessor.bufferView->byteLength); + T value = T(); + memcpy(&value, data + i*stride, elemSize); + //value >>= 8 * (sizeof(T) - elemSize); + return value; +} + +inline Image::Image() + : width(0) + , height(0) + , mData(0) + , mDataLength(0) +{ + +} + +inline void Image::Read(Value& obj, Asset& r) +{ + if (!mDataLength) { + if (Value* uri = FindString(obj, "uri")) { + const char* uristr = uri->GetString(); + + Util::DataURI dataURI; + if (ParseDataURI(uristr, uri->GetStringLength(), dataURI)) { + mimeType = dataURI.mediaType; + if (dataURI.base64) { + mDataLength = Util::DecodeBase64(dataURI.data, dataURI.dataLength, mData); + } + } + else { + this->uri = uristr; + } + } + } +} + +inline uint8_t* Image::StealData() +{ + uint8_t* data = mData; + mDataLength = 0; + mData = 0; + return data; +} + +inline void Image::SetData(uint8_t* data, size_t length, Asset& r) +{ + Ref b = r.GetBodyBuffer(); + if (b) { // binary file: append to body + std::string bvId = r.FindUniqueID(this->id, "imgdata"); + bufferView = r.bufferViews.Create(bvId); + + bufferView->buffer = b; + bufferView->byteLength = length; + bufferView->byteOffset = b->AppendData(data, length); + } + else { // text file: will be stored as a data uri + this->mData = data; + this->mDataLength = length; + } +} + +inline void Sampler::Read(Value& obj, Asset& r) +{ + SetDefaults(); + + ReadMember(obj, "name", name); + ReadMember(obj, "magFilter", magFilter); + ReadMember(obj, "minFilter", minFilter); + ReadMember(obj, "wrapS", wrapS); + ReadMember(obj, "wrapT", wrapT); +} + +inline void Sampler::SetDefaults() +{ + //only wrapping modes have defaults + wrapS = SamplerWrap::Repeat; + wrapT = SamplerWrap::Repeat; + magFilter = SamplerMagFilter::UNSET; + minFilter = SamplerMinFilter::UNSET; +} + +inline void Texture::Read(Value& obj, Asset& r) +{ + if (Value* sourceVal = FindUInt(obj, "source")) { + source = r.images.Retrieve(sourceVal->GetUint()); + } + + if (Value* samplerVal = FindUInt(obj, "sampler")) { + sampler = r.samplers.Retrieve(samplerVal->GetUint()); + } +} + +namespace { + inline void SetTextureProperties(Asset& r, Value* prop, TextureInfo& out) + { + if (Value* index = FindUInt(*prop, "index")) { + out.texture = r.textures.Retrieve(index->GetUint()); + } + + if (Value* texcoord = FindUInt(*prop, "texCoord")) { + out.texCoord = texcoord->GetUint(); + } + } + + inline void ReadTextureProperty(Asset& r, Value& vals, const char* propName, TextureInfo& out) + { + if (Value* prop = FindMember(vals, propName)) { + SetTextureProperties(r, prop, out); + } + } + + inline void ReadTextureProperty(Asset& r, Value& vals, const char* propName, NormalTextureInfo& out) + { + if (Value* prop = FindMember(vals, propName)) { + SetTextureProperties(r, prop, out); + + if (Value* scale = FindNumber(*prop, "scale")) { + out.scale = static_cast(scale->GetDouble()); + } + } + } + + inline void ReadTextureProperty(Asset& r, Value& vals, const char* propName, OcclusionTextureInfo& out) + { + if (Value* prop = FindMember(vals, propName)) { + SetTextureProperties(r, prop, out); + + if (Value* strength = FindNumber(*prop, "strength")) { + out.strength = static_cast(strength->GetDouble()); + } + } + } +} + +inline void Material::Read(Value& material, Asset& r) +{ + SetDefaults(); + + if (Value* pbrMetallicRoughness = FindObject(material, "pbrMetallicRoughness")) { + ReadMember(*pbrMetallicRoughness, "baseColorFactor", this->pbrMetallicRoughness.baseColorFactor); + ReadTextureProperty(r, *pbrMetallicRoughness, "baseColorTexture", this->pbrMetallicRoughness.baseColorTexture); + ReadTextureProperty(r, *pbrMetallicRoughness, "metallicRoughnessTexture", this->pbrMetallicRoughness.metallicRoughnessTexture); + ReadMember(*pbrMetallicRoughness, "metallicFactor", this->pbrMetallicRoughness.metallicFactor); + ReadMember(*pbrMetallicRoughness, "roughnessFactor", this->pbrMetallicRoughness.roughnessFactor); + } + + ReadTextureProperty(r, material, "normalTexture", this->normalTexture); + ReadTextureProperty(r, material, "occlusionTexture", this->occlusionTexture); + ReadTextureProperty(r, material, "emissiveTexture", this->emissiveTexture); + ReadMember(material, "emissiveFactor", this->emissiveFactor); + + ReadMember(material, "doubleSided", this->doubleSided); + ReadMember(material, "alphaMode", this->alphaMode); + ReadMember(material, "alphaCutoff", this->alphaCutoff); + + if (Value* extensions = FindObject(material, "extensions")) { + if (r.extensionsUsed.KHR_materials_pbrSpecularGlossiness) { + if (Value* pbrSpecularGlossiness = FindObject(*extensions, "KHR_materials_pbrSpecularGlossiness")) { + PbrSpecularGlossiness pbrSG; + + ReadMember(*pbrSpecularGlossiness, "diffuseFactor", pbrSG.diffuseFactor); + ReadTextureProperty(r, *pbrSpecularGlossiness, "diffuseTexture", pbrSG.diffuseTexture); + ReadTextureProperty(r, *pbrSpecularGlossiness, "specularGlossinessTexture", pbrSG.specularGlossinessTexture); + ReadMember(*pbrSpecularGlossiness, "specularFactor", pbrSG.specularFactor); + ReadMember(*pbrSpecularGlossiness, "glossinessFactor", pbrSG.glossinessFactor); + + this->pbrSpecularGlossiness = Nullable(pbrSG); + } + } + } +} + +namespace { + void SetVector(vec4& v, const float(&in)[4]) + { v[0] = in[0]; v[1] = in[1]; v[2] = in[2]; v[3] = in[3]; } + + void SetVector(vec3& v, const float(&in)[3]) + { v[0] = in[0]; v[1] = in[1]; v[2] = in[2]; } +} + +inline void Material::SetDefaults() +{ + //pbr materials + SetVector(pbrMetallicRoughness.baseColorFactor, defaultBaseColor); + pbrMetallicRoughness.metallicFactor = 1.0; + pbrMetallicRoughness.roughnessFactor = 1.0; + + SetVector(emissiveFactor, defaultEmissiveFactor); + alphaMode = "OPAQUE"; + alphaCutoff = 0.5; + doubleSided = false; +} + +inline void PbrSpecularGlossiness::SetDefaults() +{ + //pbrSpecularGlossiness properties + SetVector(diffuseFactor, defaultDiffuseFactor); + SetVector(specularFactor, defaultSpecularFactor); + glossinessFactor = 1.0; +} + +namespace { + + template + inline int Compare(const char* attr, const char (&str)[N]) { + return (strncmp(attr, str, N - 1) == 0) ? N - 1 : 0; + } + + inline bool GetAttribVector(Mesh::Primitive& p, const char* attr, Mesh::AccessorList*& v, int& pos) + { + if ((pos = Compare(attr, "POSITION"))) { + v = &(p.attributes.position); + } + else if ((pos = Compare(attr, "NORMAL"))) { + v = &(p.attributes.normal); + } + else if ((pos = Compare(attr, "TEXCOORD"))) { + v = &(p.attributes.texcoord); + } + else if ((pos = Compare(attr, "COLOR"))) { + v = &(p.attributes.color); + } + else if ((pos = Compare(attr, "JOINT"))) { + v = &(p.attributes.joint); + } + else if ((pos = Compare(attr, "JOINTMATRIX"))) { + v = &(p.attributes.jointmatrix); + } + else if ((pos = Compare(attr, "WEIGHT"))) { + v = &(p.attributes.weight); + } + else return false; + return true; + } +} + +inline void Mesh::Read(Value& pJSON_Object, Asset& pAsset_Root) +{ + if (Value* name = FindMember(pJSON_Object, "name")) { + this->name = name->GetString(); + } + + /****************** Mesh primitives ******************/ + if (Value* primitives = FindArray(pJSON_Object, "primitives")) { + this->primitives.resize(primitives->Size()); + for (unsigned int i = 0; i < primitives->Size(); ++i) { + Value& primitive = (*primitives)[i]; + + Primitive& prim = this->primitives[i]; + prim.mode = MemberOrDefault(primitive, "mode", PrimitiveMode_TRIANGLES); + + if (Value* attrs = FindObject(primitive, "attributes")) { + for (Value::MemberIterator it = attrs->MemberBegin(); it != attrs->MemberEnd(); ++it) { + if (!it->value.IsUint()) continue; + const char* attr = it->name.GetString(); + // Valid attribute semantics include POSITION, NORMAL, TEXCOORD, COLOR, JOINT, JOINTMATRIX, + // and WEIGHT.Attribute semantics can be of the form[semantic]_[set_index], e.g., TEXCOORD_0, TEXCOORD_1, etc. + + int undPos = 0; + Mesh::AccessorList* vec = 0; + if (GetAttribVector(prim, attr, vec, undPos)) { + size_t idx = (attr[undPos] == '_') ? atoi(attr + undPos + 1) : 0; + if ((*vec).size() <= idx) (*vec).resize(idx + 1); + (*vec)[idx] = pAsset_Root.accessors.Retrieve(it->value.GetUint()); + } + } + } + + if (Value* indices = FindUInt(primitive, "indices")) { + prim.indices = pAsset_Root.accessors.Retrieve(indices->GetUint()); + } + + if (Value* material = FindUInt(primitive, "material")) { + prim.material = pAsset_Root.materials.Retrieve(material->GetUint()); + } + } + } +} + +inline void Camera::Read(Value& obj, Asset& r) +{ + type = MemberOrDefault(obj, "type", Camera::Perspective); + + const char* subobjId = (type == Camera::Orthographic) ? "ortographic" : "perspective"; + + Value* it = FindObject(obj, subobjId); + if (!it) throw DeadlyImportError("GLTF: Camera missing its parameters"); + + if (type == Camera::Perspective) { + cameraProperties.perspective.aspectRatio = MemberOrDefault(*it, "aspectRatio", 0.f); + cameraProperties.perspective.yfov = MemberOrDefault(*it, "yfov", 3.1415f/2.f); + cameraProperties.perspective.zfar = MemberOrDefault(*it, "zfar", 100.f); + cameraProperties.perspective.znear = MemberOrDefault(*it, "znear", 0.01f); + } + else { + cameraProperties.ortographic.xmag = MemberOrDefault(obj, "xmag", 1.f); + cameraProperties.ortographic.ymag = MemberOrDefault(obj, "ymag", 1.f); + cameraProperties.ortographic.zfar = MemberOrDefault(obj, "zfar", 100.f); + cameraProperties.ortographic.znear = MemberOrDefault(obj, "znear", 0.01f); + } +} + +inline void Node::Read(Value& obj, Asset& r) +{ + + if (Value* children = FindArray(obj, "children")) { + this->children.reserve(children->Size()); + for (unsigned int i = 0; i < children->Size(); ++i) { + Value& child = (*children)[i]; + if (child.IsUint()) { + // get/create the child node + Ref chn = r.nodes.Retrieve(child.GetUint()); + if (chn) this->children.push_back(chn); + } + } + } + + if (Value* matrix = FindArray(obj, "matrix")) { + ReadValue(*matrix, this->matrix); + } + else { + ReadMember(obj, "translation", translation); + ReadMember(obj, "scale", scale); + ReadMember(obj, "rotation", rotation); + } + + if (Value* mesh = FindUInt(obj, "mesh")) { + unsigned numMeshes = 1; + + this->meshes.reserve(numMeshes); + + Ref meshRef = r.meshes.Retrieve((*mesh).GetUint()); + + if (meshRef) this->meshes.push_back(meshRef); + } + + if (Value* camera = FindUInt(obj, "camera")) { + this->camera = r.cameras.Retrieve(camera->GetUint()); + if (this->camera) + this->camera->id = this->id; + } +} + +inline void Scene::Read(Value& obj, Asset& r) +{ + if (Value* array = FindArray(obj, "nodes")) { + for (unsigned int i = 0; i < array->Size(); ++i) { + if (!(*array)[i].IsUint()) continue; + Ref node = r.nodes.Retrieve((*array)[i].GetUint()); + if (node) + this->nodes.push_back(node); + } + } +} + +inline void AssetMetadata::Read(Document& doc) +{ + if (Value* obj = FindObject(doc, "asset")) { + ReadMember(*obj, "copyright", copyright); + ReadMember(*obj, "generator", generator); + + if (Value* versionString = FindString(*obj, "version")) { + version = versionString->GetString(); + } else if (Value* versionNumber = FindNumber (*obj, "version")) { + char buf[4]; + + ai_snprintf(buf, 4, "%.1f", versionNumber->GetDouble()); + + version = buf; + } + + if (Value* profile = FindObject(*obj, "profile")) { + ReadMember(*profile, "api", this->profile.api); + ReadMember(*profile, "version", this->profile.version); + } + } + + if (version.empty() || version[0] != '2') { + throw DeadlyImportError("GLTF: Unsupported glTF version: " + version); + } +} + +// +// Asset methods implementation +// + +inline void Asset::Load(const std::string& pFile) +{ + mCurrentAssetDir.clear(); + int pos = std::max(int(pFile.rfind('/')), int(pFile.rfind('\\'))); + if (pos != int(std::string::npos)) mCurrentAssetDir = pFile.substr(0, pos + 1); + + shared_ptr stream(OpenFile(pFile.c_str(), "rb", true)); + if (!stream) { + throw DeadlyImportError("GLTF: Could not open file for reading"); + } + + mSceneLength = stream->FileSize(); + mBodyLength = 0; + + // read the scene data + + std::vector sceneData(mSceneLength + 1); + sceneData[mSceneLength] = '\0'; + + if (stream->Read(&sceneData[0], 1, mSceneLength) != mSceneLength) { + throw DeadlyImportError("GLTF: Could not read the file contents"); + } + + + // parse the JSON document + + Document doc; + doc.ParseInsitu(&sceneData[0]); + + if (doc.HasParseError()) { + char buffer[32]; + ai_snprintf(buffer, 32, "%d", static_cast(doc.GetErrorOffset())); + throw DeadlyImportError(std::string("GLTF: JSON parse error, offset ") + buffer + ": " + + GetParseError_En(doc.GetParseError())); + } + + if (!doc.IsObject()) { + throw DeadlyImportError("GLTF: JSON document root must be a JSON object"); + } + + // Fill the buffer instance for the current file embedded contents + if (mBodyLength > 0) { + if (!mBodyBuffer->LoadFromStream(*stream, mBodyLength, mBodyOffset)) { + throw DeadlyImportError("GLTF: Unable to read gltf file"); + } + } + + + // Load the metadata + asset.Read(doc); + ReadExtensionsUsed(doc); + + // Prepare the dictionaries + for (size_t i = 0; i < mDicts.size(); ++i) { + mDicts[i]->AttachToDocument(doc); + } + + // Read the "scene" property, which specifies which scene to load + // and recursively load everything referenced by it + if (Value* scene = FindUInt(doc, "scene")) { + unsigned int sceneIndex = scene->GetUint(); + + Ref s = scenes.Retrieve(sceneIndex); + + this->scene = s; + } + + // Clean up + for (size_t i = 0; i < mDicts.size(); ++i) { + mDicts[i]->DetachFromDocument(); + } +} + +inline void Asset::ReadExtensionsUsed(Document& doc) +{ + Value* extsUsed = FindArray(doc, "extensionsUsed"); + if (!extsUsed) return; + + std::gltf_unordered_map exts; + + for (unsigned int i = 0; i < extsUsed->Size(); ++i) { + if ((*extsUsed)[i].IsString()) { + exts[(*extsUsed)[i].GetString()] = true; + } + } + + #define CHECK_EXT(EXT) \ + if (exts.find(#EXT) != exts.end()) extensionsUsed.EXT = true; + + CHECK_EXT(KHR_materials_pbrSpecularGlossiness); + + #undef CHECK_EXT +} + +inline IOStream* Asset::OpenFile(std::string path, const char* mode, bool absolute) +{ + #ifdef ASSIMP_API + return mIOSystem->Open(path, mode); + #else + if (path.size() < 2) return 0; + if (!absolute && path[1] != ':' && path[0] != '/') { // relative? + path = mCurrentAssetDir + path; + } + FILE* f = fopen(path.c_str(), mode); + return f ? new IOStream(f) : 0; + #endif +} + +inline std::string Asset::FindUniqueID(const std::string& str, const char* suffix) +{ + std::string id = str; + + if (!id.empty()) { + if (mUsedIds.find(id) == mUsedIds.end()) + return id; + + id += "_"; + } + + id += suffix; + + Asset::IdMap::iterator it = mUsedIds.find(id); + if (it == mUsedIds.end()) + return id; + + std::vector buffer; + buffer.resize(id.size() + 16); + int offset = ai_snprintf(buffer.data(), buffer.size(), "%s_", id.c_str()); + for (int i = 0; it != mUsedIds.end(); ++i) { + ai_snprintf(buffer.data() + offset, buffer.size() - offset, "%d", i); + id = buffer.data(); + it = mUsedIds.find(id); + } + + 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/glTF2AssetWriter.h new file mode 100644 index 000000000..bce2b1bd1 --- /dev/null +++ b/code/glTF2AssetWriter.h @@ -0,0 +1,93 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 glTFWriter.h + * Declares a class to write gltf/glb files + * + * glTF Extensions Support: + * KHR_materials_pbrSpecularGlossiness: full + */ +#ifndef GLTF2ASSETWRITER_H_INC +#define GLTF2ASSETWRITER_H_INC + +#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER + +#include "glTF2Asset.h" + +namespace glTF2 +{ + +using rapidjson::MemoryPoolAllocator; + +class AssetWriter +{ + template + friend void WriteLazyDict(LazyDict& d, AssetWriter& w); + +private: + + void WriteBinaryData(IOStream* outfile, size_t sceneLength); + + void WriteMetadata(); + void WriteExtensionsUsed(); + + template + void WriteObjects(LazyDict& d); + +public: + Document mDoc; + Asset& mAsset; + + MemoryPoolAllocator<>& mAl; + + AssetWriter(Asset& asset); + + void WriteFile(const char* path); +}; + +} + +// Include the implementation of the methods +#include "glTF2AssetWriter.inl" + +#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER + +#endif // GLTF2ASSETWRITER_H_INC diff --git a/code/glTF2AssetWriter.inl b/code/glTF2AssetWriter.inl new file mode 100644 index 000000000..df28cb681 --- /dev/null +++ b/code/glTF2AssetWriter.inl @@ -0,0 +1,639 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 +#include +#include + +namespace glTF2 { + + using rapidjson::StringBuffer; + using rapidjson::PrettyWriter; + using rapidjson::Writer; + using rapidjson::StringRef; + using rapidjson::StringRef; + + namespace { + + template + inline Value& MakeValue(Value& val, float(&r)[N], MemoryPoolAllocator<>& al) { + val.SetArray(); + val.Reserve(N, al); + for (decltype(N) i = 0; i < N; ++i) { + val.PushBack(r[i], al); + } + return val; + } + + 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) { + val.PushBack(r[i], al); + } + return val; + } + + inline Value& MakeValue(Value& val, float r, MemoryPoolAllocator<>& al) { + val.SetDouble(r); + + return val; + } + + template + inline void AddRefsVector(Value& obj, const char* fieldId, std::vector< Ref >& v, MemoryPoolAllocator<>& al) { + if (v.empty()) return; + Value lst; + lst.SetArray(); + lst.Reserve(unsigned(v.size()), al); + for (size_t i = 0; i < v.size(); ++i) { + lst.PushBack(v[i]->index, al); + } + obj.AddMember(StringRef(fieldId), lst, al); + } + + + } + + inline void Write(Value& obj, Accessor& a, AssetWriter& w) + { + obj.AddMember("bufferView", a.bufferView->index, w.mAl); + obj.AddMember("byteOffset", a.byteOffset, w.mAl); + + if (a.byteStride != 0) { + obj.AddMember("byteStride", a.byteStride, w.mAl); + } + + obj.AddMember("componentType", int(a.componentType), w.mAl); + obj.AddMember("count", a.count, w.mAl); + obj.AddMember("type", StringRef(AttribType::ToString(a.type)), w.mAl); + + Value vTmpMax, vTmpMin; + obj.AddMember("max", MakeValue(vTmpMax, a.max, w.mAl), w.mAl); + obj.AddMember("min", MakeValue(vTmpMin, a.min, w.mAl), w.mAl); + } + + inline void Write(Value& obj, Animation& a, AssetWriter& w) + { + /****************** Channels *******************/ + Value channels; + channels.SetArray(); + channels.Reserve(unsigned(a.Channels.size()), w.mAl); + + for (size_t i = 0; i < unsigned(a.Channels.size()); ++i) { + Animation::AnimChannel& c = a.Channels[i]; + Value valChannel; + valChannel.SetObject(); + { + valChannel.AddMember("sampler", c.sampler, w.mAl); + + Value valTarget; + valTarget.SetObject(); + { + valTarget.AddMember("node", c.target.node->index, w.mAl); + valTarget.AddMember("path", c.target.path, w.mAl); + } + valChannel.AddMember("target", valTarget, w.mAl); + } + channels.PushBack(valChannel, w.mAl); + } + obj.AddMember("channels", channels, w.mAl); + + /****************** Samplers *******************/ + Value valSamplers; + valSamplers.SetArray(); + + for (size_t i = 0; i < unsigned(a.Samplers.size()); ++i) { + Animation::AnimSampler& s = a.Samplers[i]; + Value valSampler; + valSampler.SetObject(); + { + Ref inputAccessor = a.GetAccessor(s.input); + Ref outputAccessor = a.GetAccessor(s.output); + valSampler.AddMember("input", inputAccessor->index, w.mAl); + valSampler.AddMember("interpolation", s.interpolation, w.mAl); + valSampler.AddMember("output", outputAccessor->index, w.mAl); + } + valSamplers.PushBack(valSampler, w.mAl); + } + obj.AddMember("samplers", valSamplers, w.mAl); + } + + inline void Write(Value& obj, Buffer& b, AssetWriter& w) + { + obj.AddMember("byteLength", static_cast(b.byteLength), w.mAl); + obj.AddMember("uri", Value(b.GetURI(), w.mAl).Move(), w.mAl); + } + + inline void Write(Value& obj, BufferView& bv, AssetWriter& w) + { + obj.AddMember("buffer", bv.buffer->index, w.mAl); + obj.AddMember("byteOffset", static_cast(bv.byteOffset), w.mAl); + obj.AddMember("byteLength", static_cast(bv.byteLength), w.mAl); + obj.AddMember("target", int(bv.target), w.mAl); + } + + inline void Write(Value& obj, Camera& c, AssetWriter& w) + { + + } + + inline void Write(Value& obj, Image& img, AssetWriter& w) + { + std::string uri; + if (img.HasData()) { + uri = "data:" + (img.mimeType.empty() ? "application/octet-stream" : img.mimeType); + uri += ";base64,"; + Util::EncodeBase64(img.GetData(), img.GetDataLength(), uri); + } + else { + uri = img.uri; + } + + obj.AddMember("uri", Value(uri, w.mAl).Move(), w.mAl); + } + + namespace { + inline void SetTexBasic(TextureInfo t, Value& tex, MemoryPoolAllocator<>& al) + { + tex.SetObject(); + tex.AddMember("index", t.texture->index, al); + + if (t.texCoord != 0) { + tex.AddMember("texCoord", t.texCoord, al); + } + } + + inline void WriteTex(Value& obj, TextureInfo t, const char* propName, MemoryPoolAllocator<>& al) + { + + if (t.texture) { + Value tex; + + SetTexBasic(t, tex, al); + + obj.AddMember(StringRef(propName), tex, al); + } + } + + inline void WriteTex(Value& obj, NormalTextureInfo t, const char* propName, MemoryPoolAllocator<>& al) + { + + if (t.texture) { + Value tex; + + SetTexBasic(t, tex, al); + + if (t.scale != 1) { + tex.AddMember("scale", t.scale, al); + } + + obj.AddMember(StringRef(propName), tex, al); + } + } + + inline void WriteTex(Value& obj, OcclusionTextureInfo t, const char* propName, MemoryPoolAllocator<>& al) + { + + if (t.texture) { + Value tex; + + SetTexBasic(t, tex, al); + + if (t.strength != 1) { + tex.AddMember("strength", t.strength, al); + } + + obj.AddMember(StringRef(propName), tex, al); + } + } + + template + inline void WriteVec(Value& obj, float(&prop)[N], const char* propName, MemoryPoolAllocator<>& al) + { + Value arr; + obj.AddMember(StringRef(propName), MakeValue(arr, prop, al), al); + } + + template + inline void WriteVec(Value& obj, float(&prop)[N], const char* propName, const float(&defaultVal)[N], MemoryPoolAllocator<>& al) + { + if (!std::equal(std::begin(prop), std::end(prop), std::begin(defaultVal))) { + WriteVec(obj, prop, propName, al); + } + } + + inline void WriteFloat(Value& obj, float prop, const char* propName, MemoryPoolAllocator<>& al) + { + Value num; + obj.AddMember(StringRef(propName), MakeValue(num, prop, al), al); + } + } + + inline void Write(Value& obj, Material& m, AssetWriter& w) + { + Value pbrMetallicRoughness; + pbrMetallicRoughness.SetObject(); + { + WriteTex(pbrMetallicRoughness, m.pbrMetallicRoughness.baseColorTexture, "baseColorTexture", w.mAl); + WriteTex(pbrMetallicRoughness, m.pbrMetallicRoughness.metallicRoughnessTexture, "metallicRoughnessTexture", w.mAl); + WriteVec(pbrMetallicRoughness, m.pbrMetallicRoughness.baseColorFactor, "baseColorFactor", defaultBaseColor, w.mAl); + + if (m.pbrMetallicRoughness.metallicFactor != 1) { + WriteFloat(pbrMetallicRoughness, m.pbrMetallicRoughness.metallicFactor, "metallicFactor", w.mAl); + } + + if (m.pbrMetallicRoughness.roughnessFactor != 1) { + WriteFloat(pbrMetallicRoughness, m.pbrMetallicRoughness.roughnessFactor, "roughnessFactor", w.mAl); + } + } + + if (!pbrMetallicRoughness.ObjectEmpty()) { + obj.AddMember("pbrMetallicRoughness", pbrMetallicRoughness, w.mAl); + } + + WriteTex(obj, m.normalTexture, "normalTexture", w.mAl); + WriteTex(obj, m.emissiveTexture, "emissiveTexture", w.mAl); + WriteTex(obj, m.occlusionTexture, "occlusionTexture", w.mAl); + WriteVec(obj, m.emissiveFactor, "emissiveFactor", defaultEmissiveFactor, w.mAl); + + if (m.alphaCutoff != 0.5) { + WriteFloat(obj, m.alphaCutoff, "alphaCutoff", w.mAl); + } + + if (m.alphaMode != "OPAQUE") { + obj.AddMember("alphaMode", Value(m.alphaMode, w.mAl).Move(), w.mAl); + } + + if (m.doubleSided) { + obj.AddMember("doubleSided", m.doubleSided, w.mAl); + } + + Value exts; + exts.SetObject(); + + if (m.pbrSpecularGlossiness.isPresent) { + Value pbrSpecularGlossiness; + pbrSpecularGlossiness.SetObject(); + + PbrSpecularGlossiness &pbrSG = m.pbrSpecularGlossiness.value; + + //pbrSpecularGlossiness + WriteVec(pbrSpecularGlossiness, pbrSG.diffuseFactor, "diffuseFactor", defaultDiffuseFactor, w.mAl); + WriteVec(pbrSpecularGlossiness, pbrSG.specularFactor, "specularFactor", defaultSpecularFactor, w.mAl); + + if (pbrSG.glossinessFactor != 1) { + WriteFloat(obj, pbrSG.glossinessFactor, "glossinessFactor", w.mAl); + } + + WriteTex(pbrSpecularGlossiness, pbrSG.diffuseTexture, "diffuseTexture", w.mAl); + WriteTex(pbrSpecularGlossiness, pbrSG.specularGlossinessTexture, "specularGlossinessTexture", w.mAl); + + if (!pbrSpecularGlossiness.ObjectEmpty()) { + exts.AddMember("KHR_materials_pbrSpecularGlossiness", pbrSpecularGlossiness, w.mAl); + } + } + + if (!exts.ObjectEmpty()) { + obj.AddMember("extensions", exts, w.mAl); + } + } + + namespace { + inline void WriteAttrs(AssetWriter& w, Value& attrs, Mesh::AccessorList& lst, + const char* semantic, bool forceNumber = false) + { + if (lst.empty()) return; + if (lst.size() == 1 && !forceNumber) { + attrs.AddMember(StringRef(semantic), lst[0]->index, w.mAl); + } + else { + for (size_t i = 0; i < lst.size(); ++i) { + char buffer[32]; + ai_snprintf(buffer, 32, "%s_%d", semantic, int(i)); + attrs.AddMember(Value(buffer, w.mAl).Move(), lst[i]->index, w.mAl); + } + } + } + } + + inline void Write(Value& obj, Mesh& m, AssetWriter& w) + { + /****************** Primitives *******************/ + Value primitives; + primitives.SetArray(); + primitives.Reserve(unsigned(m.primitives.size()), w.mAl); + + for (size_t i = 0; i < m.primitives.size(); ++i) { + Mesh::Primitive& p = m.primitives[i]; + Value prim; + prim.SetObject(); + { + prim.AddMember("mode", Value(int(p.mode)).Move(), w.mAl); + + if (p.material) + prim.AddMember("material", p.material->index, w.mAl); + + if (p.indices) + prim.AddMember("indices", p.indices->index, w.mAl); + + Value attrs; + attrs.SetObject(); + { + WriteAttrs(w, attrs, p.attributes.position, "POSITION"); + WriteAttrs(w, attrs, p.attributes.normal, "NORMAL"); + WriteAttrs(w, attrs, p.attributes.texcoord, "TEXCOORD", true); + WriteAttrs(w, attrs, p.attributes.color, "COLOR", true); + WriteAttrs(w, attrs, p.attributes.joint, "JOINTS", true); + WriteAttrs(w, attrs, p.attributes.weight, "WEIGHTS", true); + } + prim.AddMember("attributes", attrs, w.mAl); + } + primitives.PushBack(prim, w.mAl); + } + + obj.AddMember("primitives", primitives, w.mAl); + } + + inline void Write(Value& obj, Node& n, AssetWriter& w) + { + + if (n.matrix.isPresent) { + Value val; + obj.AddMember("matrix", MakeValue(val, n.matrix.value, w.mAl).Move(), w.mAl); + } + + if (n.translation.isPresent) { + Value val; + obj.AddMember("translation", MakeValue(val, n.translation.value, w.mAl).Move(), w.mAl); + } + + if (n.scale.isPresent) { + Value val; + obj.AddMember("scale", MakeValue(val, n.scale.value, w.mAl).Move(), w.mAl); + } + if (n.rotation.isPresent) { + Value val; + obj.AddMember("rotation", MakeValue(val, n.rotation.value, w.mAl).Move(), w.mAl); + } + + AddRefsVector(obj, "children", n.children, w.mAl); + + if (!n.meshes.empty()) { + obj.AddMember("mesh", n.meshes[0]->index, w.mAl); + } + + AddRefsVector(obj, "skeletons", n.skeletons, w.mAl); + + if (n.skin) { + obj.AddMember("skin", n.skin->index, w.mAl); + } + + if (!n.jointName.empty()) { + obj.AddMember("jointName", n.jointName, w.mAl); + } + } + + inline void Write(Value& obj, Program& b, AssetWriter& w) + { + + } + + inline void Write(Value& obj, Sampler& b, AssetWriter& w) + { + if (!b.name.empty()) { + obj.AddMember("name", b.name, w.mAl); + } + + if (b.wrapS != SamplerWrap::UNSET && b.wrapS != SamplerWrap::Repeat) { + obj.AddMember("wrapS", static_cast(b.wrapS), w.mAl); + } + + if (b.wrapT != SamplerWrap::UNSET && b.wrapT != SamplerWrap::Repeat) { + obj.AddMember("wrapT", static_cast(b.wrapT), w.mAl); + } + + if (b.magFilter != SamplerMagFilter::UNSET) { + obj.AddMember("magFilter", static_cast(b.magFilter), w.mAl); + } + + if (b.minFilter != SamplerMinFilter::UNSET) { + obj.AddMember("minFilter", static_cast(b.minFilter), w.mAl); + } + } + + inline void Write(Value& scene, Scene& s, AssetWriter& w) + { + AddRefsVector(scene, "nodes", s.nodes, w.mAl); + } + + inline void Write(Value& obj, Shader& b, AssetWriter& w) + { + + } + + inline void Write(Value& obj, Skin& b, AssetWriter& w) + { + /****************** jointNames *******************/ + Value vJointNames; + vJointNames.SetArray(); + vJointNames.Reserve(unsigned(b.jointNames.size()), w.mAl); + + for (size_t i = 0; i < unsigned(b.jointNames.size()); ++i) { + vJointNames.PushBack(b.jointNames[i]->index, w.mAl); + } + obj.AddMember("joints", vJointNames, w.mAl); + + if (b.bindShapeMatrix.isPresent) { + Value val; + obj.AddMember("bindShapeMatrix", MakeValue(val, b.bindShapeMatrix.value, w.mAl).Move(), w.mAl); + } + + if (b.inverseBindMatrices) { + obj.AddMember("inverseBindMatrices", b.inverseBindMatrices->index, w.mAl); + } + + } + + inline void Write(Value& obj, Texture& tex, AssetWriter& w) + { + if (tex.source) { + obj.AddMember("source", tex.source->index, w.mAl); + } + if (tex.sampler) { + obj.AddMember("sampler", tex.sampler->index, w.mAl); + } + } + + + inline AssetWriter::AssetWriter(Asset& a) + : mDoc() + , mAsset(a) + , mAl(mDoc.GetAllocator()) + { + mDoc.SetObject(); + + WriteMetadata(); + WriteExtensionsUsed(); + + // Dump the contents of the dictionaries + for (size_t i = 0; i < a.mDicts.size(); ++i) { + a.mDicts[i]->WriteObjects(*this); + } + + // Add the target scene field + if (mAsset.scene) { + mDoc.AddMember("scene", mAsset.scene->index, mAl); + } + } + + inline void AssetWriter::WriteFile(const char* path) + { + std::unique_ptr jsonOutFile(mAsset.OpenFile(path, "wt", true)); + + if (jsonOutFile == 0) { + throw DeadlyExportError("Could not open output file: " + std::string(path)); + } + + StringBuffer docBuffer; + + PrettyWriter writer(docBuffer); + mDoc.Accept(writer); + + if (jsonOutFile->Write(docBuffer.GetString(), docBuffer.GetSize(), 1) != 1) { + throw DeadlyExportError("Failed to write scene data!"); + } + + // Write buffer data to separate .bin files + for (unsigned int i = 0; i < mAsset.buffers.Size(); ++i) { + Ref b = mAsset.buffers.Get(i); + + std::string binPath = b->GetURI(); + + std::unique_ptr binOutFile(mAsset.OpenFile(binPath, "wb", true)); + + if (binOutFile == 0) { + throw DeadlyExportError("Could not open output file: " + binPath); + } + + if (b->byteLength > 0) { + if (binOutFile->Write(b->GetPointer(), b->byteLength, 1) != 1) { + throw DeadlyExportError("Failed to write binary file: " + binPath); + } + } + } + } + + inline void AssetWriter::WriteMetadata() + { + Value asset; + asset.SetObject(); + asset.AddMember("version", Value(mAsset.asset.version, mAl).Move(), mAl); + asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl); + mDoc.AddMember("asset", asset, mAl); + } + + inline void AssetWriter::WriteExtensionsUsed() + { + Value exts; + exts.SetArray(); + { + // This is used to export pbrSpecularGlossiness materials with GLTF 2. + if (this->mAsset.extensionsUsed.KHR_materials_pbrSpecularGlossiness) { + exts.PushBack(StringRef("KHR_materials_pbrSpecularGlossiness"), mAl); + } + } + + if (!exts.Empty()) + mDoc.AddMember("extensionsUsed", exts, mAl); + } + + template + void AssetWriter::WriteObjects(LazyDict& d) + { + if (d.mObjs.empty()) return; + + Value* container = &mDoc; + + if (d.mExtId) { + Value* exts = FindObject(mDoc, "extensions"); + if (!exts) { + mDoc.AddMember("extensions", Value().SetObject().Move(), mDoc.GetAllocator()); + exts = FindObject(mDoc, "extensions"); + } + + if (!(container = FindObject(*exts, d.mExtId))) { + exts->AddMember(StringRef(d.mExtId), Value().SetObject().Move(), mDoc.GetAllocator()); + container = FindObject(*exts, d.mExtId); + } + } + + Value* dict; + if (!(dict = FindArray(*container, d.mDictId))) { + container->AddMember(StringRef(d.mDictId), Value().SetArray().Move(), mDoc.GetAllocator()); + dict = FindArray(*container, d.mDictId); + } + + for (size_t i = 0; i < d.mObjs.size(); ++i) { + if (d.mObjs[i]->IsSpecial()) continue; + + Value obj; + obj.SetObject(); + + if (!d.mObjs[i]->name.empty()) { + obj.AddMember("name", StringRef(d.mObjs[i]->name.c_str()), mAl); + } + + Write(obj, *d.mObjs[i], *this); + + dict->PushBack(obj, mAl); + } + } + + template + void WriteLazyDict(LazyDict& d, AssetWriter& w) + { + w.WriteObjects(d); + } + +} + + diff --git a/code/glTF2Exporter.cpp b/code/glTF2Exporter.cpp new file mode 100644 index 000000000..8f46f7dc7 --- /dev/null +++ b/code/glTF2Exporter.cpp @@ -0,0 +1,1007 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, assimp team + +All rights reserved. + +Redistribution and use of this software in source and binary forms, +with or without modification, are permitted provided that the +following conditions are met: + +* Redistributions of source code must retain the above +copyright notice, this list of conditions and the +following disclaimer. + +* Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the +following disclaimer in the documentation and/or other +materials provided with the distribution. + +* Neither the name of the assimp team, nor the names of its +contributors may be used to endorse or promote products +derived from this software without specific prior +written permission of the assimp team. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---------------------------------------------------------------------- +*/ +#ifndef ASSIMP_BUILD_NO_EXPORT +#ifndef ASSIMP_BUILD_NO_GLTF_EXPORTER + +#include "glTF2Exporter.h" + +#include "Exceptional.h" +#include "StringComparison.h" +#include "ByteSwapper.h" + +#include "SplitLargeMeshes.h" + +#include +#include +#include +#include +#include +#include + +// Header files, standart library. +#include +#include + +#include "glTF2AssetWriter.h" + +using namespace rapidjson; + +using namespace Assimp; +using namespace glTF2; + +namespace Assimp { + + // ------------------------------------------------------------------------------------------------ + // Worker function for exporting a scene to GLTF. Prototyped and registered in Exporter.cpp + void ExportSceneGLTF2(const char* pFile, IOSystem* pIOSystem, const aiScene* pScene, const ExportProperties* pProperties) + { + // invoke the exporter + glTF2Exporter exporter(pFile, pIOSystem, pScene, pProperties, false); + } + +} // end of namespace Assimp + +glTF2Exporter::glTF2Exporter(const char* filename, IOSystem* pIOSystem, const aiScene* pScene, + const ExportProperties* pProperties, bool isBinary) + : mFilename(filename) + , mIOSystem(pIOSystem) + , mProperties(pProperties) +{ + aiScene* sceneCopy_tmp; + SceneCombiner::CopyScene(&sceneCopy_tmp, pScene); + std::unique_ptr sceneCopy(sceneCopy_tmp); + + SplitLargeMeshesProcess_Triangle tri_splitter; + tri_splitter.SetLimit(0xffff); + tri_splitter.Execute(sceneCopy.get()); + + SplitLargeMeshesProcess_Vertex vert_splitter; + vert_splitter.SetLimit(0xffff); + vert_splitter.Execute(sceneCopy.get()); + + mScene = sceneCopy.get(); + + mAsset.reset( new Asset( pIOSystem ) ); + + ExportMetadata(); + + ExportMaterials(); + + if (mScene->mRootNode) { + ExportNodeHierarchy(mScene->mRootNode); + } + + ExportMeshes(); + MergeMeshes(); + + ExportScene(); + + ExportAnimations(); + + AssetWriter writer(*mAsset); + + writer.WriteFile(filename); +} + +/* + * Copy a 4x4 matrix from struct aiMatrix to typedef mat4. + * Also converts from row-major to column-major storage. + */ +static void CopyValue(const aiMatrix4x4& v, mat4& o) +{ + o[ 0] = v.a1; o[ 1] = v.b1; o[ 2] = v.c1; o[ 3] = v.d1; + o[ 4] = v.a2; o[ 5] = v.b2; o[ 6] = v.c2; o[ 7] = v.d2; + o[ 8] = v.a3; o[ 9] = v.b3; o[10] = v.c3; o[11] = v.d3; + o[12] = v.a4; o[13] = v.b4; o[14] = v.c4; o[15] = v.d4; +} + +static void CopyValue(const aiMatrix4x4& v, aiMatrix4x4& o) +{ + o.a1 = v.a1; o.a2 = v.a2; o.a3 = v.a3; o.a4 = v.a4; + o.b1 = v.b1; o.b2 = v.b2; o.b3 = v.b3; o.b4 = v.b4; + o.c1 = v.c1; o.c2 = v.c2; o.c3 = v.c3; o.c4 = v.c4; + o.d1 = v.d1; o.d2 = v.d2; o.d3 = v.d3; o.d4 = v.d4; +} + +static void IdentityMatrix4(mat4& o) +{ + o[ 0] = 1; o[ 1] = 0; o[ 2] = 0; o[ 3] = 0; + o[ 4] = 0; o[ 5] = 1; o[ 6] = 0; o[ 7] = 0; + o[ 8] = 0; o[ 9] = 0; o[10] = 1; o[11] = 0; + o[12] = 0; o[13] = 0; o[14] = 0; o[15] = 1; +} + +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) +{ + if (!count || !data) return Ref(); + + unsigned int numCompsIn = AttribType::GetNumComponents(typeIn); + unsigned int numCompsOut = AttribType::GetNumComponents(typeOut); + unsigned int bytesPerComp = ComponentTypeSize(compType); + + size_t offset = buffer->byteLength; + // make sure offset is correctly byte-aligned, as required by spec + size_t padding = offset % bytesPerComp; + offset += padding; + size_t length = count * numCompsOut * bytesPerComp; + buffer->Grow(length + padding); + + // bufferView + Ref bv = a.bufferViews.Create(a.FindUniqueID(meshName, "view")); + bv->buffer = buffer; + bv->byteOffset = unsigned(offset); + bv->byteLength = length; //! The target that the WebGL buffer should be bound to. + bv->target = isIndices ? BufferViewTarget_ELEMENT_ARRAY_BUFFER : BufferViewTarget_ARRAY_BUFFER; + + // accessor + Ref acc = a.accessors.Create(a.FindUniqueID(meshName, "accessor")); + acc->bufferView = bv; + acc->byteOffset = 0; + acc->byteStride = 0; + acc->componentType = compType; + acc->count = count; + acc->type = typeOut; + + // calculate min and max values + { + // Allocate and initialize with large values. + float float_MAX = 10000000000000.0f; + for (unsigned int i = 0 ; i < numCompsOut ; i++) { + acc->min.push_back( float_MAX); + acc->max.push_back(-float_MAX); + } + + // Search and set extreme values. + float valueTmp; + for (unsigned int i = 0 ; i < count ; i++) { + for (unsigned int j = 0 ; j < numCompsOut ; j++) { + if (numCompsOut == 1) { + valueTmp = static_cast(data)[i]; + } else { + valueTmp = static_cast(data)[i][j]; + } + + if (valueTmp < acc->min[j]) { + acc->min[j] = valueTmp; + } + if (valueTmp > acc->max[j]) { + acc->max[j] = valueTmp; + } + } + } + } + + // copy the data + acc->WriteData(count, data, numCompsIn*bytesPerComp); + + return acc; +} + +inline void SetSamplerWrap(SamplerWrap& wrap, aiTextureMapMode map) +{ + switch (map) { + case aiTextureMapMode_Clamp: + wrap = SamplerWrap::Clamp_To_Edge; + break; + case aiTextureMapMode_Mirror: + wrap = SamplerWrap::Mirrored_Repeat; + break; + case aiTextureMapMode_Wrap: + case aiTextureMapMode_Decal: + default: + wrap = SamplerWrap::Repeat; + break; + }; +} + +void glTF2Exporter::GetTexSampler(const aiMaterial* mat, Ref texture, aiTextureType tt, unsigned int slot) +{ + aiString aId; + std::string id; + if (aiGetMaterialString(mat, AI_MATKEY_GLTF_MAPPINGID(tt, slot), &aId) == AI_SUCCESS) { + id = aId.C_Str(); + } + + if (Ref ref = mAsset->samplers.Get(id.c_str())) { + texture->sampler = ref; + } else { + id = mAsset->FindUniqueID(id, "sampler"); + + texture->sampler = mAsset->samplers.Create(id.c_str()); + + aiTextureMapMode mapU, mapV; + SamplerMagFilter filterMag; + SamplerMinFilter filterMin; + + if (aiGetMaterialInteger(mat, AI_MATKEY_MAPPINGMODE_U(tt, slot), (int*)&mapU) == AI_SUCCESS) { + SetSamplerWrap(texture->sampler->wrapS, mapU); + } + + if (aiGetMaterialInteger(mat, AI_MATKEY_MAPPINGMODE_V(tt, slot), (int*)&mapV) == AI_SUCCESS) { + SetSamplerWrap(texture->sampler->wrapT, mapV); + } + + if (aiGetMaterialInteger(mat, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(tt, slot), (int*)&filterMag) == AI_SUCCESS) { + texture->sampler->magFilter = filterMag; + } + + if (aiGetMaterialInteger(mat, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(tt, slot), (int*)&filterMin) == AI_SUCCESS) { + texture->sampler->minFilter = filterMin; + } + + aiString name; + if (aiGetMaterialString(mat, AI_MATKEY_GLTF_MAPPINGNAME(tt, slot), &name) == AI_SUCCESS) { + texture->sampler->name = name.C_Str(); + } + } +} + +void glTF2Exporter::GetMatTexProp(const aiMaterial* mat, unsigned int& prop, const char* propName, aiTextureType tt, unsigned int slot) +{ + std::string textureKey = std::string(_AI_MATKEY_TEXTURE_BASE) + "." + propName; + + mat->Get(textureKey.c_str(), tt, slot, prop); +} + +void glTF2Exporter::GetMatTexProp(const aiMaterial* mat, float& prop, const char* propName, aiTextureType tt, unsigned int slot) +{ + std::string textureKey = std::string(_AI_MATKEY_TEXTURE_BASE) + "." + propName; + + mat->Get(textureKey.c_str(), tt, slot, prop); +} + +void glTF2Exporter::GetMatTex(const aiMaterial* mat, Ref& texture, aiTextureType tt, unsigned int slot = 0) +{ + + if (mat->GetTextureCount(tt) > 0) { + aiString tex; + + if (mat->Get(AI_MATKEY_TEXTURE(tt, slot), tex) == AI_SUCCESS) { + std::string path = tex.C_Str(); + + if (path.size() > 0) { + if (path[0] != '*') { + std::map::iterator it = mTexturesByPath.find(path); + if (it != mTexturesByPath.end()) { + texture = mAsset->textures.Get(it->second); + } + } + + if (!texture) { + std::string texId = mAsset->FindUniqueID("", "texture"); + texture = mAsset->textures.Create(texId); + mTexturesByPath[path] = texture.GetIndex(); + + std::string imgId = mAsset->FindUniqueID("", "image"); + texture->source = mAsset->images.Create(imgId); + + if (path[0] == '*') { // embedded + aiTexture* tex = mScene->mTextures[atoi(&path[1])]; + + uint8_t* data = reinterpret_cast(tex->pcData); + texture->source->SetData(data, tex->mWidth, *mAsset); + + if (tex->achFormatHint[0]) { + std::string mimeType = "image/"; + mimeType += (memcmp(tex->achFormatHint, "jpg", 3) == 0) ? "jpeg" : tex->achFormatHint; + texture->source->mimeType = mimeType; + } + } + else { + texture->source->uri = path; + } + + GetTexSampler(mat, texture, tt, slot); + } + } + } + } +} + +void glTF2Exporter::GetMatTex(const aiMaterial* mat, TextureInfo& prop, aiTextureType tt, unsigned int slot = 0) +{ + Ref& texture = prop.texture; + + GetMatTex(mat, texture, tt, slot); + + if (texture) { + GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot); + } +} + +void glTF2Exporter::GetMatTex(const aiMaterial* mat, NormalTextureInfo& prop, aiTextureType tt, unsigned int slot = 0) +{ + Ref& texture = prop.texture; + + GetMatTex(mat, texture, tt, slot); + + if (texture) { + GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot); + GetMatTexProp(mat, prop.scale, "scale", tt, slot); + } +} + +void glTF2Exporter::GetMatTex(const aiMaterial* mat, OcclusionTextureInfo& prop, aiTextureType tt, unsigned int slot = 0) +{ + Ref& texture = prop.texture; + + GetMatTex(mat, texture, tt, slot); + + if (texture) { + GetMatTexProp(mat, prop.texCoord, "texCoord", tt, slot); + GetMatTexProp(mat, prop.strength, "strength", tt, slot); + } +} + +void glTF2Exporter::GetMatColor(const aiMaterial* mat, vec4& prop, const char* propName, int type, int idx) +{ + aiColor4D col; + if (mat->Get(propName, type, idx, col) == AI_SUCCESS) { + prop[0] = col.r; prop[1] = col.g; prop[2] = col.b; prop[3] = col.a; + } +} + +void glTF2Exporter::GetMatColor(const aiMaterial* mat, vec3& prop, const char* propName, int type, int idx) +{ + aiColor3D col; + if (mat->Get(propName, type, idx, col) == AI_SUCCESS) { + prop[0] = col.r; prop[1] = col.g; prop[2] = col.b; + } +} + +void glTF2Exporter::ExportMaterials() +{ + aiString aiName; + for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) { + const aiMaterial* mat = mScene->mMaterials[i]; + + std::string id = "material_" + std::to_string(i); + + Ref m = mAsset->materials.Create(id); + + std::string name; + if (mat->Get(AI_MATKEY_NAME, aiName) == AI_SUCCESS) { + name = aiName.C_Str(); + } + name = mAsset->FindUniqueID(name, "material"); + + m->name = name; + + GetMatTex(mat, m->pbrMetallicRoughness.baseColorTexture, aiTextureType_DIFFUSE); + GetMatTex(mat, m->pbrMetallicRoughness.metallicRoughnessTexture, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE); + GetMatColor(mat, m->pbrMetallicRoughness.baseColorFactor, AI_MATKEY_COLOR_DIFFUSE); + + if (mat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR, m->pbrMetallicRoughness.metallicFactor) != AI_SUCCESS) { + //if metallicFactor wasn't defined, then the source is likely not a PBR file, and the metallicFactor should be 0 + m->pbrMetallicRoughness.metallicFactor = 0; + } + + mat->Get(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR, m->pbrMetallicRoughness.roughnessFactor); + + GetMatTex(mat, m->normalTexture, aiTextureType_NORMALS); + GetMatTex(mat, m->occlusionTexture, aiTextureType_LIGHTMAP); + GetMatTex(mat, m->emissiveTexture, aiTextureType_EMISSIVE); + GetMatColor(mat, m->emissiveFactor, AI_MATKEY_COLOR_EMISSIVE); + + mat->Get(AI_MATKEY_TWOSIDED, m->doubleSided); + mat->Get(AI_MATKEY_GLTF_ALPHACUTOFF, m->alphaCutoff); + + aiString alphaMode; + + if (mat->Get(AI_MATKEY_GLTF_ALPHAMODE, alphaMode) == AI_SUCCESS) { + m->alphaMode = alphaMode.C_Str(); + } else { + float opacity; + + if (mat->Get(AI_MATKEY_OPACITY, opacity) == AI_SUCCESS) { + if (opacity < 1) { + m->alphaMode = "MASK"; + m->pbrMetallicRoughness.baseColorFactor[3] *= opacity; + } + } + } + + bool hasPbrSpecularGlossiness = false; + mat->Get(AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS, hasPbrSpecularGlossiness); + + if (hasPbrSpecularGlossiness) { + + if (!mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness) { + mAsset->extensionsUsed.KHR_materials_pbrSpecularGlossiness = true; + } + + PbrSpecularGlossiness pbrSG; + + GetMatColor(mat, pbrSG.diffuseFactor, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_FACTOR); + GetMatColor(mat, pbrSG.specularFactor, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULAR_FACTOR); + mat->Get(AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR, pbrSG.glossinessFactor); + GetMatTex(mat, pbrSG.diffuseTexture, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_TEXTURE); + GetMatTex(mat, pbrSG.specularGlossinessTexture, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULARGLOSSINESS_TEXTURE); + + m->pbrSpecularGlossiness = Nullable(pbrSG); + } + } +} + +/* + * Search through node hierarchy and find the node containing the given meshID. + * Returns true on success, and false otherwise. + */ +bool FindMeshNode(Ref& nodeIn, Ref& meshNode, std::string meshID) +{ + for (unsigned int i = 0; i < nodeIn->meshes.size(); ++i) { + if (meshID.compare(nodeIn->meshes[i]->id) == 0) { + meshNode = nodeIn; + return true; + } + } + + for (unsigned int i = 0; i < nodeIn->children.size(); ++i) { + if(FindMeshNode(nodeIn->children[i], meshNode, meshID)) { + return true; + } + } + + return false; +} + +/* + * Find the root joint of the skeleton. + * Starts will any joint node and traces up the tree, + * until a parent is found that does not have a jointName. + * Returns the first parent Ref found that does not have a jointName. + */ +Ref FindSkeletonRootJoint(Ref& skinRef) +{ + Ref startNodeRef; + Ref parentNodeRef; + + // Arbitrarily use the first joint to start the search. + startNodeRef = skinRef->jointNames[0]; + parentNodeRef = skinRef->jointNames[0]; + + do { + startNodeRef = parentNodeRef; + parentNodeRef = startNodeRef->parent; + } while (!parentNodeRef->jointName.empty()); + + return parentNodeRef; +} + +void ExportSkin(Asset& mAsset, const aiMesh* aimesh, Ref& meshRef, Ref& bufferRef, Ref& skinRef, std::vector& inverseBindMatricesData) +{ + if (aimesh->mNumBones < 1) { + return; + } + + // Store the vertex joint and weight data. + const size_t NumVerts( aimesh->mNumVertices ); + vec4* vertexJointData = new vec4[ NumVerts ]; + vec4* vertexWeightData = new vec4[ NumVerts ]; + int* jointsPerVertex = new int[ NumVerts ]; + for (size_t i = 0; i < NumVerts; ++i) { + jointsPerVertex[i] = 0; + for (size_t j = 0; j < 4; ++j) { + vertexJointData[i][j] = 0; + vertexWeightData[i][j] = 0; + } + } + + for (unsigned int idx_bone = 0; idx_bone < aimesh->mNumBones; ++idx_bone) { + const aiBone* aib = aimesh->mBones[idx_bone]; + + // aib->mName =====> skinRef->jointNames + // Find the node with id = mName. + Ref nodeRef = mAsset.nodes.Get(aib->mName.C_Str()); + nodeRef->jointName = nodeRef->name; + + unsigned int jointNamesIndex = 0; + bool addJointToJointNames = true; + for ( unsigned int idx_joint = 0; idx_joint < skinRef->jointNames.size(); ++idx_joint) { + if (skinRef->jointNames[idx_joint]->jointName.compare(nodeRef->jointName) == 0) { + addJointToJointNames = false; + jointNamesIndex = idx_joint; + } + } + + if (addJointToJointNames) { + skinRef->jointNames.push_back(nodeRef); + + // aib->mOffsetMatrix =====> skinRef->inverseBindMatrices + aiMatrix4x4 tmpMatrix4; + CopyValue(aib->mOffsetMatrix, tmpMatrix4); + inverseBindMatricesData.push_back(tmpMatrix4); + jointNamesIndex = static_cast(inverseBindMatricesData.size() - 1); + } + + // aib->mWeights =====> vertexWeightData + for (unsigned int idx_weights = 0; idx_weights < aib->mNumWeights; ++idx_weights) { + unsigned int vertexId = aib->mWeights[idx_weights].mVertexId; + float vertWeight = aib->mWeights[idx_weights].mWeight; + + // A vertex can only have at most four joint weights. Ignore all others. + if (jointsPerVertex[vertexId] > 3) { + continue; + } + + vertexJointData[vertexId][jointsPerVertex[vertexId]] = static_cast(jointNamesIndex); + vertexWeightData[vertexId][jointsPerVertex[vertexId]] = vertWeight; + + jointsPerVertex[vertexId] += 1; + } + + } // End: for-loop mNumMeshes + + Mesh::Primitive& p = meshRef->primitives.back(); + Ref vertexJointAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices, vertexJointData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT); + if ( vertexJointAccessor ) { + p.attributes.joint.push_back( vertexJointAccessor ); + } + + Ref vertexWeightAccessor = ExportData(mAsset, skinRef->id, bufferRef, aimesh->mNumVertices, vertexWeightData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT); + if ( vertexWeightAccessor ) { + p.attributes.weight.push_back( vertexWeightAccessor ); + } + delete[] jointsPerVertex; + delete[] vertexWeightData; + delete[] vertexJointData; +} + +void glTF2Exporter::ExportMeshes() +{ + // Not for + // using IndicesType = decltype(aiFace::mNumIndices); + // But yes for + // using IndicesType = unsigned short; + // because "ComponentType_UNSIGNED_SHORT" used for indices. And it's a maximal type according to glTF specification. + typedef unsigned short IndicesType; + + std::string fname = std::string(mFilename); + std::string bufferIdPrefix = fname.substr(0, fname.rfind(".gltf")); + std::string bufferId = mAsset->FindUniqueID("", bufferIdPrefix.c_str()); + + Ref b = mAsset->GetBodyBuffer(); + if (!b) { + b = mAsset->buffers.Create(bufferId); + } + + //---------------------------------------- + // Initialize variables for the skin + bool createSkin = false; + for (unsigned int idx_mesh = 0; idx_mesh < mScene->mNumMeshes; ++idx_mesh) { + const aiMesh* aim = mScene->mMeshes[idx_mesh]; + if(aim->HasBones()) { + createSkin = true; + break; + } + } + + Ref skinRef; + std::string skinName = mAsset->FindUniqueID("skin", "skin"); + std::vector inverseBindMatricesData; + if(createSkin) { + skinRef = mAsset->skins.Create(skinName); + skinRef->name = skinName; + } + //---------------------------------------- + + for (unsigned int idx_mesh = 0; idx_mesh < mScene->mNumMeshes; ++idx_mesh) { + const aiMesh* aim = mScene->mMeshes[idx_mesh]; + + std::string name = aim->mName.C_Str(); + + std::string meshId = mAsset->FindUniqueID(name, "mesh"); + Ref m = mAsset->meshes.Create(meshId); + m->primitives.resize(1); + Mesh::Primitive& p = m->primitives.back(); + + m->name = name; + + p.material = mAsset->materials.Get(aim->mMaterialIndex); + + /******************* Vertices ********************/ + Ref v = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mVertices, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); + if (v) p.attributes.position.push_back(v); + + /******************** Normals ********************/ + Ref n = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mNormals, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); + if (n) p.attributes.normal.push_back(n); + + /************** Texture coordinates **************/ + for (int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++i) { + // Flip UV y coords + if (aim -> mNumUVComponents[i] > 1) { + for (unsigned int j = 0; j < aim->mNumVertices; ++j) { + aim->mTextureCoords[i][j].y = 1 - aim->mTextureCoords[i][j].y; + } + } + + if (aim->mNumUVComponents[i] > 0) { + AttribType::Value type = (aim->mNumUVComponents[i] == 2) ? AttribType::VEC2 : AttribType::VEC3; + + Ref tc = ExportData(*mAsset, meshId, b, aim->mNumVertices, aim->mTextureCoords[i], AttribType::VEC3, type, ComponentType_FLOAT, false); + if (tc) p.attributes.texcoord.push_back(tc); + } + } + + /*************** Vertices indices ****************/ + if (aim->mNumFaces > 0) { + std::vector indices; + unsigned int nIndicesPerFace = aim->mFaces[0].mNumIndices; + indices.resize(aim->mNumFaces * nIndicesPerFace); + for (size_t i = 0; i < aim->mNumFaces; ++i) { + for (size_t j = 0; j < nIndicesPerFace; ++j) { + indices[i*nIndicesPerFace + j] = uint16_t(aim->mFaces[i].mIndices[j]); + } + } + + p.indices = ExportData(*mAsset, meshId, b, unsigned(indices.size()), &indices[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_UNSIGNED_SHORT, true); + } + + switch (aim->mPrimitiveTypes) { + case aiPrimitiveType_POLYGON: + p.mode = PrimitiveMode_TRIANGLES; break; // TODO implement this + case aiPrimitiveType_LINE: + p.mode = PrimitiveMode_LINES; break; + case aiPrimitiveType_POINT: + p.mode = PrimitiveMode_POINTS; break; + default: // aiPrimitiveType_TRIANGLE + p.mode = PrimitiveMode_TRIANGLES; + } + + /*************** Skins ****************/ + if(aim->HasBones()) { + ExportSkin(*mAsset, aim, m, b, skinRef, inverseBindMatricesData); + } + } + + //---------------------------------------- + // Finish the skin + // Create the Accessor for skinRef->inverseBindMatrices + if (createSkin) { + mat4* invBindMatrixData = new mat4[inverseBindMatricesData.size()]; + for ( unsigned int idx_joint = 0; idx_joint < inverseBindMatricesData.size(); ++idx_joint) { + 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; + + // Identity Matrix =====> skinRef->bindShapeMatrix + // Temporary. Hard-coded identity matrix here + skinRef->bindShapeMatrix.isPresent = true; + IdentityMatrix4(skinRef->bindShapeMatrix.value); + + // Find nodes that contain a mesh with bones and add "skeletons" and "skin" attributes to those nodes. + Ref rootNode = mAsset->nodes.Get(unsigned(0)); + Ref meshNode; + for (unsigned int meshIndex = 0; meshIndex < mAsset->meshes.Size(); ++meshIndex) { + Ref mesh = mAsset->meshes.Get(meshIndex); + bool hasBones = false; + for (unsigned int i = 0; i < mesh->primitives.size(); ++i) { + if (!mesh->primitives[i].attributes.weight.empty()) { + hasBones = true; + break; + } + } + if (!hasBones) { + continue; + } + std::string meshID = mesh->id; + FindMeshNode(rootNode, meshNode, meshID); + Ref rootJoint = FindSkeletonRootJoint(skinRef); + meshNode->skeletons.push_back(rootJoint); + meshNode->skin = skinRef; + } + } +} + +//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) { + Ref node = mAsset->nodes.Get(n); + + unsigned int nMeshes = static_cast(node->meshes.size()); + + //skip if it's 1 or less meshes per node + if (nMeshes > 1) { + Ref firstMesh = node->meshes.at(0); + + //loop backwards to allow easy removal of a mesh from a node once it's merged + for (unsigned int m = nMeshes - 1; m >= 1; --m) { + Ref mesh = node->meshes.at(m); + + firstMesh->primitives.insert(firstMesh->primitives.end(), mesh->primitives.begin(), mesh->primitives.end()); + + node->meshes.erase(node->meshes.begin() + m); + } + + //since we were looping backwards, reverse the order of merged primitives to their original order + std::reverse(firstMesh->primitives.begin() + 1, firstMesh->primitives.end()); + } + } +} + +/* + * Export the root node of the node hierarchy. + * Calls ExportNode for all children. + */ +unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode* n) +{ + Ref node = mAsset->nodes.Create(mAsset->FindUniqueID(n->mName.C_Str(), "node")); + + if (!n->mTransformation.IsIdentity()) { + node->matrix.isPresent = true; + CopyValue(n->mTransformation, node->matrix.value); + } + + for (unsigned int i = 0; i < n->mNumMeshes; ++i) { + node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i])); + } + + for (unsigned int i = 0; i < n->mNumChildren; ++i) { + unsigned int idx = ExportNode(n->mChildren[i], node); + node->children.push_back(mAsset->nodes.Get(idx)); + } + + return node.GetIndex(); +} + +/* + * Export node and recursively calls ExportNode for all children. + * Since these nodes are not the root node, we also export the parent Ref + */ +unsigned int glTF2Exporter::ExportNode(const aiNode* n, Ref& parent) +{ + std::string name = mAsset->FindUniqueID(n->mName.C_Str(), "node"); + Ref node = mAsset->nodes.Create(name); + + node->parent = parent; + node->name = name; + + if (!n->mTransformation.IsIdentity()) { + node->matrix.isPresent = true; + CopyValue(n->mTransformation, node->matrix.value); + } + + for (unsigned int i = 0; i < n->mNumMeshes; ++i) { + node->meshes.push_back(mAsset->meshes.Get(n->mMeshes[i])); + } + + for (unsigned int i = 0; i < n->mNumChildren; ++i) { + unsigned int idx = ExportNode(n->mChildren[i], node); + node->children.push_back(mAsset->nodes.Get(idx)); + } + + return node.GetIndex(); +} + + +void glTF2Exporter::ExportScene() +{ + const char* sceneName = "defaultScene"; + Ref scene = mAsset->scenes.Create(sceneName); + + // root node will be the first one exported (idx 0) + if (mAsset->nodes.Size() > 0) { + scene->nodes.push_back(mAsset->nodes.Get(0u)); + } + + // set as the default scene + mAsset->scene = scene; +} + +void glTF2Exporter::ExportMetadata() +{ + AssetMetadata& asset = mAsset->asset; + asset.version = "2.0"; + + char buffer[256]; + ai_snprintf(buffer, 256, "Open Asset Import Library (assimp v%d.%d.%d)", + aiGetVersionMajor(), aiGetVersionMinor(), aiGetVersionRevision()); + + asset.generator = buffer; +} + +inline void ExtractAnimationData(Asset& mAsset, std::string& animId, Ref& animRef, Ref& buffer, const aiNodeAnim* nodeChannel, float ticksPerSecond) +{ + // Loop over the data and check to see if it exactly matches an existing buffer. + // If yes, then reference the existing corresponding accessor. + // Otherwise, add to the buffer and create a new accessor. + + size_t counts[3] = { + nodeChannel->mNumPositionKeys, + nodeChannel->mNumScalingKeys, + nodeChannel->mNumRotationKeys, + }; + size_t numKeyframes = 1; + for (int i = 0; i < 3; ++i) { + if (counts[i] > numKeyframes) { + numKeyframes = counts[i]; + } + } + + //------------------------------------------------------- + // Extract TIME parameter data. + // Check if the timeStamps are the same for mPositionKeys, mRotationKeys, and mScalingKeys. + if(nodeChannel->mNumPositionKeys > 0) { + typedef float TimeType; + std::vector timeData; + timeData.resize(numKeyframes); + for (size_t i = 0; i < numKeyframes; ++i) { + size_t frameIndex = i * nodeChannel->mNumPositionKeys / numKeyframes; + // mTime is measured in ticks, but GLTF time is measured in seconds, so convert. + // Check if we have to cast type here. e.g. uint16_t() + timeData[i] = static_cast(nodeChannel->mPositionKeys[frameIndex].mTime / ticksPerSecond); + } + + Ref timeAccessor = ExportData(mAsset, animId, buffer, static_cast(numKeyframes), &timeData[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_FLOAT); + if (timeAccessor) animRef->Parameters.TIME = timeAccessor; + } + + //------------------------------------------------------- + // Extract translation parameter data + if(nodeChannel->mNumPositionKeys > 0) { + C_STRUCT aiVector3D* translationData = new aiVector3D[numKeyframes]; + for (size_t i = 0; i < numKeyframes; ++i) { + size_t frameIndex = i * nodeChannel->mNumPositionKeys / numKeyframes; + translationData[i] = nodeChannel->mPositionKeys[frameIndex].mValue; + } + + Ref tranAccessor = ExportData(mAsset, animId, buffer, static_cast(numKeyframes), translationData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); + if ( tranAccessor ) { + animRef->Parameters.translation = tranAccessor; + } + delete[] translationData; + } + + //------------------------------------------------------- + // Extract scale parameter data + if(nodeChannel->mNumScalingKeys > 0) { + C_STRUCT aiVector3D* scaleData = new aiVector3D[numKeyframes]; + for (size_t i = 0; i < numKeyframes; ++i) { + size_t frameIndex = i * nodeChannel->mNumScalingKeys / numKeyframes; + scaleData[i] = nodeChannel->mScalingKeys[frameIndex].mValue; + } + + Ref scaleAccessor = ExportData(mAsset, animId, buffer, static_cast(numKeyframes), scaleData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); + if ( scaleAccessor ) { + animRef->Parameters.scale = scaleAccessor; + } + delete[] scaleData; + } + + //------------------------------------------------------- + // Extract rotation parameter data + if(nodeChannel->mNumRotationKeys > 0) { + vec4* rotationData = new vec4[numKeyframes]; + for (size_t i = 0; i < numKeyframes; ++i) { + size_t frameIndex = i * nodeChannel->mNumRotationKeys / numKeyframes; + rotationData[i][0] = nodeChannel->mRotationKeys[frameIndex].mValue.x; + rotationData[i][1] = nodeChannel->mRotationKeys[frameIndex].mValue.y; + rotationData[i][2] = nodeChannel->mRotationKeys[frameIndex].mValue.z; + rotationData[i][3] = nodeChannel->mRotationKeys[frameIndex].mValue.w; + } + + Ref rotAccessor = ExportData(mAsset, animId, buffer, static_cast(numKeyframes), rotationData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT); + if ( rotAccessor ) { + animRef->Parameters.rotation = rotAccessor; + } + delete[] rotationData; + } +} + +void glTF2Exporter::ExportAnimations() +{ + Ref bufferRef = mAsset->buffers.Get(unsigned (0)); + + for (unsigned int i = 0; i < mScene->mNumAnimations; ++i) { + const aiAnimation* anim = mScene->mAnimations[i]; + + std::string nameAnim = "anim"; + if (anim->mName.length > 0) { + nameAnim = anim->mName.C_Str(); + } + + for (unsigned int channelIndex = 0; channelIndex < anim->mNumChannels; ++channelIndex) { + const aiNodeAnim* nodeChannel = anim->mChannels[channelIndex]; + + // It appears that assimp stores this type of animation as multiple animations. + // where each aiNodeAnim in mChannels animates a specific node. + std::string name = nameAnim + "_" + to_string(channelIndex); + name = mAsset->FindUniqueID(name, "animation"); + Ref animRef = mAsset->animations.Create(name); + + // Parameters + ExtractAnimationData(*mAsset, name, animRef, bufferRef, nodeChannel, static_cast(anim->mTicksPerSecond)); + + for (unsigned int j = 0; j < 3; ++j) { + std::string channelType; + int channelSize; + switch (j) { + case 0: + channelType = "rotation"; + channelSize = nodeChannel->mNumRotationKeys; + break; + case 1: + channelType = "scale"; + channelSize = nodeChannel->mNumScalingKeys; + break; + case 2: + channelType = "translation"; + channelSize = nodeChannel->mNumPositionKeys; + break; + } + + if (channelSize < 1) { continue; } + + Animation::AnimChannel tmpAnimChannel; + Animation::AnimSampler tmpAnimSampler; + + tmpAnimChannel.sampler = static_cast(animRef->Samplers.size()); + tmpAnimChannel.target.path = channelType; + tmpAnimSampler.output = channelType; + tmpAnimSampler.id = name + "_" + channelType; + + tmpAnimChannel.target.node = mAsset->nodes.Get(nodeChannel->mNodeName.C_Str()); + + tmpAnimSampler.input = "TIME"; + tmpAnimSampler.interpolation = "LINEAR"; + + animRef->Channels.push_back(tmpAnimChannel); + animRef->Samplers.push_back(tmpAnimSampler); + } + + } + + // Assimp documentation staes this is not used (not implemented) + // for (unsigned int channelIndex = 0; channelIndex < anim->mNumMeshChannels; ++channelIndex) { + // const aiMeshAnim* meshChannel = anim->mMeshChannels[channelIndex]; + // } + + } // End: for-loop mNumAnimations +} + + +#endif // ASSIMP_BUILD_NO_GLTF_EXPORTER +#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/code/glTF2Exporter.h b/code/glTF2Exporter.h new file mode 100644 index 000000000..3aed35ae6 --- /dev/null +++ b/code/glTF2Exporter.h @@ -0,0 +1,134 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 GltfExporter.h +* Declares the exporter class to write a scene to a gltf/glb file +*/ +#ifndef AI_GLTF2EXPORTER_H_INC +#define AI_GLTF2EXPORTER_H_INC + +#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER + +#include +#include + +#include +#include +#include +#include + +struct aiScene; +struct aiNode; +struct aiMaterial; + +namespace glTF2 +{ + template + class Ref; + + class Asset; + struct TexProperty; + struct TextureInfo; + struct NormalTextureInfo; + struct OcclusionTextureInfo; + struct Node; + struct Texture; + + // Vec/matrix types, as raw float arrays + typedef float (vec3)[3]; + typedef float (vec4)[4]; +} + +namespace Assimp +{ + class IOSystem; + class IOStream; + class ExportProperties; + + // ------------------------------------------------------------------------------------------------ + /** Helper class to export a given scene to an glTF file. */ + // ------------------------------------------------------------------------------------------------ + class glTF2Exporter + { + public: + /// Constructor for a specific scene to export + glTF2Exporter(const char* filename, IOSystem* pIOSystem, const aiScene* pScene, + const ExportProperties* pProperties, bool binary); + + private: + + const char* mFilename; + IOSystem* mIOSystem; + const aiScene* mScene; + const ExportProperties* mProperties; + + std::map mTexturesByPath; + + std::shared_ptr mAsset; + + std::vector mBodyData; + + void WriteBinaryData(IOStream* outfile, std::size_t sceneLength); + + void GetTexSampler(const aiMaterial* mat, glTF2::Ref texture, aiTextureType tt, unsigned int slot); + void GetMatTexProp(const aiMaterial* mat, unsigned int& prop, const char* propName, aiTextureType tt, unsigned int idx); + void GetMatTexProp(const aiMaterial* mat, float& prop, const char* propName, aiTextureType tt, unsigned int idx); + void GetMatTex(const aiMaterial* mat, glTF2::Ref& texture, aiTextureType tt, unsigned int slot); + void GetMatTex(const aiMaterial* mat, glTF2::TextureInfo& prop, aiTextureType tt, unsigned int slot); + void GetMatTex(const aiMaterial* mat, glTF2::NormalTextureInfo& prop, aiTextureType tt, unsigned int slot); + void GetMatTex(const aiMaterial* mat, glTF2::OcclusionTextureInfo& prop, aiTextureType tt, unsigned int slot); + void GetMatColor(const aiMaterial* mat, glTF2::vec4& prop, const char* propName, int type, int idx); + void GetMatColor(const aiMaterial* mat, glTF2::vec3& prop, const char* propName, int type, int idx); + void ExportMetadata(); + void ExportMaterials(); + void ExportMeshes(); + void MergeMeshes(); + unsigned int ExportNodeHierarchy(const aiNode* n); + unsigned int ExportNode(const aiNode* node, glTF2::Ref& parent); + void ExportScene(); + void ExportAnimations(); + }; + +} + +#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER + +#endif // AI_GLTF2EXPORTER_H_INC diff --git a/code/glTF2Importer.cpp b/code/glTF2Importer.cpp new file mode 100644 index 000000000..de9f39050 --- /dev/null +++ b/code/glTF2Importer.cpp @@ -0,0 +1,654 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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_GLTF_IMPORTER + +#include "glTF2Importer.h" +#include "StringComparison.h" +#include "StringUtils.h" + +#include +#include +#include +#include +#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; + + +// +// glTF2Importer +// + +static const aiImporterDesc desc = { + "glTF2 Importer", + "", + "", + "", + aiImporterFlags_SupportTextFlavour | aiImporterFlags_LimitedSupport | aiImporterFlags_Experimental, + 0, + 0, + 0, + 0, + "gltf glb" +}; + +glTF2Importer::glTF2Importer() +: BaseImporter() +, meshOffsets() +, embeddedTexIdxs() +, mScene( NULL ) { + // empty +} + +glTF2Importer::~glTF2Importer() { + // empty +} + +const aiImporterDesc* glTF2Importer::GetInfo() const +{ + return &desc; +} + +bool glTF2Importer::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const +{ + const std::string &extension = GetExtension(pFile); + + if (extension != "gltf") // We currently can't read glTF2 binary files (.glb), yet + return false; + + if (checkSig && pIOHandler) { + glTF2::Asset asset(pIOHandler); + try { + asset.Load(pFile); + std::string version = asset.asset.version; + return !version.empty() && version[0] == '2'; + } catch (...) { + return false; + } + } + + return false; +} + + +//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) +{ + out.r = v[0]; out.g = v[1]; out.b = v[2]; out.a = 1.0; +} + +static void CopyValue(const glTF2::vec3& v, aiVector3D& out) +{ + out.x = v[0]; out.y = v[1]; out.z = v[2]; +} + +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) +{ + 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) +{ + aiColor4D col; + CopyValue(prop, col); + mat->AddProperty(&col, 1, pKey, type, idx); +} + +inline void SetMaterialColorProperty(Asset& r, vec3& prop, aiMaterial* mat, const char* pKey, unsigned int type, unsigned int idx) +{ + aiColor4D col; + CopyValue(prop, col); + mat->AddProperty(&col, 1, pKey, type, idx); +} + +inline void SetMaterialTextureProperty(std::vector& embeddedTexIdxs, Asset& r, glTF2::TextureInfo prop, aiMaterial* mat, aiTextureType texType, unsigned int texSlot = 0) +{ + if (prop.texture && prop.texture->source) { + aiString uri(prop.texture->source->uri); + + int texIdx = embeddedTexIdxs[prop.texture->source.GetIndex()]; + if (texIdx != -1) { // embedded + // setup texture reference string (copied from ColladaLoader::FindFilenameForEffectTexture) + uri.data[0] = '*'; + uri.length = 1 + ASSIMP_itoa10(uri.data + 1, MAXLEN - 1, texIdx); + } + + mat->AddProperty(&uri, AI_MATKEY_TEXTURE(texType, texSlot)); + mat->AddProperty(&prop.texCoord, 1, _AI_MATKEY_GLTF_TEXTURE_TEXCOORD_BASE, texType, texSlot); + + if (prop.texture->sampler) { + Ref sampler = prop.texture->sampler; + + aiString name(sampler->name); + aiString id(sampler->id); + + mat->AddProperty(&name, AI_MATKEY_GLTF_MAPPINGNAME(texType, texSlot)); + mat->AddProperty(&id, AI_MATKEY_GLTF_MAPPINGID(texType, texSlot)); + + mat->AddProperty(&sampler->wrapS, 1, AI_MATKEY_MAPPINGMODE_U(texType, texSlot)); + mat->AddProperty(&sampler->wrapT, 1, AI_MATKEY_MAPPINGMODE_V(texType, texSlot)); + + if (sampler->magFilter != SamplerMagFilter::UNSET) { + mat->AddProperty(&sampler->magFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MAG(texType, texSlot)); + } + + if (sampler->minFilter != SamplerMinFilter::UNSET) { + mat->AddProperty(&sampler->minFilter, 1, AI_MATKEY_GLTF_MAPPINGFILTER_MIN(texType, texSlot)); + } + } + } +} + +void glTF2Importer::ImportMaterials(glTF2::Asset& r) +{ + mScene->mNumMaterials = unsigned(r.materials.Size()); + mScene->mMaterials = new aiMaterial*[mScene->mNumMaterials]; + + for (unsigned int i = 0; i < mScene->mNumMaterials; ++i) { + aiMaterial* aimat = mScene->mMaterials[i] = new aiMaterial(); + + Material& mat = r.materials[i]; + + if (!mat.name.empty()) { + aiString str(mat.name); + + aimat->AddProperty(&str, AI_MATKEY_NAME); + } + + SetMaterialColorProperty(r, mat.pbrMetallicRoughness.baseColorFactor, aimat, AI_MATKEY_COLOR_DIFFUSE); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.baseColorTexture, aimat, aiTextureType_DIFFUSE); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.pbrMetallicRoughness.metallicRoughnessTexture, aimat, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE); + aimat->AddProperty(&mat.pbrMetallicRoughness.metallicFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLIC_FACTOR); + aimat->AddProperty(&mat.pbrMetallicRoughness.roughnessFactor, 1, AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_ROUGHNESS_FACTOR); + + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.normalTexture, aimat, aiTextureType_NORMALS); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.occlusionTexture, aimat, aiTextureType_LIGHTMAP); + SetMaterialTextureProperty(embeddedTexIdxs, r, mat.emissiveTexture, aimat, aiTextureType_EMISSIVE); + SetMaterialColorProperty(r, mat.emissiveFactor, aimat, AI_MATKEY_COLOR_EMISSIVE); + + aimat->AddProperty(&mat.doubleSided, 1, AI_MATKEY_TWOSIDED); + + aiString alphaMode(mat.alphaMode); + aimat->AddProperty(&alphaMode, AI_MATKEY_GLTF_ALPHAMODE); + aimat->AddProperty(&mat.alphaCutoff, 1, AI_MATKEY_GLTF_ALPHACUTOFF); + + //pbrSpecularGlossiness + if (mat.pbrSpecularGlossiness.isPresent) { + PbrSpecularGlossiness &pbrSG = mat.pbrSpecularGlossiness.value; + + aimat->AddProperty(&mat.pbrSpecularGlossiness.isPresent, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS); + SetMaterialColorProperty(r, pbrSG.diffuseFactor, aimat, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_FACTOR); + SetMaterialColorProperty(r, pbrSG.specularFactor, aimat, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULAR_FACTOR); + aimat->AddProperty(&pbrSG.glossinessFactor, 1, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_GLOSSINESS_FACTOR); + SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.diffuseTexture, aimat, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_DIFFUSE_TEXTURE); + SetMaterialTextureProperty(embeddedTexIdxs, r, pbrSG.specularGlossinessTexture, aimat, AI_MATKEY_GLTF_PBRSPECULARGLOSSINESS_SPECULARGLOSSINESS_TEXTURE); + } + } +} + + +static inline void SetFace(aiFace& face, int a) +{ + face.mNumIndices = 1; + face.mIndices = new unsigned int[1]; + face.mIndices[0] = a; +} + +static inline void SetFace(aiFace& face, int a, int b) +{ + face.mNumIndices = 2; + face.mIndices = new unsigned int[2]; + face.mIndices[0] = a; + face.mIndices[1] = b; +} + +static inline void SetFace(aiFace& face, int a, int b, int c) +{ + face.mNumIndices = 3; + face.mIndices = new unsigned int[3]; + face.mIndices[0] = a; + face.mIndices[1] = b; + face.mIndices[2] = c; +} + +static inline bool CheckValidFacesIndices(aiFace* faces, unsigned nFaces, unsigned nVerts) +{ + for (unsigned i = 0; i < nFaces; ++i) { + for (unsigned j = 0; j < faces[i].mNumIndices; ++j) { + unsigned idx = faces[i].mIndices[j]; + if (idx >= nVerts) + return false; + } + } + return true; +} + +void glTF2Importer::ImportMeshes(glTF2::Asset& r) +{ + std::vector meshes; + + unsigned int k = 0; + + for (unsigned int m = 0; m < r.meshes.Size(); ++m) { + Mesh& mesh = r.meshes[m]; + + meshOffsets.push_back(k); + k += unsigned(mesh.primitives.size()); + + for (unsigned int p = 0; p < mesh.primitives.size(); ++p) { + Mesh::Primitive& prim = mesh.primitives[p]; + + aiMesh* aim = new aiMesh(); + meshes.push_back(aim); + + aim->mName = mesh.name.empty() ? mesh.id : mesh.name; + + if (mesh.primitives.size() > 1) { + size_t& len = aim->mName.length; + aim->mName.data[len] = '-'; + len += 1 + ASSIMP_itoa10(aim->mName.data + len + 1, unsigned(MAXLEN - len - 1), p); + } + + switch (prim.mode) { + case PrimitiveMode_POINTS: + aim->mPrimitiveTypes |= aiPrimitiveType_POINT; + break; + + case PrimitiveMode_LINES: + case PrimitiveMode_LINE_LOOP: + case PrimitiveMode_LINE_STRIP: + aim->mPrimitiveTypes |= aiPrimitiveType_LINE; + break; + + case PrimitiveMode_TRIANGLES: + case PrimitiveMode_TRIANGLE_STRIP: + case PrimitiveMode_TRIANGLE_FAN: + aim->mPrimitiveTypes |= aiPrimitiveType_TRIANGLE; + break; + + } + + Mesh::Primitive::Attributes& attr = prim.attributes; + + if (attr.position.size() > 0 && attr.position[0]) { + aim->mNumVertices = attr.position[0]->count; + attr.position[0]->ExtractData(aim->mVertices); + } + + if (attr.normal.size() > 0 && attr.normal[0]) attr.normal[0]->ExtractData(aim->mNormals); + + for (size_t tc = 0; tc < attr.texcoord.size() && tc < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++tc) { + attr.texcoord[tc]->ExtractData(aim->mTextureCoords[tc]); + aim->mNumUVComponents[tc] = attr.texcoord[tc]->GetNumComponents(); + + aiVector3D* values = aim->mTextureCoords[tc]; + for (unsigned int i = 0; i < aim->mNumVertices; ++i) { + values[i].y = 1 - values[i].y; // Flip Y coords + } + } + + + if (prim.indices) { + aiFace* faces = 0; + unsigned int nFaces = 0; + + unsigned int count = prim.indices->count; + + Accessor::Indexer data = prim.indices->GetIndexer(); + ai_assert(data.IsValid()); + + switch (prim.mode) { + case PrimitiveMode_POINTS: { + nFaces = count; + faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; ++i) { + SetFace(faces[i], data.GetUInt(i)); + } + break; + } + + case PrimitiveMode_LINES: { + nFaces = count / 2; + faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; i += 2) { + SetFace(faces[i / 2], data.GetUInt(i), data.GetUInt(i + 1)); + } + break; + } + + case PrimitiveMode_LINE_LOOP: + case PrimitiveMode_LINE_STRIP: { + nFaces = count - ((prim.mode == PrimitiveMode_LINE_STRIP) ? 1 : 0); + faces = new aiFace[nFaces]; + SetFace(faces[0], data.GetUInt(0), data.GetUInt(1)); + for (unsigned int i = 2; i < count; ++i) { + SetFace(faces[i - 1], faces[i - 2].mIndices[1], data.GetUInt(i)); + } + if (prim.mode == PrimitiveMode_LINE_LOOP) { // close the loop + SetFace(faces[count - 1], faces[count - 2].mIndices[1], faces[0].mIndices[0]); + } + break; + } + + case PrimitiveMode_TRIANGLES: { + nFaces = count / 3; + faces = new aiFace[nFaces]; + for (unsigned int i = 0; i < count; i += 3) { + SetFace(faces[i / 3], data.GetUInt(i), data.GetUInt(i + 1), data.GetUInt(i + 2)); + } + break; + } + case PrimitiveMode_TRIANGLE_STRIP: { + nFaces = count - 2; + faces = new aiFace[nFaces]; + SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2)); + for (unsigned int i = 3; i < count; ++i) { + SetFace(faces[i - 2], faces[i - 1].mIndices[1], faces[i - 1].mIndices[2], data.GetUInt(i)); + } + break; + } + case PrimitiveMode_TRIANGLE_FAN: + nFaces = count - 2; + faces = new aiFace[nFaces]; + SetFace(faces[0], data.GetUInt(0), data.GetUInt(1), data.GetUInt(2)); + for (unsigned int i = 3; i < count; ++i) { + SetFace(faces[i - 2], faces[0].mIndices[0], faces[i - 1].mIndices[2], data.GetUInt(i)); + } + break; + } + + if (faces) { + aim->mFaces = faces; + aim->mNumFaces = nFaces; + ai_assert(CheckValidFacesIndices(faces, nFaces, aim->mNumVertices)); + } + } + + + if (prim.material) { + aim->mMaterialIndex = prim.material.GetIndex(); + } + } + } + + meshOffsets.push_back(k); + + CopyVector(meshes, mScene->mMeshes, mScene->mNumMeshes); +} + +void glTF2Importer::ImportCameras(glTF2::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.cameraProperties.perspective.aspectRatio; + aicam->mHorizontalFOV = cam.cameraProperties.perspective.yfov * aicam->mAspect; + aicam->mClipPlaneFar = cam.cameraProperties.perspective.zfar; + aicam->mClipPlaneNear = cam.cameraProperties.perspective.znear; + } + else { + // assimp does not support orthographic cameras + } + } +} + +aiNode* ImportNode(aiScene* pScene, glTF2::Asset& r, std::vector& meshOffsets, glTF2::Ref& ptr) +{ + Node& node = *ptr; + + aiNode* ainode = new aiNode(node.id); + + if (!node.children.empty()) { + ainode->mNumChildren = unsigned(node.children.size()); + ainode->mChildren = new aiNode*[ainode->mNumChildren]; + + for (unsigned int i = 0; i < ainode->mNumChildren; ++i) { + aiNode* child = ImportNode(pScene, r, meshOffsets, node.children[i]); + child->mParent = ainode; + ainode->mChildren[i] = child; + } + } + + aiMatrix4x4& matrix = ainode->mTransformation; + if (node.matrix.isPresent) { + CopyValue(node.matrix.value, matrix); + } + else { + if (node.translation.isPresent) { + aiVector3D trans; + CopyValue(node.translation.value, trans); + aiMatrix4x4 t; + aiMatrix4x4::Translation(trans, t); + matrix = t * matrix; + } + + if (node.scale.isPresent) { + aiVector3D scal(1.f); + CopyValue(node.scale.value, scal); + aiMatrix4x4 s; + aiMatrix4x4::Scaling(scal, s); + matrix = s * matrix; + } + + + if (node.rotation.isPresent) { + aiQuaternion rot; + CopyValue(node.rotation.value, rot); + matrix = aiMatrix4x4(rot.GetMatrix()) * matrix; + } + } + + if (!node.meshes.empty()) { + int count = 0; + for (size_t i = 0; i < node.meshes.size(); ++i) { + int idx = node.meshes[i].GetIndex(); + count += meshOffsets[idx + 1] - meshOffsets[idx]; + } + ainode->mNumMeshes = count; + + ainode->mMeshes = new unsigned int[count]; + + int k = 0; + for (size_t i = 0; i < node.meshes.size(); ++i) { + int idx = node.meshes[i].GetIndex(); + for (unsigned int j = meshOffsets[idx]; j < meshOffsets[idx + 1]; ++j, ++k) { + ainode->mMeshes[k] = j; + } + } + } + + if (node.camera) { + pScene->mCameras[node.camera.GetIndex()]->mName = ainode->mName; + } + + return ainode; +} + +void glTF2Importer::ImportNodes(glTF2::Asset& r) +{ + if (!r.scene) return; + + std::vector< Ref > rootNodes = r.scene->nodes; + + // The root nodes + unsigned int numRootNodes = unsigned(rootNodes.size()); + if (numRootNodes == 1) { // a single root node: use it + mScene->mRootNode = ImportNode(mScene, r, meshOffsets, rootNodes[0]); + } + else if (numRootNodes > 1) { // more than one root node: create a fake root + aiNode* root = new aiNode("ROOT"); + root->mChildren = new aiNode*[numRootNodes]; + for (unsigned int i = 0; i < numRootNodes; ++i) { + aiNode* node = ImportNode(mScene, r, meshOffsets, rootNodes[i]); + node->mParent = root; + root->mChildren[root->mNumChildren++] = node; + } + mScene->mRootNode = root; + } + + //if (!mScene->mRootNode) { + // mScene->mRootNode = new aiNode("EMPTY"); + //} +} + +void glTF2Importer::ImportEmbeddedTextures(glTF2::Asset& r) +{ + embeddedTexIdxs.resize(r.images.Size(), -1); + + int numEmbeddedTexs = 0; + for (size_t i = 0; i < r.images.Size(); ++i) { + if (r.images[i].HasData()) + numEmbeddedTexs += 1; + } + + if (numEmbeddedTexs == 0) + return; + + mScene->mTextures = new aiTexture*[numEmbeddedTexs]; + + // Add the embedded textures + for (size_t i = 0; i < r.images.Size(); ++i) { + Image img = r.images[i]; + if (!img.HasData()) continue; + + int idx = mScene->mNumTextures++; + embeddedTexIdxs[i] = idx; + + aiTexture* tex = mScene->mTextures[idx] = new aiTexture(); + + size_t length = img.GetDataLength(); + void* data = img.StealData(); + + tex->mWidth = static_cast(length); + tex->mHeight = 0; + tex->pcData = reinterpret_cast(data); + + if (!img.mimeType.empty()) { + const char* ext = strchr(img.mimeType.c_str(), '/') + 1; + if (ext) { + if (strcmp(ext, "jpeg") == 0) ext = "jpg"; + + size_t len = strlen(ext); + if (len <= 3) { + strcpy(tex->achFormatHint, ext); + } + } + } + } +} + +void glTF2Importer::InternReadFile(const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) { + + this->mScene = pScene; + + // read the asset file + glTF2::Asset asset(pIOHandler); + asset.Load(pFile); + + // + // Copy the data out + // + + ImportEmbeddedTextures(asset); + ImportMaterials(asset); + + ImportMeshes(asset); + + ImportCameras(asset); + + ImportNodes(asset); + + // TODO: it does not split the loaded vertices, should it? + //pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; + MakeVerboseFormatProcess process; + process.Execute(pScene); + + + if (pScene->mNumMeshes == 0) { + pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; + } +} + +#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER + diff --git a/code/glTF2Importer.h b/code/glTF2Importer.h new file mode 100644 index 000000000..6be7131d1 --- /dev/null +++ b/code/glTF2Importer.h @@ -0,0 +1,91 @@ +/* +Open Asset Import Library (assimp) +---------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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_GLTF2IMPORTER_H_INC +#define AI_GLTF2IMPORTER_H_INC + +#include "BaseImporter.h" +#include + +struct aiNode; + + +namespace glTF2 +{ + class Asset; +} + +namespace Assimp { + +/** + * Load the glTF2 format. + * https://github.com/KhronosGroup/glTF/tree/master/specification + */ +class glTF2Importer : public BaseImporter{ +public: + glTF2Importer(); + virtual ~glTF2Importer(); + virtual bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig ) const; + +protected: + virtual const aiImporterDesc* GetInfo() const; + virtual void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler ); + +private: + + std::vector meshOffsets; + + std::vector embeddedTexIdxs; + + aiScene* mScene; + + void ImportEmbeddedTextures(glTF2::Asset& a); + void ImportMaterials(glTF2::Asset& a); + void ImportMeshes(glTF2::Asset& a); + void ImportCameras(glTF2::Asset& a); + void ImportLights(glTF2::Asset& a); + void ImportNodes(glTF2::Asset& a); + +}; + +} // Namespace assimp + +#endif // AI_GLTF2IMPORTER_H_INC + diff --git a/code/glTFAsset.h b/code/glTFAsset.h index 1419fc11e..e018e5ace 100644 --- a/code/glTFAsset.h +++ b/code/glTFAsset.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -45,8 +46,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * KHR_binary_glTF: full * KHR_materials_common: full */ -#ifndef glTFAsset_H_INC -#define glTFAsset_H_INC +#ifndef GLTFASSET_H_INC +#define GLTFASSET_H_INC + +#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER #include #include @@ -229,7 +232,9 @@ namespace glTF case ComponentType_UNSIGNED_BYTE: return 1; default: - throw DeadlyImportError("GLTF: Unsupported Component Type "+t); + std::string err = "GLTF: Unsupported Component Type "; + err += t; + throw DeadlyImportError(err); } } @@ -1055,13 +1060,13 @@ namespace glTF std::string version; //!< Specifies the target rendering API (default: "1.0.3") } profile; //!< Specifies the target rendering API and version, e.g., WebGL 1.0.3. (default: {}) - int version; //!< The glTF format version (should be 1) + std::string version; //!< The glTF format version (should be 1.0) void Read(Document& doc); AssetMetadata() : premultipliedAlpha(false) - , version(0) + , version("") { } }; @@ -1186,4 +1191,6 @@ namespace glTF // Include the implementation of the methods #include "glTFAsset.inl" -#endif +#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER + +#endif // GLTFASSET_H_INC diff --git a/code/glTFAsset.inl b/code/glTFAsset.inl index 4ec8c2ffe..61afebfb4 100644 --- a/code/glTFAsset.inl +++ b/code/glTFAsset.inl @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -39,6 +40,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "StringUtils.h" +#include // Header files, Assimp #include @@ -127,6 +129,12 @@ namespace { return (it != val.MemberEnd() && it->value.IsString()) ? &it->value : 0; } + inline Value* FindNumber(Value& val, const char* id) + { + Value::MemberIterator it = val.FindMember(id); + return (it != val.MemberEnd() && it->value.IsNumber()) ? &it->value : 0; + } + inline Value* FindArray(Value& val, const char* id) { Value::MemberIterator it = val.FindMember(id); @@ -308,7 +316,9 @@ inline void Buffer::Read(Value& obj, Asset& r) } else { // Local file if (byteLength > 0) { - IOStream* file = r.OpenFile(uri, "rb"); + std::string dir = !r.mCurrentAssetDir.empty() ? (r.mCurrentAssetDir + "/") : ""; + + IOStream* file = r.OpenFile(dir + uri, "rb"); if (file) { bool ok = LoadFromStream(*file, byteLength); delete file; @@ -331,7 +341,7 @@ inline bool Buffer::LoadFromStream(IOStream& stream, size_t length, size_t baseO stream.Seek(baseOffset, aiOrigin_SET); } - mData.reset(new uint8_t[byteLength]); + mData.reset(new uint8_t[byteLength], std::default_delete()); if (stream.Read(mData.get(), byteLength, 1) != 1) { return false; @@ -1227,13 +1237,21 @@ inline void Scene::Read(Value& obj, Asset& r) inline void AssetMetadata::Read(Document& doc) { // read the version, etc. - int statedVersion = 0; if (Value* obj = FindObject(doc, "asset")) { ReadMember(*obj, "copyright", copyright); ReadMember(*obj, "generator", generator); premultipliedAlpha = MemberOrDefault(*obj, "premultipliedAlpha", false); - statedVersion = MemberOrDefault(*obj, "version", 0); + + if (Value* versionString = FindString(*obj, "version")) { + version = versionString->GetString(); + } else if (Value* versionNumber = FindNumber (*obj, "version")) { + char buf[4]; + + ai_snprintf(buf, 4, "%.1f", versionNumber->GetDouble()); + + version = buf; + } if (Value* profile = FindObject(*obj, "profile")) { ReadMember(*profile, "api", this->profile.api); @@ -1241,16 +1259,8 @@ inline void AssetMetadata::Read(Document& doc) } } - version = std::max(statedVersion, version); - if (version == 0) { - // if missing version, we'll assume version 1... - version = 1; - } - - if (version != 1) { - char msg[128]; - ai_snprintf(msg, 128, "GLTF: Unsupported glTF version: %d", version); - throw DeadlyImportError(msg); + if (version.empty() || version[0] != '1') { + throw DeadlyImportError("GLTF: Unsupported glTF version: " + version); } } @@ -1272,7 +1282,7 @@ inline void Asset::ReadBinaryHeader(IOStream& stream) } AI_SWAP4(header.version); - asset.version = header.version; + asset.version = std::to_string(header.version); if (header.version != 1) { throw DeadlyImportError("GLTF: Unsupported binary glTF version"); } diff --git a/code/glTFAssetWriter.h b/code/glTFAssetWriter.h index 4d2d3c919..186d32a15 100644 --- a/code/glTFAssetWriter.h +++ b/code/glTFAssetWriter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -45,8 +46,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * KHR_binary_glTF: full * KHR_materials_common: full */ -#ifndef glTFAssetWriter_H_INC -#define glTFAssetWriter_H_INC +#ifndef GLTFASSETWRITER_H_INC +#define GLTFASSETWRITER_H_INC + +#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER #include "glTFAsset.h" @@ -87,4 +90,6 @@ public: // Include the implementation of the methods #include "glTFAssetWriter.inl" -#endif +#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER + +#endif // GLTFASSETWRITER_H_INC diff --git a/code/glTFAssetWriter.inl b/code/glTFAssetWriter.inl index 1e545b497..698f0ba8f 100644 --- a/code/glTFAssetWriter.inl +++ b/code/glTFAssetWriter.inl @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -605,13 +606,8 @@ namespace glTF { { Value asset; asset.SetObject(); - { - char versionChar[10]; - ai_snprintf(versionChar, sizeof(versionChar), "%d", mAsset.asset.version); - asset.AddMember("version", Value(versionChar, mAl).Move(), mAl); - - asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl); - } + asset.AddMember("version", Value(mAsset.asset.version, mAl).Move(), mAl); + asset.AddMember("generator", Value(mAsset.asset.generator, mAl).Move(), mAl); mDoc.AddMember("asset", asset, mAl); } diff --git a/code/glTFExporter.cpp b/code/glTFExporter.cpp index 36cca86ee..92abcc15c 100644 --- a/code/glTFExporter.cpp +++ b/code/glTFExporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -47,8 +48,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "ByteSwapper.h" #include "SplitLargeMeshes.h" -#include "SceneCombiner.h" +#include #include #include #include @@ -184,8 +185,11 @@ inline Ref ExportData(Asset& a, std::string& meshName, Ref& bu unsigned int bytesPerComp = ComponentTypeSize(compType); size_t offset = buffer->byteLength; + // make sure offset is correctly byte-aligned, as required by spec + size_t padding = offset % bytesPerComp; + offset += padding; size_t length = count * numCompsOut * bytesPerComp; - buffer->Grow(length); + buffer->Grow(length + padding); // bufferView Ref bv = a.bufferViews.Create(a.FindUniqueID(meshName, "view")); @@ -440,7 +444,7 @@ void ExportSkin(Asset& mAsset, const aiMesh* aimesh, Ref& meshRef, Ref nodeRef = mAsset.nodes.Get(aib->mName.C_Str()); nodeRef->jointName = nodeRef->id; - unsigned int jointNamesIndex; + unsigned int jointNamesIndex = 0; bool addJointToJointNames = true; for ( unsigned int idx_joint = 0; idx_joint < skinRef->jointNames.size(); ++idx_joint) { if (skinRef->jointNames[idx_joint]->jointName.compare(nodeRef->jointName) == 0) { @@ -465,11 +469,11 @@ void ExportSkin(Asset& mAsset, const aiMesh* aimesh, Ref& meshRef, RefmWeights[idx_weights].mWeight; // A vertex can only have at most four joint weights. Ignore all others. - if (jointsPerVertex[vertexId] > 3) { - continue; + if (jointsPerVertex[vertexId] > 3) { + continue; } - vertexJointData[vertexId][jointsPerVertex[vertexId]] = jointNamesIndex; + vertexJointData[vertexId][jointsPerVertex[vertexId]] = static_cast(jointNamesIndex); vertexWeightData[vertexId][jointsPerVertex[vertexId]] = vertWeight; jointsPerVertex[vertexId] += 1; @@ -503,7 +507,7 @@ void glTFExporter::ExportMeshes() // Variables needed for compression. BEGIN. // Indices, not pointers - because pointer to buffer is changing while writing to it. - size_t idx_srcdata_begin;// Index of buffer before writing mesh data. Also, index of begin of coordinates array in buffer. + size_t idx_srcdata_begin = 0; // Index of buffer before writing mesh data. Also, index of begin of coordinates array in buffer. size_t idx_srcdata_normal = SIZE_MAX;// Index of begin of normals array in buffer. SIZE_MAX - mean that mesh has no normals. std::vector idx_srcdata_tc;// Array of indices. Every index point to begin of texture coordinates array in buffer. size_t idx_srcdata_ind;// Index of begin of coordinates indices array in buffer. @@ -511,7 +515,7 @@ void glTFExporter::ExportMeshes() // Variables needed for compression. END. std::string fname = std::string(mFilename); - std::string bufferIdPrefix = fname.substr(0, fname.find(".")); + std::string bufferIdPrefix = fname.substr(0, fname.rfind(".gltf")); std::string bufferId = mAsset->FindUniqueID("", bufferIdPrefix.c_str()); Ref b = mAsset->GetBodyBuffer(); @@ -839,36 +843,52 @@ void glTFExporter::ExportMetadata() asset.generator = buffer; } -inline void ExtractAnimationData(Asset& mAsset, std::string& animId, Ref& animRef, Ref& buffer, const aiNodeAnim* nodeChannel) +inline void ExtractAnimationData(Asset& mAsset, std::string& animId, Ref& animRef, Ref& buffer, const aiNodeAnim* nodeChannel, float ticksPerSecond) { // Loop over the data and check to see if it exactly matches an existing buffer. // If yes, then reference the existing corresponding accessor. // Otherwise, add to the buffer and create a new accessor. + size_t counts[3] = { + nodeChannel->mNumPositionKeys, + nodeChannel->mNumScalingKeys, + nodeChannel->mNumRotationKeys, + }; + size_t numKeyframes = 1; + for (int i = 0; i < 3; ++i) { + if (counts[i] > numKeyframes) { + numKeyframes = counts[i]; + } + } + //------------------------------------------------------- // Extract TIME parameter data. // Check if the timeStamps are the same for mPositionKeys, mRotationKeys, and mScalingKeys. if(nodeChannel->mNumPositionKeys > 0) { typedef float TimeType; std::vector timeData; - timeData.resize(nodeChannel->mNumPositionKeys); - for (size_t i = 0; i < nodeChannel->mNumPositionKeys; ++i) { - timeData[i] = nodeChannel->mPositionKeys[i].mTime; // Check if we have to cast type here. e.g. uint16_t() + timeData.resize(numKeyframes); + for (size_t i = 0; i < numKeyframes; ++i) { + size_t frameIndex = i * nodeChannel->mNumPositionKeys / numKeyframes; + // mTime is measured in ticks, but GLTF time is measured in seconds, so convert. + // Check if we have to cast type here. e.g. uint16_t() + timeData[i] = static_cast(nodeChannel->mPositionKeys[frameIndex].mTime / ticksPerSecond); } - Ref timeAccessor = ExportData(mAsset, animId, buffer, nodeChannel->mNumPositionKeys, &timeData[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_FLOAT); + Ref timeAccessor = ExportData(mAsset, animId, buffer, static_cast(numKeyframes), &timeData[0], AttribType::SCALAR, AttribType::SCALAR, ComponentType_FLOAT); if (timeAccessor) animRef->Parameters.TIME = timeAccessor; } //------------------------------------------------------- // Extract translation parameter data if(nodeChannel->mNumPositionKeys > 0) { - C_STRUCT aiVector3D* translationData = new aiVector3D[nodeChannel->mNumPositionKeys]; - for (size_t i = 0; i < nodeChannel->mNumPositionKeys; ++i) { - translationData[i] = nodeChannel->mPositionKeys[i].mValue; + C_STRUCT aiVector3D* translationData = new aiVector3D[numKeyframes]; + for (size_t i = 0; i < numKeyframes; ++i) { + size_t frameIndex = i * nodeChannel->mNumPositionKeys / numKeyframes; + translationData[i] = nodeChannel->mPositionKeys[frameIndex].mValue; } - Ref tranAccessor = ExportData(mAsset, animId, buffer, nodeChannel->mNumPositionKeys, translationData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); + Ref tranAccessor = ExportData(mAsset, animId, buffer, static_cast(numKeyframes), translationData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); if ( tranAccessor ) { animRef->Parameters.translation = tranAccessor; } @@ -878,12 +898,13 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, RefmNumScalingKeys > 0) { - C_STRUCT aiVector3D* scaleData = new aiVector3D[nodeChannel->mNumScalingKeys]; - for (size_t i = 0; i < nodeChannel->mNumScalingKeys; ++i) { - scaleData[i] = nodeChannel->mScalingKeys[i].mValue; + C_STRUCT aiVector3D* scaleData = new aiVector3D[numKeyframes]; + for (size_t i = 0; i < numKeyframes; ++i) { + size_t frameIndex = i * nodeChannel->mNumScalingKeys / numKeyframes; + scaleData[i] = nodeChannel->mScalingKeys[frameIndex].mValue; } - Ref scaleAccessor = ExportData(mAsset, animId, buffer, nodeChannel->mNumScalingKeys, scaleData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); + Ref scaleAccessor = ExportData(mAsset, animId, buffer, static_cast(numKeyframes), scaleData, AttribType::VEC3, AttribType::VEC3, ComponentType_FLOAT); if ( scaleAccessor ) { animRef->Parameters.scale = scaleAccessor; } @@ -893,15 +914,16 @@ inline void ExtractAnimationData(Asset& mAsset, std::string& animId, RefmNumRotationKeys > 0) { - vec4* rotationData = new vec4[nodeChannel->mNumRotationKeys]; - for (size_t i = 0; i < nodeChannel->mNumRotationKeys; ++i) { - rotationData[i][0] = nodeChannel->mRotationKeys[i].mValue.x; - rotationData[i][1] = nodeChannel->mRotationKeys[i].mValue.y; - rotationData[i][2] = nodeChannel->mRotationKeys[i].mValue.z; - rotationData[i][3] = nodeChannel->mRotationKeys[i].mValue.w; + vec4* rotationData = new vec4[numKeyframes]; + for (size_t i = 0; i < numKeyframes; ++i) { + size_t frameIndex = i * nodeChannel->mNumRotationKeys / numKeyframes; + rotationData[i][0] = nodeChannel->mRotationKeys[frameIndex].mValue.x; + rotationData[i][1] = nodeChannel->mRotationKeys[frameIndex].mValue.y; + rotationData[i][2] = nodeChannel->mRotationKeys[frameIndex].mValue.z; + rotationData[i][3] = nodeChannel->mRotationKeys[frameIndex].mValue.w; } - Ref rotAccessor = ExportData(mAsset, animId, buffer, nodeChannel->mNumRotationKeys, rotationData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT); + Ref rotAccessor = ExportData(mAsset, animId, buffer, static_cast(numKeyframes), rotationData, AttribType::VEC4, AttribType::VEC4, ComponentType_FLOAT); if ( rotAccessor ) { animRef->Parameters.rotation = rotAccessor; } @@ -931,7 +953,7 @@ void glTFExporter::ExportAnimations() Ref animRef = mAsset->animations.Create(name); /******************* Parameters ********************/ - ExtractAnimationData(*mAsset, name, animRef, bufferRef, nodeChannel); + ExtractAnimationData(*mAsset, name, animRef, bufferRef, nodeChannel, static_cast(anim->mTicksPerSecond)); for (unsigned int j = 0; j < 3; ++j) { std::string channelType; diff --git a/code/glTFExporter.h b/code/glTFExporter.h index 49df9193e..c813fff44 100644 --- a/code/glTFExporter.h +++ b/code/glTFExporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -44,6 +45,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_GLTFEXPORTER_H_INC #define AI_GLTFEXPORTER_H_INC +#ifndef ASSIMP_BUILD_NO_GLTF_IMPORTER + #include #include @@ -110,4 +113,6 @@ namespace Assimp } -#endif +#endif // ASSIMP_BUILD_NO_GLTF_IMPORTER + +#endif // AI_GLTFEXPORTER_H_INC diff --git a/code/glTFImporter.cpp b/code/glTFImporter.cpp index 02c60ee5e..a1d8e0cd0 100644 --- a/code/glTFImporter.cpp +++ b/code/glTFImporter.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -99,24 +100,19 @@ const aiImporterDesc* glTFImporter::GetInfo() const bool glTFImporter::CanRead(const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const { - const std::string& extension = GetExtension(pFile); + const std::string &extension = GetExtension(pFile); - if (extension == "gltf" || extension == "glb") - return true; + if (extension != "gltf" && extension != "glb") + return false; - if ((checkSig || !extension.length()) && pIOHandler) { - char buffer[4]; - - std::unique_ptr pStream(pIOHandler->Open(pFile)); - if (pStream && pStream->Read(buffer, sizeof(buffer), 1) == 1) { - if (memcmp(buffer, AI_GLB_MAGIC_NUMBER, sizeof(buffer)) == 0) { - return true; // Has GLB header - } - else if (memcmp(buffer, "{\r\n ", sizeof(buffer)) == 0 - || memcmp(buffer, "{\n ", sizeof(buffer)) == 0) { - // seems a JSON file, and we're the only format that can read them - return true; - } + if (checkSig && pIOHandler) { + glTF::Asset asset(pIOHandler); + try { + asset.Load(pFile, extension == "glb"); + std::string version = asset.asset.version; + return !version.empty() && version[0] == '1'; + } catch (...) { + return false; } } @@ -178,9 +174,7 @@ inline void SetMaterialColorProperty(std::vector& embeddedTexIdxs, Asset& r else { aiColor4D col; CopyValue(prop.color, col); - if (col.r != 1.f || col.g != 1.f || col.b != 1.f || col.a != 1.f) { - mat->AddProperty(&col, 1, pKey, type, idx); - } + mat->AddProperty(&col, 1, pKey, type, idx); } } @@ -676,7 +670,7 @@ void glTFImporter::InternReadFile(const std::string& pFile, aiScene* pScene, IOS //pScene->mFlags |= AI_SCENE_FLAGS_NON_VERBOSE_FORMAT; MakeVerboseFormatProcess process; process.Execute(pScene); - + if (pScene->mNumMeshes == 0) { pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; diff --git a/code/glTFImporter.h b/code/glTFImporter.h index 7edcc83f2..46f450f86 100644 --- a/code/glTFImporter.h +++ b/code/glTFImporter.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/irrXMLWrapper.h b/code/irrXMLWrapper.h index 5b47faefe..d7c76bf87 100644 --- a/code/irrXMLWrapper.h +++ b/code/irrXMLWrapper.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -42,7 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define INCLUDED_AI_IRRXML_WRAPPER // some long includes .... -#include "./../contrib/irrXML/irrXML.h" +#include #include "./../include/assimp/IOStream.hpp" #include "BaseImporter.h" #include diff --git a/code/qnan.h b/code/qnan.h index 80d6229f9..fcff16b74 100644 --- a/code/qnan.h +++ b/code/qnan.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/code/scene.cpp b/code/scene.cpp index fe95b3ae4..467a2895d 100644 --- a/code/scene.cpp +++ b/code/scene.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt new file mode 100644 index 000000000..362f1653d --- /dev/null +++ b/contrib/CMakeLists.txt @@ -0,0 +1,4 @@ +# Compile internal irrXML only if system is not requested +if( NOT SYSTEM_IRRXML ) + add_subdirectory(irrXML) +endif( NOT SYSTEM_IRRXML ) diff --git a/contrib/ConvertUTF/ConvertUTF.c b/contrib/ConvertUTF/ConvertUTF.c deleted file mode 100644 index 9b3deebd6..000000000 --- a/contrib/ConvertUTF/ConvertUTF.c +++ /dev/null @@ -1,539 +0,0 @@ -/* - * Copyright 2001-2004 Unicode, Inc. - * - * Disclaimer - * - * This source code is provided as is by Unicode, Inc. No claims are - * made as to fitness for any particular purpose. No warranties of any - * kind are expressed or implied. The recipient agrees to determine - * applicability of information provided. If this file has been - * purchased on magnetic or optical media from Unicode, Inc., the - * sole remedy for any claim will be exchange of defective media - * within 90 days of receipt. - * - * Limitations on Rights to Redistribute This Code - * - * Unicode, Inc. hereby grants the right to freely use the information - * supplied in this file in the creation of products supporting the - * Unicode Standard, and to make copies of this file in any form - * for internal or external distribution as long as this notice - * remains attached. - */ - -/* --------------------------------------------------------------------- - - Conversions between UTF32, UTF-16, and UTF-8. Source code file. - Author: Mark E. Davis, 1994. - Rev History: Rick McGowan, fixes & updates May 2001. - Sept 2001: fixed const & error conditions per - mods suggested by S. Parent & A. Lillich. - June 2002: Tim Dodd added detection and handling of incomplete - source sequences, enhanced error detection, added casts - to eliminate compiler warnings. - July 2003: slight mods to back out aggressive FFFE detection. - Jan 2004: updated switches in from-UTF8 conversions. - Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. - - See the header file "ConvertUTF.h" for complete documentation. - ------------------------------------------------------------------------- */ - - -#include "ConvertUTF.h" -#ifdef CVTUTF_DEBUG -#include -#endif - -static const int halfShift = 10; /* used for shifting by 10 bits */ - -static const UTF32 halfBase = 0x0010000UL; -static const UTF32 halfMask = 0x3FFUL; - -#define UNI_SUR_HIGH_START (UTF32)0xD800 -#define UNI_SUR_HIGH_END (UTF32)0xDBFF -#define UNI_SUR_LOW_START (UTF32)0xDC00 -#define UNI_SUR_LOW_END (UTF32)0xDFFF -#define false 0 -#define true 1 - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF32toUTF16 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF32* source = *sourceStart; - UTF16* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch; - if (target >= targetEnd) { - result = targetExhausted; break; - } - ch = *source++; - if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ - /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = (UTF16)ch; /* normal case */ - } - } else if (ch > UNI_MAX_LEGAL_UTF32) { - if (flags == strictConversion) { - result = sourceIllegal; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) { - --source; /* Back up source pointer! */ - result = targetExhausted; break; - } - ch -= halfBase; - *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); - } - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF16toUTF32 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF16* source = *sourceStart; - UTF32* target = *targetStart; - UTF32 ch, ch2; - while (source < sourceEnd) { - const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ - ch = *source++; - /* If we have a surrogate pair, convert to UTF32 first. */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { - /* If the 16 bits following the high surrogate are in the source buffer... */ - if (source < sourceEnd) { - ch2 = *source; - /* If it's a low surrogate, convert to UTF32. */ - if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) - + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; - } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } else { /* We don't have the 16 bits following the high surrogate. */ - --source; /* return to the high surrogate */ - result = sourceExhausted; - break; - } - } else if (flags == strictConversion) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - if (target >= targetEnd) { - source = oldSource; /* Back up source pointer! */ - result = targetExhausted; break; - } - *target++ = ch; - } - *sourceStart = source; - *targetStart = target; -#ifdef CVTUTF_DEBUG -if (result == sourceIllegal) { - fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); - fflush(stderr); -} -#endif - return result; -} - -/* --------------------------------------------------------------------- */ - -/* - * Index into the table below with the first byte of a UTF-8 sequence to - * get the number of trailing bytes that are supposed to follow it. - * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is - * left as-is for anyone who may want to do such conversion, which was - * allowed in earlier algorithms. - */ -static const char trailingBytesForUTF8[256] = { - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,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,4,4,4,4,5,5,5,5 -}; - -/* - * Magic values subtracted from a buffer value during UTF8 conversion. - * This table contains as many values as there might be trailing bytes - * in a UTF-8 sequence. - */ -static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, - 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; - -/* - * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed - * into the first byte, depending on how many bytes follow. There are - * as many entries in this table as there are UTF-8 sequence types. - * (I.e., one byte sequence, two byte... etc.). Remember that sequencs - * for *legal* UTF-8 will be 4 or fewer bytes total. - */ -static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; - -/* --------------------------------------------------------------------- */ - -/* The interface converts a whole buffer to avoid function-call overhead. - * Constants have been gathered. Loops & conditionals have been removed as - * much as possible for efficiency, in favor of drop-through switches. - * (See "Note A" at the bottom of the file for equivalent code.) - * If your compiler supports it, the "isLegalUTF8" call can be turned - * into an inline function. - */ - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF16toUTF8 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF16* source = *sourceStart; - UTF8* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch; - unsigned short bytesToWrite = 0; - const UTF32 byteMask = 0xBF; - const UTF32 byteMark = 0x80; - const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ - ch = *source++; - /* If we have a surrogate pair, convert to UTF32 first. */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { - /* If the 16 bits following the high surrogate are in the source buffer... */ - if (source < sourceEnd) { - UTF32 ch2 = *source; - /* If it's a low surrogate, convert to UTF32. */ - if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { - ch = ((ch - UNI_SUR_HIGH_START) << halfShift) - + (ch2 - UNI_SUR_LOW_START) + halfBase; - ++source; - } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } else { /* We don't have the 16 bits following the high surrogate. */ - --source; /* return to the high surrogate */ - result = sourceExhausted; - break; - } - } else if (flags == strictConversion) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - /* Figure out how many bytes the result will require */ - if (ch < (UTF32)0x80) { bytesToWrite = 1; - } else if (ch < (UTF32)0x800) { bytesToWrite = 2; - } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; - } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; - } else { bytesToWrite = 3; - ch = UNI_REPLACEMENT_CHAR; - } - - target += bytesToWrite; - if (target > targetEnd) { - source = oldSource; /* Back up source pointer! */ - target -= bytesToWrite; result = targetExhausted; break; - } - switch (bytesToWrite) { /* note: everything falls through. */ - case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); - } - target += bytesToWrite; - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -/* - * Utility routine to tell whether a sequence of bytes is legal UTF-8. - * This must be called with the length pre-determined by the first byte. - * If not calling this from ConvertUTF8to*, then the length can be set by: - * length = trailingBytesForUTF8[*source]+1; - * and the sequence is illegal right away if there aren't that many bytes - * available. - * If presented with a length > 4, this returns false. The Unicode - * definition of UTF-8 goes up to 4-byte sequences. - */ - -static Boolean isLegalUTF8(const UTF8 *source, int length) { - UTF8 a; - const UTF8 *srcptr = source+length; - switch (length) { - default: return false; - /* Everything else falls through when "true"... */ - case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; - case 2: if ((a = (*--srcptr)) > 0xBF) return false; - - switch (*source) { - /* no fall-through in this inner switch */ - case 0xE0: if (a < 0xA0) return false; break; - case 0xED: if (a > 0x9F) return false; break; - case 0xF0: if (a < 0x90) return false; break; - case 0xF4: if (a > 0x8F) return false; break; - default: if (a < 0x80) return false; - } - - case 1: if (*source >= 0x80 && *source < 0xC2) return false; - } - if (*source > 0xF4) return false; - return true; -} - -/* --------------------------------------------------------------------- */ - -/* - * Exported function to return whether a UTF-8 sequence is legal or not. - * This is not used here; it's just exported. - */ -Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { - int length = trailingBytesForUTF8[*source]+1; - if (source+length > sourceEnd) { - return false; - } - return isLegalUTF8(source, length); -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF8toUTF16 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF8* source = *sourceStart; - UTF16* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch = 0; - unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; - if (source + extraBytesToRead >= sourceEnd) { - result = sourceExhausted; break; - } - /* Do this check whether lenient or strict */ - if (! isLegalUTF8(source, extraBytesToRead+1)) { - result = sourceIllegal; - break; - } - /* - * The cases all fall through. See "Note A" below. - */ - switch (extraBytesToRead) { - case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ - case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; - } - ch -= offsetsFromUTF8[extraBytesToRead]; - - if (target >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up source pointer! */ - result = targetExhausted; break; - } - if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - source -= (extraBytesToRead+1); /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = (UTF16)ch; /* normal case */ - } - } else if (ch > UNI_MAX_UTF16) { - if (flags == strictConversion) { - result = sourceIllegal; - source -= (extraBytesToRead+1); /* return to the start */ - break; /* Bail out; shouldn't continue */ - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - /* target is a character in range 0xFFFF - 0x10FFFF. */ - if (target + 1 >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up source pointer! */ - result = targetExhausted; break; - } - ch -= halfBase; - *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); - *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); - } - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF32toUTF8 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF32* source = *sourceStart; - UTF8* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch; - unsigned short bytesToWrite = 0; - const UTF32 byteMask = 0xBF; - const UTF32 byteMark = 0x80; - ch = *source++; - if (flags == strictConversion ) { - /* UTF-16 surrogate values are illegal in UTF-32 */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - --source; /* return to the illegal value itself */ - result = sourceIllegal; - break; - } - } - /* - * Figure out how many bytes the result will require. Turn any - * illegally large UTF32 things (> Plane 17) into replacement chars. - */ - if (ch < (UTF32)0x80) { bytesToWrite = 1; - } else if (ch < (UTF32)0x800) { bytesToWrite = 2; - } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; - } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; - } else { bytesToWrite = 3; - ch = UNI_REPLACEMENT_CHAR; - result = sourceIllegal; - } - - target += bytesToWrite; - if (target > targetEnd) { - --source; /* Back up source pointer! */ - target -= bytesToWrite; result = targetExhausted; break; - } - switch (bytesToWrite) { /* note: everything falls through. */ - case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; - case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); - } - target += bytesToWrite; - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- */ - -ConversionResult ConvertUTF8toUTF32 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { - ConversionResult result = conversionOK; - const UTF8* source = *sourceStart; - UTF32* target = *targetStart; - while (source < sourceEnd) { - UTF32 ch = 0; - unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; - if (source + extraBytesToRead >= sourceEnd) { - result = sourceExhausted; break; - } - /* Do this check whether lenient or strict */ - if (! isLegalUTF8(source, extraBytesToRead+1)) { - result = sourceIllegal; - break; - } - /* - * The cases all fall through. See "Note A" below. - */ - switch (extraBytesToRead) { - case 5: ch += *source++; ch <<= 6; - case 4: ch += *source++; ch <<= 6; - case 3: ch += *source++; ch <<= 6; - case 2: ch += *source++; ch <<= 6; - case 1: ch += *source++; ch <<= 6; - case 0: ch += *source++; - } - ch -= offsetsFromUTF8[extraBytesToRead]; - - if (target >= targetEnd) { - source -= (extraBytesToRead+1); /* Back up the source pointer! */ - result = targetExhausted; break; - } - if (ch <= UNI_MAX_LEGAL_UTF32) { - /* - * UTF-16 surrogate values are illegal in UTF-32, and anything - * over Plane 17 (> 0x10FFFF) is illegal. - */ - if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { - if (flags == strictConversion) { - source -= (extraBytesToRead+1); /* return to the illegal value itself */ - result = sourceIllegal; - break; - } else { - *target++ = UNI_REPLACEMENT_CHAR; - } - } else { - *target++ = ch; - } - } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ - result = sourceIllegal; - *target++ = UNI_REPLACEMENT_CHAR; - } - } - *sourceStart = source; - *targetStart = target; - return result; -} - -/* --------------------------------------------------------------------- - - Note A. - The fall-through switches in UTF-8 reading code save a - temp variable, some decrements & conditionals. The switches - are equivalent to the following loop: - { - int tmpBytesToRead = extraBytesToRead+1; - do { - ch += *source++; - --tmpBytesToRead; - if (tmpBytesToRead) ch <<= 6; - } while (tmpBytesToRead > 0); - } - In UTF-8 writing code, the switches on "bytesToWrite" are - similarly unrolled loops. - - --------------------------------------------------------------------- */ diff --git a/contrib/ConvertUTF/ConvertUTF.h b/contrib/ConvertUTF/ConvertUTF.h deleted file mode 100644 index 05e800ad8..000000000 --- a/contrib/ConvertUTF/ConvertUTF.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright 2001-2004 Unicode, Inc. - * - * Disclaimer - * - * This source code is provided as is by Unicode, Inc. No claims are - * made as to fitness for any particular purpose. No warranties of any - * kind are expressed or implied. The recipient agrees to determine - * applicability of information provided. If this file has been - * purchased on magnetic or optical media from Unicode, Inc., the - * sole remedy for any claim will be exchange of defective media - * within 90 days of receipt. - * - * Limitations on Rights to Redistribute This Code - * - * Unicode, Inc. hereby grants the right to freely use the information - * supplied in this file in the creation of products supporting the - * Unicode Standard, and to make copies of this file in any form - * for internal or external distribution as long as this notice - * remains attached. - */ -#ifndef CONVERTUTF_H -#define CONVERTUTF_H -/* --------------------------------------------------------------------- - - Conversions between UTF32, UTF-16, and UTF-8. Header file. - - Several funtions are included here, forming a complete set of - conversions between the three formats. UTF-7 is not included - here, but is handled in a separate source file. - - Each of these routines takes pointers to input buffers and output - buffers. The input buffers are const. - - Each routine converts the text between *sourceStart and sourceEnd, - putting the result into the buffer between *targetStart and - targetEnd. Note: the end pointers are *after* the last item: e.g. - *(sourceEnd - 1) is the last item. - - The return result indicates whether the conversion was successful, - and if not, whether the problem was in the source or target buffers. - (Only the first encountered problem is indicated.) - - After the conversion, *sourceStart and *targetStart are both - updated to point to the end of last text successfully converted in - the respective buffers. - - Input parameters: - sourceStart - pointer to a pointer to the source buffer. - The contents of this are modified on return so that - it points at the next thing to be converted. - targetStart - similarly, pointer to pointer to the target buffer. - sourceEnd, targetEnd - respectively pointers to the ends of the - two buffers, for overflow checking only. - - These conversion functions take a ConversionFlags argument. When this - flag is set to strict, both irregular sequences and isolated surrogates - will cause an error. When the flag is set to lenient, both irregular - sequences and isolated surrogates are converted. - - Whether the flag is strict or lenient, all illegal sequences will cause - an error return. This includes sequences such as: , , - or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code - must check for illegal sequences. - - When the flag is set to lenient, characters over 0x10FFFF are converted - to the replacement character; otherwise (when the flag is set to strict) - they constitute an error. - - Output parameters: - The value "sourceIllegal" is returned from some routines if the input - sequence is malformed. When "sourceIllegal" is returned, the source - value will point to the illegal value that caused the problem. E.g., - in UTF-8 when a sequence is malformed, it points to the start of the - malformed sequence. - - Author: Mark E. Davis, 1994. - Rev History: Rick McGowan, fixes & updates May 2001. - Fixes & updates, Sept 2001. - ------------------------------------------------------------------------- */ - -/* --------------------------------------------------------------------- - The following 4 definitions are compiler-specific. - The C standard does not guarantee that wchar_t has at least - 16 bits, so wchar_t is no less portable than unsigned short! - All should be unsigned values to avoid sign extension during - bit mask & shift operations. ------------------------------------------------------------------------- */ - -typedef unsigned long UTF32; /* at least 32 bits */ -typedef unsigned short UTF16; /* at least 16 bits */ -typedef unsigned char UTF8; /* typically 8 bits */ -typedef unsigned char Boolean; /* 0 or 1 */ - -/* Some fundamental constants */ -#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD -#define UNI_MAX_BMP (UTF32)0x0000FFFF -#define UNI_MAX_UTF16 (UTF32)0x0010FFFF -#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF -#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF - -typedef enum { - conversionOK, /* conversion successful */ - sourceExhausted, /* partial character in source, but hit end */ - targetExhausted, /* insuff. room in target for conversion */ - sourceIllegal /* source sequence is illegal/malformed */ -} ConversionResult; - -typedef enum { - strictConversion = 0, - lenientConversion -} ConversionFlags; - -/* This is for C++ and does no harm in C */ -#ifdef __cplusplus -extern "C" { -#endif - -ConversionResult ConvertUTF8toUTF16 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF16toUTF8 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF8toUTF32 ( - const UTF8** sourceStart, const UTF8* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF32toUTF8 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF16toUTF32 ( - const UTF16** sourceStart, const UTF16* sourceEnd, - UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); - -ConversionResult ConvertUTF32toUTF16 ( - const UTF32** sourceStart, const UTF32* sourceEnd, - UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); - -Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); - -#ifdef __cplusplus -} -#endif - -/* --------------------------------------------------------------------- */ -#endif // CONVERTUTF_H diff --git a/contrib/ConvertUTF/readme.txt b/contrib/ConvertUTF/readme.txt deleted file mode 100644 index b9f17fb81..000000000 --- a/contrib/ConvertUTF/readme.txt +++ /dev/null @@ -1,43 +0,0 @@ - -The accompanying C source code file "ConvertUTF.c" and the associated header -file "ConvertUTF.h" provide for conversion between various transformation -formats of Unicode characters. The following conversions are supported: - - UTF-32 to UTF-16 - UTF-32 to UTF-8 - UTF-16 to UTF-32 - UTF-16 to UTF-8 - UTF-8 to UTF-16 - UTF-8 to UTF-32 - -In addition, there is a test harness which runs various tests. - -The files "CVTUTF7.C" and "CVTUTF7.H" are for archival and historical purposes -only. They have not been updated to Unicode 3.0 or later and should be -considered obsolescent. "CVTUTF7.C" contains two functions that can convert -between UCS2 (i.e., the BMP characters only) and UTF-7. Surrogates are -not supported, the code has not been tested, and should be considered -unsuitable for general purpose use. - -Please submit any bug reports about these programs here: - - http://www.unicode.org/unicode/reporting.html - -Version 1.0: initial version. - -Version 1.1: corrected some minor problems; added stricter checks. - -Version 1.2: corrected switch statements associated with "extraBytesToRead" - in 4 & 5 byte cases, in functions for conversion from UTF8. - Note: formally, the 4 & 5 byte cases are illegal in the latest - UTF8, but the table and this code has always catered for those, - cases since at one time they were legal. - -Version 1.3: Updated UTF-8 legality check; - updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions - Updated UTF-8 legality tests in harness.c - - -Last update: October 19, 2004 - - diff --git a/contrib/Open3DGC/o3dgcAdjacencyInfo.h b/contrib/Open3DGC/o3dgcAdjacencyInfo.h index 6b53a242d..72fe3d4c6 100644 --- a/contrib/Open3DGC/o3dgcAdjacencyInfo.h +++ b/contrib/Open3DGC/o3dgcAdjacencyInfo.h @@ -140,8 +140,8 @@ namespace o3dgc { return End(element) - Begin(element); } - long * const GetNumNeighborsBuffer() { return m_numNeighbors;} - long * const GetNeighborsBuffer() { return m_neighbors;} + long * GetNumNeighborsBuffer() { return m_numNeighbors;} + long * GetNeighborsBuffer() { return m_neighbors;} private: long m_neighborsSize; // actual allocated size for m_neighbors diff --git a/contrib/Open3DGC/o3dgcBinaryStream.h b/contrib/Open3DGC/o3dgcBinaryStream.h index 9f4aefe55..19e3df973 100644 --- a/contrib/Open3DGC/o3dgcBinaryStream.h +++ b/contrib/Open3DGC/o3dgcBinaryStream.h @@ -395,15 +395,15 @@ namespace o3dgc { return m_stream.GetSize(); } - const unsigned char * const GetBuffer(unsigned long position) const + const unsigned char * GetBuffer(unsigned long position) const { return m_stream.GetBuffer() + position; } - unsigned char * const GetBuffer(unsigned long position) + unsigned char * GetBuffer(unsigned long position) { return (m_stream.GetBuffer() + position); } - unsigned char * const GetBuffer() + unsigned char * GetBuffer() { return m_stream.GetBuffer(); } diff --git a/contrib/Open3DGC/o3dgcDynamicVector.h b/contrib/Open3DGC/o3dgcDynamicVector.h index edc97d83c..aa7fb3142 100644 --- a/contrib/Open3DGC/o3dgcDynamicVector.h +++ b/contrib/Open3DGC/o3dgcDynamicVector.h @@ -48,10 +48,10 @@ namespace o3dgc unsigned long GetNVector() const { return m_num;} unsigned long GetDimVector() const { return m_dim;} unsigned long GetStride() const { return m_stride;} - const Real * const GetMin() const { return m_min;} - const Real * const GetMax() const { return m_max;} - const Real * const GetVectors() const { return m_vectors;} - Real * const GetVectors() { return m_vectors;} + const Real * GetMin() const { return m_min;} + const Real * GetMax() const { return m_max;} + const Real * GetVectors() const { return m_vectors;} + Real * GetVectors() { return m_vectors;} Real GetMin(unsigned long j) const { return m_min[j];} Real GetMax(unsigned long j) const { return m_max[j];} diff --git a/contrib/Open3DGC/o3dgcFIFO.h b/contrib/Open3DGC/o3dgcFIFO.h index 874c26475..4a5555f2a 100644 --- a/contrib/Open3DGC/o3dgcFIFO.h +++ b/contrib/Open3DGC/o3dgcFIFO.h @@ -81,8 +81,8 @@ namespace o3dgc m_end = 0; } } - const unsigned long GetSize() const { return m_size;}; - const unsigned long GetAllocatedSize() const { return m_allocated;}; + unsigned long GetSize() const { return m_size;}; + unsigned long GetAllocatedSize() const { return m_allocated;}; void Clear() { m_start = m_end = m_size = 0;}; private: diff --git a/contrib/Open3DGC/o3dgcIndexedFaceSet.h b/contrib/Open3DGC/o3dgcIndexedFaceSet.h index 4af9de437..adb8cb001 100644 --- a/contrib/Open3DGC/o3dgcIndexedFaceSet.h +++ b/contrib/Open3DGC/o3dgcIndexedFaceSet.h @@ -62,26 +62,26 @@ namespace o3dgc } unsigned long GetNumFloatAttributes() const { return m_numFloatAttributes;} unsigned long GetNumIntAttributes() const { return m_numIntAttributes ;} - const Real * const GetCoordMin () const { return m_coordMin;} - const Real * const GetCoordMax () const { return m_coordMax;} - const Real * const GetNormalMin () const { return m_normalMin;} - const Real * const GetNormalMax () const { return m_normalMax;} + const Real * GetCoordMin () const { return m_coordMin;} + const Real * GetCoordMax () const { return m_coordMax;} + const Real * GetNormalMin () const { return m_normalMin;} + const Real * GetNormalMax () const { return m_normalMax;} Real GetCoordMin (int j) const { return m_coordMin[j] ;} Real GetCoordMax (int j) const { return m_coordMax[j] ;} Real GetNormalMin (int j) const { return m_normalMin[j] ;} Real GetNormalMax (int j) const { return m_normalMax[j] ;} - const O3DGCIFSFloatAttributeType GetFloatAttributeType(unsigned long a) const + O3DGCIFSFloatAttributeType GetFloatAttributeType(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); return m_typeFloatAttribute[a]; } - const O3DGCIFSIntAttributeType GetIntAttributeType(unsigned long a) const + O3DGCIFSIntAttributeType GetIntAttributeType(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); return m_typeIntAttribute[a]; } - const unsigned long GetFloatAttributeDim(unsigned long a) const + unsigned long GetFloatAttributeDim(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); return m_dimFloatAttribute[a]; @@ -91,12 +91,12 @@ namespace o3dgc assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); return m_dimIntAttribute[a]; } - const Real * const GetFloatAttributeMin(unsigned long a) const + const Real * GetFloatAttributeMin(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); return &(m_minFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]); } - const Real * const GetFloatAttributeMax(unsigned long a) const + const Real * GetFloatAttributeMax(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); return &(m_maxFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]); @@ -118,17 +118,17 @@ namespace o3dgc bool GetSolid() const { return m_solid ;} bool GetConvex() const { return m_convex ;} bool GetIsTriangularMesh() const { return m_isTriangularMesh;} - const unsigned long * const GetIndexBufferID() const { return m_indexBufferID ;} - const T * const GetCoordIndex() const { return m_coordIndex;} - T * const GetCoordIndex() { return m_coordIndex;} - Real * const GetCoord() const { return m_coord ;} - Real * const GetNormal() const { return m_normal ;} - Real * const GetFloatAttribute(unsigned long a) const + const unsigned long * GetIndexBufferID() const { return m_indexBufferID ;} + const T * GetCoordIndex() const { return m_coordIndex;} + T * GetCoordIndex() { return m_coordIndex;} + Real * GetCoord() const { return m_coord ;} + Real * GetNormal() const { return m_normal ;} + Real * GetFloatAttribute(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); return m_floatAttribute[a]; } - long * const GetIntAttribute(unsigned long a) const + long * GetIntAttribute(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); return m_intAttribute[a] ; diff --git a/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl b/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl index d36b62f2b..aa6f24b73 100644 --- a/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl +++ b/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl @@ -425,7 +425,7 @@ namespace o3dgc const AdjacencyInfo & v2T = m_triangleListDecoder.GetVertexToTriangle(); const T * const triangles = ifs.GetCoordIndex(); Vec3 p1, p2, p3, n0, nt; - long na0, nb0; + long na0 = 0, nb0 = 0; Real rna0, rnb0, norm0; char ni0 = 0, ni1 = 0; long a, b, c; diff --git a/contrib/Open3DGC/o3dgcSC3DMCEncoder.inl b/contrib/Open3DGC/o3dgcSC3DMCEncoder.inl index b2c438814..2d30b05a2 100644 --- a/contrib/Open3DGC/o3dgcSC3DMCEncoder.inl +++ b/contrib/Open3DGC/o3dgcSC3DMCEncoder.inl @@ -762,8 +762,8 @@ namespace o3dgc const Real * const originalNormals = ifs.GetNormal(); Vec3 p1, p2, p3, n0, nt; Vec3 n1; - long na0, nb0; - Real rna0, rnb0, na1, nb1, norm0, norm1; + long na0 = 0, nb0 = 0; + Real rna0, rnb0, na1 = 0, nb1 = 0, norm0, norm1; char ni0 = 0, ni1 = 0; long a, b, c, v; m_predictors.Clear(); diff --git a/contrib/Open3DGC/o3dgcTriangleListEncoder.h b/contrib/Open3DGC/o3dgcTriangleListEncoder.h index cf790ecc3..c09172273 100644 --- a/contrib/Open3DGC/o3dgcTriangleListEncoder.h +++ b/contrib/Open3DGC/o3dgcTriangleListEncoder.h @@ -50,10 +50,10 @@ namespace o3dgc BinaryStream & bstream); O3DGCStreamType GetStreamType() const { return m_streamType; } void SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; } - const long * const GetInvVMap() const { return m_invVMap;} - const long * const GetInvTMap() const { return m_invTMap;} - const long * const GetVMap() const { return m_vmap;} - const long * const GetTMap() const { return m_tmap;} + const long * GetInvVMap() const { return m_invVMap;} + const long * GetInvTMap() const { return m_invTMap;} + const long * GetVMap() const { return m_vmap;} + const long * GetTMap() const { return m_tmap;} const AdjacencyInfo & GetVertexToTriangle() const { return m_vertexToTriangle;} private: diff --git a/contrib/Open3DGC/o3dgcVector.h b/contrib/Open3DGC/o3dgcVector.h index e766e2b7f..08d3ed564 100644 --- a/contrib/Open3DGC/o3dgcVector.h +++ b/contrib/Open3DGC/o3dgcVector.h @@ -88,8 +88,8 @@ namespace o3dgc assert(m_size < m_allocated); m_buffer[m_size++] = value; } - const T * const GetBuffer() const { return m_buffer;}; - T * const GetBuffer() { return m_buffer;}; + const T * GetBuffer() const { return m_buffer;}; + T * GetBuffer() { return m_buffer;}; unsigned long GetSize() const { return m_size;}; void SetSize(unsigned long size) { diff --git a/contrib/irrXML/CMakeLists.txt b/contrib/irrXML/CMakeLists.txt new file mode 100644 index 000000000..48941970a --- /dev/null +++ b/contrib/irrXML/CMakeLists.txt @@ -0,0 +1,22 @@ +set( IrrXML_SRCS + CXMLReaderImpl.h + heapsort.h + irrArray.h + irrString.h + irrTypes.h + irrXML.cpp + irrXML.h +) + +if ( MSVC ) + ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS ) + ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) +endif ( MSVC ) + +add_library(IrrXML STATIC ${IrrXML_SRCS}) +set(IRRXML_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "IrrXML_Include" ) +set(IRRXML_LIBRARY "IrrXML" CACHE INTERNAL "IrrXML" ) + +install(TARGETS IrrXML + ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} + COMPONENT ${LIBASSIMP_COMPONENT}) diff --git a/contrib/openddlparser/CMakeLists.txt b/contrib/openddlparser/CMakeLists.txt index a39d0219f..9e903ca3f 100644 --- a/contrib/openddlparser/CMakeLists.txt +++ b/contrib/openddlparser/CMakeLists.txt @@ -3,18 +3,40 @@ PROJECT( OpenDDL-Parser ) SET ( OPENDDL_PARSER_VERSION_MAJOR 0 ) SET ( OPENDDL_PARSER_VERSION_MINOR 1 ) SET ( OPENDDL_PARSER_VERSION_PATCH 0 ) -SET ( OPENDDL_PARSER_VERSION ${CPPCORE_VERSION_MAJOR}.${CPPCORE_VERSION_MINOR}.${CPPCORE_VERSION_PATCH} ) +SET ( OPENDDL_PARSER_VERSION ${OPENDDL_PARSER_VERSION_MAJOR}.${OPENDDL_PARSER_VERSION_MINOR}.${OPENDDL_PARSER_VERSION_PATCH} ) SET ( PROJECT_VERSION "${OPENDDL_PARSER_VERSION}" ) +option( DDL_USE_CPP11 "Set to ON to use C++11 features ( always on on windows )." ON ) +option( DDL_DEBUG_OUTPUT "Set to ON to use output debug texts" OFF ) +option( DDL_STATIC_LIBRARY "Set to ON to build static libary of OpenDDL Parser." ON ) +option( COVERALLS "Generate coveralls data" OFF ) + +if ( DDL_USE_CPP11 ) + if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) + set( OPENDDL_CXXFLAGS -std=c++0x ) + elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") + set( OPENDDL_CXXFLAGS --std=c++11 ) + endif() +else( DDL_USE_CPP11 ) + add_definitions( -DOPENDDL_NO_USE_CPP11 ) +endif( DDL_USE_CPP11) + if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) find_package(Threads) else() add_definitions( -D_CRT_SECURE_NO_WARNINGS ) endif() +if ( DDL_STATIC_LIBRARY ) + add_definitions( -DOPENDDL_STATIC_LIBARY ) +endif() + add_definitions( -DOPENDDLPARSER_BUILD ) -add_definitions( -DOPENDDL_NO_USE_CPP11 ) add_definitions( -D_VARIADIC_MAX=10 ) +add_definitions( -DGTEST_HAS_PTHREAD=0 ) +if ( DDL_DEBUG_OUTPUT ) + add_definitions( -DDDL_DEBUG_HEADER_NAME) +endif() INCLUDE_DIRECTORIES( ./ @@ -24,9 +46,10 @@ INCLUDE_DIRECTORIES( ) link_directories( - ./ + ${CMAKE_HOME_DIRECTORY}/lib ) +set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake ) SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/lib ) SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/lib ) SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/bin ) @@ -40,18 +63,38 @@ if( WIN32 AND NOT CYGWIN ) endif() elseif( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) # Update if necessary - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic -std=c++0x") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic ${OPENDDL_CXXFLAGS}") elseif ( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic -std=c++11") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic ${OPENDDL_CXXFLAGS} -Wwrite-strings") endif() +if (COVERALLS) + include(Coveralls) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") +endif() + +# Include the doc component. +FIND_PACKAGE( doxygen ) +IF ( DOXYGEN_FOUND ) + CONFIGURE_FILE( doc/openddlparser_doc.in doc/doxygenfile @ONLY ) + ADD_CUSTOM_TARGET( doc ALL ${DOXYGEN_EXECUTABLE} doc/doxygenfile + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating API documentation with Doxygen" VERBATIM ) +ENDIF ( DOXYGEN_FOUND ) + SET ( openddl_parser_src + code/OpenDDLCommon.cpp + code/OpenDDLExport.cpp code/OpenDDLParser.cpp + code/OpenDDLStream.cpp code/DDLNode.cpp code/Value.cpp + include/openddlparser/OpenDDLCommon.h + include/openddlparser/OpenDDLExport.h include/openddlparser/OpenDDLParser.h include/openddlparser/OpenDDLParserUtils.h - include/openddlparser/OpenDDLCommon.h + include/openddlparser/OpenDDLStream.h include/openddlparser/DDLNode.h include/openddlparser/Value.h README.md @@ -59,6 +102,69 @@ SET ( openddl_parser_src SOURCE_GROUP( code FILES ${openddl_parser_src} ) -ADD_LIBRARY( openddl_parser SHARED - ${openddl_parser_src} +if ( DDL_STATIC_LIBRARY ) + ADD_LIBRARY( openddl_parser STATIC + ${openddl_parser_src} + ) +else() + ADD_LIBRARY( openddl_parser SHARED + ${openddl_parser_src} + ) +endif() + +SET ( GTEST_PATH contrib/gtest-1.7.0 ) + +SET ( gtest_src + ${GTEST_PATH}/src/gtest-death-test.cc + ${GTEST_PATH}/src/gtest-filepath.cc + ${GTEST_PATH}/src/gtest-internal-inl.h + ${GTEST_PATH}/src/gtest-port.cc + ${GTEST_PATH}/src/gtest-printers.cc + ${GTEST_PATH}/src/gtest-test-part.cc + ${GTEST_PATH}/src/gtest-typed-test.cc + ${GTEST_PATH}/src/gtest.cc + ${GTEST_PATH}/src/gtest_main.cc ) + +SET( openddl_parser_unittest_src + test/UnitTestCommon.h + test/DDLNodeTest.cpp + test/OpenDDLCommonTest.cpp + test/OpenDDLExportTest.cpp + test/OpenDDLParserTest.cpp + test/OpenDDLParserUtilsTest.cpp + test/OpenDDLStreamTest.cpp + test/OpenDDLIntegrationTest.cpp + test/ValueTest.cpp + test/OpenDDLDefectsTest.cpp +) + +SOURCE_GROUP( code FILES ${openddl_parser_unittest_src} ) +SOURCE_GROUP( gtest FILES ${gtest_src} ) + +ADD_EXECUTABLE( openddl_parser_unittest + ${gtest_src} + ${openddl_parser_unittest_src} +) + +target_link_libraries( openddl_parser_unittest openddl_parser ${CMAKE_THREAD_LIBS_INIT} ) + +SET( openddl_parser_demo_src + demo/main.cpp +) + +if (COVERALLS) + set(COVERAGE_SRCS ${gtest_src} ${openddl_parser_unittest_src} ) + + # Create the coveralls target. + coveralls_setup( + "${COVERAGE_SRCS}" # The source files. + ON # If we should upload. + "${PROJECT_SOURCE_DIR}/cmake/") # (Optional) Alternate project cmake module path. +endif() + +ADD_EXECUTABLE( openddl_parser_demo + ${openddl_parser_demo_src} +) + +target_link_libraries( openddl_parser_demo openddl_parser ) diff --git a/contrib/openddlparser/CREDITS b/contrib/openddlparser/CREDITS index a2b01eb13..d3936af83 100644 --- a/contrib/openddlparser/CREDITS +++ b/contrib/openddlparser/CREDITS @@ -12,5 +12,8 @@ Improvements value interface, serveral bugfixes. - Henry Read ( henrya2 ): Static build option, Interface improvements +- (wise86-android) +fix several mem-leaks + - Paul Holland ( pkholland ): Bugfixes. diff --git a/contrib/openddlparser/README.md b/contrib/openddlparser/README.md index 619747d23..a48ea1be0 100644 --- a/contrib/openddlparser/README.md +++ b/contrib/openddlparser/README.md @@ -11,7 +11,7 @@ Current coverity check status: Coverity Scan Build Status - +Current test coverage:[![Coverage Status](https://coveralls.io/repos/github/kimkulling/openddl-parser/badge.svg?branch=master)](https://coveralls.io/github/kimkulling/openddl-parser?branch=cpp_coveralls) Get the source code =================== You can get the code from our git repository, which is located at GitHub. You can clone the repository with the following command: @@ -25,7 +25,7 @@ After installing it you can open a console and enter: > cmake CMakeLists.txt -This command will generate a build environment for your installed build enrironment ( for Visual-Studio-users the project files will be generated, for gcc-users the makefiles will be generated ). +This command will generate a build environment for your preferred build tool ( for Visual-Studio-users the project files will be generated, for gcc-users the makefiles will be generated ). When using an IDE open the IDE and run the build. When using GNU-make type in your console: > make diff --git a/contrib/openddlparser/code/DDLNode.cpp b/contrib/openddlparser/code/DDLNode.cpp index 0cc95bdfc..6548cdf24 100644 --- a/contrib/openddlparser/code/DDLNode.cpp +++ b/contrib/openddlparser/code/DDLNode.cpp @@ -68,8 +68,8 @@ DDLNode::DDLNode( const std::string &type, const std::string &name, size_t idx, } DDLNode::~DDLNode() { - releaseDataType( m_properties ); - releaseDataType( m_value ); + delete m_properties; + delete m_value; releaseReferencedNames( m_references ); delete m_dtArrayList; @@ -77,6 +77,9 @@ DDLNode::~DDLNode() { if( s_allocatedNodes[ m_idx ] == this ) { s_allocatedNodes[ m_idx ] = ddl_nullptr; } + for ( size_t i = 0; i::iterator it; - it = std::find( m_parent->m_children.begin(), m_parent->m_children.end(), this ); + if( ddl_nullptr != m_parent ) { + DDLNodeIt it = std::find( m_parent->m_children.begin(), m_parent->m_children.end(), this ); if( m_parent->m_children.end() != it ) { m_parent->m_children.erase( it ); } @@ -126,6 +128,8 @@ const std::string &DDLNode::getName() const { } void DDLNode::setProperties( Property *prop ) { + if(m_properties!=ddl_nullptr) + delete m_properties; m_properties = prop; } @@ -187,6 +191,10 @@ Reference *DDLNode::getReferences() const { return m_references; } +void DDLNode::dump(IOStreamBase &stream) { + // Todo! +} + DDLNode *DDLNode::create( const std::string &type, const std::string &name, DDLNode *parent ) { const size_t idx( s_allocatedNodes.size() ); DDLNode *node = new DDLNode( type, name, idx, parent ); @@ -197,7 +205,7 @@ DDLNode *DDLNode::create( const std::string &type, const std::string &name, DDLN void DDLNode::releaseNodes() { if( s_allocatedNodes.size() > 0 ) { - for( DllNodeList::iterator it = s_allocatedNodes.begin(); it != s_allocatedNodes.end(); it++ ) { + for( DDLNodeIt it = s_allocatedNodes.begin(); it != s_allocatedNodes.end(); it++ ) { if( *it ) { delete *it; } diff --git a/contrib/openddlparser/code/OpenDDLCommon.cpp b/contrib/openddlparser/code/OpenDDLCommon.cpp index 13a96f7a8..5c341a780 100644 --- a/contrib/openddlparser/code/OpenDDLCommon.cpp +++ b/contrib/openddlparser/code/OpenDDLCommon.cpp @@ -22,6 +22,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------------------------*/ #include #include +#include BEGIN_ODDLPARSER_NS @@ -84,7 +85,14 @@ Name::~Name() { m_id = ddl_nullptr; } -Reference::Reference() +Name::Name( const Name &name ){ + m_type=name.m_type; + m_id=new Text(name.m_id->m_buffer,name.m_id->m_len); +} + + + + Reference::Reference() : m_numRefs( 0 ) , m_referencedName( ddl_nullptr ) { // empty @@ -96,8 +104,16 @@ Reference::Reference( size_t numrefs, Name **names ) if ( numrefs > 0 ) { m_referencedName = new Name *[ numrefs ]; for ( size_t i = 0; i < numrefs; i++ ) { - Name *name = new Name( names[ i ]->m_type, names[ i ]->m_id ); - m_referencedName[ i ] = name; + m_referencedName[ i ] = names[i]; + } + } +} +Reference::Reference(const Reference &ref) { + m_numRefs=ref.m_numRefs; + if(m_numRefs!=0){ + m_referencedName = new Name*[m_numRefs]; + for ( size_t i = 0; i < m_numRefs; i++ ) { + m_referencedName[i] = new Name(*ref.m_referencedName[i]); } } } @@ -107,6 +123,7 @@ Reference::~Reference() { delete m_referencedName[ i ]; } m_numRefs = 0; + delete [] m_referencedName; m_referencedName = ddl_nullptr; } @@ -135,21 +152,30 @@ Property::Property( Text *id ) } Property::~Property() { - m_key = ddl_nullptr; - m_value = ddl_nullptr; - m_ref = ddl_nullptr;; - m_next = ddl_nullptr;; + delete m_key; + if(m_value!=ddl_nullptr) + delete m_value; + if(m_ref!=ddl_nullptr) + delete(m_ref); + if(m_next!=ddl_nullptr) + delete m_next; } DataArrayList::DataArrayList() : m_numItems( 0 ) , m_dataList( ddl_nullptr ) -, m_next( ddl_nullptr ) { +, m_next( ddl_nullptr ) +, m_refs(ddl_nullptr) +, m_numRefs(0){ // empty } DataArrayList::~DataArrayList() { - // empty + delete m_dataList; + if(m_next!=ddl_nullptr) + delete m_next; + if(m_refs!=ddl_nullptr) + delete m_refs; } size_t DataArrayList::size() { diff --git a/contrib/openddlparser/code/OpenDDLExport.cpp b/contrib/openddlparser/code/OpenDDLExport.cpp index 49207c044..a85bc5676 100644 --- a/contrib/openddlparser/code/OpenDDLExport.cpp +++ b/contrib/openddlparser/code/OpenDDLExport.cpp @@ -29,60 +29,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. BEGIN_ODDLPARSER_NS -StreamFormatterBase::StreamFormatterBase() { - -} - -StreamFormatterBase::~StreamFormatterBase() { - -} - -std::string StreamFormatterBase::format( const std::string &statement ) { - std::string tmp( statement ); - return tmp; -} - -IOStreamBase::IOStreamBase( StreamFormatterBase *formatter ) -: m_formatter( formatter ) -, m_file( ddl_nullptr ) { - if (ddl_nullptr == m_formatter) { - m_formatter = new StreamFormatterBase; - } -} - -IOStreamBase::~IOStreamBase() { - delete m_formatter; - m_formatter = ddl_nullptr; -} - -bool IOStreamBase::open( const std::string &name ) { - m_file = ::fopen( name.c_str(), "a" ); - if (m_file == ddl_nullptr) { - return false; - } - - return true; -} - -bool IOStreamBase::close() { - if (ddl_nullptr == m_file) { - return false; - } - - ::fclose( m_file ); - m_file = ddl_nullptr; - - return true; -} - -size_t IOStreamBase::write( const std::string &statement ) { - if (ddl_nullptr == m_file) { - return 0; - } - std::string formatStatement = m_formatter->format( statement ); - return ::fwrite( formatStatement.c_str(), sizeof( char ), formatStatement.size(), m_file ); -} - struct DDLNodeIterator { const DDLNode::DllNodeList &m_childs; size_t m_idx; @@ -280,7 +226,7 @@ bool OpenDDLExport::writeValueType( Value::ValueType type, size_t numItems, std: statement += "["; char buffer[ 256 ]; ::memset( buffer, '\0', 256 * sizeof( char ) ); - sprintf( buffer, "%d", int(numItems) ); + sprintf( buffer, "%d", static_cast( numItems ) ); statement += buffer; statement += "]"; } diff --git a/contrib/openddlparser/code/OpenDDLParser.cpp b/contrib/openddlparser/code/OpenDDLParser.cpp index 6f471be36..dab976fad 100644 --- a/contrib/openddlparser/code/OpenDDLParser.cpp +++ b/contrib/openddlparser/code/OpenDDLParser.cpp @@ -36,7 +36,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. BEGIN_ODDLPARSER_NS -static const char *Version = "0.3.0"; +static const char *Version = "0.4.0"; namespace Grammar { static const char *OpenBracketToken = "{"; @@ -49,7 +49,7 @@ namespace Grammar { static const char *BoolFalse = "false"; static const char *CommaSeparator = ","; - static const char* PrimitiveTypeToken[ Value::ddl_types_max ] = { + static const char *PrimitiveTypeToken[ Value::ddl_types_max ] = { "bool", "int8", "int16", @@ -74,8 +74,8 @@ const char *getTypeToken( Value::ValueType type ) { static void logInvalidTokenError( char *in, const std::string &exp, OpenDDLParser::logCallback callback ) { std::stringstream stream; stream << "Invalid token \"" << *in << "\"" << " expected \"" << exp << "\"" << std::endl; - std::string full(in); - std::string part(full.substr(0,50)); + std::string full( in ); + std::string part( full.substr( 0, 50 ) ); stream << part; callback( ddl_error_msg, stream.str() ); } @@ -85,6 +85,7 @@ static bool isIntegerType( Value::ValueType integerType ) { integerType != Value::ddl_int32 && integerType != Value::ddl_int64 ) { return false; } + return true; } @@ -105,7 +106,7 @@ static DDLNode *createDDLNode( Text *id, OpenDDLParser *parser ) { const std::string type( id->m_buffer ); DDLNode *parent( parser->top() ); DDLNode *node = DDLNode::create( type, "", parent ); - + return node; } @@ -193,10 +194,11 @@ size_t OpenDDLParser::getBufferSize() const { void OpenDDLParser::clear() { m_buffer.resize( 0 ); if( ddl_nullptr != m_context ) { - m_context->m_root = ddl_nullptr; + delete m_context; + m_context=ddl_nullptr; } - DDLNode::releaseNodes(); +// DDLNode::releaseNodes(); } bool OpenDDLParser::parse() { @@ -212,11 +214,11 @@ bool OpenDDLParser::parse() { // do the main parsing char *current( &m_buffer[ 0 ] ); - char *end( &m_buffer[ m_buffer.size() - 1 ] + 1 ); + char *end( &m_buffer[m_buffer.size() - 1 ] + 1 ); size_t pos( current - &m_buffer[ 0 ] ); while( pos < m_buffer.size() ) { current = parseNextNode( current, end ); - if(current==ddl_nullptr) { + if ( current == ddl_nullptr ) { return false; } pos = current - &m_buffer[ 0 ]; @@ -245,7 +247,7 @@ static void dumpId( Identifier *id ) { if( ddl_nullptr != id ) { if ( ddl_nullptr != id->m_text.m_buffer ) { std::cout << id->m_text.m_buffer << std::endl; - } + } } } #endif @@ -271,14 +273,17 @@ char *OpenDDLParser::parseHeader( char *in, char *end ) { } else { std::cerr << "nullptr returned by creating DDLNode." << std::endl; } + delete id; Name *name(ddl_nullptr); in = OpenDDLParser::parseName(in, end, &name); if( ddl_nullptr != name && ddl_nullptr != node ) { const std::string nodeName( name->m_id->m_buffer ); node->setName( nodeName ); + delete name; } + Property *first(ddl_nullptr); in = lookForNextToken(in, end); if (*in == Grammar::OpenPropertyToken[0]) { @@ -303,7 +308,7 @@ char *OpenDDLParser::parseHeader( char *in, char *end ) { prev = prop; } } - in++; + ++in; } // set the properties @@ -322,17 +327,17 @@ char *OpenDDLParser::parseStructure( char *in, char *end ) { bool error( false ); in = lookForNextToken( in, end ); - if( *in == '{' ) { + if( *in == *Grammar::OpenBracketToken) { // loop over all children ( data and nodes ) do { in = parseStructureBody( in, end, error ); if(in == ddl_nullptr){ return ddl_nullptr; } - } while ( *in != '}' ); - in++; + } while ( *in != *Grammar::CloseBracketToken); + ++in; } else { - in++; + ++in; logInvalidTokenError( in, std::string( Grammar::OpenBracketToken ), m_logCallback ); error = true; return ddl_nullptr; @@ -373,7 +378,7 @@ static void setNodeDataArrayList( DDLNode *currentNode, DataArrayList *dtArrayLi char *OpenDDLParser::parseStructureBody( char *in, char *end, bool &error ) { if( !isNumeric( *in ) && !isCharacter( *in ) ) { - in++; + ++in; } in = lookForNextToken( in, end ); @@ -431,7 +436,6 @@ DDLNode *OpenDDLParser::popNode() { DDLNode *topNode( top() ); m_stack.pop_back(); - return topNode; } @@ -467,7 +471,14 @@ void OpenDDLParser::normalizeBuffer( std::vector &buffer) { for( size_t readIdx = 0; readIdx( c, end ) && !isNewLine( *c ) ) { + if (isCommentOpenTag(c, end)) { + ++readIdx; + while (!isCommentCloseTag(&buffer[readIdx], end)) { + ++readIdx; + } + ++readIdx; + ++readIdx; + } else if( !isComment( c, end ) && !isNewLine( *c ) ) { newBuffer.push_back( buffer[ readIdx ] ); } else { if( isComment( c, end ) ) { @@ -529,14 +540,17 @@ char *OpenDDLParser::parseIdentifier( char *in, char *end, Text **id ) { // get size of id size_t idLen( 0 ); char *start( in ); - while( !isSeparator( *in ) && !isNewLine( *in ) && ( in != end ) && *in != Grammar::OpenPropertyToken[ 0 ] && *in != Grammar::ClosePropertyToken[ 0 ] && *in != '$' ) { + while( !isSeparator( *in ) && + !isNewLine( *in ) && ( in != end ) && + *in != Grammar::OpenPropertyToken[ 0 ] && + *in != Grammar::ClosePropertyToken[ 0 ] && + *in != '$' ) { ++in; ++idLen; } const size_t len( idLen ); - Text *newId = new Text( start, len ); - *id = newId; + *id = new Text( start, len ); return in; } @@ -552,7 +566,7 @@ char *OpenDDLParser::parsePrimitiveDataType( char *in, char *end, Value::ValueTy for( unsigned int i = 0; i < Value::ddl_types_max; i++ ) { prim_len = strlen( Grammar::PrimitiveTypeToken[ i ] ); if( 0 == strncmp( in, Grammar::PrimitiveTypeToken[ i ], prim_len ) ) { - type = ( Value::ValueType ) i; + type = static_cast( i ); break; } } @@ -567,14 +581,14 @@ char *OpenDDLParser::parsePrimitiveDataType( char *in, char *end, Value::ValueTy bool ok( true ); if( *in == Grammar::OpenArrayToken[ 0 ] ) { ok = false; - in++; + ++in; char *start( in ); while ( in != end ) { - in++; + ++in; if( *in == Grammar::CloseArrayToken[ 0 ] ) { len = ::atoi( start ); ok = true; - in++; + ++in; break; } } @@ -623,10 +637,10 @@ char *OpenDDLParser::parseBooleanLiteral( char *in, char *end, Value **boolean ) char *start( in ); size_t len( 0 ); while( !isSeparator( *in ) && in != end ) { - in++; - len++; + ++in; + ++len; } - len++; + ++len; int res = ::strncmp( Grammar::BoolTrue, start, strlen( Grammar::BoolTrue ) ); if( 0 != res ) { res = ::strncmp( Grammar::BoolFalse, start, strlen( Grammar::BoolFalse ) ); @@ -657,7 +671,7 @@ char *OpenDDLParser::parseIntegerLiteral( char *in, char *end, Value **integer, in = lookForNextToken( in, end ); char *start( in ); while( !isSeparator( *in ) && in != end ) { - in++; + ++in; } if( isNumeric( *start ) ) { @@ -671,29 +685,29 @@ char *OpenDDLParser::parseIntegerLiteral( char *in, char *end, Value **integer, *integer = ValueAllocator::allocPrimData( integerType ); switch( integerType ) { case Value::ddl_int8: - ( *integer )->setInt8( (int8) value ); - break; + ( *integer )->setInt8( (int8) value ); + break; case Value::ddl_int16: - ( *integer )->setInt16( ( int16 ) value ); - break; + ( *integer )->setInt16( ( int16 ) value ); + break; case Value::ddl_int32: - ( *integer )->setInt32( ( int32 ) value ); - break; + ( *integer )->setInt32( ( int32 ) value ); + break; case Value::ddl_int64: - ( *integer )->setInt64( ( int64 ) value ); - break; + ( *integer )->setInt64( ( int64 ) value ); + break; case Value::ddl_unsigned_int8: - ( *integer )->setUnsignedInt8( (uint8) uvalue ); - break; + ( *integer )->setUnsignedInt8( (uint8) uvalue ); + break; case Value::ddl_unsigned_int16: - ( *integer )->setUnsignedInt16( ( uint16 ) uvalue ); - break; + ( *integer )->setUnsignedInt16( ( uint16 ) uvalue ); + break; case Value::ddl_unsigned_int32: - ( *integer )->setUnsignedInt32( ( uint32 ) uvalue ); - break; + ( *integer )->setUnsignedInt32( ( uint32 ) uvalue ); + break; case Value::ddl_unsigned_int64: - ( *integer )->setUnsignedInt64( ( uint64 ) uvalue ); - break; + ( *integer )->setUnsignedInt64( ( uint64 ) uvalue ); + break; default: break; } @@ -711,7 +725,7 @@ char *OpenDDLParser::parseFloatingLiteral( char *in, char *end, Value **floating in = lookForNextToken( in, end ); char *start( in ); while( !isSeparator( *in ) && in != end ) { - in++; + ++in; } // parse the float value @@ -732,8 +746,7 @@ char *OpenDDLParser::parseFloatingLiteral( char *in, char *end, Value **floating } if( ok ) { - if(floatType == Value::ddl_double) - { + if ( floatType == Value::ddl_double ) { const double value( atof( start ) ); *floating = ValueAllocator::allocPrimData( Value::ddl_double ); ( *floating )->setDouble( value ); @@ -757,17 +770,17 @@ char *OpenDDLParser::parseStringLiteral( char *in, char *end, Value **stringData size_t len( 0 ); char *start( in ); if( *start == '\"' ) { - start++; - in++; + ++start; + ++in; while( *in != '\"' && in != end ) { - in++; - len++; + ++in; + ++len; } *stringData = ValueAllocator::allocPrimData( Value::ddl_string, len ); ::strncpy( ( char* ) ( *stringData )->m_data, start, len ); ( *stringData )->m_data[len] = '\0'; - in++; + ++in; } return in; @@ -791,12 +804,12 @@ char *OpenDDLParser::parseHexaLiteral( char *in, char *end, Value **data ) { return in; } - in++; + ++in; if( *in != 'x' && *in != 'X' ) { return in; } - in++; + ++in; bool ok( true ); char *start( in ); int pos( 0 ); @@ -805,8 +818,8 @@ char *OpenDDLParser::parseHexaLiteral( char *in, char *end, Value **data ) { ok = false; break; } - pos++; - in++; + ++pos; + ++in; } if( !ok ) { @@ -816,9 +829,9 @@ char *OpenDDLParser::parseHexaLiteral( char *in, char *end, Value **data ) { int value( 0 ); while( pos > 0 ) { int v = hex2Decimal( *start ); - pos--; + --pos; value = ( value << 4 ) | v; - start++; + ++start; } *data = ValueAllocator::allocPrimData( Value::ddl_unsigned_int64 ); @@ -841,7 +854,7 @@ char *OpenDDLParser::parseProperty( char *in, char *end, Property **prop ) { if( ddl_nullptr != id ) { in = lookForNextToken( in, end ); if( *in == '=' ) { - in++; + ++in; in = getNextToken( in, end ); Value *primData( ddl_nullptr ); if( isInteger( in, end ) ) { @@ -862,6 +875,8 @@ char *OpenDDLParser::parseProperty( char *in, char *end, Property **prop ) { ( *prop )->m_ref = ref; } } + } else { + delete id; } } @@ -878,7 +893,7 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value::ValueType type, in = lookForNextToken( in, end ); if( *in == '{' ) { - in++; + ++in; Value *current( ddl_nullptr ), *prev( ddl_nullptr ); while( '}' != *in ) { current = ddl_nullptr; @@ -934,7 +949,7 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value::ValueType type, prev->setNext( current ); prev = current; } - numValues++; + ++numValues; } in = getNextSeparator( in, end ); @@ -942,7 +957,7 @@ char *OpenDDLParser::parseDataList( char *in, char *end, Value::ValueType type, break; } } - in++; + ++in; } return in; @@ -972,7 +987,7 @@ char *OpenDDLParser::parseDataArrayList( char *in, char *end,Value::ValueType ty in = lookForNextToken( in, end ); if( *in == Grammar::OpenBracketToken[ 0 ] ) { - in++; + ++in; Value *currentValue( ddl_nullptr ); Reference *refs( ddl_nullptr ); DataArrayList *prev( ddl_nullptr ), *currentDataList( ddl_nullptr ); @@ -995,7 +1010,7 @@ char *OpenDDLParser::parseDataArrayList( char *in, char *end,Value::ValueType ty } } while( Grammar::CommaSeparator[ 0 ] == *in && in != end ); in = lookForNextToken( in, end ); - in++; + ++in; } return in; diff --git a/contrib/openddlparser/code/OpenDDLStream.cpp b/contrib/openddlparser/code/OpenDDLStream.cpp new file mode 100644 index 000000000..7ea8331bd --- /dev/null +++ b/contrib/openddlparser/code/OpenDDLStream.cpp @@ -0,0 +1,96 @@ +/*----------------------------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2014-2015 Kim Kulling + +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. +-----------------------------------------------------------------------------------------------*/ +#include + +BEGIN_ODDLPARSER_NS + +StreamFormatterBase::StreamFormatterBase() { + // empty +} + +StreamFormatterBase::~StreamFormatterBase() { + // empty +} + +std::string StreamFormatterBase::format(const std::string &statement) { + std::string tmp(statement); + return tmp; +} + +IOStreamBase::IOStreamBase(StreamFormatterBase *formatter) + : m_formatter(formatter) + , m_file(ddl_nullptr) { + if (ddl_nullptr == m_formatter) { + m_formatter = new StreamFormatterBase; + } +} + +IOStreamBase::~IOStreamBase() { + delete m_formatter; + m_formatter = ddl_nullptr; +} + +bool IOStreamBase::open(const std::string &name) { + m_file = ::fopen(name.c_str(), "a"); + if (m_file == ddl_nullptr) { + return false; + } + + return true; +} + +bool IOStreamBase::close() { + if (ddl_nullptr == m_file) { + return false; + } + + ::fclose(m_file); + m_file = ddl_nullptr; + + return true; +} + +bool IOStreamBase::isOpen() const { + return ( ddl_nullptr != m_file ); +} + +size_t IOStreamBase::read( size_t sizeToRead, std::string &statement ) { + if (ddl_nullptr == m_file) { + return 0; + } + + statement.resize(sizeToRead); + const size_t readBytes = ::fread( &statement[0], 1, sizeToRead, m_file ); + + return readBytes; +} + +size_t IOStreamBase::write(const std::string &statement) { + if (ddl_nullptr == m_file) { + return 0; + } + std::string formatStatement = m_formatter->format(statement); + return ::fwrite(formatStatement.c_str(), sizeof(char), formatStatement.size(), m_file); +} + +END_ODDLPARSER_NS diff --git a/contrib/openddlparser/code/Value.cpp b/contrib/openddlparser/code/Value.cpp index 3e251c508..3c8b06a10 100644 --- a/contrib/openddlparser/code/Value.cpp +++ b/contrib/openddlparser/code/Value.cpp @@ -110,7 +110,17 @@ Value::Value( ValueType type ) } Value::~Value() { - // empty + if(m_data!=ddl_nullptr) { + if (m_type == ddl_ref ) { + Reference *tmp = (Reference *) m_data; + if (tmp != ddl_nullptr) + delete tmp; + }else + delete[] m_data; + + } + if(m_next!=ddl_nullptr) + delete m_next; } void Value::setBool( bool value ) { @@ -273,13 +283,7 @@ void Value::setRef( Reference *ref ) { delete [] m_data; } - m_data = new unsigned char[ sizeof( Reference ) ]; - Reference *myRef = ( Reference * ) m_data; - myRef->m_numRefs = ref->m_numRefs; - myRef->m_referencedName = new Name *[ myRef->m_numRefs ]; - for ( size_t i = 0; i < myRef->m_numRefs; i++ ) { - myRef->m_referencedName[ i ] = new Name( ref->m_referencedName[ i ]->m_type, ref->m_referencedName[ i ]->m_id ); - } + m_data = (unsigned char*) new Reference(*ref); } } } @@ -290,7 +294,7 @@ Reference *Value::getRef() const { return (Reference*) m_data; } -void Value::dump() { +void Value::dump( IOStreamBase &stream ) { switch( m_type ) { case ddl_none: std::cout << "None" << std::endl; @@ -350,7 +354,7 @@ Value *Value::getNext() const { return m_next; } -size_t Value::size(){ +size_t Value::size() const{ size_t result=1; Value *n=m_next; while( n!=ddl_nullptr) { @@ -366,7 +370,6 @@ Value *ValueAllocator::allocPrimData( Value::ValueType type, size_t len ) { } Value *data = new Value( type ); - data->m_type = type; switch( type ) { case Value::ddl_bool: data->m_size = sizeof( bool ); @@ -405,10 +408,10 @@ Value *ValueAllocator::allocPrimData( Value::ValueType type, size_t len ) { data->m_size = sizeof( double ); break; case Value::ddl_string: - data->m_size = sizeof( char ); + data->m_size = sizeof( char )*(len+1); break; case Value::ddl_ref: - data->m_size = sizeof( char ); + data->m_size = 0; break; case Value::ddl_none: case Value::ddl_types_max: @@ -417,12 +420,8 @@ Value *ValueAllocator::allocPrimData( Value::ValueType type, size_t len ) { } if( data->m_size ) { - size_t len1( len ); - if( Value::ddl_string == type ) { - len1++; - } - data->m_size *= len1; data->m_data = new unsigned char[ data->m_size ]; + ::memset(data->m_data,0,data->m_size); } return data; diff --git a/contrib/openddlparser/include/openddlparser/DDLNode.h b/contrib/openddlparser/include/openddlparser/DDLNode.h index 137135604..915bd3041 100644 --- a/contrib/openddlparser/include/openddlparser/DDLNode.h +++ b/contrib/openddlparser/include/openddlparser/DDLNode.h @@ -29,6 +29,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. BEGIN_ODDLPARSER_NS +// Forward declarations +class IOStreamBase; class Value; class OpenDDLParser; @@ -53,6 +55,9 @@ public: /// @brief The child-node-list type. typedef std::vector DllNodeList; + /// @brief The child-node-list iterator. + typedef std::vector::iterator DDLNodeIt; + public: /// @brief The class destructor. ~DDLNode(); @@ -81,7 +86,7 @@ public: const std::string &getType() const; /// Set the name of the DDLNode instance. - /// @param type [in] The name. + /// @param name [in] The name. void setName( const std::string &name ); /// @brief Returns the name of the DDLNode instance. @@ -89,7 +94,7 @@ public: const std::string &getName() const; /// @brief Set a new property set. - /// @param prop [in] The first element of the property set. + /// @param prop [in] The first element of the property set. void setProperties( Property *prop ); /// @brief Returns the first element of the assigned property set. @@ -97,7 +102,7 @@ public: Property *getProperties() const; /// @brief Looks for a given property. - /// @param name [in] The name for the property to look for. + /// @param name [in] The name for the property to look for. /// @return true, if a corresponding property is assigned to the node, false if not. bool hasProperty( const std::string &name ); @@ -106,12 +111,12 @@ public: bool hasProperties() const; /// @brief Search for a given property and returns it. Will return ddl_nullptr if no property was found. - /// @param name [in] The name for the property to look for. + /// @param name [in] The name for the property to look for. /// @return The property or ddl_nullptr if no property was found. Property *findPropertyByName( const std::string &name ); /// @brief Set a new value set. - /// @param val [in] The first value instance of the value set. + /// @param val [in] The first value instance of the value set. void setValue( Value *val ); /// @brief Returns the first element of the assigned value set. @@ -119,7 +124,7 @@ public: Value *getValue() const; /// @brief Set a new DataArrayList. - /// @param val [in] The DataArrayList instance. + /// @param dtArrayList [in] The DataArrayList instance. void setDataArrayList( DataArrayList *dtArrayList ); /// @brief Returns the DataArrayList. @@ -127,17 +132,21 @@ public: DataArrayList *getDataArrayList() const; /// @brief Set a new Reference set. - /// @param val [in] The first value instance of the Reference set. + /// @param refs [in] The first value instance of the Reference set. void setReferences( Reference *refs ); /// @brief Returns the first element of the assigned Reference set. /// @return The first property of the assigned Reference set. Reference *getReferences() const; + /// @brief Will dump the node into the stream. + /// @param stream [in] The stream to write to. + void dump(IOStreamBase &stream); + /// @brief The creation method. - /// @param type [in] The DDLNode type. - /// @param name [in] The name for the new DDLNode instance. - /// @param parent [in] The parent node instance or ddl_nullptr if no parent node is there. + /// @param type [in] The DDLNode type. + /// @param name [in] The name for the new DDLNode instance. + /// @param parent [in] The parent node instance or ddl_nullptr if no parent node is there. /// @return The new created node instance. static DDLNode *create( const std::string &type, const std::string &name, DDLNode *parent = ddl_nullptr ); diff --git a/contrib/openddlparser/include/openddlparser/OpenDDLCommon.h b/contrib/openddlparser/include/openddlparser/OpenDDLCommon.h index d3e0fb458..bec62cc9d 100644 --- a/contrib/openddlparser/include/openddlparser/OpenDDLCommon.h +++ b/contrib/openddlparser/include/openddlparser/OpenDDLCommon.h @@ -148,12 +148,12 @@ struct DLL_ODDLPARSER_EXPORT Name { /// @param type [in] The name type. /// @param id [in] The id. Name( NameType type, Text *id ); - + Name( const Name &name ); /// @brief The destructor. ~Name(); private: - Name( const Name & ) ddl_no_copy; + Name &operator = ( const Name& ) ddl_no_copy; }; @@ -164,7 +164,7 @@ struct DLL_ODDLPARSER_EXPORT Reference { /// @brief The default constructor. Reference(); - + Reference( const Reference &ref ); /// @brief The constructor with an array of ref names. /// @param numrefs [in] The number of ref names. /// @param names [in] The ref names. @@ -178,7 +178,6 @@ struct DLL_ODDLPARSER_EXPORT Reference { size_t sizeInBytes(); private: - Reference( const Reference & ) ddl_no_copy; Reference &operator = ( const Reference & ) ddl_no_copy; }; diff --git a/contrib/openddlparser/include/openddlparser/OpenDDLExport.h b/contrib/openddlparser/include/openddlparser/OpenDDLExport.h index 8ede537d9..020d662a0 100644 --- a/contrib/openddlparser/include/openddlparser/OpenDDLExport.h +++ b/contrib/openddlparser/include/openddlparser/OpenDDLExport.h @@ -23,37 +23,13 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #pragma once #include +#include #include BEGIN_ODDLPARSER_NS -//------------------------------------------------------------------------------------------------- -/// @ingroup IOStreamBase -/// @brief This class represents the stream to write out. -//------------------------------------------------------------------------------------------------- -class DLL_ODDLPARSER_EXPORT StreamFormatterBase { -public: - StreamFormatterBase(); - virtual ~StreamFormatterBase(); - virtual std::string format( const std::string &statement ); -}; - -//------------------------------------------------------------------------------------------------- -/// @ingroup IOStreamBase -/// @brief This class represents the stream to write out. -//------------------------------------------------------------------------------------------------- -class DLL_ODDLPARSER_EXPORT IOStreamBase { -public: - IOStreamBase( StreamFormatterBase *formatter = ddl_nullptr ); - virtual ~IOStreamBase(); - virtual bool open( const std::string &anme ); - virtual bool close(); - virtual size_t write( const std::string &statement ); - -private: - StreamFormatterBase *m_formatter; - FILE *m_file; -}; +// Forward declarations +class IOStreamBase; //------------------------------------------------------------------------------------------------- /// diff --git a/contrib/openddlparser/include/openddlparser/OpenDDLParser.h b/contrib/openddlparser/include/openddlparser/OpenDDLParser.h index efeab6026..e9ac665b5 100644 --- a/contrib/openddlparser/include/openddlparser/OpenDDLParser.h +++ b/contrib/openddlparser/include/openddlparser/OpenDDLParser.h @@ -39,6 +39,16 @@ struct Identifier; struct Reference; struct Property; +template +inline +bool isEmbeddedCommentOpenTag( T *in, T *end ) { + if ( in == '/' && in+1 == '*' ) { + return true; + } + + return false; +} + /// @brief Utility function to search for the next token or the end of the buffer. /// @param in [in] The start position in the buffer. /// @param end [in] The end position in the buffer. @@ -47,7 +57,7 @@ struct Property; template inline T *lookForNextToken( T *in, T *end ) { - while( ( isSpace( *in ) || isNewLine( *in ) || ',' == *in ) && ( in != end ) ) { + while( ( in != end ) && ( isSpace( *in ) || isNewLine( *in ) || ',' == *in ) ) { in++; } return in; diff --git a/contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h b/contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h index 778a1b46e..64897436e 100644 --- a/contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h +++ b/contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h @@ -84,7 +84,7 @@ static const unsigned char chartype_table[ 256 ] = { template inline bool isNumeric( const T in ) { - return ( chartype_table[ static_cast( in ) ] == 1 ); + return ( chartype_table[ static_cast( in ) ] == 1 ); } template @@ -98,7 +98,7 @@ inline bool isInteger( T *in, T *end ) { if( in != end ) { if( *in == '-' ) { - in++; + ++in; } } @@ -108,7 +108,7 @@ bool isInteger( T *in, T *end ) { if( !result ) { break; } - in++; + ++in; } return result; @@ -119,7 +119,7 @@ inline bool isFloat( T *in, T *end ) { if( in != end ) { if( *in == '-' ) { - in++; + ++in; } } @@ -134,12 +134,12 @@ bool isFloat( T *in, T *end ) { if( !result ) { return false; } - in++; + ++in; } // check for 1<.>0f if( *in == '.' ) { - in++; + ++in; } else { return false; } @@ -150,7 +150,7 @@ bool isFloat( T *in, T *end ) { if( !result ) { return false; } - in++; + ++in; } return result; @@ -208,7 +208,7 @@ template inline static T *getNextSeparator( T *in, T *end ) { while( !isSeparator( *in ) || in == end ) { - in++; + ++in; } return in; } @@ -250,5 +250,33 @@ bool isComment( T *in, T *end ) { return false; } +template +inline +bool isCommentOpenTag(T *in, T *end ) { + if (*in == '/') { + if (in + 1 != end) { + if (*(in + 1) == '*') { + return true; + } + } + } + + return false; +} + +template +inline +bool isCommentCloseTag(T *in, T *end) { + if (*in == '*') { + if (in + 1 != end) { + if (*(in + 1) == '/') { + return true; + } + } + } + + return false; +} + END_ODDLPARSER_NS diff --git a/contrib/openddlparser/include/openddlparser/OpenDDLStream.h b/contrib/openddlparser/include/openddlparser/OpenDDLStream.h new file mode 100644 index 000000000..93370da03 --- /dev/null +++ b/contrib/openddlparser/include/openddlparser/OpenDDLStream.h @@ -0,0 +1,89 @@ +/*----------------------------------------------------------------------------------------------- +The MIT License (MIT) + +Copyright (c) 2014-2015 Kim Kulling + +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. +-----------------------------------------------------------------------------------------------*/ +#pragma once + +#include + +BEGIN_ODDLPARSER_NS + +//------------------------------------------------------------------------------------------------- +/// @ingroup IOStreamBase +/// @brief This class represents the stream to write out. +//------------------------------------------------------------------------------------------------- +class DLL_ODDLPARSER_EXPORT StreamFormatterBase { +public: + /// @brief The class constructor. + StreamFormatterBase(); + + /// @brief The class destructor, virtual. + virtual ~StreamFormatterBase(); + + /// @brief Will format the sring and return the new formatted result. + /// @param statement [in] The string to reformat. + /// @return The reformatted result. + virtual std::string format(const std::string &statement); +}; + +//------------------------------------------------------------------------------------------------- +/// @ingroup IOStreamBase +/// @brief This class represents the stream to write out. +//------------------------------------------------------------------------------------------------- +class DLL_ODDLPARSER_EXPORT IOStreamBase { +public: + /// @brief The class constructor with the formatter. + /// @param formatter [in] The formatter to use. + explicit IOStreamBase(StreamFormatterBase *formatter = ddl_nullptr); + + /// @brief The class destructor, virtual. + virtual ~IOStreamBase(); + + /// @brief Will open the stream. + /// @param name [in] The name for the stream. + /// @return true, if the stream was opened successfully, false if not. + virtual bool open(const std::string &name); + + /// @brief Will close the stream. + /// @return true, if the stream was closed successfully, false if not. + virtual bool close(); + + /// @brief Returns true, if the stream is open. + /// @return true, if the stream is open, false if not. + virtual bool isOpen() const; + + /// @brief Will read a string from the stream. + /// @param sizeToRead [in] The size to read in bytes. + /// @param statement [out] The read statements. + /// @return The bytes read from the stream. + virtual size_t read( size_t sizeToRead, std::string &statement ); + + /// @brief Will write a string into the stream. + /// @param statement [in] The string to write. + /// @return The bytes written into the stream. + virtual size_t write(const std::string &statement); + +private: + StreamFormatterBase *m_formatter; + FILE *m_file; +}; + +END_ODDLPARSER_NS diff --git a/contrib/openddlparser/include/openddlparser/Value.h b/contrib/openddlparser/include/openddlparser/Value.h index 242ec8781..77c6da06b 100644 --- a/contrib/openddlparser/include/openddlparser/Value.h +++ b/contrib/openddlparser/include/openddlparser/Value.h @@ -28,8 +28,11 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. BEGIN_ODDLPARSER_NS +// Forward declarations struct ValueAllocator; +class IOStreamBase; + ///------------------------------------------------------------------------------------------------ /// @brief This class implements a value. /// @@ -213,7 +216,7 @@ public: double getDouble() const; /// @brief Assigns a std::string to the value. - /// @param value [in] The value. + /// @param str [in] The value. void setString( const std::string &str ); /// @brief Returns the std::string value. @@ -229,7 +232,8 @@ public: Reference *getRef() const; /// @brief Dumps the value. - void dump(); + /// @param stream [in] The stream to write in. + void dump( IOStreamBase &stream ); /// @brief Assigns the next value. /// @param next [n] The next value. @@ -241,7 +245,7 @@ public: /// @brief Gets the length of the array. /// @return The number of items in the array. - size_t size(); + size_t size() const; ValueType m_type; size_t m_size; diff --git a/contrib/poly2tri/poly2tri/common/shapes.cc b/contrib/poly2tri/poly2tri/common/shapes.cc index 4080445a7..d0de13e64 100644 --- a/contrib/poly2tri/poly2tri/common/shapes.cc +++ b/contrib/poly2tri/poly2tri/common/shapes.cc @@ -1,4 +1,4 @@ -/* +/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * @@ -88,7 +88,7 @@ void Triangle::Clear() points_[0]=points_[1]=points_[2] = NULL; } -void Triangle::ClearNeighbor(Triangle *triangle ) +void Triangle::ClearNeighbor(const Triangle *triangle ) { if( neighbors_[0] == triangle ) { @@ -96,14 +96,14 @@ void Triangle::ClearNeighbor(Triangle *triangle ) } else if( neighbors_[1] == triangle ) { - neighbors_[1] = NULL; + neighbors_[1] = NULL; } else { neighbors_[2] = NULL; } } - + void Triangle::ClearNeighbors() { neighbors_[0] = NULL; @@ -116,13 +116,9 @@ void Triangle::ClearDelunayEdges() delaunay_edge[0] = delaunay_edge[1] = delaunay_edge[2] = false; } -Point* Triangle::OppositePoint(Triangle& t, Point& p) +Point* Triangle::OppositePoint(Triangle& t, const Point& p) { Point *cw = t.PointCW(p); - //double x = cw->x; - //double y = cw->y; - //x = p.x; - //y = p.y; return PointCW(*cw); } @@ -164,8 +160,7 @@ int Triangle::Index(const Point* p) return 2; } assert(0); - - return 0; + return -1; } int Triangle::EdgeIndex(const Point* p1, const Point* p2) @@ -192,7 +187,7 @@ int Triangle::EdgeIndex(const Point* p1, const Point* p2) return -1; } -void Triangle::MarkConstrainedEdge(const int index) +void Triangle::MarkConstrainedEdge(int index) { constrained_edge[index] = true; } @@ -215,7 +210,7 @@ void Triangle::MarkConstrainedEdge(Point* p, Point* q) } // The point counter-clockwise to given point -Point* Triangle::PointCW(Point& point) +Point* Triangle::PointCW(const Point& point) { if (&point == points_[0]) { return points_[2]; @@ -225,12 +220,11 @@ Point* Triangle::PointCW(Point& point) return points_[1]; } assert(0); - - return 0; + return NULL; } // The point counter-clockwise to given point -Point* Triangle::PointCCW(Point& point) +Point* Triangle::PointCCW(const Point& point) { if (&point == points_[0]) { return points_[1]; @@ -240,12 +234,11 @@ Point* Triangle::PointCCW(Point& point) return points_[0]; } assert(0); - - return 0; + return NULL; } // The neighbor clockwise to given point -Triangle* Triangle::NeighborCW(Point& point) +Triangle* Triangle::NeighborCW(const Point& point) { if (&point == points_[0]) { return neighbors_[1]; @@ -256,7 +249,7 @@ Triangle* Triangle::NeighborCW(Point& point) } // The neighbor counter-clockwise to given point -Triangle* Triangle::NeighborCCW(Point& point) +Triangle* Triangle::NeighborCCW(const Point& point) { if (&point == points_[0]) { return neighbors_[2]; @@ -266,7 +259,7 @@ Triangle* Triangle::NeighborCCW(Point& point) return neighbors_[1]; } -bool Triangle::GetConstrainedEdgeCCW(Point& p) +bool Triangle::GetConstrainedEdgeCCW(const Point& p) { if (&p == points_[0]) { return constrained_edge[2]; @@ -276,7 +269,7 @@ bool Triangle::GetConstrainedEdgeCCW(Point& p) return constrained_edge[1]; } -bool Triangle::GetConstrainedEdgeCW(Point& p) +bool Triangle::GetConstrainedEdgeCW(const Point& p) { if (&p == points_[0]) { return constrained_edge[1]; @@ -286,7 +279,7 @@ bool Triangle::GetConstrainedEdgeCW(Point& p) return constrained_edge[0]; } -void Triangle::SetConstrainedEdgeCCW(Point& p, bool ce) +void Triangle::SetConstrainedEdgeCCW(const Point& p, bool ce) { if (&p == points_[0]) { constrained_edge[2] = ce; @@ -297,7 +290,7 @@ void Triangle::SetConstrainedEdgeCCW(Point& p, bool ce) } } -void Triangle::SetConstrainedEdgeCW(Point& p, bool ce) +void Triangle::SetConstrainedEdgeCW(const Point& p, bool ce) { if (&p == points_[0]) { constrained_edge[1] = ce; @@ -308,7 +301,7 @@ void Triangle::SetConstrainedEdgeCW(Point& p, bool ce) } } -bool Triangle::GetDelunayEdgeCCW(Point& p) +bool Triangle::GetDelunayEdgeCCW(const Point& p) { if (&p == points_[0]) { return delaunay_edge[2]; @@ -318,7 +311,7 @@ bool Triangle::GetDelunayEdgeCCW(Point& p) return delaunay_edge[1]; } -bool Triangle::GetDelunayEdgeCW(Point& p) +bool Triangle::GetDelunayEdgeCW(const Point& p) { if (&p == points_[0]) { return delaunay_edge[1]; @@ -328,7 +321,7 @@ bool Triangle::GetDelunayEdgeCW(Point& p) return delaunay_edge[0]; } -void Triangle::SetDelunayEdgeCCW(Point& p, bool e) +void Triangle::SetDelunayEdgeCCW(const Point& p, bool e) { if (&p == points_[0]) { delaunay_edge[2] = e; @@ -339,7 +332,7 @@ void Triangle::SetDelunayEdgeCCW(Point& p, bool e) } } -void Triangle::SetDelunayEdgeCW(Point& p, bool e) +void Triangle::SetDelunayEdgeCW(const Point& p, bool e) { if (&p == points_[0]) { delaunay_edge[1] = e; @@ -351,7 +344,7 @@ void Triangle::SetDelunayEdgeCW(Point& p, bool e) } // The neighbor across to given point -Triangle& Triangle::NeighborAcross(Point& opoint) +Triangle& Triangle::NeighborAcross(const Point& opoint) { if (&opoint == points_[0]) { return *neighbors_[0]; @@ -369,5 +362,4 @@ void Triangle::DebugPrint() cout << points_[2]->x << "," << points_[2]->y << endl; } -} - +} \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/common/shapes.h b/contrib/poly2tri/poly2tri/common/shapes.h index 4f691838f..ac7389a2d 100644 --- a/contrib/poly2tri/poly2tri/common/shapes.h +++ b/contrib/poly2tri/poly2tri/common/shapes.h @@ -113,7 +113,7 @@ struct Point { /// Convert this point into a unit point. Returns the Length. double Normalize() { - double len = Length(); + const double len = Length(); x /= len; y /= len; return len; @@ -162,50 +162,50 @@ bool constrained_edge[3]; /// Flags to determine if an edge is a Delauney edge bool delaunay_edge[3]; -Point* GetPoint(const int& index); -Point* PointCW(Point& point); -Point* PointCCW(Point& point); -Point* OppositePoint(Triangle& t, Point& p); +Point* GetPoint(int index); +Point* PointCW(const Point& point); +Point* PointCCW(const Point& point); +Point* OppositePoint(Triangle& t, const Point& p); -Triangle* GetNeighbor(const int& index); +Triangle* GetNeighbor(int index); void MarkNeighbor(Point* p1, Point* p2, Triangle* t); void MarkNeighbor(Triangle& t); -void MarkConstrainedEdge(const int index); +void MarkConstrainedEdge(int index); void MarkConstrainedEdge(Edge& edge); void MarkConstrainedEdge(Point* p, Point* q); int Index(const Point* p); int EdgeIndex(const Point* p1, const Point* p2); -Triangle* NeighborCW(Point& point); -Triangle* NeighborCCW(Point& point); -bool GetConstrainedEdgeCCW(Point& p); -bool GetConstrainedEdgeCW(Point& p); -void SetConstrainedEdgeCCW(Point& p, bool ce); -void SetConstrainedEdgeCW(Point& p, bool ce); -bool GetDelunayEdgeCCW(Point& p); -bool GetDelunayEdgeCW(Point& p); -void SetDelunayEdgeCCW(Point& p, bool e); -void SetDelunayEdgeCW(Point& p, bool e); +Triangle* NeighborCW(const Point& point); +Triangle* NeighborCCW(const Point& point); +bool GetConstrainedEdgeCCW(const Point& p); +bool GetConstrainedEdgeCW(const Point& p); +void SetConstrainedEdgeCCW(const Point& p, bool ce); +void SetConstrainedEdgeCW(const Point& p, bool ce); +bool GetDelunayEdgeCCW(const Point& p); +bool GetDelunayEdgeCW(const Point& p); +void SetDelunayEdgeCCW(const Point& p, bool e); +void SetDelunayEdgeCW(const Point& p, bool e); -bool Contains(Point* p); +bool Contains(const Point* p); bool Contains(const Edge& e); -bool Contains(Point* p, Point* q); +bool Contains(const Point* p, const Point* q); void Legalize(Point& point); void Legalize(Point& opoint, Point& npoint); /** * Clears all references to all other triangles and points */ void Clear(); -void ClearNeighbor(Triangle *triangle ); +void ClearNeighbor(const Triangle *triangle); void ClearNeighbors(); void ClearDelunayEdges(); inline bool IsInterior(); inline void IsInterior(bool b); -Triangle& NeighborAcross(Point& opoint); +Triangle& NeighborAcross(const Point& opoint); void DebugPrint(); @@ -258,7 +258,7 @@ inline bool operator ==(const Point& a, const Point& b) inline bool operator !=(const Point& a, const Point& b) { - return a.x != b.x || a.y != b.y; + return !(a.x == b.x) && !(a.y == b.y); } /// Peform the dot product on two vectors. @@ -282,22 +282,22 @@ inline Point Cross(const Point& a, double s) /// Perform the cross product on a scalar and a point. In 2D this produces /// a point. -inline Point Cross(const double s, const Point& a) +inline Point Cross(double s, const Point& a) { return Point(-s * a.y, s * a.x); } -inline Point* Triangle::GetPoint(const int& index) +inline Point* Triangle::GetPoint(int index) { return points_[index]; } -inline Triangle* Triangle::GetNeighbor(const int& index) +inline Triangle* Triangle::GetNeighbor(int index) { return neighbors_[index]; } -inline bool Triangle::Contains(Point* p) +inline bool Triangle::Contains(const Point* p) { return p == points_[0] || p == points_[1] || p == points_[2]; } @@ -307,7 +307,7 @@ inline bool Triangle::Contains(const Edge& e) return Contains(e.p) && Contains(e.q); } -inline bool Triangle::Contains(Point* p, Point* q) +inline bool Triangle::Contains(const Point* p, const Point* q) { return Contains(p) && Contains(q); } @@ -324,6 +324,4 @@ inline void Triangle::IsInterior(bool b) } -#endif - - +#endif \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/common/utils.h b/contrib/poly2tri/poly2tri/common/utils.h index f123fedaf..2424c712c 100644 --- a/contrib/poly2tri/poly2tri/common/utils.h +++ b/contrib/poly2tri/poly2tri/common/utils.h @@ -1,4 +1,4 @@ -/* +/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * @@ -28,18 +28,26 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - + #ifndef UTILS_H #define UTILS_H +// Otherwise #defines like M_PI are undeclared under Visual Studio +#define _USE_MATH_DEFINES + #include +#include + +// C99 removes M_PI from math.h +#ifndef M_PI +#define M_PI 3.14159265358979323846264338327 +#endif namespace p2t { -const double PI = 3.1415926535897932384626433832795029; -const double PI_2 = 2 * PI; -const double PI_3div4 = 3 * PI / 4; -const double EPSILON = 1e-15; +const double PI_3div4 = 3 * M_PI / 4; +const double PI_div2 = 1.57079632679489661923; +const double EPSILON = 1e-12; enum Orientation { CW, CCW, COLLINEAR }; @@ -53,7 +61,7 @@ enum Orientation { CW, CCW, COLLINEAR }; * = (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3) * */ -Orientation Orient2d(Point& pa, Point& pb, Point& pc) +Orientation Orient2d(const Point& pa, const Point& pb, const Point& pc) { double detleft = (pa.x - pc.x) * (pb.y - pc.y); double detright = (pa.y - pc.y) * (pb.x - pc.x); @@ -66,6 +74,7 @@ Orientation Orient2d(Point& pa, Point& pb, Point& pc) return CW; } +/* bool InScanArea(Point& pa, Point& pb, Point& pc, Point& pd) { double pdx = pd.x; @@ -97,7 +106,22 @@ bool InScanArea(Point& pa, Point& pb, Point& pc, Point& pd) return true; } +*/ + +bool InScanArea(const Point& pa, const Point& pb, const Point& pc, const Point& pd) +{ + double oadb = (pa.x - pb.x)*(pd.y - pb.y) - (pd.x - pb.x)*(pa.y - pb.y); + if (oadb >= -EPSILON) { + return false; + } + + double oadc = (pa.x - pc.x)*(pd.y - pc.y) - (pd.x - pc.x)*(pa.y - pc.y); + if (oadc <= EPSILON) { + return false; + } + return true; +} + } #endif - diff --git a/contrib/poly2tri/poly2tri/poly2tri.h b/contrib/poly2tri/poly2tri/poly2tri.h index 487755e2e..29a08d052 100644 --- a/contrib/poly2tri/poly2tri/poly2tri.h +++ b/contrib/poly2tri/poly2tri/poly2tri.h @@ -1,4 +1,4 @@ -/* +/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * @@ -35,5 +35,4 @@ #include "common/shapes.h" #include "sweep/cdt.h" -#endif - +#endif \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/advancing_front.cc b/contrib/poly2tri/poly2tri/sweep/advancing_front.cc index 019df4a6e..38723beef 100644 --- a/contrib/poly2tri/poly2tri/sweep/advancing_front.cc +++ b/contrib/poly2tri/poly2tri/sweep/advancing_front.cc @@ -39,7 +39,7 @@ AdvancingFront::AdvancingFront(Node& head, Node& tail) search_node_ = &head; } -Node* AdvancingFront::LocateNode(const double& x) +Node* AdvancingFront::LocateNode(double x) { Node* node = search_node_; @@ -61,7 +61,7 @@ Node* AdvancingFront::LocateNode(const double& x) return NULL; } -Node* AdvancingFront::FindSearchNode(const double& x) +Node* AdvancingFront::FindSearchNode(double x) { (void)x; // suppress compiler warnings "unused parameter 'x'" // TODO: implement BST index @@ -105,5 +105,4 @@ AdvancingFront::~AdvancingFront() { } -} - +} \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/advancing_front.h b/contrib/poly2tri/poly2tri/sweep/advancing_front.h index bab73d449..645dcec97 100644 --- a/contrib/poly2tri/poly2tri/sweep/advancing_front.h +++ b/contrib/poly2tri/poly2tri/sweep/advancing_front.h @@ -74,7 +74,7 @@ Node* search(); void set_search(Node* node); /// Locate insertion point along advancing front -Node* LocateNode(const double& x); +Node* LocateNode(double x); Node* LocatePoint(const Point* point); @@ -82,7 +82,7 @@ private: Node* head_, *tail_, *search_node_; -Node* FindSearchNode(const double& x); +Node* FindSearchNode(double x); }; inline Node* AdvancingFront::head() @@ -115,4 +115,4 @@ inline void AdvancingFront::set_search(Node* node) } -#endif +#endif \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/cdt.cc b/contrib/poly2tri/poly2tri/sweep/cdt.cc index d7838257c..09d088ae3 100644 --- a/contrib/poly2tri/poly2tri/sweep/cdt.cc +++ b/contrib/poly2tri/poly2tri/sweep/cdt.cc @@ -1,4 +1,4 @@ -/* +/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * @@ -32,13 +32,13 @@ namespace p2t { -CDT::CDT(std::vector polyline) +CDT::CDT(const std::vector& polyline) { sweep_context_ = new SweepContext(polyline); sweep_ = new Sweep; } -void CDT::AddHole(std::vector polyline) +void CDT::AddHole(const std::vector& polyline) { sweep_context_->AddHole(polyline); } @@ -68,5 +68,4 @@ CDT::~CDT() delete sweep_; } -} - +} \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/cdt.h b/contrib/poly2tri/poly2tri/sweep/cdt.h index 3e6f02408..ea3286d9a 100644 --- a/contrib/poly2tri/poly2tri/sweep/cdt.h +++ b/contrib/poly2tri/poly2tri/sweep/cdt.h @@ -1,4 +1,4 @@ -/* +/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * @@ -28,7 +28,7 @@ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - + #ifndef CDT_H #define CDT_H @@ -37,11 +37,11 @@ #include "sweep.h" /** - * + * * @author Mason Green * */ - + namespace p2t { class CDT @@ -50,40 +50,40 @@ public: /** * Constructor - add polyline with non repeating points - * + * * @param polyline */ - CDT(std::vector polyline); - + CDT(const std::vector& polyline); + /** * Destructor - clean up memory */ ~CDT(); - + /** * Add a hole - * + * * @param polyline */ - void AddHole(std::vector polyline); - + void AddHole(const std::vector& polyline); + /** * Add a steiner point - * + * * @param point */ void AddPoint(Point* point); - + /** * Triangulate - do this AFTER you've added the polyline, holes, and Steiner points */ void Triangulate(); - + /** * Get CDT triangles */ std::vector GetTriangles(); - + /** * Get triangle map */ @@ -94,7 +94,7 @@ public: /** * Internals */ - + SweepContext* sweep_context_; Sweep* sweep_; @@ -102,4 +102,4 @@ public: } -#endif +#endif \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/sweep.cc b/contrib/poly2tri/poly2tri/sweep/sweep.cc index ed7c49ac4..826905ceb 100644 --- a/contrib/poly2tri/poly2tri/sweep/sweep.cc +++ b/contrib/poly2tri/poly2tri/sweep/sweep.cc @@ -49,7 +49,7 @@ void Sweep::Triangulate(SweepContext& tcx) void Sweep::SweepPoints(SweepContext& tcx) { - for (int i = 1; i < tcx.point_count(); i++) { + for (size_t i = 1; i < tcx.point_count(); i++) { Point& point = *tcx.GetPoint(i); Node* node = &PointEvent(tcx, point); for (unsigned int i = 0; i < point.edge_list.size(); i++) { @@ -117,7 +117,7 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl throw std::runtime_error("EdgeEvent - collinear points not supported"); if( triangle->Contains(&eq, p1)) { triangle->MarkConstrainedEdge(&eq, p1 ); - // We are modifying the constraint maybe it would be better to + // We are modifying the constraint maybe it would be better to // not change the given constraint and just keep a variable for the new constraint tcx.edge_event.constrained_edge->q = p1; triangle = &triangle->NeighborAcross(point); @@ -137,7 +137,7 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl if( triangle->Contains(&eq, p2)) { triangle->MarkConstrainedEdge(&eq, p2 ); - // We are modifying the constraint maybe it would be better to + // We are modifying the constraint maybe it would be better to // not change the given constraint and just keep a variable for the new constraint tcx.edge_event.constrained_edge->q = p2; triangle = &triangle->NeighborAcross(point); @@ -166,7 +166,7 @@ void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangl bool Sweep::IsEdgeSideOfTriangle(Triangle& triangle, Point& ep, Point& eq) { - int index = triangle.EdgeIndex(&ep, &eq); + const int index = triangle.EdgeIndex(&ep, &eq); if (index != -1) { triangle.MarkConstrainedEdge(index); @@ -230,8 +230,8 @@ void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n) Node* node = n.next; while (node->next) { - double angle = HoleAngle(*node); - if (angle > PI_2 || angle < -PI_2) break; + // if HoleAngle exceeds 90 degrees then break. + if (LargeHole_DontFill(node)) break; Fill(tcx, *node); node = node->next; } @@ -240,29 +240,81 @@ void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n) node = n.prev; while (node->prev) { - double angle = HoleAngle(*node); - if (angle > PI_2 || angle < -PI_2) break; + // if HoleAngle exceeds 90 degrees then break. + if (LargeHole_DontFill(node)) break; Fill(tcx, *node); node = node->prev; } // Fill right basins if (n.next && n.next->next) { - double angle = BasinAngle(n); + const double angle = BasinAngle(n); if (angle < PI_3div4) { FillBasin(tcx, n); } } } -double Sweep::BasinAngle(Node& node) +// True if HoleAngle exceeds 90 degrees. +bool Sweep::LargeHole_DontFill(const Node* node) const { + + const Node* nextNode = node->next; + const Node* prevNode = node->prev; + if (!AngleExceeds90Degrees(node->point, nextNode->point, prevNode->point)) + return false; + + // Check additional points on front. + const Node* next2Node = nextNode->next; + // "..Plus.." because only want angles on same side as point being added. + if ((next2Node != NULL) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, next2Node->point, prevNode->point)) + return false; + + const Node* prev2Node = prevNode->prev; + // "..Plus.." because only want angles on same side as point being added. + if ((prev2Node != NULL) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, nextNode->point, prev2Node->point)) + return false; + + return true; +} + +bool Sweep::AngleExceeds90Degrees(const Point* origin, const Point* pa, const Point* pb) const { + const double angle = Angle(origin, pa, pb); + return ((angle > PI_div2) || (angle < -PI_div2)); +} + +bool Sweep::AngleExceedsPlus90DegreesOrIsNegative(const Point* origin, const Point* pa, const Point* pb) const { + const double angle = Angle(origin, pa, pb); + return (angle > PI_div2) || (angle < 0); +} + +double Sweep::Angle(const Point* origin, const Point* pa, const Point* pb) const { + /* Complex plane + * ab = cosA +i*sinA + * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx) + * atan2(y,x) computes the principal value of the argument function + * applied to the complex number x+iy + * Where x = ax*bx + ay*by + * y = ax*by - ay*bx + */ + const double px = origin->x; + const double py = origin->y; + const double ax = pa->x- px; + const double ay = pa->y - py; + const double bx = pb->x - px; + const double by = pb->y - py; + const double x = ax * by - ay * bx; + const double y = ax * bx + ay * by; + return atan2(x, y); +} + +double Sweep::BasinAngle(const Node& node) const { - double ax = node.point->x - node.next->next->point->x; - double ay = node.point->y - node.next->next->point->y; + const double ax = node.point->x - node.next->next->point->x; + const double ay = node.point->y - node.next->next->point->y; return atan2(ay, ax); } -double Sweep::HoleAngle(Node& node) +double Sweep::HoleAngle(const Node& node) const { /* Complex plane * ab = cosA +i*sinA @@ -272,10 +324,10 @@ double Sweep::HoleAngle(Node& node) * Where x = ax*bx + ay*by * y = ax*by - ay*bx */ - double ax = node.next->point->x - node.point->x; - double ay = node.next->point->y - node.point->y; - double bx = node.prev->point->x - node.point->x; - double by = node.prev->point->y - node.point->y; + const double ax = node.next->point->x - node.point->x; + const double ay = node.next->point->y - node.point->y; + const double bx = node.prev->point->x - node.point->x; + const double by = node.prev->point->y - node.point->y; return atan2(ax * by - ay * bx, ax * bx + ay * by); } @@ -340,43 +392,43 @@ bool Sweep::Legalize(SweepContext& tcx, Triangle& t) return false; } -bool Sweep::Incircle(Point& pa, Point& pb, Point& pc, Point& pd) +bool Sweep::Incircle(const Point& pa, const Point& pb, const Point& pc, const Point& pd) const { - double adx = pa.x - pd.x; - double ady = pa.y - pd.y; - double bdx = pb.x - pd.x; - double bdy = pb.y - pd.y; + const double adx = pa.x - pd.x; + const double ady = pa.y - pd.y; + const double bdx = pb.x - pd.x; + const double bdy = pb.y - pd.y; - double adxbdy = adx * bdy; - double bdxady = bdx * ady; - double oabd = adxbdy - bdxady; + const double adxbdy = adx * bdy; + const double bdxady = bdx * ady; + const double oabd = adxbdy - bdxady; if (oabd <= 0) return false; - double cdx = pc.x - pd.x; - double cdy = pc.y - pd.y; + const double cdx = pc.x - pd.x; + const double cdy = pc.y - pd.y; - double cdxady = cdx * ady; - double adxcdy = adx * cdy; - double ocad = cdxady - adxcdy; + const double cdxady = cdx * ady; + const double adxcdy = adx * cdy; + const double ocad = cdxady - adxcdy; if (ocad <= 0) return false; - double bdxcdy = bdx * cdy; - double cdxbdy = cdx * bdy; + const double bdxcdy = bdx * cdy; + const double cdxbdy = cdx * bdy; - double alift = adx * adx + ady * ady; - double blift = bdx * bdx + bdy * bdy; - double clift = cdx * cdx + cdy * cdy; + const double alift = adx * adx + ady * ady; + const double blift = bdx * bdx + bdy * bdy; + const double clift = cdx * cdx + cdy * cdy; - double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd; + const double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd; return det > 0; } -void Sweep::RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op) +void Sweep::RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op) const { Triangle* n1, *n2, *n3, *n4; n1 = t.NeighborCCW(p); @@ -708,11 +760,8 @@ Point& Sweep::NextFlipPoint(Point& ep, Point& eq, Triangle& ot, Point& op) } else if (o2d == CCW) { // Left return *ot.PointCW(op); - } else{ - //throw new RuntimeException("[Unsupported] Opposing point on constrained edge"); - // ASSIMP_CHANGE (aramis_acg) - throw std::runtime_error("[Unsupported] Opposing point on constrained edge"); } + throw std::runtime_error("[Unsupported] Opposing point on constrained edge"); } void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& flip_triangle, @@ -740,7 +789,7 @@ void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& Sweep::~Sweep() { // Clean up memory - for(unsigned int i = 0; i < nodes_.size(); i++) { + for(size_t i = 0; i < nodes_.size(); i++) { delete nodes_[i]; } diff --git a/contrib/poly2tri/poly2tri/sweep/sweep.h b/contrib/poly2tri/poly2tri/sweep/sweep.h index bd98adfc5..33e34a714 100644 --- a/contrib/poly2tri/poly2tri/sweep/sweep.h +++ b/contrib/poly2tri/poly2tri/sweep/sweep.h @@ -33,7 +33,7 @@ * Zalik, B.(2008)'Sweep-line algorithm for constrained Delaunay triangulation', * International Journal of Geographical Information Science * - * "FlipScan" Constrained Edge Algorithm invented by Thomas Åhlén, thahlen@gmail.com + * "FlipScan" Constrained Edge Algorithm invented by Thomas ?hl?n, thahlen@gmail.com */ #ifndef SWEEP_H @@ -49,17 +49,17 @@ struct Point; struct Edge; class Triangle; -class Sweep +class Sweep { public: /** * Triangulate - * + * * @param tcx */ void Triangulate(SweepContext& tcx); - + /** * Destructor - clean up memory */ @@ -69,7 +69,7 @@ private: /** * Start sweeping the Y-sorted point set from bottom to top - * + * * @param tcx */ void SweepPoints(SweepContext& tcx); @@ -86,8 +86,8 @@ private: Node& PointEvent(SweepContext& tcx, Point& point); /** - * - * + * + * * @param tcx * @param edge * @param node @@ -98,7 +98,7 @@ private: /** * Creates a new front triangle and legalize it - * + * * @param tcx * @param point * @param node @@ -142,7 +142,7 @@ private: * @param d - point opposite a * @return true if d is inside circle, false if on circle edge */ - bool Incircle(Point& pa, Point& pb, Point& pc, Point& pd); + bool Incircle(const Point& pa, const Point& pb, const Point& pc, const Point& pd) const; /** * Rotates a triangle pair one vertex CW @@ -158,7 +158,7 @@ private: * n4 n4 * */ - void RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op); + void RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op) const; /** * Fills holes in the Advancing Front @@ -169,17 +169,24 @@ private: */ void FillAdvancingFront(SweepContext& tcx, Node& n); + // Decision-making about when to Fill hole. + // Contributed by ToolmakerSteve2 + bool LargeHole_DontFill(const Node* node) const; + bool AngleExceeds90Degrees(const Point* origin, const Point* pa, const Point* pb) const; + bool AngleExceedsPlus90DegreesOrIsNegative(const Point* origin, const Point* pa, const Point* pb) const; + double Angle(const Point* origin, const Point* pa, const Point* pb) const; + /** * * @param node - middle node * @return the angle between 3 front nodes */ - double HoleAngle(Node& node); + double HoleAngle(const Node& node) const; /** * The basin angle is decided against the horizontal line [1,0] */ - double BasinAngle(Node& node); + double BasinAngle(const Node& node) const; /** * Fills a basin that has formed on the Advancing Front to the right @@ -228,22 +235,22 @@ private: /** * After a flip we have two triangles and know that only one will still be * intersecting the edge. So decide which to contiune with and legalize the other - * + * * @param tcx * @param o - should be the result of an orient2d( eq, op, ep ) * @param t - triangle 1 * @param ot - triangle 2 - * @param p - a point shared by both triangles + * @param p - a point shared by both triangles * @param op - another point shared by both triangles * @return returns the triangle still intersecting the edge */ Triangle& NextFlipTriangle(SweepContext& tcx, int o, Triangle& t, Triangle& ot, Point& p, Point& op); /** - * When we need to traverse from one triangle to the next we need + * When we need to traverse from one triangle to the next we need * the point in current triangle that is the opposite point to the next - * triangle. - * + * triangle. + * * @param ep * @param eq * @param ot @@ -254,10 +261,10 @@ private: /** * Scan part of the FlipScan algorithm
- * When a triangle pair isn't flippable we will scan for the next - * point that is inside the flip triangle scan area. When found + * When a triangle pair isn't flippable we will scan for the next + * point that is inside the flip triangle scan area. When found * we generate a new flipEdgeEvent - * + * * @param tcx * @param ep - last point on the edge we are traversing * @param eq - first point on the edge we are traversing @@ -275,4 +282,4 @@ private: } -#endif +#endif \ No newline at end of file diff --git a/contrib/poly2tri/poly2tri/sweep/sweep_context.cc b/contrib/poly2tri/poly2tri/sweep/sweep_context.cc index 184457cf2..a9f1fdf8e 100644 --- a/contrib/poly2tri/poly2tri/sweep/sweep_context.cc +++ b/contrib/poly2tri/poly2tri/sweep/sweep_context.cc @@ -34,17 +34,18 @@ namespace p2t { -SweepContext::SweepContext(std::vector polyline) +SweepContext::SweepContext(const std::vector& polyline) : points_(polyline), + front_(0), + head_(0), + tail_(0), + af_head_(0), + af_middle_(0), + af_tail_(0) { - basin = Basin(); - edge_event = EdgeEvent(); - - points_ = polyline; - InitEdges(points_); } -void SweepContext::AddHole(std::vector polyline) +void SweepContext::AddHole(const std::vector& polyline) { InitEdges(polyline); for(unsigned int i = 0; i < polyline.size(); i++) { @@ -56,12 +57,12 @@ void SweepContext::AddPoint(Point* point) { points_.push_back(point); } -std::vector SweepContext::GetTriangles() +std::vector &SweepContext::GetTriangles() { return triangles_; } -std::list SweepContext::GetMap() +std::list &SweepContext::GetMap() { return map_; } @@ -94,16 +95,16 @@ void SweepContext::InitTriangulation() } -void SweepContext::InitEdges(std::vector polyline) +void SweepContext::InitEdges(const std::vector& polyline) { - int num_points = static_cast(polyline.size()); - for (int i = 0; i < num_points; i++) { - int j = i < num_points - 1 ? i + 1 : 0; + size_t num_points = polyline.size(); + for (size_t i = 0; i < num_points; i++) { + size_t j = i < num_points - 1 ? i + 1 : 0; edge_list.push_back(new Edge(*polyline[i], *polyline[j])); } } -Point* SweepContext::GetPoint(const int& index) +Point* SweepContext::GetPoint(size_t index) { return points_[index]; } @@ -113,13 +114,13 @@ void SweepContext::AddToMap(Triangle* triangle) map_.push_back(triangle); } -Node& SweepContext::LocateNode(Point& point) +Node& SweepContext::LocateNode(const Point& point) { // TODO implement search tree return *front_->LocateNode(point.x); } -void SweepContext::CreateAdvancingFront(std::vector nodes) +void SweepContext::CreateAdvancingFront(const std::vector& nodes) { (void) nodes; @@ -164,12 +165,20 @@ void SweepContext::RemoveFromMap(Triangle* triangle) void SweepContext::MeshClean(Triangle& triangle) { - if (!triangle.IsInterior()) { - triangle.IsInterior(true); - triangles_.push_back(&triangle); - for (int i = 0; i < 3; i++) { - if (!triangle.constrained_edge[i]) - MeshClean(*triangle.GetNeighbor(i)); + std::vector triangles; + triangles.push_back(&triangle); + + while(!triangles.empty()){ + Triangle *t = triangles.back(); + triangles.pop_back(); + + if (t != NULL && !t->IsInterior()) { + t->IsInterior(true); + triangles_.push_back(t); + for (int i = 0; i < 3; i++) { + if (!t->constrained_edge[i]) + triangles.push_back(t->GetNeighbor(i)); + } } } } diff --git a/contrib/poly2tri/poly2tri/sweep/sweep_context.h b/contrib/poly2tri/poly2tri/sweep/sweep_context.h index 2f7d8e982..ba0d06581 100644 --- a/contrib/poly2tri/poly2tri/sweep/sweep_context.h +++ b/contrib/poly2tri/poly2tri/sweep/sweep_context.h @@ -52,47 +52,47 @@ class SweepContext { public: /// Constructor -SweepContext(std::vector polyline); +SweepContext(const std::vector& polyline); /// Destructor ~SweepContext(); void set_head(Point* p1); -Point* head(); +Point* head() const; void set_tail(Point* p1); -Point* tail(); +Point* tail() const; -int point_count(); +size_t point_count() const; -Node& LocateNode(Point& point); +Node& LocateNode(const Point& point); void RemoveNode(Node* node); -void CreateAdvancingFront(std::vector nodes); +void CreateAdvancingFront(const std::vector& nodes); /// Try to map a node to all sides of this triangle that don't have a neighbor void MapTriangleToNodes(Triangle& t); void AddToMap(Triangle* triangle); -Point* GetPoint(const int& index); +Point* GetPoint(size_t index); Point* GetPoints(); void RemoveFromMap(Triangle* triangle); -void AddHole(std::vector polyline); +void AddHole(const std::vector& polyline); void AddPoint(Point* point); -AdvancingFront* front(); +AdvancingFront* front() const; void MeshClean(Triangle& triangle); -std::vector GetTriangles(); -std::list GetMap(); +std::vector &GetTriangles(); +std::list &GetMap(); std::vector edge_list; @@ -147,18 +147,18 @@ Point* tail_; Node *af_head_, *af_middle_, *af_tail_; void InitTriangulation(); -void InitEdges(std::vector polyline); +void InitEdges(const std::vector& polyline); }; -inline AdvancingFront* SweepContext::front() +inline AdvancingFront* SweepContext::front() const { return front_; } -inline int SweepContext::point_count() +inline size_t SweepContext::point_count() const { - return static_cast(points_.size()); + return points_.size(); } inline void SweepContext::set_head(Point* p1) @@ -166,7 +166,7 @@ inline void SweepContext::set_head(Point* p1) head_ = p1; } -inline Point* SweepContext::head() +inline Point* SweepContext::head() const { return head_; } @@ -176,7 +176,7 @@ inline void SweepContext::set_tail(Point* p1) tail_ = p1; } -inline Point* SweepContext::tail() +inline Point* SweepContext::tail() const { return tail_; } diff --git a/contrib/rapidjson/include/rapidjson/allocators.h b/contrib/rapidjson/include/rapidjson/allocators.h index d74a67155..655f4a385 100644 --- a/contrib/rapidjson/include/rapidjson/allocators.h +++ b/contrib/rapidjson/include/rapidjson/allocators.h @@ -179,9 +179,10 @@ public: size = RAPIDJSON_ALIGN(size); if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) - AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size); + if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) + return NULL; - void *buffer = reinterpret_cast(chunkHead_ + 1) + chunkHead_->size; + void *buffer = reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; chunkHead_->size += size; return buffer; } @@ -194,14 +195,16 @@ public: if (newSize == 0) return NULL; + originalSize = RAPIDJSON_ALIGN(originalSize); + newSize = RAPIDJSON_ALIGN(newSize); + // Do not shrink if new size is smaller than original if (originalSize >= newSize) return originalPtr; // Simply expand it if it is the last allocation and there is sufficient space - if (originalPtr == (char *)(chunkHead_ + 1) + chunkHead_->size - originalSize) { + if (originalPtr == reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { size_t increment = static_cast(newSize - originalSize); - increment = RAPIDJSON_ALIGN(increment); if (chunkHead_->size + increment <= chunkHead_->capacity) { chunkHead_->size += increment; return originalPtr; @@ -209,11 +212,13 @@ public: } // Realloc process: allocate and copy memory, do not free original buffer. - void* newBuffer = Malloc(newSize); - RAPIDJSON_ASSERT(newBuffer != 0); // Do not handle out-of-memory explicitly. - if (originalSize) - std::memcpy(newBuffer, originalPtr, originalSize); - return newBuffer; + if (void* newBuffer = Malloc(newSize)) { + if (originalSize) + std::memcpy(newBuffer, originalPtr, originalSize); + return newBuffer; + } + else + return NULL; } //! Frees a memory block (concept Allocator) @@ -227,15 +232,20 @@ private: //! Creates a new chunk. /*! \param capacity Capacity of the chunk in bytes. + \return true if success. */ - void AddChunk(size_t capacity) { + bool AddChunk(size_t capacity) { if (!baseAllocator_) - ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator()); - ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(sizeof(ChunkHeader) + capacity)); - chunk->capacity = capacity; - chunk->size = 0; - chunk->next = chunkHead_; - chunkHead_ = chunk; + ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)(); + if (ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) { + chunk->capacity = capacity; + chunk->size = 0; + chunk->next = chunkHead_; + chunkHead_ = chunk; + return true; + } + else + return false; } static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. diff --git a/contrib/rapidjson/include/rapidjson/document.h b/contrib/rapidjson/include/rapidjson/document.h index c6acbd907..93b091f64 100644 --- a/contrib/rapidjson/include/rapidjson/document.h +++ b/contrib/rapidjson/include/rapidjson/document.h @@ -20,40 +20,29 @@ #include "reader.h" #include "internal/meta.h" #include "internal/strfunc.h" +#include "memorystream.h" +#include "encodedstream.h" #include // placement new +#include +RAPIDJSON_DIAG_PUSH #ifdef _MSC_VER -RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant -#elif defined(__GNUC__) -RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(switch-enum) +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + +#ifdef __GNUC__ RAPIDJSON_DIAG_OFF(effc++) +#if __GNUC__ >= 6 +RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_NOEXCEPT functions #endif - -/////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_HAS_STDSTRING - -#ifndef RAPIDJSON_HAS_STDSTRING -#ifdef RAPIDJSON_DOXYGEN_RUNNING -#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation -#else -#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default -#endif -/*! \def RAPIDJSON_HAS_STDSTRING - \ingroup RAPIDJSON_CONFIG - \brief Enable RapidJSON support for \c std::string - - By defining this preprocessor symbol to \c 1, several convenience functions for using - \ref rapidjson::GenericValue with \c std::string are enabled, especially - for construction and comparison. - - \hideinitializer -*/ -#endif // !defined(RAPIDJSON_HAS_STDSTRING) - -#if RAPIDJSON_HAS_STDSTRING -#include -#endif // RAPIDJSON_HAS_STDSTRING +#endif // __GNUC__ #ifndef RAPIDJSON_NOMEMBERITERATORCLASS #include // std::iterator, std::random_access_iterator_tag @@ -69,6 +58,9 @@ RAPIDJSON_NAMESPACE_BEGIN template class GenericValue; +template +class GenericDocument; + //! Name-value pair in a JSON object value. /*! This class was internal to GenericValue. It used to be a inner struct. @@ -155,6 +147,7 @@ public: Otherwise, the copy constructor is implicitly defined. */ GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} + Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; } //! @name stepping //@{ @@ -257,6 +250,7 @@ struct GenericStringRef { typedef CharType Ch; //!< character type of the string //! Create string reference from \c const character array +#ifndef __clang__ // -Wdocumentation /*! This constructor implicitly creates a constant string reference from a \c const character array. It has better performance than @@ -279,11 +273,13 @@ struct GenericStringRef { In such cases, the referenced string should be \b copied to the GenericValue instead. */ +#endif template GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT : s(str), length(N-1) {} //! Explicitly create string reference from \c const character pointer +#ifndef __clang__ // -Wdocumentation /*! This constructor can be used to \b explicitly create a reference to a constant string pointer. @@ -302,18 +298,23 @@ struct GenericStringRef { In such cases, the referenced string should be \b copied to the GenericValue instead. */ +#endif explicit GenericStringRef(const CharType* str) - : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != NULL); } + : s(str), length(NotNullStrLen(str)) {} //! Create constant string reference from pointer and length +#ifndef __clang__ // -Wdocumentation /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \param len length of the string, excluding the trailing NULL terminator \post \ref s == str && \ref length == len \note Constant complexity. */ +#endif GenericStringRef(const CharType* str, SizeType len) - : s(str), length(len) { RAPIDJSON_ASSERT(s != NULL); } + : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); } + + GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {} //! implicit conversion to plain CharType pointer operator const Ch *() const { return s; } @@ -322,13 +323,24 @@ struct GenericStringRef { const SizeType length; //!< length of the string (excluding the trailing NULL terminator) private: - //! Disallow copy-assignment - GenericStringRef operator=(const GenericStringRef&); + SizeType NotNullStrLen(const CharType* str) { + RAPIDJSON_ASSERT(str != 0); + return internal::StrLen(str); + } + + /// Empty string - used when passing in a NULL pointer + static const Ch emptyString[]; + //! Disallow construction from non-const array template GenericStringRef(CharType (&str)[N]) /* = delete */; + //! Copy assignment operator not permitted - immutable type + GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */; }; +template +const CharType GenericStringRef::emptyString[] = { CharType() }; + //! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function can be used to avoid copying a character string to be referenced as a @@ -343,7 +355,7 @@ private: */ template inline GenericStringRef StringRef(const CharType* str) { - return GenericStringRef(str, internal::StrLen(str)); + return GenericStringRef(str); } //! Mark a character pointer as constant string @@ -401,6 +413,127 @@ template struct IsGenericValue : IsGenericValueImpl::Type {}; } // namespace internal +/////////////////////////////////////////////////////////////////////////////// +// TypeHelper + +namespace internal { + +template +struct TypeHelper {}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsBool(); } + static bool Get(const ValueType& v) { return v.GetBool(); } + static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); } + static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt(); } + static int Get(const ValueType& v) { return v.GetInt(); } + static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); } + static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint(); } + static unsigned Get(const ValueType& v) { return v.GetUint(); } + static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); } + static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsInt64(); } + static int64_t Get(const ValueType& v) { return v.GetInt64(); } + static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); } + static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsUint64(); } + static uint64_t Get(const ValueType& v) { return v.GetUint64(); } + static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); } + static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsDouble(); } + static double Get(const ValueType& v) { return v.GetDouble(); } + static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); } + static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); } +}; + +template +struct TypeHelper { + static bool Is(const ValueType& v) { return v.IsFloat(); } + static float Get(const ValueType& v) { return v.GetFloat(); } + static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); } + static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); } +}; + +template +struct TypeHelper { + typedef const typename ValueType::Ch* StringType; + static bool Is(const ValueType& v) { return v.IsString(); } + static StringType Get(const ValueType& v) { return v.GetString(); } + static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); } + static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } +}; + +#if RAPIDJSON_HAS_STDSTRING +template +struct TypeHelper > { + typedef std::basic_string StringType; + static bool Is(const ValueType& v) { return v.IsString(); } + static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); } + static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } +}; +#endif + +template +struct TypeHelper { + typedef typename ValueType::Array ArrayType; + static bool Is(const ValueType& v) { return v.IsArray(); } + static ArrayType Get(ValueType& v) { return v.GetArray(); } + static ValueType& Set(ValueType& v, ArrayType data) { return v = data; } + static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; } +}; + +template +struct TypeHelper { + typedef typename ValueType::ConstArray ArrayType; + static bool Is(const ValueType& v) { return v.IsArray(); } + static ArrayType Get(const ValueType& v) { return v.GetArray(); } +}; + +template +struct TypeHelper { + typedef typename ValueType::Object ObjectType; + static bool Is(const ValueType& v) { return v.IsObject(); } + static ObjectType Get(ValueType& v) { return v.GetObject(); } + static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } + static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; } +}; + +template +struct TypeHelper { + typedef typename ValueType::ConstObject ObjectType; + static bool Is(const ValueType& v) { return v.IsObject(); } + static ObjectType Get(const ValueType& v) { return v.GetObject(); } +}; + +} // namespace internal + +// Forward declarations +template class GenericArray; +template class GenericObject; + /////////////////////////////////////////////////////////////////////////////// // GenericValue @@ -428,17 +561,21 @@ public: typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. typedef GenericValue ValueType; //!< Value type of itself. + typedef GenericArray Array; + typedef GenericArray ConstArray; + typedef GenericObject Object; + typedef GenericObject ConstObject; //!@name Constructors and destructor. //@{ //! Default constructor creates a null value. - GenericValue() RAPIDJSON_NOEXCEPT : data_(), flags_(kNullFlag) {} + GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 - GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_), flags_(rhs.flags_) { - rhs.flags_ = kNullFlag; // give up contents + GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) { + rhs.data_.f.flags = kNullFlag; // give up contents } #endif @@ -446,6 +583,16 @@ private: //! Copy constructor is not permitted. GenericValue(const GenericValue& rhs); +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Moving from a GenericDocument is not permitted. + template + GenericValue(GenericDocument&& rhs); + + //! Move assignment from a GenericDocument is not permitted. + template + GenericValue& operator=(GenericDocument&& rhs); +#endif + public: //! Constructor with JSON value type. @@ -453,13 +600,13 @@ public: \param type Type of the value. \note Default content for number is zero. */ - explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_(), flags_() { - static const unsigned defaultFlags[7] = { + explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() { + static const uint16_t defaultFlags[7] = { kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, kNumberAnyFlag }; - RAPIDJSON_ASSERT(type <= kNumberType); - flags_ = defaultFlags[type]; + RAPIDJSON_ASSERT(type >= kNullType && type <= kNumberType); + data_.f.flags = defaultFlags[type]; // Use ShortString to store empty string. if (type == kStringType) @@ -471,10 +618,50 @@ public: \tparam SourceAllocator allocator of \c rhs \param rhs Value to copy from (read-only) \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). + \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) \see CopyFrom() */ - template< typename SourceAllocator > - GenericValue(const GenericValue& rhs, Allocator & allocator); + template + GenericValue(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { + switch (rhs.GetType()) { + case kObjectType: { + SizeType count = rhs.data_.o.size; + Member* lm = reinterpret_cast(allocator.Malloc(count * sizeof(Member))); + const typename GenericValue::Member* rm = rhs.GetMembersPointer(); + for (SizeType i = 0; i < count; i++) { + new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings); + new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings); + } + data_.f.flags = kObjectFlag; + data_.o.size = data_.o.capacity = count; + SetMembersPointer(lm); + } + break; + case kArrayType: { + SizeType count = rhs.data_.a.size; + GenericValue* le = reinterpret_cast(allocator.Malloc(count * sizeof(GenericValue))); + const GenericValue* re = rhs.GetElementsPointer(); + for (SizeType i = 0; i < count; i++) + new (&le[i]) GenericValue(re[i], allocator, copyConstStrings); + data_.f.flags = kArrayFlag; + data_.a.size = data_.a.capacity = count; + SetElementsPointer(le); + } + break; + case kStringType: + if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) { + data_.f.flags = rhs.data_.f.flags; + data_ = *reinterpret_cast(&rhs.data_); + } + else + SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); + break; + default: + data_.f.flags = rhs.data_.f.flags; + data_ = *reinterpret_cast(&rhs.data_); + break; + } + } //! Constructor for boolean value. /*! \param b Boolean value @@ -484,96 +671,125 @@ public: */ #ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen template - explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame))) RAPIDJSON_NOEXCEPT + explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame))) RAPIDJSON_NOEXCEPT // See #472 #else explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT #endif - : data_(), flags_(b ? kTrueFlag : kFalseFlag) { + : data_() { // safe-guard against failing SFINAE RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value)); + data_.f.flags = b ? kTrueFlag : kFalseFlag; } //! Constructor for int value. - explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberIntFlag) { + explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() { data_.n.i64 = i; - if (i >= 0) - flags_ |= kUintFlag | kUint64Flag; + data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag; } //! Constructor for unsigned value. - explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUintFlag) { + explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() { data_.n.u64 = u; - if (!(u & 0x80000000)) - flags_ |= kIntFlag | kInt64Flag; + data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag); } //! Constructor for int64_t value. - explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberInt64Flag) { + explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() { data_.n.i64 = i64; + data_.f.flags = kNumberInt64Flag; if (i64 >= 0) { - flags_ |= kNumberUint64Flag; + data_.f.flags |= kNumberUint64Flag; if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) - flags_ |= kUintFlag; + data_.f.flags |= kUintFlag; if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - flags_ |= kIntFlag; + data_.f.flags |= kIntFlag; } else if (i64 >= static_cast(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - flags_ |= kIntFlag; + data_.f.flags |= kIntFlag; } //! Constructor for uint64_t value. - explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberUint64Flag) { + explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() { data_.n.u64 = u64; + data_.f.flags = kNumberUint64Flag; if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) - flags_ |= kInt64Flag; + data_.f.flags |= kInt64Flag; if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) - flags_ |= kUintFlag; + data_.f.flags |= kUintFlag; if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) - flags_ |= kIntFlag; + data_.f.flags |= kIntFlag; } //! Constructor for double value. - explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_(), flags_(kNumberDoubleFlag) { data_.n.d = d; } + explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; } + + //! Constructor for float value. + explicit GenericValue(float f) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast(f); data_.f.flags = kNumberDoubleFlag; } //! Constructor for constant string (i.e. do not make a copy of string) - GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(StringRef(s, length)); } + GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); } //! Constructor for constant string (i.e. do not make a copy of string) - explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_(), flags_() { SetStringRaw(s); } + explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); } //! Constructor for copy-string (i.e. do make a copy of string) - GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s, length), allocator); } + GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); } //! Constructor for copy-string (i.e. do make a copy of string) - GenericValue(const Ch*s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); } + GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } #if RAPIDJSON_HAS_STDSTRING //! Constructor for copy-string from a string object (i.e. do make a copy of string) /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ - GenericValue(const std::basic_string& s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); } + GenericValue(const std::basic_string& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } #endif + //! Constructor for Array. + /*! + \param a An array obtained by \c GetArray(). + \note \c Array is always pass-by-value. + \note the source array is moved into this value and the sourec array becomes empty. + */ + GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) { + a.value_.data_ = Data(); + a.value_.data_.f.flags = kArrayFlag; + } + + //! Constructor for Object. + /*! + \param o An object obtained by \c GetObject(). + \note \c Object is always pass-by-value. + \note the source object is moved into this value and the sourec object becomes empty. + */ + GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) { + o.value_.data_ = Data(); + o.value_.data_.f.flags = kObjectFlag; + } + //! Destructor. /*! Need to destruct elements of array, members of object, or copy-string. */ ~GenericValue() { if (Allocator::kNeedFree) { // Shortcut by Allocator's trait - switch(flags_) { + switch(data_.f.flags) { case kArrayFlag: - for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) - v->~GenericValue(); - Allocator::Free(data_.a.elements); + { + GenericValue* e = GetElementsPointer(); + for (GenericValue* v = e; v != e + data_.a.size; ++v) + v->~GenericValue(); + Allocator::Free(e); + } break; case kObjectFlag: for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) m->~Member(); - Allocator::Free(data_.o.members); + Allocator::Free(GetMembersPointer()); break; case kCopyStringFlag: - Allocator::Free(const_cast(data_.s.str)); + Allocator::Free(const_cast(GetStringPointer())); break; default: @@ -638,12 +854,13 @@ public: \tparam SourceAllocator Allocator type of \c rhs \param rhs Value to copy from (read-only) \param allocator Allocator to use for copying + \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) */ template - GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator) { - RAPIDJSON_ASSERT((void*)this != (void const*)&rhs); + GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { + RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs)); this->~GenericValue(); - new (this) GenericValue(rhs, allocator); + new (this) GenericValue(rhs, allocator, copyConstStrings); return *this; } @@ -660,6 +877,20 @@ public: return *this; } + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.value, b.value); + // ... + } + \endcode + \see Swap() + */ + friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } + //! Prepare Value for move semantics /*! \return *this */ GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } @@ -709,7 +940,7 @@ public: else return data_.n.u64 == rhs.data_.n.u64; - default: // kTrueType, kFalseType, kNullType + default: return true; } } @@ -757,20 +988,58 @@ public: //!@name Type //@{ - Type GetType() const { return static_cast(flags_ & kTypeMask); } - bool IsNull() const { return flags_ == kNullFlag; } - bool IsFalse() const { return flags_ == kFalseFlag; } - bool IsTrue() const { return flags_ == kTrueFlag; } - bool IsBool() const { return (flags_ & kBoolFlag) != 0; } - bool IsObject() const { return flags_ == kObjectFlag; } - bool IsArray() const { return flags_ == kArrayFlag; } - bool IsNumber() const { return (flags_ & kNumberFlag) != 0; } - bool IsInt() const { return (flags_ & kIntFlag) != 0; } - bool IsUint() const { return (flags_ & kUintFlag) != 0; } - bool IsInt64() const { return (flags_ & kInt64Flag) != 0; } - bool IsUint64() const { return (flags_ & kUint64Flag) != 0; } - bool IsDouble() const { return (flags_ & kDoubleFlag) != 0; } - bool IsString() const { return (flags_ & kStringFlag) != 0; } + Type GetType() const { return static_cast(data_.f.flags & kTypeMask); } + bool IsNull() const { return data_.f.flags == kNullFlag; } + bool IsFalse() const { return data_.f.flags == kFalseFlag; } + bool IsTrue() const { return data_.f.flags == kTrueFlag; } + bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; } + bool IsObject() const { return data_.f.flags == kObjectFlag; } + bool IsArray() const { return data_.f.flags == kArrayFlag; } + bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; } + bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; } + bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; } + bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; } + bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; } + bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; } + bool IsString() const { return (data_.f.flags & kStringFlag) != 0; } + + // Checks whether a number can be losslessly converted to a double. + bool IsLosslessDouble() const { + if (!IsNumber()) return false; + if (IsUint64()) { + uint64_t u = GetUint64(); + volatile double d = static_cast(u); + return (d >= 0.0) + && (d < static_cast((std::numeric_limits::max)())) + && (u == static_cast(d)); + } + if (IsInt64()) { + int64_t i = GetInt64(); + volatile double d = static_cast(i); + return (d >= static_cast((std::numeric_limits::min)())) + && (d < static_cast((std::numeric_limits::max)())) + && (i == static_cast(d)); + } + return true; // double, int, uint are always lossless + } + + // Checks whether a number is a float (possible lossy). + bool IsFloat() const { + if ((data_.f.flags & kDoubleFlag) == 0) + return false; + double d = GetDouble(); + return d >= -3.4028234e38 && d <= 3.4028234e38; + } + // Checks whether a number can be losslessly converted to a float. + bool IsLosslessFloat() const { + if (!IsNumber()) return false; + double a = GetDouble(); + if (a < static_cast(-(std::numeric_limits::max)()) + || a > static_cast((std::numeric_limits::max)())) + return false; + double b = static_cast(static_cast(a)); + return a >= b && a <= b; // Prevent -Wfloat-equal + } //@} @@ -784,7 +1053,7 @@ public: //!@name Bool //@{ - bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return flags_ == kTrueFlag; } + bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; } //!< Set boolean value /*! \post IsBool() == true */ GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } @@ -837,8 +1106,14 @@ public: return member->value; else { RAPIDJSON_ASSERT(false); // see above note - static GenericValue NullValue; - return NullValue; + + // This will generate -Wexit-time-destructors in clang + // static GenericValue NullValue; + // return NullValue; + + // Use static buffer and placement-new to prevent destruction + static char buffer[sizeof(GenericValue)]; + return *new (buffer) GenericValue(); } } template @@ -852,16 +1127,16 @@ public: //! Const member iterator /*! \pre IsObject() == true */ - ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members); } + ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); } //! Const \em past-the-end member iterator /*! \pre IsObject() == true */ - ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(data_.o.members + data_.o.size); } + ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); } //! Member iterator /*! \pre IsObject() == true */ - MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members); } + MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); } //! \em Past-the-end member iterator /*! \pre IsObject() == true */ - MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(data_.o.members + data_.o.size); } + MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); } //! Check whether a member exists in the object. /*! @@ -949,8 +1224,8 @@ public: \return Iterator to member, if it exists. Otherwise returns \ref MemberEnd(). */ - MemberIterator FindMember(const std::basic_string& name) { return FindMember(StringRef(name)); } - ConstMemberIterator FindMember(const std::basic_string& name) const { return FindMember(StringRef(name)); } + MemberIterator FindMember(const std::basic_string& name) { return FindMember(GenericValue(StringRef(name))); } + ConstMemberIterator FindMember(const std::basic_string& name) const { return FindMember(GenericValue(StringRef(name))); } #endif //! Add a member (name-value pair) to the object. @@ -967,20 +1242,21 @@ public: RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString()); - Object& o = data_.o; + ObjectData& o = data_.o; if (o.size >= o.capacity) { if (o.capacity == 0) { o.capacity = kDefaultObjectCapacity; - o.members = reinterpret_cast(allocator.Malloc(o.capacity * sizeof(Member))); + SetMembersPointer(reinterpret_cast(allocator.Malloc(o.capacity * sizeof(Member)))); } else { SizeType oldCapacity = o.capacity; o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5 - o.members = reinterpret_cast(allocator.Realloc(o.members, oldCapacity * sizeof(Member), o.capacity * sizeof(Member))); + SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member)))); } } - o.members[o.size].name.RawAssign(name); - o.members[o.size].value.RawAssign(value); + Member* members = GetMembersPointer(); + members[o.size].name.RawAssign(name); + members[o.size].value.RawAssign(value); o.size++; return *this; } @@ -1159,18 +1435,14 @@ public: MemberIterator RemoveMember(MemberIterator m) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(data_.o.size > 0); - RAPIDJSON_ASSERT(data_.o.members != 0); + RAPIDJSON_ASSERT(GetMembersPointer() != 0); RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); - MemberIterator last(data_.o.members + (data_.o.size - 1)); - if (data_.o.size > 1 && m != last) { - // Move the last one to this place - *m = *last; - } - else { - // Only one left, just destroy - m->~Member(); - } + MemberIterator last(GetMembersPointer() + (data_.o.size - 1)); + if (data_.o.size > 1 && m != last) + *m = *last; // Move the last one to this place + else + m->~Member(); // Only one left, just destroy --data_.o.size; return m; } @@ -1200,7 +1472,7 @@ public: MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(data_.o.size > 0); - RAPIDJSON_ASSERT(data_.o.members != 0); + RAPIDJSON_ASSERT(GetMembersPointer() != 0); RAPIDJSON_ASSERT(first >= MemberBegin()); RAPIDJSON_ASSERT(first <= last); RAPIDJSON_ASSERT(last <= MemberEnd()); @@ -1208,11 +1480,39 @@ public: MemberIterator pos = MemberBegin() + (first - MemberBegin()); for (MemberIterator itr = pos; itr != last; ++itr) itr->~Member(); - std::memmove(&*pos, &*last, (MemberEnd() - last) * sizeof(Member)); - data_.o.size -= (last - first); + std::memmove(&*pos, &*last, static_cast(MemberEnd() - last) * sizeof(Member)); + data_.o.size -= static_cast(last - first); return pos; } + //! Erase a member in object by its name. + /*! \param name Name of member to be removed. + \return Whether the member existed. + \note Linear time complexity. + */ + bool EraseMember(const Ch* name) { + GenericValue n(StringRef(name)); + return EraseMember(n); + } + +#if RAPIDJSON_HAS_STDSTRING + bool EraseMember(const std::basic_string& name) { return EraseMember(GenericValue(StringRef(name))); } +#endif + + template + bool EraseMember(const GenericValue& name) { + MemberIterator m = FindMember(name); + if (m != MemberEnd()) { + EraseMember(m); + return true; + } + else + return false; + } + + Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } + ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } + //@} //!@name Array @@ -1220,7 +1520,7 @@ public: //! Set this value as an empty array. /*! \post IsArray == true */ - GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } + GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } //! Get the number of elements in array. SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } @@ -1237,8 +1537,9 @@ public: */ void Clear() { RAPIDJSON_ASSERT(IsArray()); - for (SizeType i = 0; i < data_.a.size; ++i) - data_.a.elements[i].~GenericValue(); + GenericValue* e = GetElementsPointer(); + for (GenericValue* v = e; v != e + data_.a.size; ++v) + v->~GenericValue(); data_.a.size = 0; } @@ -1250,16 +1551,16 @@ public: GenericValue& operator[](SizeType index) { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(index < data_.a.size); - return data_.a.elements[index]; + return GetElementsPointer()[index]; } const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } //! Element iterator /*! \pre IsArray() == true */ - ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements; } + ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); } //! \em Past-the-end element iterator /*! \pre IsArray() == true */ - ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return data_.a.elements + data_.a.size; } + ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; } //! Constant element iterator /*! \pre IsArray() == true */ ConstValueIterator Begin() const { return const_cast(*this).Begin(); } @@ -1276,7 +1577,7 @@ public: GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { RAPIDJSON_ASSERT(IsArray()); if (newCapacity > data_.a.capacity) { - data_.a.elements = (GenericValue*)allocator.Realloc(data_.a.elements, data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)); + SetElementsPointer(reinterpret_cast(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)))); data_.a.capacity = newCapacity; } return *this; @@ -1296,7 +1597,7 @@ public: RAPIDJSON_ASSERT(IsArray()); if (data_.a.size >= data_.a.capacity) Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator); - data_.a.elements[data_.a.size++].RawAssign(value); + GetElementsPointer()[data_.a.size++].RawAssign(value); return *this; } @@ -1350,7 +1651,7 @@ public: GenericValue& PopBack() { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(!Empty()); - data_.a.elements[--data_.a.size].~GenericValue(); + GetElementsPointer()[--data_.a.size].~GenericValue(); return *this; } @@ -1376,35 +1677,48 @@ public: ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(data_.a.size > 0); - RAPIDJSON_ASSERT(data_.a.elements != 0); + RAPIDJSON_ASSERT(GetElementsPointer() != 0); RAPIDJSON_ASSERT(first >= Begin()); RAPIDJSON_ASSERT(first <= last); RAPIDJSON_ASSERT(last <= End()); ValueIterator pos = Begin() + (first - Begin()); for (ValueIterator itr = pos; itr != last; ++itr) itr->~GenericValue(); - std::memmove(pos, last, (End() - last) * sizeof(GenericValue)); - data_.a.size -= (last - first); + std::memmove(pos, last, static_cast(End() - last) * sizeof(GenericValue)); + data_.a.size -= static_cast(last - first); return pos; } + Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); } + ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); } + //@} //!@name Number //@{ - int GetInt() const { RAPIDJSON_ASSERT(flags_ & kIntFlag); return data_.n.i.i; } - unsigned GetUint() const { RAPIDJSON_ASSERT(flags_ & kUintFlag); return data_.n.u.u; } - int64_t GetInt64() const { RAPIDJSON_ASSERT(flags_ & kInt64Flag); return data_.n.i64; } - uint64_t GetUint64() const { RAPIDJSON_ASSERT(flags_ & kUint64Flag); return data_.n.u64; } + int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; } + unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; } + int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; } + uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; } + //! Get the value as double type. + /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless. + */ double GetDouble() const { RAPIDJSON_ASSERT(IsNumber()); - if ((flags_ & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. - if ((flags_ & kIntFlag) != 0) return data_.n.i.i; // int -> double - if ((flags_ & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double - if ((flags_ & kInt64Flag) != 0) return (double)data_.n.i64; // int64_t -> double (may lose precision) - RAPIDJSON_ASSERT((flags_ & kUint64Flag) != 0); return (double)data_.n.u64; // uint64_t -> double (may lose precision) + if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. + if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double + if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double + if ((data_.f.flags & kInt64Flag) != 0) return static_cast(data_.n.i64); // int64_t -> double (may lose precision) + RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast(data_.n.u64); // uint64_t -> double (may lose precision) + } + + //! Get the value as float type. + /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless. + */ + float GetFloat() const { + return static_cast(GetDouble()); } GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } @@ -1412,18 +1726,19 @@ public: GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } + GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast(f)); return *this; } //@} //!@name String //@{ - const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? data_.ss.str : data_.s.str); } + const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); } //! Get the length of string. /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). */ - SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((flags_ & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } + SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } //! Set this value as a string without copying source string. /*! This version has better performance with supplied length, and also support string containing null character. @@ -1450,7 +1765,7 @@ public: \return The value itself for fluent API. \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ - GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; } + GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); } //! Set this value as a string by copying from source string. /*! \param s source string. @@ -1458,7 +1773,15 @@ public: \return The value itself for fluent API. \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ - GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); } + GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); } + + //! Set this value as a string by copying from source string. + /*! \param s source string reference + \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). + \return The value itself for fluent API. + \post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length + */ + GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; } #if RAPIDJSON_HAS_STDSTRING //! Set this value as a string by copying from source string. @@ -1468,11 +1791,35 @@ public: \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ - GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); } + GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(StringRef(s), allocator); } #endif //@} + //!@name Array + //@{ + + //! Templated version for checking whether this value is type T. + /*! + \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string + */ + template + bool Is() const { return internal::TypeHelper::Is(*this); } + + template + T Get() const { return internal::TypeHelper::Get(*this); } + + template + T Get() { return internal::TypeHelper::Get(*this); } + + template + ValueType& Set(const T& data) { return internal::TypeHelper::Set(*this, data); } + + template + ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper::Set(*this, data, allocator); } + + //@} + //! Generate events of this value to a Handler. /*! This function adopts the GoF visitor pattern. Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. @@ -1488,35 +1835,35 @@ public: case kTrueType: return handler.Bool(true); case kObjectType: - if (!handler.StartObject()) + if (RAPIDJSON_UNLIKELY(!handler.StartObject())) return false; for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. - if (!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.flags_ & kCopyFlag) != 0)) + if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0))) return false; - if (!m->value.Accept(handler)) + if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler))) return false; } return handler.EndObject(data_.o.size); case kArrayType: - if (!handler.StartArray()) + if (RAPIDJSON_UNLIKELY(!handler.StartArray())) return false; - for (GenericValue* v = data_.a.elements; v != data_.a.elements + data_.a.size; ++v) - if (!v->Accept(handler)) + for (const GenericValue* v = Begin(); v != End(); ++v) + if (RAPIDJSON_UNLIKELY(!v->Accept(handler))) return false; return handler.EndArray(data_.a.size); case kStringType: - return handler.String(GetString(), GetStringLength(), (flags_ & kCopyFlag) != 0); + return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0); default: RAPIDJSON_ASSERT(GetType() == kNumberType); - if (IsInt()) return handler.Int(data_.n.i.i); + if (IsDouble()) return handler.Double(data_.n.d); + else if (IsInt()) return handler.Int(data_.n.i.i); else if (IsUint()) return handler.Uint(data_.n.u.u); else if (IsInt64()) return handler.Int64(data_.n.i64); - else if (IsUint64()) return handler.Uint64(data_.n.u64); - else return handler.Double(data_.n.d); + else return handler.Uint64(data_.n.u64); } } @@ -1525,16 +1872,16 @@ private: template friend class GenericDocument; enum { - kBoolFlag = 0x100, - kNumberFlag = 0x200, - kIntFlag = 0x400, - kUintFlag = 0x800, - kInt64Flag = 0x1000, - kUint64Flag = 0x2000, - kDoubleFlag = 0x4000, - kStringFlag = 0x100000, - kCopyFlag = 0x200000, - kInlineStrFlag = 0x400000, + kBoolFlag = 0x0008, + kNumberFlag = 0x0010, + kIntFlag = 0x0020, + kUintFlag = 0x0040, + kInt64Flag = 0x0080, + kUint64Flag = 0x0100, + kDoubleFlag = 0x0200, + kStringFlag = 0x0400, + kCopyFlag = 0x0800, + kInlineStrFlag = 0x1000, // Initial flags of different types. kNullFlag = kNullType, @@ -1552,16 +1899,27 @@ private: kObjectFlag = kObjectType, kArrayFlag = kArrayType, - kTypeMask = 0xFF // bitwise-and with mask of 0xFF can be optimized by compiler + kTypeMask = 0x07 }; static const SizeType kDefaultArrayCapacity = 16; static const SizeType kDefaultObjectCapacity = 16; + struct Flag { +#if RAPIDJSON_48BITPOINTER_OPTIMIZATION + char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer +#elif RAPIDJSON_64BIT + char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes +#else + char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes +#endif + uint16_t flags; + }; + struct String { - const Ch* str; SizeType length; - unsigned hashcode; //!< reserved + SizeType hashcode; //!< reserved + const Ch* str; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars @@ -1570,15 +1928,15 @@ private: // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as // the string terminator as well. For getting the string length back from that value just use // "MaxSize - str[LenPos]". - // This allows to store 11-chars strings in 32-bit mode and 15-chars strings in 64-bit mode - // inline (for `UTF8`-encoded strings). + // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode, + // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings). struct ShortString { - enum { MaxChars = sizeof(String) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; + enum { MaxChars = sizeof(static_cast(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; Ch str[MaxChars]; - inline static bool Usable(SizeType len) { return (MaxSize >= len); } - inline void SetLength(SizeType len) { str[LenPos] = (Ch)(MaxSize - len); } - inline SizeType GetLength() const { return (SizeType)(MaxSize - str[LenPos]); } + inline static bool Usable(SizeType len) { return (MaxSize >= len); } + inline void SetLength(SizeType len) { str[LenPos] = static_cast(MaxSize - len); } + inline SizeType GetLength() const { return static_cast(MaxSize - str[LenPos]); } }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode // By using proper binary layout, retrieval of different integer types do not need conversions. @@ -1607,69 +1965,79 @@ private: double d; }; // 8 bytes - struct Object { - Member* members; + struct ObjectData { SizeType size; SizeType capacity; + Member* members; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode - struct Array { - GenericValue* elements; + struct ArrayData { SizeType size; SizeType capacity; + GenericValue* elements; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode union Data { String s; ShortString ss; Number n; - Object o; - Array a; - }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode + ObjectData o; + ArrayData a; + Flag f; + }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION + + RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); } + RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); } + RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); } + RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); } + RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); } + RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); } // Initialize this value as array with initial data, without calling destructor. void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { - flags_ = kArrayFlag; + data_.f.flags = kArrayFlag; if (count) { - data_.a.elements = (GenericValue*)allocator.Malloc(count * sizeof(GenericValue)); - std::memcpy(data_.a.elements, values, count * sizeof(GenericValue)); + GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue))); + SetElementsPointer(e); + std::memcpy(e, values, count * sizeof(GenericValue)); } else - data_.a.elements = NULL; + SetElementsPointer(0); data_.a.size = data_.a.capacity = count; } //! Initialize this value as object with initial data, without calling destructor. void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { - flags_ = kObjectFlag; + data_.f.flags = kObjectFlag; if (count) { - data_.o.members = (Member*)allocator.Malloc(count * sizeof(Member)); - std::memcpy(data_.o.members, members, count * sizeof(Member)); + Member* m = static_cast(allocator.Malloc(count * sizeof(Member))); + SetMembersPointer(m); + std::memcpy(m, members, count * sizeof(Member)); } else - data_.o.members = NULL; + SetMembersPointer(0); data_.o.size = data_.o.capacity = count; } //! Initialize this value as constant string, without calling destructor. void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT { - flags_ = kConstStringFlag; - data_.s.str = s; + data_.f.flags = kConstStringFlag; + SetStringPointer(s); data_.s.length = s.length; } //! Initialize this value as copy string with initial data, without calling destructor. void SetStringRaw(StringRefType s, Allocator& allocator) { - Ch* str = NULL; - if(ShortString::Usable(s.length)) { - flags_ = kShortStringFlag; + Ch* str = 0; + if (ShortString::Usable(s.length)) { + data_.f.flags = kShortStringFlag; data_.ss.SetLength(s.length); str = data_.ss.str; } else { - flags_ = kCopyStringFlag; + data_.f.flags = kCopyStringFlag; data_.s.length = s.length; - str = (Ch *)allocator.Malloc((s.length + 1) * sizeof(Ch)); - data_.s.str = str; + str = static_cast(allocator.Malloc((s.length + 1) * sizeof(Ch))); + SetStringPointer(str); } std::memcpy(str, s, s.length * sizeof(Ch)); str[s.length] = '\0'; @@ -1678,8 +2046,8 @@ private: //! Assignment without calling destructor void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT { data_ = rhs.data_; - flags_ = rhs.flags_; - rhs.flags_ = kNullFlag; + // data_.f.flags = rhs.data_.f.flags; + rhs.data_.f.flags = kNullFlag; } template @@ -1699,7 +2067,6 @@ private: } Data data_; - unsigned flags_; }; //! GenericValue with UTF8 encoding @@ -1724,7 +2091,22 @@ public: typedef Allocator AllocatorType; //!< Allocator type from template parameter. //! Constructor - /*! \param allocator Optional allocator for allocating memory. + /*! Creates an empty document of specified type. + \param type Mandatory type of object to create. + \param allocator Optional allocator for allocating memory. + \param stackCapacity Optional initial capacity of stack in bytes. + \param stackAllocator Optional allocator for allocating memory for stack. + */ + explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : + GenericValue(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() + { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + } + + //! Constructor + /*! Creates an empty document which type is Null. + \param allocator Optional allocator for allocating memory. \param stackCapacity Optional initial capacity of stack in bytes. \param stackAllocator Optional allocator for allocating memory for stack. */ @@ -1732,13 +2114,13 @@ public: allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT - : ValueType(std::move(rhs)), + : ValueType(std::forward(rhs)), // explicit cast to avoid prohibited move from Document allocator_(rhs.allocator_), ownAllocator_(rhs.ownAllocator_), stack_(std::move(rhs.stack_)), @@ -1778,6 +2160,54 @@ public: } #endif + //! Exchange the contents of this document with those of another. + /*! + \param rhs Another document. + \note Constant complexity. + \see GenericValue::Swap + */ + GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT { + ValueType::Swap(rhs); + stack_.Swap(rhs.stack_); + internal::Swap(allocator_, rhs.allocator_); + internal::Swap(ownAllocator_, rhs.ownAllocator_); + internal::Swap(parseResult_, rhs.parseResult_); + return *this; + } + + // Allow Swap with ValueType. + // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names. + using ValueType::Swap; + + //! free-standing swap function helper + /*! + Helper function to enable support for common swap implementation pattern based on \c std::swap: + \code + void swap(MyClass& a, MyClass& b) { + using std::swap; + swap(a.doc, b.doc); + // ... + } + \endcode + \see Swap() + */ + friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } + + //! Populate this document by a generator which produces SAX events. + /*! \tparam Generator A functor with bool f(Handler) prototype. + \param g Generator functor which sends SAX events to the parameter. + \return The document itself for fluent API. + */ + template + GenericDocument& Populate(Generator& g) { + ClearStackOnExit scope(*this); + if (g(*this)) { + RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object + ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document + } + return *this; + } + //!@name Parse from stream //!@{ @@ -1790,13 +2220,13 @@ public: */ template GenericDocument& ParseStream(InputStream& is) { - ValueType::SetNull(); // Remove existing root if exist - GenericReader reader(&stack_.GetAllocator()); + GenericReader reader( + stack_.HasAllocator() ? &stack_.GetAllocator() : 0); ClearStackOnExit scope(*this); parseResult_ = reader.template Parse(is, *this); if (parseResult_) { RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object - this->RawAssign(*stack_.template Pop(1)); // Add this-> to prevent issue 13. + ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document } return *this; } @@ -1855,7 +2285,7 @@ public: \param str Read-only zero-terminated string to be parsed. */ template - GenericDocument& Parse(const Ch* str) { + GenericDocument& Parse(const typename SourceEncoding::Ch* str) { RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); GenericStringStream s(str); return ParseStream(s); @@ -1876,6 +2306,42 @@ public: GenericDocument& Parse(const Ch* str) { return Parse(str); } + + template + GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) { + RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); + MemoryStream ms(reinterpret_cast(str), length * sizeof(typename SourceEncoding::Ch)); + EncodedInputStream is(ms); + ParseStream(is); + return *this; + } + + template + GenericDocument& Parse(const Ch* str, size_t length) { + return Parse(str, length); + } + + GenericDocument& Parse(const Ch* str, size_t length) { + return Parse(str, length); + } + +#if RAPIDJSON_HAS_STDSTRING + template + GenericDocument& Parse(const std::basic_string& str) { + // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t) + return Parse(str.c_str()); + } + + template + GenericDocument& Parse(const std::basic_string& str) { + return Parse(str.c_str()); + } + + GenericDocument& Parse(const std::basic_string& str) { + return Parse(str); + } +#endif // RAPIDJSON_HAS_STDSTRING + //!@} //!@name Handling parse errors @@ -1890,10 +2356,26 @@ public: //! Get the position of last parsing error in input, 0 otherwise. size_t GetErrorOffset() const { return parseResult_.Offset(); } + //! Implicit conversion to get the last parse result +#ifndef __clang // -Wdocumentation + /*! \return \ref ParseResult of the last parse operation + + \code + Document doc; + ParseResult ok = doc.Parse(json); + if (!ok) + printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset()); + \endcode + */ +#endif + operator ParseResult() const { return parseResult_; } //!@} //! Get the allocator of this document. - Allocator& GetAllocator() { return *allocator_; } + Allocator& GetAllocator() { + RAPIDJSON_ASSERT(allocator_); + return *allocator_; + } //! Get the capacity of stack in bytes. size_t GetStackCapacity() const { return stack_.GetCapacity(); } @@ -1910,9 +2392,10 @@ private: }; // callers of the following private Handler functions - template friend class GenericReader; // for parsing + // template friend class GenericReader; // for parsing template friend class GenericValue; // for deep copying +public: // Implementation of Handler bool Null() { new (stack_.template Push()) ValueType(); return true; } bool Bool(bool b) { new (stack_.template Push()) ValueType(b); return true; } @@ -1922,6 +2405,14 @@ private: bool Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); return true; } bool Double(double d) { new (stack_.template Push()) ValueType(d); return true; } + bool RawNumber(const Ch* str, SizeType length, bool copy) { + if (copy) + new (stack_.template Push()) ValueType(str, length, GetAllocator()); + else + new (stack_.template Push()) ValueType(str, length); + return true; + } + bool String(const Ch* str, SizeType length, bool copy) { if (copy) new (stack_.template Push()) ValueType(str, length, GetAllocator()); @@ -1936,7 +2427,7 @@ private: bool EndObject(SizeType memberCount) { typename ValueType::Member* members = stack_.template Pop(memberCount); - stack_.template Top()->SetObjectRaw(members, (SizeType)memberCount, GetAllocator()); + stack_.template Top()->SetObjectRaw(members, memberCount, GetAllocator()); return true; } @@ -1977,38 +2468,146 @@ private: //! GenericDocument with UTF8 encoding typedef GenericDocument > Document; -// defined here due to the dependency on GenericDocument -template -template -inline -GenericValue::GenericValue(const GenericValue& rhs, Allocator& allocator) -{ - switch (rhs.GetType()) { - case kObjectType: - case kArrayType: { // perform deep copy via SAX Handler - GenericDocument d(&allocator); - rhs.Accept(d); - RawAssign(*d.stack_.template Pop(1)); - } - break; - case kStringType: - if (rhs.flags_ == kConstStringFlag) { - flags_ = rhs.flags_; - data_ = *reinterpret_cast(&rhs.data_); - } else { - SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); - } - break; - default: // kNumberType, kTrueType, kFalseType, kNullType - flags_ = rhs.flags_; - data_ = *reinterpret_cast(&rhs.data_); - } -} +//! Helper class for accessing Value of array type. +/*! + Instance of this helper class is obtained by \c GenericValue::GetArray(). + In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. +*/ +template +class GenericArray { +public: + typedef GenericArray ConstArray; + typedef GenericArray Array; + typedef ValueT PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + typedef ValueType* ValueIterator; // This may be const or non-const iterator + typedef const ValueT* ConstValueIterator; + typedef typename ValueType::AllocatorType AllocatorType; + typedef typename ValueType::StringRefType StringRefType; -RAPIDJSON_NAMESPACE_END + template + friend class GenericValue; -#if defined(_MSC_VER) || defined(__GNUC__) -RAPIDJSON_DIAG_POP + GenericArray(const GenericArray& rhs) : value_(rhs.value_) {} + GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; } + ~GenericArray() {} + + SizeType Size() const { return value_.Size(); } + SizeType Capacity() const { return value_.Capacity(); } + bool Empty() const { return value_.Empty(); } + void Clear() const { value_.Clear(); } + ValueType& operator[](SizeType index) const { return value_[index]; } + ValueIterator Begin() const { return value_.Begin(); } + ValueIterator End() const { return value_.End(); } + GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; } + GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } + GenericArray PopBack() const { value_.PopBack(); return *this; } + ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); } + ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); } + +#if RAPIDJSON_HAS_CXX11_RANGE_FOR + ValueIterator begin() const { return value_.Begin(); } + ValueIterator end() const { return value_.End(); } #endif +private: + GenericArray(); + GenericArray(ValueType& value) : value_(value) {} + ValueType& value_; +}; + +//! Helper class for accessing Value of object type. +/*! + Instance of this helper class is obtained by \c GenericValue::GetObject(). + In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. +*/ +template +class GenericObject { +public: + typedef GenericObject ConstObject; + typedef GenericObject Object; + typedef ValueT PlainType; + typedef typename internal::MaybeAddConst::Type ValueType; + typedef GenericMemberIterator MemberIterator; // This may be const or non-const iterator + typedef GenericMemberIterator ConstMemberIterator; + typedef typename ValueType::AllocatorType AllocatorType; + typedef typename ValueType::StringRefType StringRefType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename ValueType::Ch Ch; + + template + friend class GenericValue; + + GenericObject(const GenericObject& rhs) : value_(rhs.value_) {} + GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; } + ~GenericObject() {} + + SizeType MemberCount() const { return value_.MemberCount(); } + bool ObjectEmpty() const { return value_.ObjectEmpty(); } + template ValueType& operator[](T* name) const { return value_[name]; } + template ValueType& operator[](const GenericValue& name) const { return value_[name]; } +#if RAPIDJSON_HAS_STDSTRING + ValueType& operator[](const std::basic_string& name) const { return value_[name]; } +#endif + MemberIterator MemberBegin() const { return value_.MemberBegin(); } + MemberIterator MemberEnd() const { return value_.MemberEnd(); } + bool HasMember(const Ch* name) const { return value_.HasMember(name); } +#if RAPIDJSON_HAS_STDSTRING + bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); } +#endif + template bool HasMember(const GenericValue& name) const { return value_.HasMember(name); } + MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); } + template MemberIterator FindMember(const GenericValue& name) const { return value_.FindMember(name); } +#if RAPIDJSON_HAS_STDSTRING + MemberIterator FindMember(const std::basic_string& name) const { return value_.FindMember(name); } +#endif + GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } +#if RAPIDJSON_HAS_STDSTRING + GenericObject AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } +#endif + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } +#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS + GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } + void RemoveAllMembers() { value_.RemoveAllMembers(); } + bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); } +#if RAPIDJSON_HAS_STDSTRING + bool RemoveMember(const std::basic_string& name) const { return value_.RemoveMember(name); } +#endif + template bool RemoveMember(const GenericValue& name) const { return value_.RemoveMember(name); } + MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); } + MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); } + MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); } + bool EraseMember(const Ch* name) const { return value_.EraseMember(name); } +#if RAPIDJSON_HAS_STDSTRING + bool EraseMember(const std::basic_string& name) const { return EraseMember(ValueType(StringRef(name))); } +#endif + template bool EraseMember(const GenericValue& name) const { return value_.EraseMember(name); } + +#if RAPIDJSON_HAS_CXX11_RANGE_FOR + MemberIterator begin() const { return value_.MemberBegin(); } + MemberIterator end() const { return value_.MemberEnd(); } +#endif + +private: + GenericObject(); + GenericObject(ValueType& value) : value_(value) {} + ValueType& value_; +}; + +RAPIDJSON_NAMESPACE_END +RAPIDJSON_DIAG_POP + #endif // RAPIDJSON_DOCUMENT_H_ diff --git a/contrib/rapidjson/include/rapidjson/encodedstream.h b/contrib/rapidjson/include/rapidjson/encodedstream.h index 7c8863fee..223601c05 100644 --- a/contrib/rapidjson/include/rapidjson/encodedstream.h +++ b/contrib/rapidjson/include/rapidjson/encodedstream.h @@ -15,13 +15,19 @@ #ifndef RAPIDJSON_ENCODEDSTREAM_H_ #define RAPIDJSON_ENCODEDSTREAM_H_ -#include "rapidjson.h" +#include "stream.h" +#include "memorystream.h" #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + RAPIDJSON_NAMESPACE_BEGIN //! Input byte stream wrapper with a statically bound encoding. @@ -57,10 +63,38 @@ private: Ch current_; }; +//! Specialized for UTF8 MemoryStream. +template <> +class EncodedInputStream, MemoryStream> { +public: + typedef UTF8<>::Ch Ch; + + EncodedInputStream(MemoryStream& is) : is_(is) { + if (static_cast(is_.Peek()) == 0xEFu) is_.Take(); + if (static_cast(is_.Peek()) == 0xBBu) is_.Take(); + if (static_cast(is_.Peek()) == 0xBFu) is_.Take(); + } + Ch Peek() const { return is_.Peek(); } + Ch Take() { return is_.Take(); } + size_t Tell() const { return is_.Tell(); } + + // Not implemented + void Put(Ch) {} + void Flush() {} + Ch* PutBegin() { return 0; } + size_t PutEnd(Ch*) { return 0; } + + MemoryStream& is_; + +private: + EncodedInputStream(const EncodedInputStream&); + EncodedInputStream& operator=(const EncodedInputStream&); +}; + //! Output byte stream wrapper with statically bound encoding. /*! \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. - \tparam InputByteStream Type of input byte stream. For example, FileWriteStream. + \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream. */ template class EncodedOutputStream { @@ -77,8 +111,8 @@ public: void Flush() { os_.Flush(); } // Not implemented - Ch Peek() const { RAPIDJSON_ASSERT(false); } - Ch Take() { RAPIDJSON_ASSERT(false); } + Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} + Ch Take() { RAPIDJSON_ASSERT(false); return 0;} size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } @@ -142,11 +176,11 @@ private: // FF FE UTF-16LE // EF BB BF UTF-8 - const unsigned char* c = (const unsigned char *)is_->Peek4(); + const unsigned char* c = reinterpret_cast(is_->Peek4()); if (!c) return; - unsigned bom = c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24); + unsigned bom = static_cast(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); hasBOM_ = false; if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } @@ -166,7 +200,7 @@ private: // xx xx xx xx UTF-8 if (!hasBOM_) { - unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); + int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); switch (pattern) { case 0x08: type_ = kUTF32BE; break; case 0x0A: type_ = kUTF16BE; break; @@ -193,7 +227,7 @@ private: //! Output stream wrapper with dynamically bound encoding and automatic encoding detection. /*! \tparam CharType Type of character for writing. - \tparam InputByteStream type of output byte stream to be wrapped. + \tparam OutputByteStream type of output byte stream to be wrapped. */ template class AutoUTFOutputStream { @@ -227,8 +261,8 @@ public: void Flush() { os_->Flush(); } // Not implemented - Ch Peek() const { RAPIDJSON_ASSERT(false); } - Ch Take() { RAPIDJSON_ASSERT(false); } + Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} + Ch Take() { RAPIDJSON_ASSERT(false); return 0;} size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } @@ -254,6 +288,10 @@ private: RAPIDJSON_NAMESPACE_END +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif diff --git a/contrib/rapidjson/include/rapidjson/encodings.h b/contrib/rapidjson/include/rapidjson/encodings.h index 90b46ed32..0df1c3435 100644 --- a/contrib/rapidjson/include/rapidjson/encodings.h +++ b/contrib/rapidjson/include/rapidjson/encodings.h @@ -120,19 +120,45 @@ struct UTF8 { } } + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + if (codepoint <= 0x7F) + PutUnsafe(os, static_cast(codepoint & 0xFF)); + else if (codepoint <= 0x7FF) { + PutUnsafe(os, static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint & 0x3F)))); + } + else if (codepoint <= 0xFFFF) { + PutUnsafe(os, static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + PutUnsafe(os, static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); + PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); + } + } + template static bool Decode(InputStream& is, unsigned* codepoint) { -#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | ((unsigned char)c & 0x3Fu) -#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) +#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) +#define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) #define TAIL() COPY(); TRANS(0x70) - Ch c = is.Take(); + typename InputStream::Ch c = is.Take(); if (!(c & 0x80)) { - *codepoint = (unsigned char)c; + *codepoint = static_cast(c); return true; } - unsigned char type = GetRange((unsigned char)c); - *codepoint = (0xFF >> type) & (unsigned char)c; + unsigned char type = GetRange(static_cast(c)); + if (type >= 32) { + *codepoint = 0; + } else { + *codepoint = (0xFFu >> type) & static_cast(c); + } bool result = true; switch (type) { case 2: TAIL(); return result; @@ -152,7 +178,7 @@ struct UTF8 { template static bool Validate(InputStream& is, OutputStream& os) { #define COPY() os.Put(c = is.Take()) -#define TRANS(mask) result &= ((GetRange((unsigned char)c) & mask) != 0) +#define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) #define TAIL() COPY(); TRANS(0x70) Ch c; COPY(); @@ -160,7 +186,7 @@ struct UTF8 { return true; bool result = true; - switch (GetRange((unsigned char)c)) { + switch (GetRange(static_cast(c))) { case 2: TAIL(); return result; case 3: TAIL(); TAIL(); return result; case 4: COPY(); TRANS(0x50); TAIL(); return result; @@ -196,12 +222,12 @@ struct UTF8 { template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - Ch c = Take(is); - if ((unsigned char)c != 0xEFu) return c; + typename InputByteStream::Ch c = Take(is); + if (static_cast(c) != 0xEFu) return c; c = is.Take(); - if ((unsigned char)c != 0xBBu) return c; + if (static_cast(c) != 0xBBu) return c; c = is.Take(); - if ((unsigned char)c != 0xBFu) return c; + if (static_cast(c) != 0xBFu) return c; c = is.Take(); return c; } @@ -209,13 +235,15 @@ struct UTF8 { template static Ch Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - return is.Take(); + return static_cast(is.Take()); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(0xEFu); os.Put(0xBBu); os.Put(0xBFu); + os.Put(static_cast(0xEFu)); + os.Put(static_cast(0xBBu)); + os.Put(static_cast(0xBFu)); } template @@ -255,22 +283,38 @@ struct UTF16 { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); unsigned v = codepoint - 0x10000; os.Put(static_cast((v >> 10) | 0xD800)); - os.Put((v & 0x3FF) | 0xDC00); + os.Put(static_cast((v & 0x3FF) | 0xDC00)); + } + } + + + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); + if (codepoint <= 0xFFFF) { + RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair + PutUnsafe(os, static_cast(codepoint)); + } + else { + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + unsigned v = codepoint - 0x10000; + PutUnsafe(os, static_cast((v >> 10) | 0xD800)); + PutUnsafe(os, static_cast((v & 0x3FF) | 0xDC00)); } } template static bool Decode(InputStream& is, unsigned* codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); - Ch c = is.Take(); + typename InputStream::Ch c = is.Take(); if (c < 0xD800 || c > 0xDFFF) { - *codepoint = c; + *codepoint = static_cast(c); return true; } else if (c <= 0xDBFF) { - *codepoint = (c & 0x3FF) << 10; + *codepoint = (static_cast(c) & 0x3FF) << 10; c = is.Take(); - *codepoint |= (c & 0x3FF); + *codepoint |= (static_cast(c) & 0x3FF); *codepoint += 0x10000; return c >= 0xDC00 && c <= 0xDFFF; } @@ -281,8 +325,8 @@ struct UTF16 { static bool Validate(InputStream& is, OutputStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); - Ch c; - os.Put(c = is.Take()); + typename InputStream::Ch c; + os.Put(static_cast(c = is.Take())); if (c < 0xD800 || c > 0xDFFF) return true; else if (c <= 0xDBFF) { @@ -300,28 +344,29 @@ struct UTF16LE : UTF16 { static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); - return (unsigned short)c == 0xFEFFu ? Take(is) : c; + return static_cast(c) == 0xFEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = (unsigned char)is.Take(); - c |= (unsigned char)is.Take() << 8; - return c; + unsigned c = static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())) << 8; + return static_cast(c); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(0xFFu); os.Put(0xFEu); + os.Put(static_cast(0xFFu)); + os.Put(static_cast(0xFEu)); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(c & 0xFFu); - os.Put((c >> 8) & 0xFFu); + os.Put(static_cast(static_cast(c) & 0xFFu)); + os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); } }; @@ -332,28 +377,29 @@ struct UTF16BE : UTF16 { static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); - return (unsigned short)c == 0xFEFFu ? Take(is) : c; + return static_cast(c) == 0xFEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = (unsigned char)is.Take() << 8; - c |= (unsigned char)is.Take(); - return c; + unsigned c = static_cast(static_cast(is.Take())) << 8; + c |= static_cast(is.Take()); + return static_cast(c); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(0xFEu); os.Put(0xFFu); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0xFFu)); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put((c >> 8) & 0xFFu); - os.Put(c & 0xFFu); + os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); + os.Put(static_cast(static_cast(c) & 0xFFu)); } }; @@ -382,6 +428,13 @@ struct UTF32 { os.Put(codepoint); } + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); + RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); + PutUnsafe(os, codepoint); + } + template static bool Decode(InputStream& is, unsigned* codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); @@ -406,32 +459,35 @@ struct UTF32LE : UTF32 { static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); - return (unsigned)c == 0x0000FEFFu ? Take(is) : c; + return static_cast(c) == 0x0000FEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = (unsigned char)is.Take(); - c |= (unsigned char)is.Take() << 8; - c |= (unsigned char)is.Take() << 16; - c |= (unsigned char)is.Take() << 24; - return c; + unsigned c = static_cast(is.Take()); + c |= static_cast(static_cast(is.Take())) << 8; + c |= static_cast(static_cast(is.Take())) << 16; + c |= static_cast(static_cast(is.Take())) << 24; + return static_cast(c); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(0xFFu); os.Put(0xFEu); os.Put(0x00u); os.Put(0x00u); + os.Put(static_cast(0xFFu)); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0x00u)); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(c & 0xFFu); - os.Put((c >> 8) & 0xFFu); - os.Put((c >> 16) & 0xFFu); - os.Put((c >> 24) & 0xFFu); + os.Put(static_cast(c & 0xFFu)); + os.Put(static_cast((c >> 8) & 0xFFu)); + os.Put(static_cast((c >> 16) & 0xFFu)); + os.Put(static_cast((c >> 24) & 0xFFu)); } }; @@ -442,32 +498,35 @@ struct UTF32BE : UTF32 { static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); - return (unsigned)c == 0x0000FEFFu ? Take(is) : c; + return static_cast(c) == 0x0000FEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - CharType c = (unsigned char)is.Take() << 24; - c |= (unsigned char)is.Take() << 16; - c |= (unsigned char)is.Take() << 8; - c |= (unsigned char)is.Take(); - return c; + unsigned c = static_cast(static_cast(is.Take())) << 24; + c |= static_cast(static_cast(is.Take())) << 16; + c |= static_cast(static_cast(is.Take())) << 8; + c |= static_cast(static_cast(is.Take())); + return static_cast(c); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put(0x00u); os.Put(0x00u); os.Put(0xFEu); os.Put(0xFFu); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0x00u)); + os.Put(static_cast(0xFEu)); + os.Put(static_cast(0xFFu)); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); - os.Put((c >> 24) & 0xFFu); - os.Put((c >> 16) & 0xFFu); - os.Put((c >> 8) & 0xFFu); - os.Put(c & 0xFFu); + os.Put(static_cast((c >> 24) & 0xFFu)); + os.Put(static_cast((c >> 16) & 0xFFu)); + os.Put(static_cast((c >> 8) & 0xFFu)); + os.Put(static_cast(c & 0xFFu)); } }; @@ -491,31 +550,37 @@ struct ASCII { os.Put(static_cast(codepoint & 0xFF)); } + template + static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + RAPIDJSON_ASSERT(codepoint <= 0x7F); + PutUnsafe(os, static_cast(codepoint & 0xFF)); + } + template static bool Decode(InputStream& is, unsigned* codepoint) { - unsigned char c = static_cast(is.Take()); + uint8_t c = static_cast(is.Take()); *codepoint = c; return c <= 0X7F; } template static bool Validate(InputStream& is, OutputStream& os) { - unsigned char c = is.Take(); - os.Put(c); + uint8_t c = static_cast(is.Take()); + os.Put(static_cast(c)); return c <= 0x7F; } template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - Ch c = Take(is); - return c; + uint8_t c = static_cast(Take(is)); + return static_cast(c); } template static Ch Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); - return is.Take(); + return static_cast(is.Take()); } template @@ -555,21 +620,28 @@ struct AutoUTF { #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x template - RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) { + static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) { typedef void (*EncodeFunc)(OutputStream&, unsigned); static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; (*f[os.GetType()])(os, codepoint); } + template + static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) { + typedef void (*EncodeFunc)(OutputStream&, unsigned); + static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; + (*f[os.GetType()])(os, codepoint); + } + template - RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) { + static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) { typedef bool (*DecodeFunc)(InputStream&, unsigned*); static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; return (*f[is.GetType()])(is, codepoint); } template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { typedef bool (*ValidateFunc)(InputStream&, OutputStream&); static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; return (*f[is.GetType()])(is, os); @@ -586,7 +658,7 @@ template struct Transcoder { //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. template - RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; @@ -594,31 +666,50 @@ struct Transcoder { return true; } + template + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + unsigned codepoint; + if (!SourceEncoding::Decode(is, &codepoint)) + return false; + TargetEncoding::EncodeUnsafe(os, codepoint); + return true; + } + //! Validate one Unicode codepoint from an encoded stream. template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { return Transcode(is, os); // Since source/target encoding is different, must transcode. } }; +// Forward declaration. +template +inline void PutUnsafe(Stream& stream, typename Stream::Ch c); + //! Specialization of Transcoder with same source and target encoding. template struct Transcoder { template - RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. return true; } template - RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) { + static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { + PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. + return true; + } + + template + static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { return Encoding::Validate(is, os); // source/target encoding are the same } }; RAPIDJSON_NAMESPACE_END -#if defined(__GNUC__) || defined(_MSV_VER) +#if defined(__GNUC__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif diff --git a/contrib/rapidjson/include/rapidjson/error/en.h b/contrib/rapidjson/include/rapidjson/error/en.h index d5f9caab8..2db838bff 100644 --- a/contrib/rapidjson/include/rapidjson/error/en.h +++ b/contrib/rapidjson/include/rapidjson/error/en.h @@ -12,11 +12,17 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef RAPIDJSON_ERROR_EN_H__ -#define RAPIDJSON_ERROR_EN_H__ +#ifndef RAPIDJSON_ERROR_EN_H_ +#define RAPIDJSON_ERROR_EN_H_ #include "error.h" +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(switch-enum) +RAPIDJSON_DIAG_OFF(covered-switch-default) +#endif + RAPIDJSON_NAMESPACE_BEGIN //! Maps error code of parsing into error message. @@ -32,7 +38,7 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); - case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not follow by other values."); + case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); @@ -55,11 +61,14 @@ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErro case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); - default: - return RAPIDJSON_ERROR_STRING("Unknown error."); + default: return RAPIDJSON_ERROR_STRING("Unknown error."); } } RAPIDJSON_NAMESPACE_END -#endif // RAPIDJSON_ERROR_EN_H__ +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ERROR_EN_H_ diff --git a/contrib/rapidjson/include/rapidjson/error/error.h b/contrib/rapidjson/include/rapidjson/error/error.h index f9094fb95..9311d2f03 100644 --- a/contrib/rapidjson/include/rapidjson/error/error.h +++ b/contrib/rapidjson/include/rapidjson/error/error.h @@ -12,11 +12,16 @@ // CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. -#ifndef RAPIDJSON_ERROR_ERROR_H__ -#define RAPIDJSON_ERROR_ERROR_H__ +#ifndef RAPIDJSON_ERROR_ERROR_H_ +#define RAPIDJSON_ERROR_ERROR_H_ #include "../rapidjson.h" +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + /*! \file error.h */ /*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ @@ -99,7 +104,9 @@ enum ParseErrorCode { \see GenericReader::Parse, GenericDocument::Parse */ struct ParseResult { - + //!! Unspecified boolean type + typedef bool (ParseResult::*BooleanType)() const; +public: //! Default constructor, no error. ParseResult() : code_(kParseErrorNone), offset_(0) {} //! Constructor to set an error. @@ -110,8 +117,8 @@ struct ParseResult { //! Get the error offset, if \ref IsError(), 0 otherwise. size_t Offset() const { return offset_; } - //! Conversion to \c bool, returns \c true, iff !\ref IsError(). - operator bool() const { return !IsError(); } + //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). + operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; } //! Whether the result is an error. bool IsError() const { return code_ != kParseErrorNone; } @@ -119,6 +126,10 @@ struct ParseResult { bool operator==(ParseErrorCode code) const { return code_ == code; } friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } + bool operator!=(const ParseResult& that) const { return !(*this == that); } + bool operator!=(ParseErrorCode code) const { return !(*this == code); } + friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; } + //! Reset error code. void Clear() { Set(kParseErrorNone); } //! Update error code and offset. @@ -143,4 +154,8 @@ typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); RAPIDJSON_NAMESPACE_END -#endif // RAPIDJSON_ERROR_ERROR_H__ +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_ERROR_ERROR_H_ diff --git a/contrib/rapidjson/include/rapidjson/filereadstream.h b/contrib/rapidjson/include/rapidjson/filereadstream.h index 3913eb74b..b56ea13b3 100644 --- a/contrib/rapidjson/include/rapidjson/filereadstream.h +++ b/contrib/rapidjson/include/rapidjson/filereadstream.h @@ -15,9 +15,16 @@ #ifndef RAPIDJSON_FILEREADSTREAM_H_ #define RAPIDJSON_FILEREADSTREAM_H_ -#include "rapidjson.h" +#include "stream.h" #include +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(missing-noreturn) +#endif + RAPIDJSON_NAMESPACE_BEGIN //! File byte stream for input using fread(). @@ -85,4 +92,8 @@ private: RAPIDJSON_NAMESPACE_END +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_FILESTREAM_H_ diff --git a/contrib/rapidjson/include/rapidjson/filewritestream.h b/contrib/rapidjson/include/rapidjson/filewritestream.h index dfb9cbd02..6378dd60e 100644 --- a/contrib/rapidjson/include/rapidjson/filewritestream.h +++ b/contrib/rapidjson/include/rapidjson/filewritestream.h @@ -15,9 +15,14 @@ #ifndef RAPIDJSON_FILEWRITESTREAM_H_ #define RAPIDJSON_FILEWRITESTREAM_H_ -#include "rapidjson.h" +#include "stream.h" #include +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(unreachable-code) +#endif + RAPIDJSON_NAMESPACE_BEGIN //! Wrapper of C file stream for input using fread(). @@ -57,7 +62,11 @@ public: void Flush() { if (current_ != buffer_) { - fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); + size_t result = fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); + if (result < static_cast(current_ - buffer_)) { + // failure deliberately ignored at this time + // added to avoid warn_unused_result build errors + } current_ = buffer_; } } @@ -88,4 +97,8 @@ inline void PutN(FileWriteStream& stream, char c, size_t n) { RAPIDJSON_NAMESPACE_END +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_FILESTREAM_H_ diff --git a/contrib/rapidjson/include/rapidjson/fwd.h b/contrib/rapidjson/include/rapidjson/fwd.h new file mode 100644 index 000000000..e8104e841 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/fwd.h @@ -0,0 +1,151 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_FWD_H_ +#define RAPIDJSON_FWD_H_ + +#include "rapidjson.h" + +RAPIDJSON_NAMESPACE_BEGIN + +// encodings.h + +template struct UTF8; +template struct UTF16; +template struct UTF16BE; +template struct UTF16LE; +template struct UTF32; +template struct UTF32BE; +template struct UTF32LE; +template struct ASCII; +template struct AutoUTF; + +template +struct Transcoder; + +// allocators.h + +class CrtAllocator; + +template +class MemoryPoolAllocator; + +// stream.h + +template +struct GenericStringStream; + +typedef GenericStringStream > StringStream; + +template +struct GenericInsituStringStream; + +typedef GenericInsituStringStream > InsituStringStream; + +// stringbuffer.h + +template +class GenericStringBuffer; + +typedef GenericStringBuffer, CrtAllocator> StringBuffer; + +// filereadstream.h + +class FileReadStream; + +// filewritestream.h + +class FileWriteStream; + +// memorybuffer.h + +template +struct GenericMemoryBuffer; + +typedef GenericMemoryBuffer MemoryBuffer; + +// memorystream.h + +struct MemoryStream; + +// reader.h + +template +struct BaseReaderHandler; + +template +class GenericReader; + +typedef GenericReader, UTF8, CrtAllocator> Reader; + +// writer.h + +template +class Writer; + +// prettywriter.h + +template +class PrettyWriter; + +// document.h + +template +struct GenericMember; + +template +class GenericMemberIterator; + +template +struct GenericStringRef; + +template +class GenericValue; + +typedef GenericValue, MemoryPoolAllocator > Value; + +template +class GenericDocument; + +typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; + +// pointer.h + +template +class GenericPointer; + +typedef GenericPointer Pointer; + +// schema.h + +template +class IGenericRemoteSchemaDocumentProvider; + +template +class GenericSchemaDocument; + +typedef GenericSchemaDocument SchemaDocument; +typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; + +template < + typename SchemaDocumentType, + typename OutputHandler, + typename StateAllocator> +class GenericSchemaValidator; + +typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_RAPIDJSONFWD_H_ diff --git a/contrib/rapidjson/include/rapidjson/internal/biginteger.h b/contrib/rapidjson/include/rapidjson/internal/biginteger.h index 99a30acf6..9d3e88c99 100644 --- a/contrib/rapidjson/include/rapidjson/internal/biginteger.h +++ b/contrib/rapidjson/include/rapidjson/internal/biginteger.h @@ -19,6 +19,7 @@ #if defined(_MSC_VER) && defined(_M_AMD64) #include // for _umul128 +#pragma intrinsic(_umul128) #endif RAPIDJSON_NAMESPACE_BEGIN @@ -50,7 +51,16 @@ public: if (length > 0) AppendDecimal64(decimals + i, decimals + i + length); } - + + BigInteger& operator=(const BigInteger &rhs) + { + if (this != &rhs) { + count_ = rhs.count_; + std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); + } + return *this; + } + BigInteger& operator=(uint64_t u) { digits_[0] = u; count_ = 1; @@ -230,7 +240,7 @@ private: uint64_t r = 0; for (const char* p = begin; p != end; ++p) { RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); - r = r * 10 + (*p - '0'); + r = r * 10u + static_cast(*p - '0'); } return r; } diff --git a/contrib/rapidjson/include/rapidjson/internal/diyfp.h b/contrib/rapidjson/include/rapidjson/internal/diyfp.h index 3b6c4238c..29abf8046 100644 --- a/contrib/rapidjson/include/rapidjson/internal/diyfp.h +++ b/contrib/rapidjson/include/rapidjson/internal/diyfp.h @@ -21,9 +21,10 @@ #include "../rapidjson.h" -#if defined(_MSC_VER) && defined(_M_AMD64) +#if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) #include #pragma intrinsic(_BitScanReverse64) +#pragma intrinsic(_umul128) #endif RAPIDJSON_NAMESPACE_BEGIN @@ -34,8 +35,13 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + struct DiyFp { - DiyFp() {} + DiyFp() : f(), e() {} DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} @@ -232,8 +238,8 @@ inline DiyFp GetCachedPower(int e, int* K) { } inline DiyFp GetCachedPower10(int exp, int *outExp) { - unsigned index = (exp + 348) / 8; - *outExp = -348 + index * 8; + unsigned index = (static_cast(exp) + 348u) / 8u; + *outExp = -348 + static_cast(index) * 8; return GetCachedPowerByIndex(index); } @@ -241,6 +247,11 @@ inline DiyFp GetCachedPower10(int exp, int *outExp) { RAPIDJSON_DIAG_POP #endif +#ifdef __clang__ +RAPIDJSON_DIAG_POP +RAPIDJSON_DIAG_OFF(padded) +#endif + } // namespace internal RAPIDJSON_NAMESPACE_END diff --git a/contrib/rapidjson/include/rapidjson/internal/dtoa.h b/contrib/rapidjson/include/rapidjson/internal/dtoa.h index 2d8d2e46a..bf2e9b2e5 100644 --- a/contrib/rapidjson/include/rapidjson/internal/dtoa.h +++ b/contrib/rapidjson/include/rapidjson/internal/dtoa.h @@ -29,6 +29,7 @@ namespace internal { #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) +RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 #endif inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { @@ -40,7 +41,7 @@ inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uin } } -inline unsigned CountDecimalDigit32(uint32_t n) { +inline int CountDecimalDigit32(uint32_t n) { // Simple pure C++ implementation was faster than __builtin_clz version in this situation. if (n < 10) return 1; if (n < 100) return 2; @@ -101,7 +102,8 @@ inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buff kappa--; if (p2 < delta) { *K += kappa; - GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]); + int index = -kappa; + GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0)); return; } } @@ -145,10 +147,10 @@ inline char* WriteExponent(int K, char* buffer) { return buffer; } -inline char* Prettify(char* buffer, int length, int k) { +inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { const int kk = length + k; // 10^(kk-1) <= v < 10^kk - if (length <= kk && kk <= 21) { + if (0 <= k && kk <= 21) { // 1234e7 -> 12340000000 for (int i = length; i < kk; i++) buffer[i] = '0'; @@ -158,19 +160,44 @@ inline char* Prettify(char* buffer, int length, int k) { } else if (0 < kk && kk <= 21) { // 1234e-2 -> 12.34 - std::memmove(&buffer[kk + 1], &buffer[kk], length - kk); + std::memmove(&buffer[kk + 1], &buffer[kk], static_cast(length - kk)); buffer[kk] = '.'; - return &buffer[length + 1]; + if (0 > k + maxDecimalPlaces) { + // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 + // Remove extra trailing zeros (at least one) after truncation. + for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) + if (buffer[i] != '0') + return &buffer[i + 1]; + return &buffer[kk + 2]; // Reserve one zero + } + else + return &buffer[length + 1]; } else if (-6 < kk && kk <= 0) { // 1234e-6 -> 0.001234 const int offset = 2 - kk; - std::memmove(&buffer[offset], &buffer[0], length); + std::memmove(&buffer[offset], &buffer[0], static_cast(length)); buffer[0] = '0'; buffer[1] = '.'; for (int i = 2; i < offset; i++) buffer[i] = '0'; - return &buffer[length + offset]; + if (length - kk > maxDecimalPlaces) { + // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 + // Remove extra trailing zeros (at least one) after truncation. + for (int i = maxDecimalPlaces + 1; i > 2; i--) + if (buffer[i] != '0') + return &buffer[i + 1]; + return &buffer[3]; // Reserve one zero + } + else + return &buffer[length + offset]; + } + else if (kk < -maxDecimalPlaces) { + // Truncate to zero + buffer[0] = '0'; + buffer[1] = '.'; + buffer[2] = '0'; + return &buffer[3]; } else if (length == 1) { // 1e30 @@ -179,14 +206,15 @@ inline char* Prettify(char* buffer, int length, int k) { } else { // 1234e30 -> 1.234e33 - std::memmove(&buffer[2], &buffer[1], length - 1); + std::memmove(&buffer[2], &buffer[1], static_cast(length - 1)); buffer[1] = '.'; buffer[length + 1] = 'e'; return WriteExponent(kk - 1, &buffer[0 + length + 2]); } } -inline char* dtoa(double value, char* buffer) { +inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { + RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); Double d(value); if (d.IsZero()) { if (d.Sign()) @@ -203,7 +231,7 @@ inline char* dtoa(double value, char* buffer) { } int length, K; Grisu2(value, buffer, &length, &K); - return Prettify(buffer, length, K); + return Prettify(buffer, length, K, maxDecimalPlaces); } } diff --git a/contrib/rapidjson/include/rapidjson/internal/ieee754.h b/contrib/rapidjson/include/rapidjson/internal/ieee754.h index e3f03364c..c2684ba2a 100644 --- a/contrib/rapidjson/include/rapidjson/internal/ieee754.h +++ b/contrib/rapidjson/include/rapidjson/internal/ieee754.h @@ -40,6 +40,7 @@ public: bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } + bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } @@ -47,7 +48,7 @@ public: int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } - static unsigned EffectiveSignificandSize(int order) { + static int EffectiveSignificandSize(int order) { if (order >= -1021) return 53; else if (order <= -1074) diff --git a/contrib/rapidjson/include/rapidjson/internal/regex.h b/contrib/rapidjson/include/rapidjson/internal/regex.h new file mode 100644 index 000000000..e1a2faae5 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/internal/regex.h @@ -0,0 +1,734 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_INTERNAL_REGEX_H_ +#define RAPIDJSON_INTERNAL_REGEX_H_ + +#include "../allocators.h" +#include "../stream.h" +#include "stack.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(switch-enum) +RAPIDJSON_DIAG_OFF(implicit-fallthrough) +#endif + +#ifdef __GNUC__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(effc++) +#if __GNUC__ >= 7 +RAPIDJSON_DIAG_OFF(implicit-fallthrough) +#endif +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +#ifndef RAPIDJSON_REGEX_VERBOSE +#define RAPIDJSON_REGEX_VERBOSE 0 +#endif + +RAPIDJSON_NAMESPACE_BEGIN +namespace internal { + +/////////////////////////////////////////////////////////////////////////////// +// DecodedStream + +template +class DecodedStream { +public: + DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); } + unsigned Peek() { return codepoint_; } + unsigned Take() { + unsigned c = codepoint_; + if (c) // No further decoding when '\0' + Decode(); + return c; + } + +private: + void Decode() { + if (!Encoding::Decode(ss_, &codepoint_)) + codepoint_ = 0; + } + + SourceStream& ss_; + unsigned codepoint_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericRegex + +static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1 +static const SizeType kRegexInvalidRange = ~SizeType(0); + +template +class GenericRegexSearch; + +//! Regular expression engine with subset of ECMAscript grammar. +/*! + Supported regular expression syntax: + - \c ab Concatenation + - \c a|b Alternation + - \c a? Zero or one + - \c a* Zero or more + - \c a+ One or more + - \c a{3} Exactly 3 times + - \c a{3,} At least 3 times + - \c a{3,5} 3 to 5 times + - \c (ab) Grouping + - \c ^a At the beginning + - \c a$ At the end + - \c . Any character + - \c [abc] Character classes + - \c [a-c] Character class range + - \c [a-z0-9_] Character class combination + - \c [^abc] Negated character classes + - \c [^a-c] Negated character class range + - \c [\b] Backspace (U+0008) + - \c \\| \\\\ ... Escape characters + - \c \\f Form feed (U+000C) + - \c \\n Line feed (U+000A) + - \c \\r Carriage return (U+000D) + - \c \\t Tab (U+0009) + - \c \\v Vertical tab (U+000B) + + \note This is a Thompson NFA engine, implemented with reference to + Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).", + https://swtch.com/~rsc/regexp/regexp1.html +*/ +template +class GenericRegex { +public: + typedef Encoding EncodingType; + typedef typename Encoding::Ch Ch; + template friend class GenericRegexSearch; + + GenericRegex(const Ch* source, Allocator* allocator = 0) : + states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), + anchorBegin_(), anchorEnd_() + { + GenericStringStream ss(source); + DecodedStream, Encoding> ds(ss); + Parse(ds); + } + + ~GenericRegex() {} + + bool IsValid() const { + return root_ != kRegexInvalidState; + } + +private: + enum Operator { + kZeroOrOne, + kZeroOrMore, + kOneOrMore, + kConcatenation, + kAlternation, + kLeftParenthesis + }; + + static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.' + static const unsigned kRangeCharacterClass = 0xFFFFFFFE; + static const unsigned kRangeNegationFlag = 0x80000000; + + struct Range { + unsigned start; // + unsigned end; + SizeType next; + }; + + struct State { + SizeType out; //!< Equals to kInvalid for matching state + SizeType out1; //!< Equals to non-kInvalid for split + SizeType rangeStart; + unsigned codepoint; + }; + + struct Frag { + Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {} + SizeType start; + SizeType out; //!< link-list of all output states + SizeType minIndex; + }; + + State& GetState(SizeType index) { + RAPIDJSON_ASSERT(index < stateCount_); + return states_.template Bottom()[index]; + } + + const State& GetState(SizeType index) const { + RAPIDJSON_ASSERT(index < stateCount_); + return states_.template Bottom()[index]; + } + + Range& GetRange(SizeType index) { + RAPIDJSON_ASSERT(index < rangeCount_); + return ranges_.template Bottom()[index]; + } + + const Range& GetRange(SizeType index) const { + RAPIDJSON_ASSERT(index < rangeCount_); + return ranges_.template Bottom()[index]; + } + + template + void Parse(DecodedStream& ds) { + Allocator allocator; + Stack operandStack(&allocator, 256); // Frag + Stack operatorStack(&allocator, 256); // Operator + Stack atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis) + + *atomCountStack.template Push() = 0; + + unsigned codepoint; + while (ds.Peek() != 0) { + switch (codepoint = ds.Take()) { + case '^': + anchorBegin_ = true; + break; + + case '$': + anchorEnd_ = true; + break; + + case '|': + while (!operatorStack.Empty() && *operatorStack.template Top() < kAlternation) + if (!Eval(operandStack, *operatorStack.template Pop(1))) + return; + *operatorStack.template Push() = kAlternation; + *atomCountStack.template Top() = 0; + break; + + case '(': + *operatorStack.template Push() = kLeftParenthesis; + *atomCountStack.template Push() = 0; + break; + + case ')': + while (!operatorStack.Empty() && *operatorStack.template Top() != kLeftParenthesis) + if (!Eval(operandStack, *operatorStack.template Pop(1))) + return; + if (operatorStack.Empty()) + return; + operatorStack.template Pop(1); + atomCountStack.template Pop(1); + ImplicitConcatenation(atomCountStack, operatorStack); + break; + + case '?': + if (!Eval(operandStack, kZeroOrOne)) + return; + break; + + case '*': + if (!Eval(operandStack, kZeroOrMore)) + return; + break; + + case '+': + if (!Eval(operandStack, kOneOrMore)) + return; + break; + + case '{': + { + unsigned n, m; + if (!ParseUnsigned(ds, &n)) + return; + + if (ds.Peek() == ',') { + ds.Take(); + if (ds.Peek() == '}') + m = kInfinityQuantifier; + else if (!ParseUnsigned(ds, &m) || m < n) + return; + } + else + m = n; + + if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}') + return; + ds.Take(); + } + break; + + case '.': + PushOperand(operandStack, kAnyCharacterClass); + ImplicitConcatenation(atomCountStack, operatorStack); + break; + + case '[': + { + SizeType range; + if (!ParseRange(ds, &range)) + return; + SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass); + GetState(s).rangeStart = range; + *operandStack.template Push() = Frag(s, s, s); + } + ImplicitConcatenation(atomCountStack, operatorStack); + break; + + case '\\': // Escape character + if (!CharacterEscape(ds, &codepoint)) + return; // Unsupported escape character + // fall through to default + + default: // Pattern character + PushOperand(operandStack, codepoint); + ImplicitConcatenation(atomCountStack, operatorStack); + } + } + + while (!operatorStack.Empty()) + if (!Eval(operandStack, *operatorStack.template Pop(1))) + return; + + // Link the operand to matching state. + if (operandStack.GetSize() == sizeof(Frag)) { + Frag* e = operandStack.template Pop(1); + Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0)); + root_ = e->start; + +#if RAPIDJSON_REGEX_VERBOSE + printf("root: %d\n", root_); + for (SizeType i = 0; i < stateCount_ ; i++) { + State& s = GetState(i); + printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint); + } + printf("\n"); +#endif + } + } + + SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) { + State* s = states_.template Push(); + s->out = out; + s->out1 = out1; + s->codepoint = codepoint; + s->rangeStart = kRegexInvalidRange; + return stateCount_++; + } + + void PushOperand(Stack& operandStack, unsigned codepoint) { + SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint); + *operandStack.template Push() = Frag(s, s, s); + } + + void ImplicitConcatenation(Stack& atomCountStack, Stack& operatorStack) { + if (*atomCountStack.template Top()) + *operatorStack.template Push() = kConcatenation; + (*atomCountStack.template Top())++; + } + + SizeType Append(SizeType l1, SizeType l2) { + SizeType old = l1; + while (GetState(l1).out != kRegexInvalidState) + l1 = GetState(l1).out; + GetState(l1).out = l2; + return old; + } + + void Patch(SizeType l, SizeType s) { + for (SizeType next; l != kRegexInvalidState; l = next) { + next = GetState(l).out; + GetState(l).out = s; + } + } + + bool Eval(Stack& operandStack, Operator op) { + switch (op) { + case kConcatenation: + RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2); + { + Frag e2 = *operandStack.template Pop(1); + Frag e1 = *operandStack.template Pop(1); + Patch(e1.out, e2.start); + *operandStack.template Push() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex)); + } + return true; + + case kAlternation: + if (operandStack.GetSize() >= sizeof(Frag) * 2) { + Frag e2 = *operandStack.template Pop(1); + Frag e1 = *operandStack.template Pop(1); + SizeType s = NewState(e1.start, e2.start, 0); + *operandStack.template Push() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex)); + return true; + } + return false; + + case kZeroOrOne: + if (operandStack.GetSize() >= sizeof(Frag)) { + Frag e = *operandStack.template Pop(1); + SizeType s = NewState(kRegexInvalidState, e.start, 0); + *operandStack.template Push() = Frag(s, Append(e.out, s), e.minIndex); + return true; + } + return false; + + case kZeroOrMore: + if (operandStack.GetSize() >= sizeof(Frag)) { + Frag e = *operandStack.template Pop(1); + SizeType s = NewState(kRegexInvalidState, e.start, 0); + Patch(e.out, s); + *operandStack.template Push() = Frag(s, s, e.minIndex); + return true; + } + return false; + + default: + RAPIDJSON_ASSERT(op == kOneOrMore); + if (operandStack.GetSize() >= sizeof(Frag)) { + Frag e = *operandStack.template Pop(1); + SizeType s = NewState(kRegexInvalidState, e.start, 0); + Patch(e.out, s); + *operandStack.template Push() = Frag(e.start, s, e.minIndex); + return true; + } + return false; + } + } + + bool EvalQuantifier(Stack& operandStack, unsigned n, unsigned m) { + RAPIDJSON_ASSERT(n <= m); + RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag)); + + if (n == 0) { + if (m == 0) // a{0} not support + return false; + else if (m == kInfinityQuantifier) + Eval(operandStack, kZeroOrMore); // a{0,} -> a* + else { + Eval(operandStack, kZeroOrOne); // a{0,5} -> a? + for (unsigned i = 0; i < m - 1; i++) + CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a? + for (unsigned i = 0; i < m - 1; i++) + Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a? + } + return true; + } + + for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a + CloneTopOperand(operandStack); + + if (m == kInfinityQuantifier) + Eval(operandStack, kOneOrMore); // a{3,} -> a a a+ + else if (m > n) { + CloneTopOperand(operandStack); // a{3,5} -> a a a a + Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a? + for (unsigned i = n; i < m - 1; i++) + CloneTopOperand(operandStack); // a{3,5} -> a a a a? a? + for (unsigned i = n; i < m; i++) + Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a? + } + + for (unsigned i = 0; i < n - 1; i++) + Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a? + + return true; + } + + static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; } + + void CloneTopOperand(Stack& operandStack) { + const Frag src = *operandStack.template Top(); // Copy constructor to prevent invalidation + SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_) + State* s = states_.template Push(count); + memcpy(s, &GetState(src.minIndex), count * sizeof(State)); + for (SizeType j = 0; j < count; j++) { + if (s[j].out != kRegexInvalidState) + s[j].out += count; + if (s[j].out1 != kRegexInvalidState) + s[j].out1 += count; + } + *operandStack.template Push() = Frag(src.start + count, src.out + count, src.minIndex + count); + stateCount_ += count; + } + + template + bool ParseUnsigned(DecodedStream& ds, unsigned* u) { + unsigned r = 0; + if (ds.Peek() < '0' || ds.Peek() > '9') + return false; + while (ds.Peek() >= '0' && ds.Peek() <= '9') { + if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295 + return false; // overflow + r = r * 10 + (ds.Take() - '0'); + } + *u = r; + return true; + } + + template + bool ParseRange(DecodedStream& ds, SizeType* range) { + bool isBegin = true; + bool negate = false; + int step = 0; + SizeType start = kRegexInvalidRange; + SizeType current = kRegexInvalidRange; + unsigned codepoint; + while ((codepoint = ds.Take()) != 0) { + if (isBegin) { + isBegin = false; + if (codepoint == '^') { + negate = true; + continue; + } + } + + switch (codepoint) { + case ']': + if (start == kRegexInvalidRange) + return false; // Error: nothing inside [] + if (step == 2) { // Add trailing '-' + SizeType r = NewRange('-'); + RAPIDJSON_ASSERT(current != kRegexInvalidRange); + GetRange(current).next = r; + } + if (negate) + GetRange(start).start |= kRangeNegationFlag; + *range = start; + return true; + + case '\\': + if (ds.Peek() == 'b') { + ds.Take(); + codepoint = 0x0008; // Escape backspace character + } + else if (!CharacterEscape(ds, &codepoint)) + return false; + // fall through to default + + default: + switch (step) { + case 1: + if (codepoint == '-') { + step++; + break; + } + // fall through to step 0 for other characters + + case 0: + { + SizeType r = NewRange(codepoint); + if (current != kRegexInvalidRange) + GetRange(current).next = r; + if (start == kRegexInvalidRange) + start = r; + current = r; + } + step = 1; + break; + + default: + RAPIDJSON_ASSERT(step == 2); + GetRange(current).end = codepoint; + step = 0; + } + } + } + return false; + } + + SizeType NewRange(unsigned codepoint) { + Range* r = ranges_.template Push(); + r->start = r->end = codepoint; + r->next = kRegexInvalidRange; + return rangeCount_++; + } + + template + bool CharacterEscape(DecodedStream& ds, unsigned* escapedCodepoint) { + unsigned codepoint; + switch (codepoint = ds.Take()) { + case '^': + case '$': + case '|': + case '(': + case ')': + case '?': + case '*': + case '+': + case '.': + case '[': + case ']': + case '{': + case '}': + case '\\': + *escapedCodepoint = codepoint; return true; + case 'f': *escapedCodepoint = 0x000C; return true; + case 'n': *escapedCodepoint = 0x000A; return true; + case 'r': *escapedCodepoint = 0x000D; return true; + case 't': *escapedCodepoint = 0x0009; return true; + case 'v': *escapedCodepoint = 0x000B; return true; + default: + return false; // Unsupported escape character + } + } + + Stack states_; + Stack ranges_; + SizeType root_; + SizeType stateCount_; + SizeType rangeCount_; + + static const unsigned kInfinityQuantifier = ~0u; + + // For SearchWithAnchoring() + bool anchorBegin_; + bool anchorEnd_; +}; + +template +class GenericRegexSearch { +public: + typedef typename RegexType::EncodingType Encoding; + typedef typename Encoding::Ch Ch; + + GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) : + regex_(regex), allocator_(allocator), ownAllocator_(0), + state0_(allocator, 0), state1_(allocator, 0), stateSet_() + { + RAPIDJSON_ASSERT(regex_.IsValid()); + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + stateSet_ = static_cast(allocator_->Malloc(GetStateSetSize())); + state0_.template Reserve(regex_.stateCount_); + state1_.template Reserve(regex_.stateCount_); + } + + ~GenericRegexSearch() { + Allocator::Free(stateSet_); + RAPIDJSON_DELETE(ownAllocator_); + } + + template + bool Match(InputStream& is) { + return SearchWithAnchoring(is, true, true); + } + + bool Match(const Ch* s) { + GenericStringStream is(s); + return Match(is); + } + + template + bool Search(InputStream& is) { + return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_); + } + + bool Search(const Ch* s) { + GenericStringStream is(s); + return Search(is); + } + +private: + typedef typename RegexType::State State; + typedef typename RegexType::Range Range; + + template + bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) { + DecodedStream ds(is); + + state0_.Clear(); + Stack *current = &state0_, *next = &state1_; + const size_t stateSetSize = GetStateSetSize(); + std::memset(stateSet_, 0, stateSetSize); + + bool matched = AddState(*current, regex_.root_); + unsigned codepoint; + while (!current->Empty() && (codepoint = ds.Take()) != 0) { + std::memset(stateSet_, 0, stateSetSize); + next->Clear(); + matched = false; + for (const SizeType* s = current->template Bottom(); s != current->template End(); ++s) { + const State& sr = regex_.GetState(*s); + if (sr.codepoint == codepoint || + sr.codepoint == RegexType::kAnyCharacterClass || + (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) + { + matched = AddState(*next, sr.out) || matched; + if (!anchorEnd && matched) + return true; + } + if (!anchorBegin) + AddState(*next, regex_.root_); + } + internal::Swap(current, next); + } + + return matched; + } + + size_t GetStateSetSize() const { + return (regex_.stateCount_ + 31) / 32 * 4; + } + + // Return whether the added states is a match state + bool AddState(Stack& l, SizeType index) { + RAPIDJSON_ASSERT(index != kRegexInvalidState); + + const State& s = regex_.GetState(index); + if (s.out1 != kRegexInvalidState) { // Split + bool matched = AddState(l, s.out); + return AddState(l, s.out1) || matched; + } + else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) { + stateSet_[index >> 5] |= (1u << (index & 31)); + *l.template PushUnsafe() = index; + } + return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation. + } + + bool MatchRange(SizeType rangeIndex, unsigned codepoint) const { + bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0; + while (rangeIndex != kRegexInvalidRange) { + const Range& r = regex_.GetRange(rangeIndex); + if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end) + return yes; + rangeIndex = r.next; + } + return !yes; + } + + const RegexType& regex_; + Allocator* allocator_; + Allocator* ownAllocator_; + Stack state0_; + Stack state1_; + uint32_t* stateSet_; +}; + +typedef GenericRegex > Regex; +typedef GenericRegexSearch RegexSearch; + +} // namespace internal +RAPIDJSON_NAMESPACE_END + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_POP +#endif + +#endif // RAPIDJSON_INTERNAL_REGEX_H_ diff --git a/contrib/rapidjson/include/rapidjson/internal/stack.h b/contrib/rapidjson/include/rapidjson/internal/stack.h index 722d56923..5c5398c35 100644 --- a/contrib/rapidjson/include/rapidjson/internal/stack.h +++ b/contrib/rapidjson/include/rapidjson/internal/stack.h @@ -15,7 +15,13 @@ #ifndef RAPIDJSON_INTERNAL_STACK_H_ #define RAPIDJSON_INTERNAL_STACK_H_ -#include "../rapidjson.h" +#include "../allocators.h" +#include "swap.h" + +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { @@ -32,7 +38,6 @@ public: // Optimization note: Do not allocate memory for stack_ in constructor. // Do it lazily when first Push() -> Expand() -> Resize(). Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { - RAPIDJSON_ASSERT(stackCapacity > 0); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS @@ -81,6 +86,15 @@ public: } #endif + void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { + internal::Swap(allocator_, rhs.allocator_); + internal::Swap(ownAllocator_, rhs.ownAllocator_); + internal::Swap(stack_, rhs.stack_); + internal::Swap(stackTop_, rhs.stackTop_); + internal::Swap(stackEnd_, rhs.stackEnd_); + internal::Swap(initialCapacity_, rhs.initialCapacity_); + } + void Clear() { stackTop_ = stack_; } void ShrinkToFit() { @@ -98,11 +112,22 @@ public: // Optimization note: try to minimize the size of this function for force inline. // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. template - RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { + RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { // Expand the stack if needed - if (stackTop_ + sizeof(T) * count >= stackEnd_) + if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_)) Expand(count); + } + template + RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { + Reserve(count); + return PushUnsafe(count); + } + + template + RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { + RAPIDJSON_ASSERT(stackTop_); + RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_); T* ret = reinterpret_cast(stackTop_); stackTop_ += sizeof(T) * count; return ret; @@ -122,9 +147,32 @@ public: } template - T* Bottom() { return (T*)stack_; } + const T* Top() const { + RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); + return reinterpret_cast(stackTop_ - sizeof(T)); + } + + template + T* End() { return reinterpret_cast(stackTop_); } + + template + const T* End() const { return reinterpret_cast(stackTop_); } + + template + T* Bottom() { return reinterpret_cast(stack_); } + + template + const T* Bottom() const { return reinterpret_cast(stack_); } + + bool HasAllocator() const { + return allocator_ != 0; + } + + Allocator& GetAllocator() { + RAPIDJSON_ASSERT(allocator_); + return *allocator_; + } - Allocator& GetAllocator() { return *allocator_; } bool Empty() const { return stackTop_ == stack_; } size_t GetSize() const { return static_cast(stackTop_ - stack_); } size_t GetCapacity() const { return static_cast(stackEnd_ - stack_); } @@ -136,7 +184,7 @@ private: size_t newCapacity; if (stack_ == 0) { if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); newCapacity = initialCapacity_; } else { newCapacity = GetCapacity(); @@ -151,7 +199,7 @@ private: void Resize(size_t newCapacity) { const size_t size = GetSize(); // Backup the current size - stack_ = (char*)allocator_->Realloc(stack_, GetCapacity(), newCapacity); + stack_ = static_cast(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); stackTop_ = stack_ + size; stackEnd_ = stack_ + newCapacity; } @@ -176,4 +224,8 @@ private: } // namespace internal RAPIDJSON_NAMESPACE_END +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_STACK_H_ diff --git a/contrib/rapidjson/include/rapidjson/internal/strfunc.h b/contrib/rapidjson/include/rapidjson/internal/strfunc.h index 84405065a..226439a76 100644 --- a/contrib/rapidjson/include/rapidjson/internal/strfunc.h +++ b/contrib/rapidjson/include/rapidjson/internal/strfunc.h @@ -15,7 +15,8 @@ #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ #define RAPIDJSON_INTERNAL_STRFUNC_H_ -#include "../rapidjson.h" +#include "../stream.h" +#include RAPIDJSON_NAMESPACE_BEGIN namespace internal { @@ -28,11 +29,40 @@ namespace internal { */ template inline SizeType StrLen(const Ch* s) { + RAPIDJSON_ASSERT(s != 0); const Ch* p = s; while (*p) ++p; return SizeType(p - s); } +template <> +inline SizeType StrLen(const char* s) { + return SizeType(std::strlen(s)); +} + +template <> +inline SizeType StrLen(const wchar_t* s) { + return SizeType(std::wcslen(s)); +} + +//! Returns number of code points in a encoded string. +template +bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { + RAPIDJSON_ASSERT(s != 0); + RAPIDJSON_ASSERT(outCount != 0); + GenericStringStream is(s); + const typename Encoding::Ch* end = s + length; + SizeType count = 0; + while (is.src_ < end) { + unsigned codepoint; + if (!Encoding::Decode(is, &codepoint)) + return false; + count++; + } + *outCount = count; + return true; +} + } // namespace internal RAPIDJSON_NAMESPACE_END diff --git a/contrib/rapidjson/include/rapidjson/internal/strtod.h b/contrib/rapidjson/include/rapidjson/internal/strtod.h index ace65f677..adf49e349 100644 --- a/contrib/rapidjson/include/rapidjson/internal/strtod.h +++ b/contrib/rapidjson/include/rapidjson/internal/strtod.h @@ -15,7 +15,6 @@ #ifndef RAPIDJSON_STRTOD_ #define RAPIDJSON_STRTOD_ -#include "../rapidjson.h" #include "ieee754.h" #include "biginteger.h" #include "diyfp.h" @@ -95,13 +94,13 @@ inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { hS_Exp2 -= common_Exp2; BigInteger dS = d; - dS.MultiplyPow5(dS_Exp5) <<= dS_Exp2; + dS.MultiplyPow5(static_cast(dS_Exp5)) <<= static_cast(dS_Exp2); BigInteger bS(bInt); - bS.MultiplyPow5(bS_Exp5) <<= bS_Exp2; + bS.MultiplyPow5(static_cast(bS_Exp5)) <<= static_cast(bS_Exp2); BigInteger hS(1); - hS.MultiplyPow5(hS_Exp5) <<= hS_Exp2; + hS.MultiplyPow5(static_cast(hS_Exp5)) <<= static_cast(hS_Exp2); BigInteger delta(0); dS.Difference(bS, &delta); @@ -134,22 +133,22 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) break; - significand = significand * 10 + (decimals[i] - '0'); + significand = significand * 10u + static_cast(decimals[i] - '0'); } if (i < length && decimals[i] >= '5') // Rounding significand++; size_t remaining = length - i; - const unsigned kUlpShift = 3; - const unsigned kUlp = 1 << kUlpShift; - int error = (remaining == 0) ? 0 : kUlp / 2; + const int kUlpShift = 3; + const int kUlp = 1 << kUlpShift; + int64_t error = (remaining == 0) ? 0 : kUlp / 2; DiyFp v(significand, 0); v = v.Normalize(); error <<= -v.e; - const int dExp = (int)decimalPosition - (int)i + exp; + const int dExp = static_cast(decimalPosition) - static_cast(i) + exp; int actualExp; DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); @@ -163,10 +162,10 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6 DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7 }; - int adjustment = dExp - actualExp - 1; + int adjustment = dExp - actualExp - 1; RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); v = v * kPow10[adjustment]; - if (length + adjustment > 19) // has more digits than decimal digits in 64-bit + if (length + static_cast(adjustment)> 19u) // has more digits than decimal digits in 64-bit error += kUlp / 2; } @@ -178,10 +177,10 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit v = v.Normalize(); error <<= oldExp - v.e; - const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); - unsigned precisionSize = 64 - effectiveSignificandSize; + const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); + int precisionSize = 64 - effectiveSignificandSize; if (precisionSize + kUlpShift >= 64) { - unsigned scaleExp = (precisionSize + kUlpShift) - 63; + int scaleExp = (precisionSize + kUlpShift) - 63; v.f >>= scaleExp; v.e += scaleExp; error = (error >> scaleExp) + 1 + kUlp; @@ -191,7 +190,7 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit DiyFp rounded(v.f >> precisionSize, v.e + precisionSize); const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; - if (precisionBits >= halfWay + error) { + if (precisionBits >= halfWay + static_cast(error)) { rounded.f++; if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) rounded.f >>= 1; @@ -201,12 +200,12 @@ inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosit *result = rounded.ToDouble(); - return halfWay - error >= precisionBits || precisionBits >= halfWay + error; + return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); } inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { const BigInteger dInt(decimals, length); - const int dExp = (int)decimalPosition - (int)length + exp; + const int dExp = static_cast(decimalPosition) - static_cast(length) + exp; Double a(approx); int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); if (cmp < 0) @@ -246,10 +245,10 @@ inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t // Trim right-most digits const int kMaxDecimalDigit = 780; - if ((int)length > kMaxDecimalDigit) { - int delta = (int(length) - kMaxDecimalDigit); + if (static_cast(length) > kMaxDecimalDigit) { + int delta = (static_cast(length) - kMaxDecimalDigit); exp += delta; - decimalPosition -= delta; + decimalPosition -= static_cast(delta); length = kMaxDecimalDigit; } diff --git a/contrib/rapidjson/include/rapidjson/internal/swap.h b/contrib/rapidjson/include/rapidjson/internal/swap.h index 0590921f1..666e49f97 100644 --- a/contrib/rapidjson/include/rapidjson/internal/swap.h +++ b/contrib/rapidjson/include/rapidjson/internal/swap.h @@ -17,6 +17,11 @@ #include "../rapidjson.h" +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + RAPIDJSON_NAMESPACE_BEGIN namespace internal { @@ -34,4 +39,8 @@ inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { } // namespace internal RAPIDJSON_NAMESPACE_END +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_INTERNAL_SWAP_H_ diff --git a/contrib/rapidjson/include/rapidjson/istreamwrapper.h b/contrib/rapidjson/include/rapidjson/istreamwrapper.h new file mode 100644 index 000000000..8639c8c3c --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/istreamwrapper.h @@ -0,0 +1,115 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_ISTREAMWRAPPER_H_ +#define RAPIDJSON_ISTREAMWRAPPER_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. +/*! + The classes can be wrapped including but not limited to: + + - \c std::istringstream + - \c std::stringstream + - \c std::wistringstream + - \c std::wstringstream + - \c std::ifstream + - \c std::fstream + - \c std::wifstream + - \c std::wfstream + + \tparam StreamType Class derived from \c std::basic_istream. +*/ + +template +class BasicIStreamWrapper { +public: + typedef typename StreamType::char_type Ch; + BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {} + + Ch Peek() const { + typename StreamType::int_type c = stream_.peek(); + return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast(c) : static_cast('\0'); + } + + Ch Take() { + typename StreamType::int_type c = stream_.get(); + if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) { + count_++; + return static_cast(c); + } + else + return '\0'; + } + + // tellg() may return -1 when failed. So we count by ourself. + size_t Tell() const { return count_; } + + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + // For encoding detection only. + const Ch* Peek4() const { + RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream. + int i; + bool hasError = false; + for (i = 0; i < 4; ++i) { + typename StreamType::int_type c = stream_.get(); + if (c == StreamType::traits_type::eof()) { + hasError = true; + stream_.clear(); + break; + } + peekBuffer_[i] = static_cast(c); + } + for (--i; i >= 0; --i) + stream_.putback(peekBuffer_[i]); + return !hasError ? peekBuffer_ : 0; + } + +private: + BasicIStreamWrapper(const BasicIStreamWrapper&); + BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); + + StreamType& stream_; + size_t count_; //!< Number of characters read. Note: + mutable Ch peekBuffer_[4]; +}; + +typedef BasicIStreamWrapper IStreamWrapper; +typedef BasicIStreamWrapper WIStreamWrapper; + +#if defined(__clang__) || defined(_MSC_VER) +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_ISTREAMWRAPPER_H_ diff --git a/contrib/rapidjson/include/rapidjson/memorybuffer.h b/contrib/rapidjson/include/rapidjson/memorybuffer.h index 2484b2185..39bee1dec 100644 --- a/contrib/rapidjson/include/rapidjson/memorybuffer.h +++ b/contrib/rapidjson/include/rapidjson/memorybuffer.h @@ -15,7 +15,7 @@ #ifndef RAPIDJSON_MEMORYBUFFER_H_ #define RAPIDJSON_MEMORYBUFFER_H_ -#include "rapidjson.h" +#include "stream.h" #include "internal/stack.h" RAPIDJSON_NAMESPACE_BEGIN diff --git a/contrib/rapidjson/include/rapidjson/memorystream.h b/contrib/rapidjson/include/rapidjson/memorystream.h index 99feae5d7..1d71d8a4f 100644 --- a/contrib/rapidjson/include/rapidjson/memorystream.h +++ b/contrib/rapidjson/include/rapidjson/memorystream.h @@ -15,7 +15,13 @@ #ifndef RAPIDJSON_MEMORYSTREAM_H_ #define RAPIDJSON_MEMORYSTREAM_H_ -#include "rapidjson.h" +#include "stream.h" + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(missing-noreturn) +#endif RAPIDJSON_NAMESPACE_BEGIN @@ -36,8 +42,8 @@ struct MemoryStream { MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} - Ch Peek() const { return (src_ == end_) ? '\0' : *src_; } - Ch Take() { return (src_ == end_) ? '\0' : *src_++; } + Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } + Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } size_t Tell() const { return static_cast(src_ - begin_); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } @@ -58,4 +64,8 @@ struct MemoryStream { RAPIDJSON_NAMESPACE_END +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_MEMORYBUFFER_H_ diff --git a/contrib/rapidjson/include/rapidjson/msinttypes/stdint.h b/contrib/rapidjson/include/rapidjson/msinttypes/stdint.h index a26fff4bf..3d4477b9a 100644 --- a/contrib/rapidjson/include/rapidjson/msinttypes/stdint.h +++ b/contrib/rapidjson/include/rapidjson/msinttypes/stdint.h @@ -89,14 +89,14 @@ #include // For Visual Studio 6 in C++ mode and for many Visual Studio versions when -// compiling for ARM we should wrap include with 'extern "C++" {}' -// or compiler give many errors like this: +// compiling for ARM we have to wrap include with 'extern "C++" {}' +// or compiler would give many errors like this: // error C2733: second C linkage of overloaded function 'wmemchr' not allowed -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(_M_ARM) extern "C" { #endif # include -#ifdef __cplusplus +#if defined(__cplusplus) && !defined(_M_ARM) } #endif diff --git a/contrib/rapidjson/include/rapidjson/ostreamwrapper.h b/contrib/rapidjson/include/rapidjson/ostreamwrapper.h new file mode 100644 index 000000000..6f4667c08 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/ostreamwrapper.h @@ -0,0 +1,81 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#ifndef RAPIDJSON_OSTREAMWRAPPER_H_ +#define RAPIDJSON_OSTREAMWRAPPER_H_ + +#include "stream.h" +#include + +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. +/*! + The classes can be wrapped including but not limited to: + + - \c std::ostringstream + - \c std::stringstream + - \c std::wpstringstream + - \c std::wstringstream + - \c std::ifstream + - \c std::fstream + - \c std::wofstream + - \c std::wfstream + + \tparam StreamType Class derived from \c std::basic_ostream. +*/ + +template +class BasicOStreamWrapper { +public: + typedef typename StreamType::char_type Ch; + BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} + + void Put(Ch c) { + stream_.put(c); + } + + void Flush() { + stream_.flush(); + } + + // Not implemented + char Peek() const { RAPIDJSON_ASSERT(false); return 0; } + char Take() { RAPIDJSON_ASSERT(false); return 0; } + size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } + char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } + +private: + BasicOStreamWrapper(const BasicOStreamWrapper&); + BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); + + StreamType& stream_; +}; + +typedef BasicOStreamWrapper OStreamWrapper; +typedef BasicOStreamWrapper WOStreamWrapper; + +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_OSTREAMWRAPPER_H_ diff --git a/contrib/rapidjson/include/rapidjson/pointer.h b/contrib/rapidjson/include/rapidjson/pointer.h index 5d2aa8d63..0f377efec 100644 --- a/contrib/rapidjson/include/rapidjson/pointer.h +++ b/contrib/rapidjson/include/rapidjson/pointer.h @@ -18,6 +18,16 @@ #include "document.h" #include "internal/itoa.h" +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(switch-enum) +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + RAPIDJSON_NAMESPACE_BEGIN static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token @@ -71,7 +81,7 @@ template class GenericPointer { public: typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value - typedef typename EncodingType::Ch Ch; //!< Character type from Value + typedef typename ValueType::Ch Ch; //!< Character type from Value //! A token is the basic units of internal representation. /*! @@ -96,7 +106,7 @@ public: //@{ //! Default constructor. - GenericPointer() : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} + GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} //! Constructor that parses a string or URI fragment representation. /*! @@ -155,7 +165,7 @@ public: GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} //! Copy constructor. - GenericPointer(const GenericPointer& rhs) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { + GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { *this = rhs; } @@ -230,7 +240,7 @@ public: template RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) Append(T* name, Allocator* allocator = 0) const { - return Append(name, StrLen(name), allocator); + return Append(name, internal::StrLen(name), allocator); } #if RAPIDJSON_HAS_STDSTRING @@ -253,17 +263,18 @@ public: */ GenericPointer Append(SizeType index, Allocator* allocator = 0) const { char buffer[21]; - SizeType length = (sizeof(SizeType) == 4 ? internal::u32toa(index, buffer): internal::u64toa(index, buffer)) - buffer; + char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer); + SizeType length = static_cast(end - buffer); buffer[length] = '\0'; if (sizeof(Ch) == 1) { - Token token = { (Ch*)buffer, length, index }; + Token token = { reinterpret_cast(buffer), length, index }; return Append(token, allocator); } else { Ch name[21]; for (size_t i = 0; i <= length; i++) - name[i] = buffer[i]; + name[i] = static_cast(buffer[i]); Token token = { name, length, index }; return Append(token, allocator); } @@ -271,7 +282,7 @@ public: //! Append a token by value, and return a new Pointer /*! - \param value Value (either Uint or String) to be appended. + \param token token to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ @@ -299,6 +310,9 @@ public: //@} + //! Get the allocator of this pointer. + Allocator& GetAllocator() { return *allocator_; } + //!@name Tokens //@{ @@ -390,7 +404,7 @@ public: bool exist = true; for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { if (v->IsArray() && t->name[0] == '-' && t->length == 1) { - v->PushBack(Value().Move(), allocator); + v->PushBack(ValueType().Move(), allocator); v = &((*v)[v->Size() - 1]); exist = false; } @@ -408,7 +422,7 @@ public: if (t->index >= v->Size()) { v->Reserve(t->index + 1, allocator); while (t->index >= v->Size()) - v->PushBack(Value().Move(), allocator); + v->PushBack(ValueType().Move(), allocator); exist = false; } v = &((*v)[t->index]); @@ -416,7 +430,7 @@ public: else { typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); if (m == v->MemberEnd()) { - v->AddMember(Value(t->name, t->length, allocator).Move(), Value().Move(), allocator); + v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator); v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end exist = false; } @@ -435,7 +449,6 @@ public: //! Creates a value in a document. /*! \param document A document to be resolved. - \param allocator Allocator for creating the values if the specified value or its parents are not exist. \param alreadyExist If non-null, it stores whether the resolved value is already exist. \return The resolved newly created, or already exists value. */ @@ -452,9 +465,18 @@ public: //! Query a value in a subtree. /*! \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. + \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. \return Pointer to the value if it can be resolved. Otherwise null. + + \note + There are only 3 situations when a value cannot be resolved: + 1. A value in the path is not an array nor object. + 2. An object value does not contain the token. + 3. A token is out of range of an array value. + + Use unresolvedTokenIndex to retrieve the token index. */ - ValueType* Get(ValueType& root) const { + ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const { RAPIDJSON_ASSERT(IsValid()); ValueType* v = &root; for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { @@ -463,18 +485,23 @@ public: { typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); if (m == v->MemberEnd()) - return 0; + break; v = &m->value; } - break; + continue; case kArrayType: if (t->index == kPointerInvalidIndex || t->index >= v->Size()) - return 0; + break; v = &((*v)[t->index]); - break; + continue; default: - return 0; + break; } + + // Error: unresolved token + if (unresolvedTokenIndex) + *unresolvedTokenIndex = static_cast(t - tokens_); + return 0; } return v; } @@ -484,7 +511,9 @@ public: \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \return Pointer to the value if it can be resolved. Otherwise null. */ - const ValueType* Get(const ValueType& root) const { return Get(const_cast(root)); } + const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const { + return Get(const_cast(root), unresolvedTokenIndex); + } //@} @@ -525,7 +554,7 @@ public: //! Query a value in a subtree with default primitive value. /*! - \tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) @@ -555,7 +584,7 @@ public: //! Query a value in a document with default primitive value. /*! - \tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) @@ -601,7 +630,7 @@ public: //! Set a primitive value in a subtree. /*! - \tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) @@ -637,7 +666,7 @@ public: //! Set a primitive value in a document. /*! - \tparam T \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool + \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) @@ -729,7 +758,7 @@ private: */ Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) { if (!allocator_) // allocator is independently owned. - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) @@ -738,8 +767,12 @@ private: tokenCount_ = rhs.tokenCount_ + extraToken; tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); - std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); - std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); + if (rhs.tokenCount_ > 0) { + std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); + } + if (nameBufferSize > 0) { + std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); + } // Adjust pointers to name buffer std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; @@ -759,11 +792,13 @@ private: } //! Parse a JSON String or its URI fragment representation into tokens. +#ifndef __clang__ // -Wdocumentation /*! \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated. \param length Length of the source string. \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped. */ +#endif void Parse(const Ch* source, size_t length) { RAPIDJSON_ASSERT(source != NULL); RAPIDJSON_ASSERT(nameBuffer_ == 0); @@ -771,7 +806,7 @@ private: // Create own allocator if user did not supply. if (!allocator_) - ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator()); + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); // Count number of '/' as tokenCount tokenCount_ = 0; @@ -857,7 +892,7 @@ private: *name++ = c; } - token->length = name - token->name; + token->length = static_cast(name - token->name); if (token->length == 0) isNumber = false; *name++ = '\0'; // Null terminator @@ -944,6 +979,8 @@ private: */ class PercentDecodeStream { public: + typedef typename ValueType::Ch Ch; + //! Constructor /*! \param source Start of the stream @@ -959,11 +996,11 @@ private: src_++; Ch c = 0; for (int j = 0; j < 2; j++) { - c <<= 4; + c = static_cast(c << 4); Ch h = *src_; - if (h >= '0' && h <= '9') c += h - '0'; - else if (h >= 'A' && h <= 'F') c += h - 'A' + 10; - else if (h >= 'a' && h <= 'f') c += h - 'a' + 10; + if (h >= '0' && h <= '9') c = static_cast(c + h - '0'); + else if (h >= 'A' && h <= 'F') c = static_cast(c + h - 'A' + 10); + else if (h >= 'a' && h <= 'f') c = static_cast(c + h - 'a' + 10); else { valid_ = false; return 0; @@ -973,7 +1010,7 @@ private: return c; } - size_t Tell() const { return src_ - head_; } + size_t Tell() const { return static_cast(src_ - head_); } bool IsValid() const { return valid_; } private: @@ -992,8 +1029,8 @@ private: unsigned char u = static_cast(c); static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; os_.Put('%'); - os_.Put(hexDigits[u >> 4]); - os_.Put(hexDigits[u & 15]); + os_.Put(static_cast(hexDigits[u >> 4])); + os_.Put(static_cast(hexDigits[u & 15])); } private: OutputStream& os_; @@ -1041,23 +1078,23 @@ typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, c ////////////////////////////////////////////////////////////////////////////// template -typename T::ValueType* GetValueByPointer(T& root, const GenericPointer& pointer) { - return pointer.Get(root); +typename T::ValueType* GetValueByPointer(T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { + return pointer.Get(root, unresolvedTokenIndex); } template -const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer& pointer) { - return pointer.Get(root); +const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { + return pointer.Get(root, unresolvedTokenIndex); } template -typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N]) { - return GenericPointer(source, N - 1).Get(root); +typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) { + return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); } template -const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N]) { - return GenericPointer(source, N - 1).Get(root); +const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) { + return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); } ////////////////////////////////////////////////////////////////////////////// @@ -1310,4 +1347,12 @@ bool EraseValueByPointer(T& root, const CharType(&source)[N]) { RAPIDJSON_NAMESPACE_END +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_POINTER_H_ diff --git a/contrib/rapidjson/include/rapidjson/prettywriter.h b/contrib/rapidjson/include/rapidjson/prettywriter.h index 416dd492e..98dfb3060 100644 --- a/contrib/rapidjson/include/rapidjson/prettywriter.h +++ b/contrib/rapidjson/include/rapidjson/prettywriter.h @@ -22,8 +22,21 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + RAPIDJSON_NAMESPACE_BEGIN +//! Combination of PrettyWriter format flags. +/*! \see PrettyWriter::SetFormatOptions + */ +enum PrettyFormatOptions { + kFormatDefault = 0, //!< Default pretty formatting. + kFormatSingleLineArray = 1 //!< Format arrays on a single line. +}; + //! Writer with indentation and spacing. /*! \tparam OutputStream Type of ouptut os. @@ -31,10 +44,10 @@ RAPIDJSON_NAMESPACE_BEGIN \tparam TargetEncoding Encoding of output stream. \tparam StackAllocator Type of allocator for allocating memory of stack. */ -template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator> -class PrettyWriter : public Writer { +template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> +class PrettyWriter : public Writer { public: - typedef Writer Base; + typedef Writer Base; typedef typename Base::Ch Ch; //! Constructor @@ -42,8 +55,17 @@ public: \param allocator User supplied allocator. If it is null, it will create a private one. \param levelDepth Initial capacity of stack. */ - PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : - Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} + explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} + + + explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : + Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + PrettyWriter(PrettyWriter&& rhs) : + Base(std::forward(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {} +#endif //! Set custom indentation. /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). @@ -57,6 +79,14 @@ public: return *this; } + //! Set pretty writer formatting options. + /*! \param options Formatting options. + */ + PrettyWriter& SetFormatOptions(PrettyFormatOptions options) { + formatOptions_ = options; + return *this; + } + /*! @name Implementation of Handler \see Handler */ @@ -70,7 +100,15 @@ public: bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); } bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } + bool RawNumber(const Ch* str, SizeType length, bool copy = false) { + RAPIDJSON_ASSERT(str != 0); + (void)copy; + PrettyPrefix(kNumberType); + return Base::WriteString(str, length); + } + bool String(const Ch* str, SizeType length, bool copy = false) { + RAPIDJSON_ASSERT(str != 0); (void)copy; PrettyPrefix(kStringType); return Base::WriteString(str, length); @@ -89,11 +127,19 @@ public: } bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } + +#if RAPIDJSON_HAS_STDSTRING + bool Key(const std::basic_string& str) { + return Key(str.data(), SizeType(str.size())); + } +#endif bool EndObject(SizeType memberCount = 0) { (void)memberCount; - RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); - RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); + RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object + RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); // currently inside an Array, not Object + RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value + bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; if (!empty) { @@ -104,7 +150,7 @@ public: (void)ret; RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text - Base::os_->Flush(); + Base::Flush(); return true; } @@ -120,7 +166,7 @@ public: RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; - if (!empty) { + if (!empty && !(formatOptions_ & kFormatSingleLineArray)) { Base::os_->Put('\n'); WriteIndent(); } @@ -128,7 +174,7 @@ public: (void)ret; RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text - Base::os_->Flush(); + Base::Flush(); return true; } @@ -142,6 +188,22 @@ public: bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } //@} + + //! Write a raw JSON value. + /*! + For user to write a stringified JSON as a value. + + \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. + \param length Length of the json. + \param type Type of the root of json. + \note When using PrettyWriter::RawValue(), the result json may not be indented correctly. + */ + bool RawValue(const Ch* json, size_t length, Type type) { + RAPIDJSON_ASSERT(json != 0); + PrettyPrefix(type); + return Base::WriteRawValue(json, length); + } + protected: void PrettyPrefix(Type type) { (void)type; @@ -151,11 +213,14 @@ protected: if (level->inArray) { if (level->valueCount > 0) { Base::os_->Put(','); // add comma if it is not the first element in array - Base::os_->Put('\n'); + if (formatOptions_ & kFormatSingleLineArray) + Base::os_->Put(' '); } - else + + if (!(formatOptions_ & kFormatSingleLineArray)) { Base::os_->Put('\n'); - WriteIndent(); + WriteIndent(); + } } else { // in object if (level->valueCount > 0) { @@ -186,11 +251,12 @@ protected: void WriteIndent() { size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; - PutN(*Base::os_, indentChar_, count); + PutN(*Base::os_, static_cast(indentChar_), count); } Ch indentChar_; unsigned indentCharCount_; + PrettyFormatOptions formatOptions_; private: // Prohibit copy constructor & assignment operator. @@ -200,6 +266,10 @@ private: RAPIDJSON_NAMESPACE_END +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif diff --git a/contrib/rapidjson/include/rapidjson/rapidjson.h b/contrib/rapidjson/include/rapidjson/rapidjson.h index f22130d3c..5716fdc06 100644 --- a/contrib/rapidjson/include/rapidjson/rapidjson.h +++ b/contrib/rapidjson/include/rapidjson/rapidjson.h @@ -49,6 +49,11 @@ // token stringification #define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) #define RAPIDJSON_DO_STRINGIFY(x) #x + +// token concatenation +#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) +#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) +#define RAPIDJSON_DO_JOIN2(X, Y) X##Y //!@endcond /*! \def RAPIDJSON_MAJOR_VERSION @@ -68,8 +73,8 @@ \brief Version of RapidJSON in ".." string format. */ #define RAPIDJSON_MAJOR_VERSION 1 -#define RAPIDJSON_MINOR_VERSION 0 -#define RAPIDJSON_PATCH_VERSION 2 +#define RAPIDJSON_MINOR_VERSION 1 +#define RAPIDJSON_PATCH_VERSION 0 #define RAPIDJSON_VERSION_STRING \ RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) @@ -119,6 +124,31 @@ #define RAPIDJSON_NAMESPACE_END } #endif +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_HAS_STDSTRING + +#ifndef RAPIDJSON_HAS_STDSTRING +#ifdef RAPIDJSON_DOXYGEN_RUNNING +#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation +#else +#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default +#endif +/*! \def RAPIDJSON_HAS_STDSTRING + \ingroup RAPIDJSON_CONFIG + \brief Enable RapidJSON support for \c std::string + + By defining this preprocessor symbol to \c 1, several convenience functions for using + \ref rapidjson::GenericValue with \c std::string are enabled, especially + for construction and comparison. + + \hideinitializer +*/ +#endif // !defined(RAPIDJSON_HAS_STDSTRING) + +#if RAPIDJSON_HAS_STDSTRING +#include +#endif // RAPIDJSON_HAS_STDSTRING + /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NO_INT64DEFINE @@ -134,7 +164,7 @@ */ #ifndef RAPIDJSON_NO_INT64DEFINE //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#ifdef _MSC_VER +#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 #include "msinttypes/stdint.h" #include "msinttypes/inttypes.h" #else @@ -153,9 +183,9 @@ #ifndef RAPIDJSON_FORCEINLINE //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN -#if defined(_MSC_VER) && !defined(NDEBUG) +#if defined(_MSC_VER) && defined(NDEBUG) #define RAPIDJSON_FORCEINLINE __forceinline -#elif defined(__GNUC__) && __GNUC__ >= 4 && !defined(NDEBUG) +#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG) #define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) #else #define RAPIDJSON_FORCEINLINE @@ -211,6 +241,8 @@ # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN +# elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) +# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(RAPIDJSON_DOXYGEN_RUNNING) # define RAPIDJSON_ENDIAN # else @@ -223,7 +255,7 @@ //! Whether using 64-bit architecture #ifndef RAPIDJSON_64BIT -#if defined(__LP64__) || defined(_WIN64) +#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__) #define RAPIDJSON_64BIT 1 #else #define RAPIDJSON_64BIT 0 @@ -238,13 +270,14 @@ \param x pointer to align Some machines require strict data alignment. Currently the default uses 4 bytes - alignment. User can customize by defining the RAPIDJSON_ALIGN function macro., + alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms. + User can customize by defining the RAPIDJSON_ALIGN function macro. */ #ifndef RAPIDJSON_ALIGN #if RAPIDJSON_64BIT == 1 -#define RAPIDJSON_ALIGN(x) ((x + 7u) & ~7u) +#define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) #else -#define RAPIDJSON_ALIGN(x) ((x + 3u) & ~3u) +#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u) #endif #endif @@ -262,17 +295,47 @@ #endif /////////////////////////////////////////////////////////////////////////////// -// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD +// RAPIDJSON_48BITPOINTER_OPTIMIZATION + +//! Use only lower 48-bit address for some pointers. +/*! + \ingroup RAPIDJSON_CONFIG + + This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address. + The higher 16-bit can be used for storing other data. + \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture. +*/ +#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION +#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1 +#else +#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 +#endif +#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION + +#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1 +#if RAPIDJSON_64BIT != 1 +#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1 +#endif +#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast((reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast(reinterpret_cast(x)))) +#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast(reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF)))) +#else +#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x)) +#define RAPIDJSON_GETPOINTER(type, p) (p) +#endif + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD /*! \def RAPIDJSON_SIMD \ingroup RAPIDJSON_CONFIG - \brief Enable SSE2/SSE4.2 optimization. + \brief Enable SSE2/SSE4.2/Neon optimization. RapidJSON supports optimized implementations for some parsing operations - based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible - processors. + based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel + or ARM compatible processors. - To enable these optimizations, two different symbols can be defined; + To enable these optimizations, three different symbols can be defined; \code // Enable SSE2 optimization. #define RAPIDJSON_SSE2 @@ -281,13 +344,17 @@ #define RAPIDJSON_SSE42 \endcode - \c RAPIDJSON_SSE42 takes precedence, if both are defined. + // Enable ARM Neon optimization. + #define RAPIDJSON_NEON + \endcode + + \c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined. If any of these symbols is defined, RapidJSON defines the macro \c RAPIDJSON_SIMD to indicate the availability of the optimized code. */ #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ - || defined(RAPIDJSON_DOXYGEN_RUNNING) + || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING) #define RAPIDJSON_SIMD #endif @@ -347,25 +414,33 @@ RAPIDJSON_NAMESPACE_END /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_STATIC_ASSERT -// Adopt from boost +// Prefer C++11 static_assert, if available #ifndef RAPIDJSON_STATIC_ASSERT +#if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 ) +#define RAPIDJSON_STATIC_ASSERT(x) \ + static_assert(x, RAPIDJSON_STRINGIFY(x)) +#endif // C++11 +#endif // RAPIDJSON_STATIC_ASSERT + +// Adopt C++03 implementation from boost +#ifndef RAPIDJSON_STATIC_ASSERT +#ifndef __clang__ //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN +#endif RAPIDJSON_NAMESPACE_BEGIN template struct STATIC_ASSERTION_FAILURE; template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; -template struct StaticAssertTest {}; +template struct StaticAssertTest {}; RAPIDJSON_NAMESPACE_END -#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) -#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) -#define RAPIDJSON_DO_JOIN2(X, Y) X##Y - #if defined(__GNUC__) #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) #else #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE #endif +#ifndef __clang__ //!@endcond +#endif /*! \def RAPIDJSON_STATIC_ASSERT \brief (Internal) macro to check for conditions at compile-time @@ -376,6 +451,35 @@ RAPIDJSON_NAMESPACE_END typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \ RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE +#endif // RAPIDJSON_STATIC_ASSERT + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY + +//! Compiler branching hint for expression with high probability to be true. +/*! + \ingroup RAPIDJSON_CONFIG + \param x Boolean expression likely to be true. +*/ +#ifndef RAPIDJSON_LIKELY +#if defined(__GNUC__) || defined(__clang__) +#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1) +#else +#define RAPIDJSON_LIKELY(x) (x) +#endif +#endif + +//! Compiler branching hint for expression with low probability to be true. +/*! + \ingroup RAPIDJSON_CONFIG + \param x Boolean expression unlikely to be true. +*/ +#ifndef RAPIDJSON_UNLIKELY +#if defined(__GNUC__) || defined(__clang__) +#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define RAPIDJSON_UNLIKELY(x) (x) +#endif #endif /////////////////////////////////////////////////////////////////////////////// @@ -438,8 +542,12 @@ RAPIDJSON_NAMESPACE_END #ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS #if defined(__clang__) -#define RAPIDJSON_HAS_CXX11_RVALUE_REFS __has_feature(cxx_rvalue_references) && \ +#if __has_feature(cxx_rvalue_references) && \ (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 +#else +#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 +#endif #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ (defined(_MSC_VER) && _MSC_VER >= 1600) @@ -470,6 +578,17 @@ RAPIDJSON_NAMESPACE_END #define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 #endif +#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR +#if defined(__clang__) +#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) +#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ + (defined(_MSC_VER) && _MSC_VER >= 1700) +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 +#else +#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 +#endif +#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR + //!@endcond /////////////////////////////////////////////////////////////////////////////// @@ -477,7 +596,7 @@ RAPIDJSON_NAMESPACE_END #ifndef RAPIDJSON_NEW ///! customization point for global \c new -#define RAPIDJSON_NEW(x) new x +#define RAPIDJSON_NEW(TypeName) new TypeName #endif #ifndef RAPIDJSON_DELETE ///! customization point for global \c delete @@ -485,10 +604,7 @@ RAPIDJSON_NAMESPACE_END #endif /////////////////////////////////////////////////////////////////////////////// -// Allocators and Encodings - -#include "allocators.h" -#include "encodings.h" +// Type /*! \namespace rapidjson \brief main RapidJSON namespace @@ -496,148 +612,6 @@ RAPIDJSON_NAMESPACE_END */ RAPIDJSON_NAMESPACE_BEGIN -/////////////////////////////////////////////////////////////////////////////// -// Stream - -/*! \class rapidjson::Stream - \brief Concept for reading and writing characters. - - For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). - - For write-only stream, only need to implement Put() and Flush(). - -\code -concept Stream { - typename Ch; //!< Character type of the stream. - - //! Read the current character from stream without moving the read cursor. - Ch Peek() const; - - //! Read the current character from stream and moving the read cursor to next character. - Ch Take(); - - //! Get the current read cursor. - //! \return Number of characters read from start. - size_t Tell(); - - //! Begin writing operation at the current read pointer. - //! \return The begin writer pointer. - Ch* PutBegin(); - - //! Write a character. - void Put(Ch c); - - //! Flush the buffer. - void Flush(); - - //! End the writing operation. - //! \param begin The begin write pointer returned by PutBegin(). - //! \return Number of characters written. - size_t PutEnd(Ch* begin); -} -\endcode -*/ - -//! Provides additional information for stream. -/*! - By using traits pattern, this type provides a default configuration for stream. - For custom stream, this type can be specialized for other configuration. - See TEST(Reader, CustomStringStream) in readertest.cpp for example. -*/ -template -struct StreamTraits { - //! Whether to make local copy of stream for optimization during parsing. - /*! - By default, for safety, streams do not use local copy optimization. - Stream that can be copied fast should specialize this, like StreamTraits. - */ - enum { copyOptimization = 0 }; -}; - -//! Put N copies of a character to a stream. -template -inline void PutN(Stream& stream, Ch c, size_t n) { - for (size_t i = 0; i < n; i++) - stream.Put(c); -} - -/////////////////////////////////////////////////////////////////////////////// -// StringStream - -//! Read-only string stream. -/*! \note implements Stream concept -*/ -template -struct GenericStringStream { - typedef typename Encoding::Ch Ch; - - GenericStringStream(const Ch *src) : src_(src), head_(src) {} - - Ch Peek() const { return *src_; } - Ch Take() { return *src_++; } - size_t Tell() const { return static_cast(src_ - head_); } - - Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } - void Put(Ch) { RAPIDJSON_ASSERT(false); } - void Flush() { RAPIDJSON_ASSERT(false); } - size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } - - const Ch* src_; //!< Current read position. - const Ch* head_; //!< Original head of the string. -}; - -template -struct StreamTraits > { - enum { copyOptimization = 1 }; -}; - -//! String stream with UTF8 encoding. -typedef GenericStringStream > StringStream; - -/////////////////////////////////////////////////////////////////////////////// -// InsituStringStream - -//! A read-write string stream. -/*! This string stream is particularly designed for in-situ parsing. - \note implements Stream concept -*/ -template -struct GenericInsituStringStream { - typedef typename Encoding::Ch Ch; - - GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} - - // Read - Ch Peek() { return *src_; } - Ch Take() { return *src_++; } - size_t Tell() { return static_cast(src_ - head_); } - - // Write - void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } - - Ch* PutBegin() { return dst_ = src_; } - size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } - void Flush() {} - - Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } - void Pop(size_t count) { dst_ -= count; } - - Ch* src_; - Ch* dst_; - Ch* head_; -}; - -template -struct StreamTraits > { - enum { copyOptimization = 1 }; -}; - -//! Insitu string stream with UTF8 encoding. -typedef GenericInsituStringStream > InsituStringStream; - -/////////////////////////////////////////////////////////////////////////////// -// Type - //! Type of JSON value enum Type { kNullType = 0, //!< null diff --git a/contrib/rapidjson/include/rapidjson/reader.h b/contrib/rapidjson/include/rapidjson/reader.h index c5ecf4be5..120c31115 100644 --- a/contrib/rapidjson/include/rapidjson/reader.h +++ b/contrib/rapidjson/include/rapidjson/reader.h @@ -1,5 +1,5 @@ // Tencent is pleased to support the open source community by making RapidJSON available. -// +// // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except @@ -7,9 +7,9 @@ // // http://opensource.org/licenses/MIT // -// Unless required by applicable law or agreed to in writing, software distributed -// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR -// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the // specific language governing permissions and limitations under the License. #ifndef RAPIDJSON_READER_H_ @@ -17,11 +17,13 @@ /*! \file reader.h */ -#include "rapidjson.h" -#include "encodings.h" +#include "allocators.h" +#include "stream.h" +#include "encodedstream.h" #include "internal/meta.h" #include "internal/stack.h" #include "internal/strtod.h" +#include #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) #include @@ -31,6 +33,8 @@ #include #elif defined(RAPIDJSON_SSE2) #include +#elif defined(RAPIDJSON_NEON) +#include #endif #ifdef _MSC_VER @@ -39,6 +43,13 @@ RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4702) // unreachable code #endif +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(old-style-cast) +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(switch-enum) +#endif + #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) @@ -49,7 +60,7 @@ RAPIDJSON_DIAG_OFF(effc++) #ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN #define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ - if (HasParseError()) { return value; } \ + if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \ RAPIDJSON_MULTILINEMACRO_END #endif #define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ @@ -120,7 +131,7 @@ RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // ParseFlag -/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS +/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS \ingroup RAPIDJSON_CONFIG \brief User-defined kParseDefaultFlags definition. @@ -140,6 +151,10 @@ enum ParseFlag { kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower). + kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments. + kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings. + kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays. + kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles. kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS }; @@ -148,7 +163,7 @@ enum ParseFlag { /*! \class rapidjson::Handler \brief Concept for receiving events from GenericReader upon parsing. - The functions return true if no error occurs. If they return false, + The functions return true if no error occurs. If they return false, the event publisher should terminate the process. \code concept Handler { @@ -161,6 +176,8 @@ concept Handler { bool Int64(int64_t i); bool Uint64(uint64_t i); bool Double(double d); + /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) + bool RawNumber(const Ch* str, SizeType length, bool copy); bool String(const Ch* str, SizeType length, bool copy); bool StartObject(); bool Key(const Ch* str, SizeType length, bool copy); @@ -191,6 +208,8 @@ struct BaseReaderHandler { bool Int64(int64_t) { return static_cast(*this).Default(); } bool Uint64(uint64_t) { return static_cast(*this).Default(); } bool Double(double) { return static_cast(*this).Default(); } + /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) + bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } bool String(const Ch*, SizeType, bool) { return static_cast(*this).Default(); } bool StartObject() { return static_cast(*this).Default(); } bool Key(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } @@ -248,10 +267,17 @@ void SkipWhitespace(InputStream& is) { internal::StreamLocalCopy copy(is); InputStream& s(copy.s); - while (s.Peek() == ' ' || s.Peek() == '\n' || s.Peek() == '\r' || s.Peek() == '\t') + typename InputStream::Ch c; + while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t') s.Take(); } +inline const char* SkipWhitespace(const char* p, const char* end) { + while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + return p; +} + #ifdef RAPIDJSON_SSE42 //! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { @@ -262,7 +288,7 @@ inline const char *SkipWhitespace_SIMD(const char* p) { return p; // 16-byte align to the next boundary - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & ~15); + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; @@ -271,23 +297,37 @@ inline const char *SkipWhitespace_SIMD(const char* p) { // The rest of string using SIMD static const char whitespace[16] = " \n\r\t"; - const __m128i w = _mm_load_si128((const __m128i *)&whitespace[0]); + const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); for (;; p += 16) { - const __m128i s = _mm_load_si128((const __m128i *)p); - const unsigned r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY)); - if (r != 0) { // some of characters is non-whitespace -#ifdef _MSC_VER // Find the index of first non-whitespace - unsigned long offset; - _BitScanForward(&offset, r); - return p + offset; -#else - return p + __builtin_ffs(r) - 1; -#endif - } + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); + if (r != 16) // some of characters is non-whitespace + return p + r; } } +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + // The middle of string using SIMD + static const char whitespace[16] = " \n\r\t"; + const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); + + for (; p <= end - 16; p += 16) { + const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); + const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); + if (r != 16) // some of characters is non-whitespace + return p + r; + } + + return SkipWhitespace(p, end); +} + #elif defined(RAPIDJSON_SSE2) //! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. @@ -299,7 +339,7 @@ inline const char *SkipWhitespace_SIMD(const char* p) { return p; // 16-byte align to the next boundary - const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & ~15); + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; @@ -307,24 +347,22 @@ inline const char *SkipWhitespace_SIMD(const char* p) { return p; // The rest of string - static const char whitespaces[4][17] = { - " ", - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", - "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r", - "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"}; + #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } + static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; + #undef C16 - const __m128i w0 = _mm_loadu_si128((const __m128i *)&whitespaces[0][0]); - const __m128i w1 = _mm_loadu_si128((const __m128i *)&whitespaces[1][0]); - const __m128i w2 = _mm_loadu_si128((const __m128i *)&whitespaces[2][0]); - const __m128i w3 = _mm_loadu_si128((const __m128i *)&whitespaces[3][0]); + const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); + const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); + const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); + const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); for (;; p += 16) { - const __m128i s = _mm_load_si128((const __m128i *)p); + const __m128i s = _mm_load_si128(reinterpret_cast(p)); __m128i x = _mm_cmpeq_epi8(s, w0); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); - unsigned short r = (unsigned short)~_mm_movemask_epi8(x); + unsigned short r = static_cast(~_mm_movemask_epi8(x)); if (r != 0) { // some of characters may be non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace unsigned long offset; @@ -337,11 +375,134 @@ inline const char *SkipWhitespace_SIMD(const char* p) { } } -#endif // RAPIDJSON_SSE2 +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + // The rest of string + #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } + static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; + #undef C16 + + const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); + const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); + const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); + const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); + + for (; p <= end - 16; p += 16) { + const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); + __m128i x = _mm_cmpeq_epi8(s, w0); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); + x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); + unsigned short r = static_cast(~_mm_movemask_epi8(x)); + if (r != 0) { // some of characters may be non-whitespace +#ifdef _MSC_VER // Find the index of first non-whitespace + unsigned long offset; + _BitScanForward(&offset, r); + return p + offset; +#else + return p + __builtin_ffs(r) - 1; +#endif + } + } + + return SkipWhitespace(p, end); +} + +#elif defined(RAPIDJSON_NEON) + +//! Skip whitespace with ARM Neon instructions, testing 16 8-byte characters at once. +inline const char *SkipWhitespace_SIMD(const char* p) { + // Fast return for single non-whitespace + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + // 16-byte align to the next boundary + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') + ++p; + else + return p; + + const uint8x16_t w0 = vmovq_n_u8(' '); + const uint8x16_t w1 = vmovq_n_u8('\n'); + const uint8x16_t w2 = vmovq_n_u8('\r'); + const uint8x16_t w3 = vmovq_n_u8('\t'); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, w0); + x = vorrq_u8(x, vceqq_u8(s, w1)); + x = vorrq_u8(x, vceqq_u8(s, w2)); + x = vorrq_u8(x, vceqq_u8(s, w3)); + + x = vmvnq_u8(x); // Negate + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + if (low == 0) { + if (high != 0) { + int lz =__builtin_clzll(high);; + return p + 8 + (lz >> 3); + } + } else { + int lz = __builtin_clzll(low);; + return p + (lz >> 3); + } + } +} + +inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { + // Fast return for single non-whitespace + if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) + ++p; + else + return p; + + const uint8x16_t w0 = vmovq_n_u8(' '); + const uint8x16_t w1 = vmovq_n_u8('\n'); + const uint8x16_t w2 = vmovq_n_u8('\r'); + const uint8x16_t w3 = vmovq_n_u8('\t'); + + for (; p <= end - 16; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, w0); + x = vorrq_u8(x, vceqq_u8(s, w1)); + x = vorrq_u8(x, vceqq_u8(s, w2)); + x = vorrq_u8(x, vceqq_u8(s, w3)); + + x = vmvnq_u8(x); // Negate + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + if (low == 0) { + if (high != 0) { + int lz = __builtin_clzll(high); + return p + 8 + (lz >> 3); + } + } else { + int lz = __builtin_clzll(low); + return p + (lz >> 3); + } + } + + return SkipWhitespace(p, end); +} + +#endif // RAPIDJSON_NEON #ifdef RAPIDJSON_SIMD //! Template function specialization for InsituStringStream -template<> inline void SkipWhitespace(InsituStringStream& is) { +template<> inline void SkipWhitespace(InsituStringStream& is) { is.src_ = const_cast(SkipWhitespace_SIMD(is.src_)); } @@ -349,23 +510,27 @@ template<> inline void SkipWhitespace(InsituStringStream& is) { template<> inline void SkipWhitespace(StringStream& is) { is.src_ = SkipWhitespace_SIMD(is.src_); } + +template<> inline void SkipWhitespace(EncodedInputStream, MemoryStream>& is) { + is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_); +} #endif // RAPIDJSON_SIMD /////////////////////////////////////////////////////////////////////////////// // GenericReader //! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator. -/*! GenericReader parses JSON text from a stream, and send events synchronously to an +/*! GenericReader parses JSON text from a stream, and send events synchronously to an object implementing Handler concept. - It needs to allocate a stack for storing a single decoded string during + It needs to allocate a stack for storing a single decoded string during non-destructive parsing. - For in-situ parsing, the decoded string is directly written to the source + For in-situ parsing, the decoded string is directly written to the source text string, no temporary buffer is required. A GenericReader object can be reused for parsing multiple JSON text. - + \tparam SourceEncoding Encoding of the input stream. \tparam TargetEncoding Encoding of the parse output. \tparam StackAllocator Allocator type for stack. @@ -398,9 +563,10 @@ public: ClearStackOnExit scope(*this); - SkipWhitespace(is); + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - if (is.Peek() == '\0') { + if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } @@ -409,9 +575,10 @@ public: RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); if (!(parseFlags & kParseStopWhenDoneFlag)) { - SkipWhitespace(is); + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); - if (is.Peek() != '\0') { + if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } @@ -433,9 +600,86 @@ public: return Parse(is, handler); } + //! Initialize JSON text token-by-token parsing + /*! + */ + void IterativeParseInit() { + parseResult_.Clear(); + state_ = IterativeParsingStartState; + } + + //! Parse one token from JSON text + /*! \tparam InputStream Type of input stream, implementing Stream concept + \tparam Handler Type of handler, implementing Handler concept. + \param is Input stream to be parsed. + \param handler The handler to receive events. + \return Whether the parsing is successful. + */ + template + bool IterativeParseNext(InputStream& is, Handler& handler) { + while (RAPIDJSON_LIKELY(is.Peek() != '\0')) { + SkipWhitespaceAndComments(is); + + Token t = Tokenize(is.Peek()); + IterativeParsingState n = Predict(state_, t); + IterativeParsingState d = Transit(state_, t, n, is, handler); + + // If we've finished or hit an error... + if (RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) { + // Report errors. + if (d == IterativeParsingErrorState) { + HandleError(state_, is); + return false; + } + + // Transition to the finish state. + RAPIDJSON_ASSERT(d == IterativeParsingFinishState); + state_ = d; + + // If StopWhenDone is not set... + if (!(parseFlags & kParseStopWhenDoneFlag)) { + // ... and extra non-whitespace data is found... + SkipWhitespaceAndComments(is); + if (is.Peek() != '\0') { + // ... this is considered an error. + HandleError(state_, is); + return false; + } + } + + // Success! We are done! + return true; + } + + // Transition to the new state. + state_ = d; + + // If we parsed anything other than a delimiter, we invoked the handler, so we can return true now. + if (!IsIterativeParsingDelimiterState(n)) + return true; + } + + // We reached the end of file. + stack_.Clear(); + + if (state_ != IterativeParsingFinishState) { + HandleError(state_, is); + return false; + } + + return true; + } + + //! Check if token-by-token parsing JSON text is complete + /*! \return Whether the JSON has been fully decoded. + */ + RAPIDJSON_FORCEINLINE bool IterativeParseComplete() { + return IsIterativeParsingCompleteState(state_); + } + //! Whether a parse error has occured in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } - + //! Get the \ref ParseErrorCode of last parsing. ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } @@ -462,52 +706,98 @@ private: ClearStackOnExit& operator=(const ClearStackOnExit&); }; + template + void SkipWhitespaceAndComments(InputStream& is) { + SkipWhitespace(is); + + if (parseFlags & kParseCommentsFlag) { + while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) { + if (Consume(is, '*')) { + while (true) { + if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + else if (Consume(is, '*')) { + if (Consume(is, '/')) + break; + } + else + is.Take(); + } + } + else if (RAPIDJSON_LIKELY(Consume(is, '/'))) + while (is.Peek() != '\0' && is.Take() != '\n') {} + else + RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); + + SkipWhitespace(is); + } + } + } + // Parse object: { string : value, ... } template void ParseObject(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == '{'); is.Take(); // Skip '{' - - if (!handler.StartObject()) + + if (RAPIDJSON_UNLIKELY(!handler.StartObject())) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - SkipWhitespace(is); + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (is.Peek() == '}') { - is.Take(); - if (!handler.EndObject(0)) // empty object + if (Consume(is, '}')) { + if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } for (SizeType memberCount = 0;;) { - if (is.Peek() != '"') + if (RAPIDJSON_UNLIKELY(is.Peek() != '"')) RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); ParseString(is, handler, true); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - SkipWhitespace(is); + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (is.Take() != ':') + if (RAPIDJSON_UNLIKELY(!Consume(is, ':'))) RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); - SkipWhitespace(is); + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ParseValue(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - SkipWhitespace(is); + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ++memberCount; - switch (is.Take()) { - case ',': SkipWhitespace(is); break; - case '}': - if (!handler.EndObject(memberCount)) + switch (is.Peek()) { + case ',': + is.Take(); + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + break; + case '}': + is.Take(); + if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; - default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); + default: + RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy + } + + if (parseFlags & kParseTrailingCommasFlag) { + if (is.Peek() == '}') { + if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + is.Take(); + return; + } } } } @@ -517,15 +807,15 @@ private: void ParseArray(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == '['); is.Take(); // Skip '[' - - if (!handler.StartArray()) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); - - SkipWhitespace(is); - if (is.Peek() == ']') { - is.Take(); - if (!handler.EndArray(0)) // empty array + if (RAPIDJSON_UNLIKELY(!handler.StartArray())) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + + if (Consume(is, ']')) { + if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } @@ -535,15 +825,28 @@ private: RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ++elementCount; - SkipWhitespace(is); + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - switch (is.Take()) { - case ',': SkipWhitespace(is); break; - case ']': - if (!handler.EndArray(elementCount)) + if (Consume(is, ',')) { + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; + } + else if (Consume(is, ']')) { + if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + return; + } + else + RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); + + if (parseFlags & kParseTrailingCommasFlag) { + if (is.Peek() == ']') { + if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); + is.Take(); return; - default: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); + } } } } @@ -553,12 +856,12 @@ private: RAPIDJSON_ASSERT(is.Peek() == 'n'); is.Take(); - if (is.Take() == 'u' && is.Take() == 'l' && is.Take() == 'l') { - if (!handler.Null()) + if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) { + if (RAPIDJSON_UNLIKELY(!handler.Null())) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); } template @@ -566,12 +869,12 @@ private: RAPIDJSON_ASSERT(is.Peek() == 't'); is.Take(); - if (is.Take() == 'r' && is.Take() == 'u' && is.Take() == 'e') { - if (!handler.Bool(true)) + if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) { + if (RAPIDJSON_UNLIKELY(!handler.Bool(true))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); } template @@ -579,20 +882,30 @@ private: RAPIDJSON_ASSERT(is.Peek() == 'f'); is.Take(); - if (is.Take() == 'a' && is.Take() == 'l' && is.Take() == 's' && is.Take() == 'e') { - if (!handler.Bool(false)) + if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) { + if (RAPIDJSON_UNLIKELY(!handler.Bool(false))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else - RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell() - 1); + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); + } + + template + RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) { + if (RAPIDJSON_LIKELY(is.Peek() == expect)) { + is.Take(); + return true; + } + else + return false; } // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). template - unsigned ParseHex4(InputStream& is) { + unsigned ParseHex4(InputStream& is, size_t escapeOffset) { unsigned codepoint = 0; for (int i = 0; i < 4; i++) { - Ch c = is.Take(); + Ch c = is.Peek(); codepoint <<= 4; codepoint += static_cast(c); if (c >= '0' && c <= '9') @@ -602,9 +915,10 @@ private: else if (c >= 'a' && c <= 'f') codepoint -= 'a' - 10; else { - RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, is.Tell() - 1); + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); } + is.Take(); } return codepoint; } @@ -619,7 +933,14 @@ private: *stack_.template Push() = c; ++length_; } + + RAPIDJSON_FORCEINLINE void* Push(SizeType count) { + length_ += count; + return stack_.template Push(count); + } + size_t Length() const { return length_; } + Ch* Pop() { return stack_.template Pop(length_); } @@ -638,6 +959,9 @@ private: internal::StreamLocalCopy copy(is); InputStream& s(copy.s); + RAPIDJSON_ASSERT(s.Peek() == '\"'); + s.Take(); // Skip '\"' + bool success = false; if (parseFlags & kParseInsituFlag) { typename InputStream::Ch *head = s.PutBegin(); @@ -645,7 +969,7 @@ private: RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; size_t length = s.PutEnd(head) - 1; RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); - const typename TargetEncoding::Ch* const str = (typename TargetEncoding::Ch*)head; + const typename TargetEncoding::Ch* const str = reinterpret_cast(head); success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false)); } else { @@ -656,7 +980,7 @@ private: const typename TargetEncoding::Ch* const str = stackStream.Pop(); success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true)); } - if (!success) + if (RAPIDJSON_UNLIKELY(!success)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); } @@ -667,74 +991,421 @@ private: //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 static const char escape[256] = { - Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', - Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, - 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, - 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', + Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, + 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, + 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 }; #undef Z16 //!@endcond - RAPIDJSON_ASSERT(is.Peek() == '\"'); - is.Take(); // Skip '\"' - for (;;) { + // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation. + if (!(parseFlags & kParseValidateEncodingFlag)) + ScanCopyUnescapedString(is, os); + Ch c = is.Peek(); - if (c == '\\') { // Escape + if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape + size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset is.Take(); - Ch e = is.Take(); - if ((sizeof(Ch) == 1 || unsigned(e) < 256) && escape[(unsigned char)e]) { - os.Put(escape[(unsigned char)e]); + Ch e = is.Peek(); + if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast(e)])) { + is.Take(); + os.Put(static_cast(escape[static_cast(e)])); } - else if (e == 'u') { // Unicode - unsigned codepoint = ParseHex4(is); + else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode + is.Take(); + unsigned codepoint = ParseHex4(is, escapeOffset); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (codepoint >= 0xD800 && codepoint <= 0xDBFF) { + if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) { // Handle UTF-16 surrogate pair - if (is.Take() != '\\' || is.Take() != 'u') - RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); - unsigned codepoint2 = ParseHex4(is); + if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u'))) + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); + unsigned codepoint2 = ParseHex4(is, escapeOffset); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; - if (codepoint2 < 0xDC00 || codepoint2 > 0xDFFF) - RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, is.Tell() - 2); + if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) + RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; } TEncoding::Encode(os, codepoint); } else - RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); + RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset); } - else if (c == '"') { // Closing double quote + else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote is.Take(); os.Put('\0'); // null-terminate the string return; } - else if (c == '\0') - RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell() - 1); - else if ((unsigned)c < 0x20) // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF - RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell() - 1); - else { - if (parseFlags & kParseValidateEncodingFlag ? - !Transcoder::Validate(is, os) : - !Transcoder::Transcode(is, os)) + else if (RAPIDJSON_UNLIKELY(static_cast(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF + if (c == '\0') + RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell()); + else RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); } + else { + size_t offset = is.Tell(); + if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? + !Transcoder::Validate(is, os) : + !Transcoder::Transcode(is, os)))) + RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset); + } } } - template + template + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) { + // Do nothing for generic version + } + +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) + // StringStream -> StackStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { + const char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + return; + } + else + os.Put(*p++); + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + SizeType length; + #ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; + #else + length = static_cast(__builtin_ffs(r) - 1); + #endif + if (length != 0) { + char* q = reinterpret_cast(os.Push(length)); + for (size_t i = 0; i < length; i++) + q[i] = p[i]; + + p += length; + } + break; + } + _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s); + } + + is.src_ = p; + } + + // InsituStringStream -> InsituStringStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { + RAPIDJSON_ASSERT(&is == &os); + (void)os; + + if (is.src_ == is.dst_) { + SkipUnescapedString(is); + return; + } + + char* p = is.src_; + char *q = is.dst_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + is.dst_ = q; + return; + } + else + *q++ = *p++; + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16, q += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + size_t length; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; +#else + length = static_cast(__builtin_ffs(r) - 1); +#endif + for (const char* pend = p + length; p != pend; ) + *q++ = *p++; + break; + } + _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s); + } + + is.src_ = p; + is.dst_ = q; + } + + // When read/write pointers are the same for insitu stream, just skip unescaped characters + static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { + RAPIDJSON_ASSERT(is.src_ == is.dst_); + char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + for (; p != nextAligned; p++) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = is.dst_ = p; + return; + } + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (;; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + size_t length; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + length = offset; +#else + length = static_cast(__builtin_ffs(r) - 1); +#endif + p += length; + break; + } + } + + is.src_ = is.dst_ = p; + } +#elif defined(RAPIDJSON_NEON) + // StringStream -> StackStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { + const char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + return; + } + else + os.Put(*p++); + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + SizeType length = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + unsigned lz = (unsigned)__builtin_clzll(high);; + length = 8 + (lz >> 3); + escaped = true; + } + } else { + unsigned lz = (unsigned)__builtin_clzll(low);; + length = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + if (length != 0) { + char* q = reinterpret_cast(os.Push(length)); + for (size_t i = 0; i < length; i++) + q[i] = p[i]; + + p += length; + } + break; + } + vst1q_u8(reinterpret_cast(os.Push(16)), s); + } + + is.src_ = p; + } + + // InsituStringStream -> InsituStringStream + static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { + RAPIDJSON_ASSERT(&is == &os); + (void)os; + + if (is.src_ == is.dst_) { + SkipUnescapedString(is); + return; + } + + char* p = is.src_; + char *q = is.dst_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + while (p != nextAligned) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = p; + is.dst_ = q; + return; + } + else + *q++ = *p++; + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16, q += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + SizeType length = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + unsigned lz = (unsigned)__builtin_clzll(high); + length = 8 + (lz >> 3); + escaped = true; + } + } else { + unsigned lz = (unsigned)__builtin_clzll(low); + length = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + for (const char* pend = p + length; p != pend; ) { + *q++ = *p++; + } + break; + } + vst1q_u8(reinterpret_cast(q), s); + } + + is.src_ = p; + is.dst_ = q; + } + + // When read/write pointers are the same for insitu stream, just skip unescaped characters + static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { + RAPIDJSON_ASSERT(is.src_ == is.dst_); + char* p = is.src_; + + // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + for (; p != nextAligned; p++) + if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { + is.src_ = is.dst_ = p; + return; + } + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (;; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + if (low == 0) { + if (high != 0) { + int lz = __builtin_clzll(high); + p += 8 + (lz >> 3); + break; + } + } else { + int lz = __builtin_clzll(low); + p += lz >> 3; + break; + } + } + + is.src_ = is.dst_ = p; + } +#endif // RAPIDJSON_NEON + + template class NumberStream; template - class NumberStream { + class NumberStream { public: + typedef typename InputStream::Ch Ch; + NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } - ~NumberStream() {} RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } + RAPIDJSON_FORCEINLINE void Push(char) {} + size_t Tell() { return is.Tell(); } size_t Length() { return 0; } const char* Pop() { return 0; } @@ -746,17 +1417,20 @@ private: }; template - class NumberStream : public NumberStream { - typedef NumberStream Base; + class NumberStream : public NumberStream { + typedef NumberStream Base; public: - NumberStream(GenericReader& reader, InputStream& is) : NumberStream(reader, is), stackStream(reader.stack_) {} - ~NumberStream() {} + NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {} RAPIDJSON_FORCEINLINE Ch TakePush() { - stackStream.Put((char)Base::is.Peek()); + stackStream.Put(static_cast(Base::is.Peek())); return Base::is.Take(); } + RAPIDJSON_FORCEINLINE void Push(char c) { + stackStream.Put(c); + } + size_t Length() { return stackStream.Length(); } const char* Pop() { @@ -768,34 +1442,48 @@ private: StackStream stackStream; }; + template + class NumberStream : public NumberStream { + typedef NumberStream Base; + public: + NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {} + + RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } + }; + template void ParseNumber(InputStream& is, Handler& handler) { internal::StreamLocalCopy copy(is); - NumberStream s(*this, copy.s); + NumberStream s(*this, copy.s); + + size_t startOffset = s.Tell(); + double d = 0.0; + bool useNanOrInf = false; // Parse minus - bool minus = false; - if (s.Peek() == '-') { - minus = true; - s.Take(); - } + bool minus = Consume(s, '-'); // Parse int: zero / ( digit1-9 *DIGIT ) unsigned i = 0; uint64_t i64 = 0; bool use64bit = false; int significandDigit = 0; - if (s.Peek() == '0') { + if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) { i = 0; s.TakePush(); } - else if (s.Peek() >= '1' && s.Peek() <= '9') { + else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) { i = static_cast(s.TakePush() - '0'); if (minus) - while (s.Peek() >= '0' && s.Peek() <= '9') { - if (i >= 214748364) { // 2^31 = 2147483648 - if (i != 214748364 || s.Peek() > '8') { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648 + if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) { i64 = i; use64bit = true; break; @@ -805,9 +1493,9 @@ private: significandDigit++; } else - while (s.Peek() >= '0' && s.Peek() <= '9') { - if (i >= 429496729) { // 2^32 - 1 = 4294967295 - if (i != 429496729 || s.Peek() > '5') { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295 + if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) { i64 = i; use64bit = true; break; @@ -817,18 +1505,41 @@ private: significandDigit++; } } + // Parse NaN or Infinity here + else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) { + if (Consume(s, 'N')) { + if (Consume(s, 'a') && Consume(s, 'N')) { + d = std::numeric_limits::quiet_NaN(); + useNanOrInf = true; + } + } + else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) { + if (Consume(s, 'n') && Consume(s, 'f')) { + d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); + useNanOrInf = true; + + if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') + && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) { + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } + } + } + + if (RAPIDJSON_UNLIKELY(!useNanOrInf)) { + RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); + } + } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); // Parse 64bit int bool useDouble = false; - double d = 0.0; if (use64bit) { - if (minus) - while (s.Peek() >= '0' && s.Peek() <= '9') { - if (i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC)) // 2^63 = 9223372036854775808 - if (i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8') { - d = i64; + if (minus) + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808 + if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) { + d = static_cast(i64); useDouble = true; break; } @@ -836,10 +1547,10 @@ private: significandDigit++; } else - while (s.Peek() >= '0' && s.Peek() <= '9') { - if (i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999)) // 2^64 - 1 = 18446744073709551615 - if (i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5') { - d = i64; + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615 + if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) { + d = static_cast(i64); useDouble = true; break; } @@ -850,9 +1561,9 @@ private: // Force double for big integer if (useDouble) { - while (s.Peek() >= '0' && s.Peek() <= '9') { - if (d >= 1.7976931348623157e307) // DBL_MAX / 10.0 - RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0 + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); d = d * 10 + (s.TakePush() - '0'); } } @@ -860,11 +1571,10 @@ private: // Parse frac = decimal-point 1*DIGIT int expFrac = 0; size_t decimalPosition; - if (s.Peek() == '.') { - s.Take(); + if (Consume(s, '.')) { decimalPosition = s.Length(); - if (!(s.Peek() >= '0' && s.Peek() <= '9')) + if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); if (!useDouble) { @@ -872,8 +1582,8 @@ private: // Use i64 to store significand in 64-bit architecture if (!use64bit) i64 = i; - - while (s.Peek() >= '0' && s.Peek() <= '9') { + + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path break; else { @@ -884,19 +1594,19 @@ private: } } - d = (double)i64; + d = static_cast(i64); #else // Use double to store significand in 32-bit architecture - d = use64bit ? (double)i64 : (double)i; + d = static_cast(use64bit ? i64 : i); #endif useDouble = true; } - while (s.Peek() >= '0' && s.Peek() <= '9') { + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (significandDigit < 17) { d = d * 10.0 + (s.TakePush() - '0'); --expFrac; - if (d > 0.0) + if (RAPIDJSON_LIKELY(d > 0.0)) significandDigit++; } else @@ -908,38 +1618,35 @@ private: // Parse exp = e [ minus / plus ] 1*DIGIT int exp = 0; - if (s.Peek() == 'e' || s.Peek() == 'E') { + if (Consume(s, 'e') || Consume(s, 'E')) { if (!useDouble) { - d = use64bit ? i64 : i; + d = static_cast(use64bit ? i64 : i); useDouble = true; } - s.Take(); bool expMinus = false; - if (s.Peek() == '+') - s.Take(); - else if (s.Peek() == '-') { - s.Take(); + if (Consume(s, '+')) + ; + else if (Consume(s, '-')) expMinus = true; - } - if (s.Peek() >= '0' && s.Peek() <= '9') { - exp = s.Take() - '0'; + if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + exp = static_cast(s.Take() - '0'); if (expMinus) { - while (s.Peek() >= '0' && s.Peek() <= '9') { - exp = exp * 10 + (s.Take() - '0'); + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + exp = exp * 10 + static_cast(s.Take() - '0'); if (exp >= 214748364) { // Issue #313: prevent overflow exponent - while (s.Peek() >= '0' && s.Peek() <= '9') // Consume the rest of exponent + while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent s.Take(); } } } else { // positive exp int maxExp = 308 - expFrac; - while (s.Peek() >= '0' && s.Peek() <= '9') { - exp = exp * 10 + (s.Take() - '0'); - if (exp > maxExp) - RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, s.Tell()); + while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { + exp = exp * 10 + static_cast(s.Take() - '0'); + if (RAPIDJSON_UNLIKELY(exp > maxExp)) + RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); } } } @@ -952,34 +1659,63 @@ private: // Finish parsing, call event according to the type of number. bool cont = true; - size_t length = s.Length(); - const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not. - if (useDouble) { - int p = exp + expFrac; - if (parseFlags & kParseFullPrecisionFlag) - d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp); - else - d = internal::StrtodNormalPrecision(d, p); - - cont = handler.Double(minus ? -d : d); - } - else { - if (use64bit) { - if (minus) - cont = handler.Int64(-(int64_t)i64); - else - cont = handler.Uint64(i64); + if (parseFlags & kParseNumbersAsStringsFlag) { + if (parseFlags & kParseInsituFlag) { + s.Pop(); // Pop stack no matter if it will be used or not. + typename InputStream::Ch* head = is.PutBegin(); + const size_t length = s.Tell() - startOffset; + RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); + // unable to insert the \0 character here, it will erase the comma after this number + const typename TargetEncoding::Ch* const str = reinterpret_cast(head); + cont = handler.RawNumber(str, SizeType(length), false); } else { - if (minus) - cont = handler.Int(-(int)i); - else - cont = handler.Uint(i); + SizeType numCharsToCopy = static_cast(s.Length()); + StringStream srcStream(s.Pop()); + StackStream dstStream(stack_); + while (numCharsToCopy--) { + Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); + } + dstStream.Put('\0'); + const typename TargetEncoding::Ch* str = dstStream.Pop(); + const SizeType length = static_cast(dstStream.Length()) - 1; + cont = handler.RawNumber(str, SizeType(length), true); } } - if (!cont) - RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); + else { + size_t length = s.Length(); + const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not. + + if (useDouble) { + int p = exp + expFrac; + if (parseFlags & kParseFullPrecisionFlag) + d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp); + else + d = internal::StrtodNormalPrecision(d, p); + + cont = handler.Double(minus ? -d : d); + } + else if (useNanOrInf) { + cont = handler.Double(d); + } + else { + if (use64bit) { + if (minus) + cont = handler.Int64(static_cast(~i64 + 1)); + else + cont = handler.Uint64(i64); + } + else { + if (minus) + cont = handler.Int(static_cast(~i + 1)); + else + cont = handler.Uint(i); + } + } + } + if (RAPIDJSON_UNLIKELY(!cont)) + RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset); } // Parse any JSON value @@ -992,7 +1728,10 @@ private: case '"': ParseString(is, handler); break; case '{': ParseObject(is, handler); break; case '[': ParseArray (is, handler); break; - default : ParseNumber(is, handler); + default : + ParseNumber(is, handler); + break; + } } @@ -1000,27 +1739,29 @@ private: // States enum IterativeParsingState { - IterativeParsingStartState = 0, - IterativeParsingFinishState, - IterativeParsingErrorState, + IterativeParsingFinishState = 0, // sink states at top + IterativeParsingErrorState, // sink states at top + IterativeParsingStartState, // Object states IterativeParsingObjectInitialState, IterativeParsingMemberKeyState, - IterativeParsingKeyValueDelimiterState, IterativeParsingMemberValueState, - IterativeParsingMemberDelimiterState, IterativeParsingObjectFinishState, // Array states IterativeParsingArrayInitialState, IterativeParsingElementState, - IterativeParsingElementDelimiterState, IterativeParsingArrayFinishState, // Single value state IterativeParsingValueState, - + + // Delimiter states (at bottom) + IterativeParsingElementDelimiterState, + IterativeParsingMemberDelimiterState, + IterativeParsingKeyValueDelimiterState, + cIterativeParsingStateCount }; @@ -1064,9 +1805,9 @@ private: #undef N #undef N16 //!@endcond - - if (sizeof(Ch) == 1 || unsigned(c) < 256) - return (Token)tokenMap[(unsigned char)c]; + + if (sizeof(Ch) == 1 || static_cast(c) < 256) + return static_cast(tokenMap[static_cast(c)]); else return NumberToken; } @@ -1074,6 +1815,18 @@ private: RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { // current state x one lookahead token -> new state static const char G[cIterativeParsingStateCount][kTokenCount] = { + // Finish(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, + // Error(sink state) + { + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, + IterativeParsingErrorState + }, // Start { IterativeParsingArrayInitialState, // Left bracket @@ -1088,18 +1841,6 @@ private: IterativeParsingValueState, // Null IterativeParsingValueState // Number }, - // Finish(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, - // Error(sink state) - { - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, - IterativeParsingErrorState - }, // ObjectInitial { IterativeParsingErrorState, // Left bracket @@ -1128,20 +1869,6 @@ private: IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, - // KeyValueDelimiter - { - IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) - IterativeParsingErrorState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberValueState, // String - IterativeParsingMemberValueState, // False - IterativeParsingMemberValueState, // True - IterativeParsingMemberValueState, // Null - IterativeParsingMemberValueState // Number - }, // MemberValue { IterativeParsingErrorState, // Left bracket @@ -1156,20 +1883,6 @@ private: IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, - // MemberDelimiter - { - IterativeParsingErrorState, // Left bracket - IterativeParsingErrorState, // Right bracket - IterativeParsingErrorState, // Left curly bracket - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingMemberKeyState, // String - IterativeParsingErrorState, // False - IterativeParsingErrorState, // True - IterativeParsingErrorState, // Null - IterativeParsingErrorState // Number - }, // ObjectFinish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, @@ -1204,20 +1917,6 @@ private: IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, - // ElementDelimiter - { - IterativeParsingArrayInitialState, // Left bracket(push Element state) - IterativeParsingErrorState, // Right bracket - IterativeParsingObjectInitialState, // Left curly bracket(push Element state) - IterativeParsingErrorState, // Right curly bracket - IterativeParsingErrorState, // Comma - IterativeParsingErrorState, // Colon - IterativeParsingElementState, // String - IterativeParsingElementState, // False - IterativeParsingElementState, // True - IterativeParsingElementState, // Null - IterativeParsingElementState // Number - }, // ArrayFinish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, @@ -1229,10 +1928,52 @@ private: IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState - } + }, + // ElementDelimiter + { + IterativeParsingArrayInitialState, // Left bracket(push Element state) + IterativeParsingArrayFinishState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push Element state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingElementState, // String + IterativeParsingElementState, // False + IterativeParsingElementState, // True + IterativeParsingElementState, // Null + IterativeParsingElementState // Number + }, + // MemberDelimiter + { + IterativeParsingErrorState, // Left bracket + IterativeParsingErrorState, // Right bracket + IterativeParsingErrorState, // Left curly bracket + IterativeParsingObjectFinishState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberKeyState, // String + IterativeParsingErrorState, // False + IterativeParsingErrorState, // True + IterativeParsingErrorState, // Null + IterativeParsingErrorState // Number + }, + // KeyValueDelimiter + { + IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) + IterativeParsingErrorState, // Right bracket + IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) + IterativeParsingErrorState, // Right curly bracket + IterativeParsingErrorState, // Comma + IterativeParsingErrorState, // Colon + IterativeParsingMemberValueState, // String + IterativeParsingMemberValueState, // False + IterativeParsingMemberValueState, // True + IterativeParsingMemberValueState, // Null + IterativeParsingMemberValueState // Number + }, }; // End of G - return (IterativeParsingState)G[state][token]; + return static_cast(G[state][token]); } // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). @@ -1309,6 +2050,11 @@ private: case IterativeParsingObjectFinishState: { + // Transit from delimiter is only allowed when trailing commas are enabled + if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell()); + return IterativeParsingErrorState; + } // Get member count. SizeType c = *stack_.template Pop(1); // If the object is not empty, count the last member. @@ -1334,6 +2080,11 @@ private: case IterativeParsingArrayFinishState: { + // Transit from delimiter is only allowed when trailing commas are enabled + if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) { + RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell()); + return IterativeParsingErrorState; + } // Get element count. SizeType c = *stack_.template Pop(1); // If the array is not empty, count the last element. @@ -1385,55 +2136,68 @@ private: // Error flag has been set. return; } - + switch (src) { - case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); - case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); + case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; + case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; case IterativeParsingObjectInitialState: - case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); - case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); - case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); - case IterativeParsingElementState: RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); - default: RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); - } + case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return; + case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; + case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; + case IterativeParsingKeyValueDelimiterState: + case IterativeParsingArrayInitialState: + case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return; + default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; + } } + RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) { + return s >= IterativeParsingElementDelimiterState; + } + + RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) { + return s <= IterativeParsingErrorState; + } + template ParseResult IterativeParse(InputStream& is, Handler& handler) { parseResult_.Clear(); ClearStackOnExit scope(*this); IterativeParsingState state = IterativeParsingStartState; - - SkipWhitespace(is); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); while (is.Peek() != '\0') { Token t = Tokenize(is.Peek()); IterativeParsingState n = Predict(state, t); IterativeParsingState d = Transit(state, t, n, is, handler); - + if (d == IterativeParsingErrorState) { HandleError(state, is); break; } - + state = d; - + // Do not further consume streams if a root JSON has been parsed. if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) break; - - SkipWhitespace(is); + + SkipWhitespaceAndComments(is); + RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } - + // Handle the end of file. if (state != IterativeParsingFinishState) HandleError(state, is); - + return parseResult_; } static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. ParseResult parseResult_; + IterativeParsingState state_; }; // class GenericReader //! Reader with UTF8 encoding and default allocator. @@ -1441,6 +2205,11 @@ typedef GenericReader, UTF8<> > Reader; RAPIDJSON_NAMESPACE_END +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + + #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif diff --git a/contrib/rapidjson/include/rapidjson/schema.h b/contrib/rapidjson/include/rapidjson/schema.h new file mode 100644 index 000000000..abcf1a102 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/schema.h @@ -0,0 +1,2016 @@ +// Tencent is pleased to support the open source community by making RapidJSON available-> +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved-> +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License-> You may obtain a copy of the License at +// +// http://opensource->org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied-> See the License for the +// specific language governing permissions and limitations under the License-> + +#ifndef RAPIDJSON_SCHEMA_H_ +#define RAPIDJSON_SCHEMA_H_ + +#include "document.h" +#include "pointer.h" +#include // abs, floor + +#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) +#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 +#else +#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 +#endif + +#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) +#define RAPIDJSON_SCHEMA_USE_STDREGEX 1 +#else +#define RAPIDJSON_SCHEMA_USE_STDREGEX 0 +#endif + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX +#include "internal/regex.h" +#elif RAPIDJSON_SCHEMA_USE_STDREGEX +#include +#endif + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX +#define RAPIDJSON_SCHEMA_HAS_REGEX 1 +#else +#define RAPIDJSON_SCHEMA_HAS_REGEX 0 +#endif + +#ifndef RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_SCHEMA_VERBOSE 0 +#endif + +#if RAPIDJSON_SCHEMA_VERBOSE +#include "stringbuffer.h" +#endif + +RAPIDJSON_DIAG_PUSH + +#if defined(__GNUC__) +RAPIDJSON_DIAG_OFF(effc++) +#endif + +#ifdef __clang__ +RAPIDJSON_DIAG_OFF(weak-vtables) +RAPIDJSON_DIAG_OFF(exit-time-destructors) +RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) +RAPIDJSON_DIAG_OFF(variadic-macros) +#endif + +#ifdef _MSC_VER +RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated +#endif + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Verbose Utilities + +#if RAPIDJSON_SCHEMA_VERBOSE + +namespace internal { + +inline void PrintInvalidKeyword(const char* keyword) { + printf("Fail keyword: %s\n", keyword); +} + +inline void PrintInvalidKeyword(const wchar_t* keyword) { + wprintf(L"Fail keyword: %ls\n", keyword); +} + +inline void PrintInvalidDocument(const char* document) { + printf("Fail document: %s\n\n", document); +} + +inline void PrintInvalidDocument(const wchar_t* document) { + wprintf(L"Fail document: %ls\n\n", document); +} + +inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) { + printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d); +} + +inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) { + wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d); +} + +} // namespace internal + +#endif // RAPIDJSON_SCHEMA_VERBOSE + +/////////////////////////////////////////////////////////////////////////////// +// RAPIDJSON_INVALID_KEYWORD_RETURN + +#if RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword) +#else +#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) +#endif + +#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\ +RAPIDJSON_MULTILINEMACRO_BEGIN\ + context.invalidKeyword = keyword.GetString();\ + RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\ + return false;\ +RAPIDJSON_MULTILINEMACRO_END + +/////////////////////////////////////////////////////////////////////////////// +// Forward declarations + +template +class GenericSchemaDocument; + +namespace internal { + +template +class Schema; + +/////////////////////////////////////////////////////////////////////////////// +// ISchemaValidator + +class ISchemaValidator { +public: + virtual ~ISchemaValidator() {} + virtual bool IsValid() const = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// ISchemaStateFactory + +template +class ISchemaStateFactory { +public: + virtual ~ISchemaStateFactory() {} + virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0; + virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0; + virtual void* CreateHasher() = 0; + virtual uint64_t GetHashCode(void* hasher) = 0; + virtual void DestroryHasher(void* hasher) = 0; + virtual void* MallocState(size_t size) = 0; + virtual void FreeState(void* p) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Hasher + +// For comparison of compound value +template +class Hasher { +public: + typedef typename Encoding::Ch Ch; + + Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {} + + bool Null() { return WriteType(kNullType); } + bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); } + bool Int(int i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } + bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } + bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } + bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } + bool Double(double d) { + Number n; + if (d < 0) n.u.i = static_cast(d); + else n.u.u = static_cast(d); + n.d = d; + return WriteNumber(n); + } + + bool RawNumber(const Ch* str, SizeType len, bool) { + WriteBuffer(kNumberType, str, len * sizeof(Ch)); + return true; + } + + bool String(const Ch* str, SizeType len, bool) { + WriteBuffer(kStringType, str, len * sizeof(Ch)); + return true; + } + + bool StartObject() { return true; } + bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); } + bool EndObject(SizeType memberCount) { + uint64_t h = Hash(0, kObjectType); + uint64_t* kv = stack_.template Pop(memberCount * 2); + for (SizeType i = 0; i < memberCount; i++) + h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive + *stack_.template Push() = h; + return true; + } + + bool StartArray() { return true; } + bool EndArray(SizeType elementCount) { + uint64_t h = Hash(0, kArrayType); + uint64_t* e = stack_.template Pop(elementCount); + for (SizeType i = 0; i < elementCount; i++) + h = Hash(h, e[i]); // Use hash to achieve element order sensitive + *stack_.template Push() = h; + return true; + } + + bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); } + + uint64_t GetHashCode() const { + RAPIDJSON_ASSERT(IsValid()); + return *stack_.template Top(); + } + +private: + static const size_t kDefaultSize = 256; + struct Number { + union U { + uint64_t u; + int64_t i; + }u; + double d; + }; + + bool WriteType(Type type) { return WriteBuffer(type, 0, 0); } + + bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); } + + bool WriteBuffer(Type type, const void* data, size_t len) { + // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/ + uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type); + const unsigned char* d = static_cast(data); + for (size_t i = 0; i < len; i++) + h = Hash(h, d[i]); + *stack_.template Push() = h; + return true; + } + + static uint64_t Hash(uint64_t h, uint64_t d) { + static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3); + h ^= d; + h *= kPrime; + return h; + } + + Stack stack_; +}; + +/////////////////////////////////////////////////////////////////////////////// +// SchemaValidationContext + +template +struct SchemaValidationContext { + typedef Schema SchemaType; + typedef ISchemaStateFactory SchemaValidatorFactoryType; + typedef typename SchemaType::ValueType ValueType; + typedef typename ValueType::Ch Ch; + + enum PatternValidatorType { + kPatternValidatorOnly, + kPatternValidatorWithProperty, + kPatternValidatorWithAdditionalProperty + }; + + SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) : + factory(f), + schema(s), + valueSchema(), + invalidKeyword(), + hasher(), + arrayElementHashCodes(), + validators(), + validatorCount(), + patternPropertiesValidators(), + patternPropertiesValidatorCount(), + patternPropertiesSchemas(), + patternPropertiesSchemaCount(), + valuePatternValidatorType(kPatternValidatorOnly), + propertyExist(), + inArray(false), + valueUniqueness(false), + arrayUniqueness(false) + { + } + + ~SchemaValidationContext() { + if (hasher) + factory.DestroryHasher(hasher); + if (validators) { + for (SizeType i = 0; i < validatorCount; i++) + factory.DestroySchemaValidator(validators[i]); + factory.FreeState(validators); + } + if (patternPropertiesValidators) { + for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) + factory.DestroySchemaValidator(patternPropertiesValidators[i]); + factory.FreeState(patternPropertiesValidators); + } + if (patternPropertiesSchemas) + factory.FreeState(patternPropertiesSchemas); + if (propertyExist) + factory.FreeState(propertyExist); + } + + SchemaValidatorFactoryType& factory; + const SchemaType* schema; + const SchemaType* valueSchema; + const Ch* invalidKeyword; + void* hasher; // Only validator access + void* arrayElementHashCodes; // Only validator access this + ISchemaValidator** validators; + SizeType validatorCount; + ISchemaValidator** patternPropertiesValidators; + SizeType patternPropertiesValidatorCount; + const SchemaType** patternPropertiesSchemas; + SizeType patternPropertiesSchemaCount; + PatternValidatorType valuePatternValidatorType; + PatternValidatorType objectPatternValidatorType; + SizeType arrayElementIndex; + bool* propertyExist; + bool inArray; + bool valueUniqueness; + bool arrayUniqueness; +}; + +/////////////////////////////////////////////////////////////////////////////// +// Schema + +template +class Schema { +public: + typedef typename SchemaDocumentType::ValueType ValueType; + typedef typename SchemaDocumentType::AllocatorType AllocatorType; + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + typedef SchemaValidationContext Context; + typedef Schema SchemaType; + typedef GenericValue SValue; + friend class GenericSchemaDocument; + + Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : + allocator_(allocator), + typeless_(schemaDocument->GetTypeless()), + enum_(), + enumCount_(), + not_(), + type_((1 << kTotalSchemaType) - 1), // typeless + validatorCount_(), + properties_(), + additionalPropertiesSchema_(), + patternProperties_(), + patternPropertyCount_(), + propertyCount_(), + minProperties_(), + maxProperties_(SizeType(~0)), + additionalProperties_(true), + hasDependencies_(), + hasRequired_(), + hasSchemaDependencies_(), + additionalItemsSchema_(), + itemsList_(), + itemsTuple_(), + itemsTupleCount_(), + minItems_(), + maxItems_(SizeType(~0)), + additionalItems_(true), + uniqueItems_(false), + pattern_(), + minLength_(0), + maxLength_(~SizeType(0)), + exclusiveMinimum_(false), + exclusiveMaximum_(false) + { + typedef typename SchemaDocumentType::ValueType ValueType; + typedef typename ValueType::ConstValueIterator ConstValueIterator; + typedef typename ValueType::ConstMemberIterator ConstMemberIterator; + + if (!value.IsObject()) + return; + + if (const ValueType* v = GetMember(value, GetTypeString())) { + type_ = 0; + if (v->IsString()) + AddType(*v); + else if (v->IsArray()) + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) + AddType(*itr); + } + + if (const ValueType* v = GetMember(value, GetEnumString())) + if (v->IsArray() && v->Size() > 0) { + enum_ = static_cast(allocator_->Malloc(sizeof(uint64_t) * v->Size())); + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) { + typedef Hasher > EnumHasherType; + char buffer[256 + 24]; + MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer)); + EnumHasherType h(&hasherAllocator, 256); + itr->Accept(h); + enum_[enumCount_++] = h.GetHashCode(); + } + } + + if (schemaDocument) { + AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); + AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); + AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); + } + + if (const ValueType* v = GetMember(value, GetNotString())) { + schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document); + notValidatorIndex_ = validatorCount_; + validatorCount_++; + } + + // Object + + const ValueType* properties = GetMember(value, GetPropertiesString()); + const ValueType* required = GetMember(value, GetRequiredString()); + const ValueType* dependencies = GetMember(value, GetDependenciesString()); + { + // Gather properties from properties/required/dependencies + SValue allProperties(kArrayType); + + if (properties && properties->IsObject()) + for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) + AddUniqueElement(allProperties, itr->name); + + if (required && required->IsArray()) + for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) + if (itr->IsString()) + AddUniqueElement(allProperties, *itr); + + if (dependencies && dependencies->IsObject()) + for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { + AddUniqueElement(allProperties, itr->name); + if (itr->value.IsArray()) + for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i) + if (i->IsString()) + AddUniqueElement(allProperties, *i); + } + + if (allProperties.Size() > 0) { + propertyCount_ = allProperties.Size(); + properties_ = static_cast(allocator_->Malloc(sizeof(Property) * propertyCount_)); + for (SizeType i = 0; i < propertyCount_; i++) { + new (&properties_[i]) Property(); + properties_[i].name = allProperties[i]; + properties_[i].schema = typeless_; + } + } + } + + if (properties && properties->IsObject()) { + PointerType q = p.Append(GetPropertiesString(), allocator_); + for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) { + SizeType index; + if (FindPropertyIndex(itr->name, &index)) + schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document); + } + } + + if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) { + PointerType q = p.Append(GetPatternPropertiesString(), allocator_); + patternProperties_ = static_cast(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount())); + patternPropertyCount_ = 0; + + for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) { + new (&patternProperties_[patternPropertyCount_]) PatternProperty(); + patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name); + schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document); + patternPropertyCount_++; + } + } + + if (required && required->IsArray()) + for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) + if (itr->IsString()) { + SizeType index; + if (FindPropertyIndex(*itr, &index)) { + properties_[index].required = true; + hasRequired_ = true; + } + } + + if (dependencies && dependencies->IsObject()) { + PointerType q = p.Append(GetDependenciesString(), allocator_); + hasDependencies_ = true; + for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { + SizeType sourceIndex; + if (FindPropertyIndex(itr->name, &sourceIndex)) { + if (itr->value.IsArray()) { + properties_[sourceIndex].dependencies = static_cast(allocator_->Malloc(sizeof(bool) * propertyCount_)); + std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_); + for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) { + SizeType targetIndex; + if (FindPropertyIndex(*targetItr, &targetIndex)) + properties_[sourceIndex].dependencies[targetIndex] = true; + } + } + else if (itr->value.IsObject()) { + hasSchemaDependencies_ = true; + schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document); + properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; + validatorCount_++; + } + } + } + } + + if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) { + if (v->IsBool()) + additionalProperties_ = v->GetBool(); + else if (v->IsObject()) + schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document); + } + + AssignIfExist(minProperties_, value, GetMinPropertiesString()); + AssignIfExist(maxProperties_, value, GetMaxPropertiesString()); + + // Array + if (const ValueType* v = GetMember(value, GetItemsString())) { + PointerType q = p.Append(GetItemsString(), allocator_); + if (v->IsObject()) // List validation + schemaDocument->CreateSchema(&itemsList_, q, *v, document); + else if (v->IsArray()) { // Tuple validation + itemsTuple_ = static_cast(allocator_->Malloc(sizeof(const Schema*) * v->Size())); + SizeType index = 0; + for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++) + schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document); + } + } + + AssignIfExist(minItems_, value, GetMinItemsString()); + AssignIfExist(maxItems_, value, GetMaxItemsString()); + + if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) { + if (v->IsBool()) + additionalItems_ = v->GetBool(); + else if (v->IsObject()) + schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document); + } + + AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); + + // String + AssignIfExist(minLength_, value, GetMinLengthString()); + AssignIfExist(maxLength_, value, GetMaxLengthString()); + + if (const ValueType* v = GetMember(value, GetPatternString())) + pattern_ = CreatePattern(*v); + + // Number + if (const ValueType* v = GetMember(value, GetMinimumString())) + if (v->IsNumber()) + minimum_.CopyFrom(*v, *allocator_); + + if (const ValueType* v = GetMember(value, GetMaximumString())) + if (v->IsNumber()) + maximum_.CopyFrom(*v, *allocator_); + + AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString()); + AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString()); + + if (const ValueType* v = GetMember(value, GetMultipleOfString())) + if (v->IsNumber() && v->GetDouble() > 0.0) + multipleOf_.CopyFrom(*v, *allocator_); + } + + ~Schema() { + AllocatorType::Free(enum_); + if (properties_) { + for (SizeType i = 0; i < propertyCount_; i++) + properties_[i].~Property(); + AllocatorType::Free(properties_); + } + if (patternProperties_) { + for (SizeType i = 0; i < patternPropertyCount_; i++) + patternProperties_[i].~PatternProperty(); + AllocatorType::Free(patternProperties_); + } + AllocatorType::Free(itemsTuple_); +#if RAPIDJSON_SCHEMA_HAS_REGEX + if (pattern_) { + pattern_->~RegexType(); + AllocatorType::Free(pattern_); + } +#endif + } + + bool BeginValue(Context& context) const { + if (context.inArray) { + if (uniqueItems_) + context.valueUniqueness = true; + + if (itemsList_) + context.valueSchema = itemsList_; + else if (itemsTuple_) { + if (context.arrayElementIndex < itemsTupleCount_) + context.valueSchema = itemsTuple_[context.arrayElementIndex]; + else if (additionalItemsSchema_) + context.valueSchema = additionalItemsSchema_; + else if (additionalItems_) + context.valueSchema = typeless_; + else + RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString()); + } + else + context.valueSchema = typeless_; + + context.arrayElementIndex++; + } + return true; + } + + RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { + if (context.patternPropertiesValidatorCount > 0) { + bool otherValid = false; + SizeType count = context.patternPropertiesValidatorCount; + if (context.objectPatternValidatorType != Context::kPatternValidatorOnly) + otherValid = context.patternPropertiesValidators[--count]->IsValid(); + + bool patternValid = true; + for (SizeType i = 0; i < count; i++) + if (!context.patternPropertiesValidators[i]->IsValid()) { + patternValid = false; + break; + } + + if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { + if (!patternValid) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } + else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { + if (!patternValid || !otherValid) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } + else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); + } + + if (enum_) { + const uint64_t h = context.factory.GetHashCode(context.hasher); + for (SizeType i = 0; i < enumCount_; i++) + if (enum_[i] == h) + goto foundEnum; + RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString()); + foundEnum:; + } + + if (allOf_.schemas) + for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) + if (!context.validators[i]->IsValid()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString()); + + if (anyOf_.schemas) { + for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) + if (context.validators[i]->IsValid()) + goto foundAny; + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString()); + foundAny:; + } + + if (oneOf_.schemas) { + bool oneValid = false; + for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) + if (context.validators[i]->IsValid()) { + if (oneValid) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); + else + oneValid = true; + } + if (!oneValid) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); + } + + if (not_ && context.validators[notValidatorIndex_]->IsValid()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString()); + + return true; + } + + bool Null(Context& context) const { + if (!(type_ & (1 << kNullSchemaType))) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + return CreateParallelValidator(context); + } + + bool Bool(Context& context, bool) const { + if (!(type_ & (1 << kBooleanSchemaType))) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + return CreateParallelValidator(context); + } + + bool Int(Context& context, int i) const { + if (!CheckInt(context, i)) + return false; + return CreateParallelValidator(context); + } + + bool Uint(Context& context, unsigned u) const { + if (!CheckUint(context, u)) + return false; + return CreateParallelValidator(context); + } + + bool Int64(Context& context, int64_t i) const { + if (!CheckInt(context, i)) + return false; + return CreateParallelValidator(context); + } + + bool Uint64(Context& context, uint64_t u) const { + if (!CheckUint(context, u)) + return false; + return CreateParallelValidator(context); + } + + bool Double(Context& context, double d) const { + if (!(type_ & (1 << kNumberSchemaType))) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + + if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) + return false; + + if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) + return false; + + if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) + return false; + + return CreateParallelValidator(context); + } + + bool String(Context& context, const Ch* str, SizeType length, bool) const { + if (!(type_ & (1 << kStringSchemaType))) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + + if (minLength_ != 0 || maxLength_ != SizeType(~0)) { + SizeType count; + if (internal::CountStringCodePoint(str, length, &count)) { + if (count < minLength_) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString()); + if (count > maxLength_) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString()); + } + } + + if (pattern_ && !IsPatternMatch(pattern_, str, length)) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString()); + + return CreateParallelValidator(context); + } + + bool StartObject(Context& context) const { + if (!(type_ & (1 << kObjectSchemaType))) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + + if (hasDependencies_ || hasRequired_) { + context.propertyExist = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); + std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_); + } + + if (patternProperties_) { // pre-allocate schema array + SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType + context.patternPropertiesSchemas = static_cast(context.factory.MallocState(sizeof(const SchemaType*) * count)); + context.patternPropertiesSchemaCount = 0; + std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count); + } + + return CreateParallelValidator(context); + } + + bool Key(Context& context, const Ch* str, SizeType len, bool) const { + if (patternProperties_) { + context.patternPropertiesSchemaCount = 0; + for (SizeType i = 0; i < patternPropertyCount_; i++) + if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; + context.valueSchema = typeless_; + } + } + + SizeType index; + if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { + if (context.patternPropertiesSchemaCount > 0) { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; + context.valueSchema = typeless_; + context.valuePatternValidatorType = Context::kPatternValidatorWithProperty; + } + else + context.valueSchema = properties_[index].schema; + + if (context.propertyExist) + context.propertyExist[index] = true; + + return true; + } + + if (additionalPropertiesSchema_) { + if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) { + context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; + context.valueSchema = typeless_; + context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; + } + else + context.valueSchema = additionalPropertiesSchema_; + return true; + } + else if (additionalProperties_) { + context.valueSchema = typeless_; + return true; + } + + if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties + RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString()); + + return true; + } + + bool EndObject(Context& context, SizeType memberCount) const { + if (hasRequired_) + for (SizeType index = 0; index < propertyCount_; index++) + if (properties_[index].required) + if (!context.propertyExist[index]) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); + + if (memberCount < minProperties_) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); + + if (memberCount > maxProperties_) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString()); + + if (hasDependencies_) { + for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) + if (context.propertyExist[sourceIndex]) { + if (properties_[sourceIndex].dependencies) { + for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) + if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex]) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); + } + else if (properties_[sourceIndex].dependenciesSchema) + if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); + } + } + + return true; + } + + bool StartArray(Context& context) const { + if (!(type_ & (1 << kArraySchemaType))) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + + context.arrayElementIndex = 0; + context.inArray = true; + + return CreateParallelValidator(context); + } + + bool EndArray(Context& context, SizeType elementCount) const { + context.inArray = false; + + if (elementCount < minItems_) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString()); + + if (elementCount > maxItems_) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString()); + + return true; + } + + // Generate functions for string literal according to Ch +#define RAPIDJSON_STRING_(name, ...) \ + static const ValueType& Get##name##String() {\ + static const Ch s[] = { __VA_ARGS__, '\0' };\ + static const ValueType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1));\ + return v;\ + } + + RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') + RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n') + RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't') + RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y') + RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g') + RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r') + RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r') + RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e') + RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm') + RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f') + RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f') + RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f') + RAPIDJSON_STRING_(Not, 'n', 'o', 't') + RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd') + RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's') + RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') + RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's') + RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h') + RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h') + RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n') + RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') + RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') + +#undef RAPIDJSON_STRING_ + +private: + enum SchemaValueType { + kNullSchemaType, + kBooleanSchemaType, + kObjectSchemaType, + kArraySchemaType, + kStringSchemaType, + kNumberSchemaType, + kIntegerSchemaType, + kTotalSchemaType + }; + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX + typedef internal::GenericRegex RegexType; +#elif RAPIDJSON_SCHEMA_USE_STDREGEX + typedef std::basic_regex RegexType; +#else + typedef char RegexType; +#endif + + struct SchemaArray { + SchemaArray() : schemas(), count() {} + ~SchemaArray() { AllocatorType::Free(schemas); } + const SchemaType** schemas; + SizeType begin; // begin index of context.validators + SizeType count; + }; + + template + void AddUniqueElement(V1& a, const V2& v) { + for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) + if (*itr == v) + return; + V1 c(v, *allocator_); + a.PushBack(c, *allocator_); + } + + static const ValueType* GetMember(const ValueType& value, const ValueType& name) { + typename ValueType::ConstMemberIterator itr = value.FindMember(name); + return itr != value.MemberEnd() ? &(itr->value) : 0; + } + + static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) { + if (const ValueType* v = GetMember(value, name)) + if (v->IsBool()) + out = v->GetBool(); + } + + static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) { + if (const ValueType* v = GetMember(value, name)) + if (v->IsUint64() && v->GetUint64() <= SizeType(~0)) + out = static_cast(v->GetUint64()); + } + + void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) { + if (const ValueType* v = GetMember(value, name)) { + if (v->IsArray() && v->Size() > 0) { + PointerType q = p.Append(name, allocator_); + out.count = v->Size(); + out.schemas = static_cast(allocator_->Malloc(out.count * sizeof(const Schema*))); + memset(out.schemas, 0, sizeof(Schema*)* out.count); + for (SizeType i = 0; i < out.count; i++) + schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document); + out.begin = validatorCount_; + validatorCount_ += out.count; + } + } + } + +#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX + template + RegexType* CreatePattern(const ValueType& value) { + if (value.IsString()) { + RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString()); + if (!r->IsValid()) { + r->~RegexType(); + AllocatorType::Free(r); + r = 0; + } + return r; + } + return 0; + } + + static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { + GenericRegexSearch rs(*pattern); + return rs.Search(str); + } +#elif RAPIDJSON_SCHEMA_USE_STDREGEX + template + RegexType* CreatePattern(const ValueType& value) { + if (value.IsString()) + try { + return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); + } + catch (const std::regex_error&) { + } + return 0; + } + + static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) { + std::match_results r; + return std::regex_search(str, str + length, r, *pattern); + } +#else + template + RegexType* CreatePattern(const ValueType&) { return 0; } + + static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; } +#endif // RAPIDJSON_SCHEMA_USE_STDREGEX + + void AddType(const ValueType& type) { + if (type == GetNullString() ) type_ |= 1 << kNullSchemaType; + else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType; + else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType; + else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType; + else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType; + else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType; + else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); + } + + bool CreateParallelValidator(Context& context) const { + if (enum_ || context.arrayUniqueness) + context.hasher = context.factory.CreateHasher(); + + if (validatorCount_) { + RAPIDJSON_ASSERT(context.validators == 0); + context.validators = static_cast(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_)); + context.validatorCount = validatorCount_; + + if (allOf_.schemas) + CreateSchemaValidators(context, allOf_); + + if (anyOf_.schemas) + CreateSchemaValidators(context, anyOf_); + + if (oneOf_.schemas) + CreateSchemaValidators(context, oneOf_); + + if (not_) + context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_); + + if (hasSchemaDependencies_) { + for (SizeType i = 0; i < propertyCount_; i++) + if (properties_[i].dependenciesSchema) + context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema); + } + } + + return true; + } + + void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const { + for (SizeType i = 0; i < schemas.count; i++) + context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]); + } + + // O(n) + bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const { + SizeType len = name.GetStringLength(); + const Ch* str = name.GetString(); + for (SizeType index = 0; index < propertyCount_; index++) + if (properties_[index].name.GetStringLength() == len && + (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0)) + { + *outIndex = index; + return true; + } + return false; + } + + bool CheckInt(Context& context, int64_t i) const { + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + + if (!minimum_.IsNull()) { + if (minimum_.IsInt64()) { + if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } + else if (minimum_.IsUint64()) { + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64() + } + else if (!CheckDoubleMinimum(context, static_cast(i))) + return false; + } + + if (!maximum_.IsNull()) { + if (maximum_.IsInt64()) { + if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } + else if (maximum_.IsUint64()) { } + /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64() + else if (!CheckDoubleMaximum(context, static_cast(i))) + return false; + } + + if (!multipleOf_.IsNull()) { + if (multipleOf_.IsUint64()) { + if (static_cast(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } + else if (!CheckDoubleMultipleOf(context, static_cast(i))) + return false; + } + + return true; + } + + bool CheckUint(Context& context, uint64_t i) const { + if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); + + if (!minimum_.IsNull()) { + if (minimum_.IsUint64()) { + if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + } + else if (minimum_.IsInt64()) + /* do nothing */; // i >= 0 > minimum.Getint64() + else if (!CheckDoubleMinimum(context, static_cast(i))) + return false; + } + + if (!maximum_.IsNull()) { + if (maximum_.IsUint64()) { + if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + } + else if (maximum_.IsInt64()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_ + else if (!CheckDoubleMaximum(context, static_cast(i))) + return false; + } + + if (!multipleOf_.IsNull()) { + if (multipleOf_.IsUint64()) { + if (i % multipleOf_.GetUint64() != 0) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + } + else if (!CheckDoubleMultipleOf(context, static_cast(i))) + return false; + } + + return true; + } + + bool CheckDoubleMinimum(Context& context, double d) const { + if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); + return true; + } + + bool CheckDoubleMaximum(Context& context, double d) const { + if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); + return true; + } + + bool CheckDoubleMultipleOf(Context& context, double d) const { + double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); + double q = std::floor(a / b); + double r = a - q * b; + if (r > 0.0) + RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); + return true; + } + + struct Property { + Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {} + ~Property() { AllocatorType::Free(dependencies); } + SValue name; + const SchemaType* schema; + const SchemaType* dependenciesSchema; + SizeType dependenciesValidatorIndex; + bool* dependencies; + bool required; + }; + + struct PatternProperty { + PatternProperty() : schema(), pattern() {} + ~PatternProperty() { + if (pattern) { + pattern->~RegexType(); + AllocatorType::Free(pattern); + } + } + const SchemaType* schema; + RegexType* pattern; + }; + + AllocatorType* allocator_; + const SchemaType* typeless_; + uint64_t* enum_; + SizeType enumCount_; + SchemaArray allOf_; + SchemaArray anyOf_; + SchemaArray oneOf_; + const SchemaType* not_; + unsigned type_; // bitmask of kSchemaType + SizeType validatorCount_; + SizeType notValidatorIndex_; + + Property* properties_; + const SchemaType* additionalPropertiesSchema_; + PatternProperty* patternProperties_; + SizeType patternPropertyCount_; + SizeType propertyCount_; + SizeType minProperties_; + SizeType maxProperties_; + bool additionalProperties_; + bool hasDependencies_; + bool hasRequired_; + bool hasSchemaDependencies_; + + const SchemaType* additionalItemsSchema_; + const SchemaType* itemsList_; + const SchemaType** itemsTuple_; + SizeType itemsTupleCount_; + SizeType minItems_; + SizeType maxItems_; + bool additionalItems_; + bool uniqueItems_; + + RegexType* pattern_; + SizeType minLength_; + SizeType maxLength_; + + SValue minimum_; + SValue maximum_; + SValue multipleOf_; + bool exclusiveMinimum_; + bool exclusiveMaximum_; +}; + +template +struct TokenHelper { + RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { + *documentStack.template Push() = '/'; + char buffer[21]; + size_t length = static_cast((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer); + for (size_t i = 0; i < length; i++) + *documentStack.template Push() = static_cast(buffer[i]); + } +}; + +// Partial specialized version for char to prevent buffer copying. +template +struct TokenHelper { + RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { + if (sizeof(SizeType) == 4) { + char *buffer = documentStack.template Push(1 + 10); // '/' + uint + *buffer++ = '/'; + const char* end = internal::u32toa(index, buffer); + documentStack.template Pop(static_cast(10 - (end - buffer))); + } + else { + char *buffer = documentStack.template Push(1 + 20); // '/' + uint64 + *buffer++ = '/'; + const char* end = internal::u64toa(index, buffer); + documentStack.template Pop(static_cast(20 - (end - buffer))); + } + } +}; + +} // namespace internal + +/////////////////////////////////////////////////////////////////////////////// +// IGenericRemoteSchemaDocumentProvider + +template +class IGenericRemoteSchemaDocumentProvider { +public: + typedef typename SchemaDocumentType::Ch Ch; + + virtual ~IGenericRemoteSchemaDocumentProvider() {} + virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; +}; + +/////////////////////////////////////////////////////////////////////////////// +// GenericSchemaDocument + +//! JSON schema document. +/*! + A JSON schema document is a compiled version of a JSON schema. + It is basically a tree of internal::Schema. + + \note This is an immutable class (i.e. its instance cannot be modified after construction). + \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding. + \tparam Allocator Allocator type for allocating memory of this document. +*/ +template +class GenericSchemaDocument { +public: + typedef ValueT ValueType; + typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProviderType; + typedef Allocator AllocatorType; + typedef typename ValueType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + typedef internal::Schema SchemaType; + typedef GenericPointer PointerType; + friend class internal::Schema; + template + friend class GenericSchemaValidator; + + //! Constructor. + /*! + Compile a JSON document into schema document. + + \param document A JSON document as source. + \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. + \param allocator An optional allocator instance for allocating memory. Can be null. + */ + explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : + remoteProvider_(remoteProvider), + allocator_(allocator), + ownAllocator_(), + root_(), + typeless_(), + schemaMap_(allocator, kInitialSchemaMapSize), + schemaRef_(allocator, kInitialSchemaRefSize) + { + if (!allocator_) + ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); + + typeless_ = static_cast(allocator_->Malloc(sizeof(SchemaType))); + new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0); + + // Generate root schema, it will call CreateSchema() to create sub-schemas, + // And call AddRefSchema() if there are $ref. + CreateSchemaRecursive(&root_, PointerType(), document, document); + + // Resolve $ref + while (!schemaRef_.Empty()) { + SchemaRefEntry* refEntry = schemaRef_.template Pop(1); + if (const SchemaType* s = GetSchema(refEntry->target)) { + if (refEntry->schema) + *refEntry->schema = s; + + // Create entry in map if not exist + if (!GetSchema(refEntry->source)) { + new (schemaMap_.template Push()) SchemaEntry(refEntry->source, const_cast(s), false, allocator_); + } + } + else if (refEntry->schema) + *refEntry->schema = typeless_; + + refEntry->~SchemaRefEntry(); + } + + RAPIDJSON_ASSERT(root_ != 0); + + schemaRef_.ShrinkToFit(); // Deallocate all memory for ref + } + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + //! Move constructor in C++11 + GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT : + remoteProvider_(rhs.remoteProvider_), + allocator_(rhs.allocator_), + ownAllocator_(rhs.ownAllocator_), + root_(rhs.root_), + typeless_(rhs.typeless_), + schemaMap_(std::move(rhs.schemaMap_)), + schemaRef_(std::move(rhs.schemaRef_)) + { + rhs.remoteProvider_ = 0; + rhs.allocator_ = 0; + rhs.ownAllocator_ = 0; + rhs.typeless_ = 0; + } +#endif + + //! Destructor + ~GenericSchemaDocument() { + while (!schemaMap_.Empty()) + schemaMap_.template Pop(1)->~SchemaEntry(); + + if (typeless_) { + typeless_->~SchemaType(); + Allocator::Free(typeless_); + } + + RAPIDJSON_DELETE(ownAllocator_); + } + + //! Get the root schema. + const SchemaType& GetRoot() const { return *root_; } + +private: + //! Prohibit copying + GenericSchemaDocument(const GenericSchemaDocument&); + //! Prohibit assignment + GenericSchemaDocument& operator=(const GenericSchemaDocument&); + + struct SchemaRefEntry { + SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {} + PointerType source; + PointerType target; + const SchemaType** schema; + }; + + struct SchemaEntry { + SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {} + ~SchemaEntry() { + if (owned) { + schema->~SchemaType(); + Allocator::Free(schema); + } + } + PointerType pointer; + SchemaType* schema; + bool owned; + }; + + void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { + if (schema) + *schema = typeless_; + + if (v.GetType() == kObjectType) { + const SchemaType* s = GetSchema(pointer); + if (!s) + CreateSchema(schema, pointer, v, document); + + for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) + CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document); + } + else if (v.GetType() == kArrayType) + for (SizeType i = 0; i < v.Size(); i++) + CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document); + } + + void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { + RAPIDJSON_ASSERT(pointer.IsValid()); + if (v.IsObject()) { + if (!HandleRefSchema(pointer, schema, v, document)) { + SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_); + new (schemaMap_.template Push()) SchemaEntry(pointer, s, true, allocator_); + if (schema) + *schema = s; + } + } + } + + bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) { + static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' }; + static const ValueType kRefValue(kRefString, 4); + + typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue); + if (itr == v.MemberEnd()) + return false; + + if (itr->value.IsString()) { + SizeType len = itr->value.GetStringLength(); + if (len > 0) { + const Ch* s = itr->value.GetString(); + SizeType i = 0; + while (i < len && s[i] != '#') // Find the first # + i++; + + if (i > 0) { // Remote reference, resolve immediately + if (remoteProvider_) { + if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) { + PointerType pointer(&s[i], len - i, allocator_); + if (pointer.IsValid()) { + if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) { + if (schema) + *schema = sc; + return true; + } + } + } + } + } + else if (s[i] == '#') { // Local reference, defer resolution + PointerType pointer(&s[i], len - i, allocator_); + if (pointer.IsValid()) { + if (const ValueType* nv = pointer.Get(document)) + if (HandleRefSchema(source, schema, *nv, document)) + return true; + + new (schemaRef_.template Push()) SchemaRefEntry(source, pointer, schema, allocator_); + return true; + } + } + } + } + return false; + } + + const SchemaType* GetSchema(const PointerType& pointer) const { + for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) + if (pointer == target->pointer) + return target->schema; + return 0; + } + + PointerType GetPointer(const SchemaType* schema) const { + for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) + if (schema == target->schema) + return target->pointer; + return PointerType(); + } + + const SchemaType* GetTypeless() const { return typeless_; } + + static const size_t kInitialSchemaMapSize = 64; + static const size_t kInitialSchemaRefSize = 64; + + IRemoteSchemaDocumentProviderType* remoteProvider_; + Allocator *allocator_; + Allocator *ownAllocator_; + const SchemaType* root_; //!< Root schema. + SchemaType* typeless_; + internal::Stack schemaMap_; // Stores created Pointer -> Schemas + internal::Stack schemaRef_; // Stores Pointer from $ref and schema which holds the $ref +}; + +//! GenericSchemaDocument using Value type. +typedef GenericSchemaDocument SchemaDocument; +//! IGenericRemoteSchemaDocumentProvider using SchemaDocument. +typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; + +/////////////////////////////////////////////////////////////////////////////// +// GenericSchemaValidator + +//! JSON Schema Validator. +/*! + A SAX style JSON schema validator. + It uses a \c GenericSchemaDocument to validate SAX events. + It delegates the incoming SAX events to an output handler. + The default output handler does nothing. + It can be reused multiple times by calling \c Reset(). + + \tparam SchemaDocumentType Type of schema document. + \tparam OutputHandler Type of output handler. Default handler does nothing. + \tparam StateAllocator Allocator for storing the internal validation states. +*/ +template < + typename SchemaDocumentType, + typename OutputHandler = BaseReaderHandler, + typename StateAllocator = CrtAllocator> +class GenericSchemaValidator : + public internal::ISchemaStateFactory, + public internal::ISchemaValidator +{ +public: + typedef typename SchemaDocumentType::SchemaType SchemaType; + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename SchemaType::EncodingType EncodingType; + typedef typename EncodingType::Ch Ch; + + //! Constructor without output handler. + /*! + \param schemaDocument The schema document to conform to. + \param allocator Optional allocator for storing internal validation states. + \param schemaStackCapacity Optional initial capacity of schema path stack. + \param documentStackCapacity Optional initial capacity of document path stack. + */ + GenericSchemaValidator( + const SchemaDocumentType& schemaDocument, + StateAllocator* allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(schemaDocument.GetRoot()), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + outputHandler_(0), + valid_(true) +#if RAPIDJSON_SCHEMA_VERBOSE + , depth_(0) +#endif + { + } + + //! Constructor with output handler. + /*! + \param schemaDocument The schema document to conform to. + \param allocator Optional allocator for storing internal validation states. + \param schemaStackCapacity Optional initial capacity of schema path stack. + \param documentStackCapacity Optional initial capacity of document path stack. + */ + GenericSchemaValidator( + const SchemaDocumentType& schemaDocument, + OutputHandler& outputHandler, + StateAllocator* allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(schemaDocument.GetRoot()), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + outputHandler_(&outputHandler), + valid_(true) +#if RAPIDJSON_SCHEMA_VERBOSE + , depth_(0) +#endif + { + } + + //! Destructor. + ~GenericSchemaValidator() { + Reset(); + RAPIDJSON_DELETE(ownStateAllocator_); + } + + //! Reset the internal states. + void Reset() { + while (!schemaStack_.Empty()) + PopSchema(); + documentStack_.Clear(); + valid_ = true; + } + + //! Checks whether the current state is valid. + // Implementation of ISchemaValidator + virtual bool IsValid() const { return valid_; } + + //! Gets the JSON pointer pointed to the invalid schema. + PointerType GetInvalidSchemaPointer() const { + return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema()); + } + + //! Gets the keyword of invalid schema. + const Ch* GetInvalidSchemaKeyword() const { + return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword; + } + + //! Gets the JSON pointer pointed to the invalid value. + PointerType GetInvalidDocumentPointer() const { + return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); + } + +#if RAPIDJSON_SCHEMA_VERBOSE +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \ +RAPIDJSON_MULTILINEMACRO_BEGIN\ + *documentStack_.template Push() = '\0';\ + documentStack_.template Pop(1);\ + internal::PrintInvalidDocument(documentStack_.template Bottom());\ +RAPIDJSON_MULTILINEMACRO_END +#else +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() +#endif + +#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ + if (!valid_) return false; \ + if (!BeginValue() || !CurrentSchema().method arg1) {\ + RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\ + return valid_ = false;\ + } + +#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ + for (Context* context = schemaStack_.template Bottom(); context != schemaStack_.template End(); context++) {\ + if (context->hasher)\ + static_cast(context->hasher)->method arg2;\ + if (context->validators)\ + for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\ + static_cast(context->validators[i_])->method arg2;\ + if (context->patternPropertiesValidators)\ + for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\ + static_cast(context->patternPropertiesValidators[i_])->method arg2;\ + } + +#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ + return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2) + +#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ + RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ + RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) + + bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); } + bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); } + bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); } + bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); } + bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } + bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } + bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } + bool RawNumber(const Ch* str, SizeType length, bool copy) + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } + bool String(const Ch* str, SizeType length, bool copy) + { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } + + bool StartObject() { + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); + return valid_ = !outputHandler_ || outputHandler_->StartObject(); + } + + bool Key(const Ch* str, SizeType len, bool copy) { + if (!valid_) return false; + AppendToken(str, len); + if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); + return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy); + } + + bool EndObject(SizeType memberCount) { + if (!valid_) return false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); + if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false; + RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); + } + + bool StartArray() { + RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); + return valid_ = !outputHandler_ || outputHandler_->StartArray(); + } + + bool EndArray(SizeType elementCount) { + if (!valid_) return false; + RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); + if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false; + RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); + } + +#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_ +#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ +#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ +#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ + + // Implementation of ISchemaStateFactory + virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) { + return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, +#if RAPIDJSON_SCHEMA_VERBOSE + depth_ + 1, +#endif + &GetStateAllocator()); + } + + virtual void DestroySchemaValidator(ISchemaValidator* validator) { + GenericSchemaValidator* v = static_cast(validator); + v->~GenericSchemaValidator(); + StateAllocator::Free(v); + } + + virtual void* CreateHasher() { + return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator()); + } + + virtual uint64_t GetHashCode(void* hasher) { + return static_cast(hasher)->GetHashCode(); + } + + virtual void DestroryHasher(void* hasher) { + HasherType* h = static_cast(hasher); + h->~HasherType(); + StateAllocator::Free(h); + } + + virtual void* MallocState(size_t size) { + return GetStateAllocator().Malloc(size); + } + + virtual void FreeState(void* p) { + StateAllocator::Free(p); + } + +private: + typedef typename SchemaType::Context Context; + typedef GenericValue, StateAllocator> HashCodeArray; + typedef internal::Hasher HasherType; + + GenericSchemaValidator( + const SchemaDocumentType& schemaDocument, + const SchemaType& root, +#if RAPIDJSON_SCHEMA_VERBOSE + unsigned depth, +#endif + StateAllocator* allocator = 0, + size_t schemaStackCapacity = kDefaultSchemaStackCapacity, + size_t documentStackCapacity = kDefaultDocumentStackCapacity) + : + schemaDocument_(&schemaDocument), + root_(root), + stateAllocator_(allocator), + ownStateAllocator_(0), + schemaStack_(allocator, schemaStackCapacity), + documentStack_(allocator, documentStackCapacity), + outputHandler_(0), + valid_(true) +#if RAPIDJSON_SCHEMA_VERBOSE + , depth_(depth) +#endif + { + } + + StateAllocator& GetStateAllocator() { + if (!stateAllocator_) + stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)(); + return *stateAllocator_; + } + + bool BeginValue() { + if (schemaStack_.Empty()) + PushSchema(root_); + else { + if (CurrentContext().inArray) + internal::TokenHelper, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); + + if (!CurrentSchema().BeginValue(CurrentContext())) + return false; + + SizeType count = CurrentContext().patternPropertiesSchemaCount; + const SchemaType** sa = CurrentContext().patternPropertiesSchemas; + typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; + bool valueUniqueness = CurrentContext().valueUniqueness; + RAPIDJSON_ASSERT(CurrentContext().valueSchema); + PushSchema(*CurrentContext().valueSchema); + + if (count > 0) { + CurrentContext().objectPatternValidatorType = patternValidatorType; + ISchemaValidator**& va = CurrentContext().patternPropertiesValidators; + SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount; + va = static_cast(MallocState(sizeof(ISchemaValidator*) * count)); + for (SizeType i = 0; i < count; i++) + va[validatorCount++] = CreateSchemaValidator(*sa[i]); + } + + CurrentContext().arrayUniqueness = valueUniqueness; + } + return true; + } + + bool EndValue() { + if (!CurrentSchema().EndValue(CurrentContext())) + return false; + +#if RAPIDJSON_SCHEMA_VERBOSE + GenericStringBuffer sb; + schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb); + + *documentStack_.template Push() = '\0'; + documentStack_.template Pop(1); + internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom()); +#endif + + uint64_t h = CurrentContext().arrayUniqueness ? static_cast(CurrentContext().hasher)->GetHashCode() : 0; + + PopSchema(); + + if (!schemaStack_.Empty()) { + Context& context = CurrentContext(); + if (context.valueUniqueness) { + HashCodeArray* a = static_cast(context.arrayElementHashCodes); + if (!a) + CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType); + for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr) + if (itr->GetUint64() == h) + RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString()); + a->PushBack(h, GetStateAllocator()); + } + } + + // Remove the last token of document pointer + while (!documentStack_.Empty() && *documentStack_.template Pop(1) != '/') + ; + + return true; + } + + void AppendToken(const Ch* str, SizeType len) { + documentStack_.template Reserve(1 + len * 2); // worst case all characters are escaped as two characters + *documentStack_.template PushUnsafe() = '/'; + for (SizeType i = 0; i < len; i++) { + if (str[i] == '~') { + *documentStack_.template PushUnsafe() = '~'; + *documentStack_.template PushUnsafe() = '0'; + } + else if (str[i] == '/') { + *documentStack_.template PushUnsafe() = '~'; + *documentStack_.template PushUnsafe() = '1'; + } + else + *documentStack_.template PushUnsafe() = str[i]; + } + } + + RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, &schema); } + + RAPIDJSON_FORCEINLINE void PopSchema() { + Context* c = schemaStack_.template Pop(1); + if (HashCodeArray* a = static_cast(c->arrayElementHashCodes)) { + a->~HashCodeArray(); + StateAllocator::Free(a); + } + c->~Context(); + } + + const SchemaType& CurrentSchema() const { return *schemaStack_.template Top()->schema; } + Context& CurrentContext() { return *schemaStack_.template Top(); } + const Context& CurrentContext() const { return *schemaStack_.template Top(); } + + static const size_t kDefaultSchemaStackCapacity = 1024; + static const size_t kDefaultDocumentStackCapacity = 256; + const SchemaDocumentType* schemaDocument_; + const SchemaType& root_; + StateAllocator* stateAllocator_; + StateAllocator* ownStateAllocator_; + internal::Stack schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) + internal::Stack documentStack_; //!< stack to store the current path of validating document (Ch) + OutputHandler* outputHandler_; + bool valid_; +#if RAPIDJSON_SCHEMA_VERBOSE + unsigned depth_; +#endif +}; + +typedef GenericSchemaValidator SchemaValidator; + +/////////////////////////////////////////////////////////////////////////////// +// SchemaValidatingReader + +//! A helper class for parsing with validation. +/*! + This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate(). + + \tparam parseFlags Combination of \ref ParseFlag. + \tparam InputStream Type of input stream, implementing Stream concept. + \tparam SourceEncoding Encoding of the input stream. + \tparam SchemaDocumentType Type of schema document. + \tparam StackAllocator Allocator type for stack. +*/ +template < + unsigned parseFlags, + typename InputStream, + typename SourceEncoding, + typename SchemaDocumentType = SchemaDocument, + typename StackAllocator = CrtAllocator> +class SchemaValidatingReader { +public: + typedef typename SchemaDocumentType::PointerType PointerType; + typedef typename InputStream::Ch Ch; + + //! Constructor + /*! + \param is Input stream. + \param sd Schema document. + */ + SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {} + + template + bool operator()(Handler& handler) { + GenericReader reader; + GenericSchemaValidator validator(sd_, handler); + parseResult_ = reader.template Parse(is_, validator); + + isValid_ = validator.IsValid(); + if (isValid_) { + invalidSchemaPointer_ = PointerType(); + invalidSchemaKeyword_ = 0; + invalidDocumentPointer_ = PointerType(); + } + else { + invalidSchemaPointer_ = validator.GetInvalidSchemaPointer(); + invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword(); + invalidDocumentPointer_ = validator.GetInvalidDocumentPointer(); + } + + return parseResult_; + } + + const ParseResult& GetParseResult() const { return parseResult_; } + bool IsValid() const { return isValid_; } + const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; } + const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; } + const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; } + +private: + InputStream& is_; + const SchemaDocumentType& sd_; + + ParseResult parseResult_; + PointerType invalidSchemaPointer_; + const Ch* invalidSchemaKeyword_; + PointerType invalidDocumentPointer_; + bool isValid_; +}; + +RAPIDJSON_NAMESPACE_END +RAPIDJSON_DIAG_POP + +#endif // RAPIDJSON_SCHEMA_H_ diff --git a/contrib/rapidjson/include/rapidjson/stream.h b/contrib/rapidjson/include/rapidjson/stream.h new file mode 100644 index 000000000..fef82c252 --- /dev/null +++ b/contrib/rapidjson/include/rapidjson/stream.h @@ -0,0 +1,179 @@ +// Tencent is pleased to support the open source community by making RapidJSON available. +// +// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. +// +// Licensed under the MIT License (the "License"); you may not use this file except +// in compliance with the License. You may obtain a copy of the License at +// +// http://opensource.org/licenses/MIT +// +// Unless required by applicable law or agreed to in writing, software distributed +// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +// CONDITIONS OF ANY KIND, either express or implied. See the License for the +// specific language governing permissions and limitations under the License. + +#include "rapidjson.h" + +#ifndef RAPIDJSON_STREAM_H_ +#define RAPIDJSON_STREAM_H_ + +#include "encodings.h" + +RAPIDJSON_NAMESPACE_BEGIN + +/////////////////////////////////////////////////////////////////////////////// +// Stream + +/*! \class rapidjson::Stream + \brief Concept for reading and writing characters. + + For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). + + For write-only stream, only need to implement Put() and Flush(). + +\code +concept Stream { + typename Ch; //!< Character type of the stream. + + //! Read the current character from stream without moving the read cursor. + Ch Peek() const; + + //! Read the current character from stream and moving the read cursor to next character. + Ch Take(); + + //! Get the current read cursor. + //! \return Number of characters read from start. + size_t Tell(); + + //! Begin writing operation at the current read pointer. + //! \return The begin writer pointer. + Ch* PutBegin(); + + //! Write a character. + void Put(Ch c); + + //! Flush the buffer. + void Flush(); + + //! End the writing operation. + //! \param begin The begin write pointer returned by PutBegin(). + //! \return Number of characters written. + size_t PutEnd(Ch* begin); +} +\endcode +*/ + +//! Provides additional information for stream. +/*! + By using traits pattern, this type provides a default configuration for stream. + For custom stream, this type can be specialized for other configuration. + See TEST(Reader, CustomStringStream) in readertest.cpp for example. +*/ +template +struct StreamTraits { + //! Whether to make local copy of stream for optimization during parsing. + /*! + By default, for safety, streams do not use local copy optimization. + Stream that can be copied fast should specialize this, like StreamTraits. + */ + enum { copyOptimization = 0 }; +}; + +//! Reserve n characters for writing to a stream. +template +inline void PutReserve(Stream& stream, size_t count) { + (void)stream; + (void)count; +} + +//! Write character to a stream, presuming buffer is reserved. +template +inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { + stream.Put(c); +} + +//! Put N copies of a character to a stream. +template +inline void PutN(Stream& stream, Ch c, size_t n) { + PutReserve(stream, n); + for (size_t i = 0; i < n; i++) + PutUnsafe(stream, c); +} + +/////////////////////////////////////////////////////////////////////////////// +// StringStream + +//! Read-only string stream. +/*! \note implements Stream concept +*/ +template +struct GenericStringStream { + typedef typename Encoding::Ch Ch; + + GenericStringStream(const Ch *src) : src_(src), head_(src) {} + + Ch Peek() const { return *src_; } + Ch Take() { return *src_++; } + size_t Tell() const { return static_cast(src_ - head_); } + + Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } + void Put(Ch) { RAPIDJSON_ASSERT(false); } + void Flush() { RAPIDJSON_ASSERT(false); } + size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } + + const Ch* src_; //!< Current read position. + const Ch* head_; //!< Original head of the string. +}; + +template +struct StreamTraits > { + enum { copyOptimization = 1 }; +}; + +//! String stream with UTF8 encoding. +typedef GenericStringStream > StringStream; + +/////////////////////////////////////////////////////////////////////////////// +// InsituStringStream + +//! A read-write string stream. +/*! This string stream is particularly designed for in-situ parsing. + \note implements Stream concept +*/ +template +struct GenericInsituStringStream { + typedef typename Encoding::Ch Ch; + + GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} + + // Read + Ch Peek() { return *src_; } + Ch Take() { return *src_++; } + size_t Tell() { return static_cast(src_ - head_); } + + // Write + void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } + + Ch* PutBegin() { return dst_ = src_; } + size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } + void Flush() {} + + Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } + void Pop(size_t count) { dst_ -= count; } + + Ch* src_; + Ch* dst_; + Ch* head_; +}; + +template +struct StreamTraits > { + enum { copyOptimization = 1 }; +}; + +//! Insitu string stream with UTF8 encoding. +typedef GenericInsituStringStream > InsituStringStream; + +RAPIDJSON_NAMESPACE_END + +#endif // RAPIDJSON_STREAM_H_ diff --git a/contrib/rapidjson/include/rapidjson/stringbuffer.h b/contrib/rapidjson/include/rapidjson/stringbuffer.h index 1c9c80b79..4e38b82c3 100644 --- a/contrib/rapidjson/include/rapidjson/stringbuffer.h +++ b/contrib/rapidjson/include/rapidjson/stringbuffer.h @@ -15,7 +15,8 @@ #ifndef RAPIDJSON_STRINGBUFFER_H_ #define RAPIDJSON_STRINGBUFFER_H_ -#include "rapidjson.h" +#include "stream.h" +#include "internal/stack.h" #if RAPIDJSON_HAS_CXX11_RVALUE_REFS #include // std::move @@ -23,6 +24,11 @@ #include "internal/stack.h" +#if defined(__clang__) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory output stream. @@ -48,6 +54,7 @@ public: #endif void Put(Ch c) { *stack_.template Push() = c; } + void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } void Flush() {} void Clear() { stack_.Clear(); } @@ -57,7 +64,10 @@ public: stack_.ShrinkToFit(); stack_.template Pop(1); } + + void Reserve(size_t count) { stack_.template Reserve(count); } Ch* Push(size_t count) { return stack_.template Push(count); } + Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe(count); } void Pop(size_t count) { stack_.template Pop(count); } const Ch* GetString() const { @@ -68,8 +78,12 @@ public: return stack_.template Bottom(); } + //! Get the size of string in bytes in the string buffer. size_t GetSize() const { return stack_.GetSize(); } + //! Get the length of string in Ch in the string buffer. + size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } + static const size_t kDefaultCapacity = 256; mutable internal::Stack stack_; @@ -82,6 +96,16 @@ private: //! String buffer with UTF8 encoding typedef GenericStringBuffer > StringBuffer; +template +inline void PutReserve(GenericStringBuffer& stream, size_t count) { + stream.Reserve(count); +} + +template +inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { + stream.PutUnsafe(c); +} + //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { @@ -90,4 +114,8 @@ inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { RAPIDJSON_NAMESPACE_END +#if defined(__clang__) +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_STRINGBUFFER_H_ diff --git a/contrib/rapidjson/include/rapidjson/writer.h b/contrib/rapidjson/include/rapidjson/writer.h index e1eea38b9..e610ebb60 100644 --- a/contrib/rapidjson/include/rapidjson/writer.h +++ b/contrib/rapidjson/include/rapidjson/writer.h @@ -15,7 +15,8 @@ #ifndef RAPIDJSON_WRITER_H_ #define RAPIDJSON_WRITER_H_ -#include "rapidjson.h" +#include "stream.h" +#include "internal/meta.h" #include "internal/stack.h" #include "internal/strfunc.h" #include "internal/dtoa.h" @@ -23,8 +24,16 @@ #include "stringbuffer.h" #include // placement new -#if RAPIDJSON_HAS_STDSTRING -#include +#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) +#include +#pragma intrinsic(_BitScanForward) +#endif +#ifdef RAPIDJSON_SSE42 +#include +#elif defined(RAPIDJSON_SSE2) +#include +#elif defined(RAPIDJSON_NEON) +#include #endif #ifdef _MSC_VER @@ -32,8 +41,36 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant #endif +#ifdef __clang__ +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(padded) +RAPIDJSON_DIAG_OFF(unreachable-code) +RAPIDJSON_DIAG_OFF(c++98-compat) +#endif + RAPIDJSON_NAMESPACE_BEGIN +/////////////////////////////////////////////////////////////////////////////// +// WriteFlag + +/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS + \ingroup RAPIDJSON_CONFIG + \brief User-defined kWriteDefaultFlags definition. + + User can define this as any \c WriteFlag combinations. +*/ +#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS +#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags +#endif + +//! Combination of writeFlags +enum WriteFlag { + kWriteNoFlags = 0, //!< No flags are set. + kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. + kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN. + kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS +}; + //! JSON writer /*! Writer implements the concept Handler. It generates JSON text by events to an output os. @@ -50,11 +87,13 @@ RAPIDJSON_NAMESPACE_BEGIN \tparam StackAllocator Type of allocator for allocating memory of stack. \note implements Handler concept */ -template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator> +template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> class Writer { public: typedef typename SourceEncoding::Ch Ch; + static const int kDefaultMaxDecimalPlaces = 324; + //! Constructor /*! \param os Output stream. \param stackAllocator User supplied allocator. If it is null, it will create a private one. @@ -62,11 +101,18 @@ public: */ explicit Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : - os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), hasRoot_(false) {} + os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} explicit Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : - os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), hasRoot_(false) {} + os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} + +#if RAPIDJSON_HAS_CXX11_RVALUE_REFS + Writer(Writer&& rhs) : + os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) { + rhs.os_ = 0; + } +#endif //! Reset the writer with a new stream. /*! @@ -100,29 +146,66 @@ public: return hasRoot_ && level_stack_.Empty(); } + int GetMaxDecimalPlaces() const { + return maxDecimalPlaces_; + } + + //! Sets the maximum number of decimal places for double output. + /*! + This setting truncates the output with specified number of decimal places. + + For example, + + \code + writer.SetMaxDecimalPlaces(3); + writer.StartArray(); + writer.Double(0.12345); // "0.123" + writer.Double(0.0001); // "0.0" + writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent) + writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent) + writer.EndArray(); + \endcode + + The default setting does not truncate any decimal places. You can restore to this setting by calling + \code + writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces); + \endcode + */ + void SetMaxDecimalPlaces(int maxDecimalPlaces) { + maxDecimalPlaces_ = maxDecimalPlaces; + } + /*!@name Implementation of Handler \see Handler */ //@{ - bool Null() { Prefix(kNullType); return WriteNull(); } - bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return WriteBool(b); } - bool Int(int i) { Prefix(kNumberType); return WriteInt(i); } - bool Uint(unsigned u) { Prefix(kNumberType); return WriteUint(u); } - bool Int64(int64_t i64) { Prefix(kNumberType); return WriteInt64(i64); } - bool Uint64(uint64_t u64) { Prefix(kNumberType); return WriteUint64(u64); } + bool Null() { Prefix(kNullType); return EndValue(WriteNull()); } + bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); } + bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); } + bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); } + bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); } + bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); } //! Writes the given \c double value to the stream /*! \param d The value to be written. \return Whether it is succeed. */ - bool Double(double d) { Prefix(kNumberType); return WriteDouble(d); } + bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); } + + bool RawNumber(const Ch* str, SizeType length, bool copy = false) { + RAPIDJSON_ASSERT(str != 0); + (void)copy; + Prefix(kNumberType); + return EndValue(WriteString(str, length)); + } bool String(const Ch* str, SizeType length, bool copy = false) { + RAPIDJSON_ASSERT(str != 0); (void)copy; Prefix(kStringType); - return WriteString(str, length); + return EndValue(WriteString(str, length)); } #if RAPIDJSON_HAS_STDSTRING @@ -138,16 +221,21 @@ public: } bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } + +#if RAPIDJSON_HAS_STDSTRING + bool Key(const std::basic_string& str) + { + return Key(str.data(), SizeType(str.size())); + } +#endif bool EndObject(SizeType memberCount = 0) { (void)memberCount; - RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); - RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); + RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object + RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); // currently inside an Array, not Object + RAPIDJSON_ASSERT(0 == level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value level_stack_.template Pop(1); - bool ret = WriteEndObject(); - if (level_stack_.Empty()) // end of json text - os_->Flush(); - return ret; + return EndValue(WriteEndObject()); } bool StartArray() { @@ -161,10 +249,7 @@ public: RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); level_stack_.template Pop(1); - bool ret = WriteEndArray(); - if (level_stack_.Empty()) // end of json text - os_->Flush(); - return ret; + return EndValue(WriteEndArray()); } //@} @@ -172,11 +257,33 @@ public: //@{ //! Simpler but slower overload. - bool String(const Ch* str) { return String(str, internal::StrLen(str)); } - bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } - + bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); } + bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); } + //@} + //! Write a raw JSON value. + /*! + For user to write a stringified JSON as a value. + + \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. + \param length Length of the json. + \param type Type of the root of json. + */ + bool RawValue(const Ch* json, size_t length, Type type) { + RAPIDJSON_ASSERT(json != 0); + Prefix(type); + return EndValue(WriteRawValue(json, length)); + } + + //! Flush the output stream. + /*! + Allows the user to flush the output stream immediately. + */ + void Flush() { + os_->Flush(); + } + protected: //! Information for each nested level struct Level { @@ -188,15 +295,18 @@ protected: static const size_t kDefaultLevelDepth = 32; bool WriteNull() { - os_->Put('n'); os_->Put('u'); os_->Put('l'); os_->Put('l'); return true; + PutReserve(*os_, 4); + PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; } bool WriteBool(bool b) { if (b) { - os_->Put('t'); os_->Put('r'); os_->Put('u'); os_->Put('e'); + PutReserve(*os_, 4); + PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e'); } else { - os_->Put('f'); os_->Put('a'); os_->Put('l'); os_->Put('s'); os_->Put('e'); + PutReserve(*os_, 5); + PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e'); } return true; } @@ -204,45 +314,69 @@ protected: bool WriteInt(int i) { char buffer[11]; const char* end = internal::i32toa(i, buffer); + PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) - os_->Put(*p); + PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteUint(unsigned u) { char buffer[10]; const char* end = internal::u32toa(u, buffer); + PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) - os_->Put(*p); + PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteInt64(int64_t i64) { char buffer[21]; const char* end = internal::i64toa(i64, buffer); + PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) - os_->Put(*p); + PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteUint64(uint64_t u64) { char buffer[20]; char* end = internal::u64toa(u64, buffer); + PutReserve(*os_, static_cast(end - buffer)); for (char* p = buffer; p != end; ++p) - os_->Put(*p); + PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteDouble(double d) { + if (internal::Double(d).IsNanOrInf()) { + if (!(writeFlags & kWriteNanAndInfFlag)) + return false; + if (internal::Double(d).IsNan()) { + PutReserve(*os_, 3); + PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); + return true; + } + if (internal::Double(d).Sign()) { + PutReserve(*os_, 9); + PutUnsafe(*os_, '-'); + } + else + PutReserve(*os_, 8); + PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); + PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); + return true; + } + char buffer[25]; - char* end = internal::dtoa(d, buffer); + char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); + PutReserve(*os_, static_cast(end - buffer)); for (char* p = buffer; p != end; ++p) - os_->Put(*p); + PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteString(const Ch* str, SizeType length) { - static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; + static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static const char escape[256] = { #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //0 1 2 3 4 5 6 7 8 9 A B C D E F @@ -255,22 +389,27 @@ protected: #undef Z16 }; - os_->Put('\"'); + if (TargetEncoding::supportUnicode) + PutReserve(*os_, 2 + length * 6); // "\uxxxx..." + else + PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..." + + PutUnsafe(*os_, '\"'); GenericStringStream is(str); - while (is.Tell() < length) { + while (ScanWriteUnescapedString(is, length)) { const Ch c = is.Peek(); - if (!TargetEncoding::supportUnicode && (unsigned)c >= 0x80) { + if (!TargetEncoding::supportUnicode && static_cast(c) >= 0x80) { // Unicode escaping unsigned codepoint; - if (!SourceEncoding::Decode(is, &codepoint)) + if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) return false; - os_->Put('\\'); - os_->Put('u'); + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, 'u'); if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { - os_->Put(hexDigits[(codepoint >> 12) & 15]); - os_->Put(hexDigits[(codepoint >> 8) & 15]); - os_->Put(hexDigits[(codepoint >> 4) & 15]); - os_->Put(hexDigits[(codepoint ) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(codepoint ) & 15]); } else { RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); @@ -278,45 +417,59 @@ protected: unsigned s = codepoint - 0x010000; unsigned lead = (s >> 10) + 0xD800; unsigned trail = (s & 0x3FF) + 0xDC00; - os_->Put(hexDigits[(lead >> 12) & 15]); - os_->Put(hexDigits[(lead >> 8) & 15]); - os_->Put(hexDigits[(lead >> 4) & 15]); - os_->Put(hexDigits[(lead ) & 15]); - os_->Put('\\'); - os_->Put('u'); - os_->Put(hexDigits[(trail >> 12) & 15]); - os_->Put(hexDigits[(trail >> 8) & 15]); - os_->Put(hexDigits[(trail >> 4) & 15]); - os_->Put(hexDigits[(trail ) & 15]); + PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(lead ) & 15]); + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, 'u'); + PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); + PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]); + PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]); + PutUnsafe(*os_, hexDigits[(trail ) & 15]); } } - else if ((sizeof(Ch) == 1 || (unsigned)c < 256) && escape[(unsigned char)c]) { + else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast(c)])) { is.Take(); - os_->Put('\\'); - os_->Put(escape[(unsigned char)c]); - if (escape[(unsigned char)c] == 'u') { - os_->Put('0'); - os_->Put('0'); - os_->Put(hexDigits[(unsigned char)c >> 4]); - os_->Put(hexDigits[(unsigned char)c & 0xF]); + PutUnsafe(*os_, '\\'); + PutUnsafe(*os_, static_cast(escape[static_cast(c)])); + if (escape[static_cast(c)] == 'u') { + PutUnsafe(*os_, '0'); + PutUnsafe(*os_, '0'); + PutUnsafe(*os_, hexDigits[static_cast(c) >> 4]); + PutUnsafe(*os_, hexDigits[static_cast(c) & 0xF]); } } - else - if (!Transcoder::Transcode(is, *os_)) - return false; + else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? + Transcoder::Validate(is, *os_) : + Transcoder::TranscodeUnsafe(is, *os_)))) + return false; } - os_->Put('\"'); + PutUnsafe(*os_, '\"'); return true; } + bool ScanWriteUnescapedString(GenericStringStream& is, size_t length) { + return RAPIDJSON_LIKELY(is.Tell() < length); + } + bool WriteStartObject() { os_->Put('{'); return true; } bool WriteEndObject() { os_->Put('}'); return true; } bool WriteStartArray() { os_->Put('['); return true; } bool WriteEndArray() { os_->Put(']'); return true; } + bool WriteRawValue(const Ch* json, size_t length) { + PutReserve(*os_, length); + for (size_t i = 0; i < length; i++) { + RAPIDJSON_ASSERT(json[i] != '\0'); + PutUnsafe(*os_, json[i]); + } + return true; + } + void Prefix(Type type) { (void)type; - if (level_stack_.GetSize() != 0) { // this value is not at root + if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root Level* level = level_stack_.template Top(); if (level->valueCount > 0) { if (level->inArray) @@ -334,8 +487,16 @@ protected: } } + // Flush the value if it is the top level one. + bool EndValue(bool ret) { + if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text + Flush(); + return ret; + } + OutputStream* os_; internal::Stack level_stack_; + int maxDecimalPlaces_; bool hasRoot_; private: @@ -350,7 +511,7 @@ template<> inline bool Writer::WriteInt(int i) { char *buffer = os_->Push(11); const char* end = internal::i32toa(i, buffer); - os_->Pop(11 - (end - buffer)); + os_->Pop(static_cast(11 - (end - buffer))); return true; } @@ -358,7 +519,7 @@ template<> inline bool Writer::WriteUint(unsigned u) { char *buffer = os_->Push(10); const char* end = internal::u32toa(u, buffer); - os_->Pop(10 - (end - buffer)); + os_->Pop(static_cast(10 - (end - buffer))); return true; } @@ -366,7 +527,7 @@ template<> inline bool Writer::WriteInt64(int64_t i64) { char *buffer = os_->Push(21); const char* end = internal::i64toa(i64, buffer); - os_->Pop(21 - (end - buffer)); + os_->Pop(static_cast(21 - (end - buffer))); return true; } @@ -374,22 +535,177 @@ template<> inline bool Writer::WriteUint64(uint64_t u) { char *buffer = os_->Push(20); const char* end = internal::u64toa(u, buffer); - os_->Pop(20 - (end - buffer)); + os_->Pop(static_cast(20 - (end - buffer))); return true; } template<> inline bool Writer::WriteDouble(double d) { + if (internal::Double(d).IsNanOrInf()) { + // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). + if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) + return false; + if (internal::Double(d).IsNan()) { + PutReserve(*os_, 3); + PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); + return true; + } + if (internal::Double(d).Sign()) { + PutReserve(*os_, 9); + PutUnsafe(*os_, '-'); + } + else + PutReserve(*os_, 8); + PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); + PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); + return true; + } + char *buffer = os_->Push(25); - char* end = internal::dtoa(d, buffer); - os_->Pop(25 - (end - buffer)); + char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); + os_->Pop(static_cast(25 - (end - buffer))); return true; } +#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) +template<> +inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { + if (length < 16) + return RAPIDJSON_LIKELY(is.Tell() < length); + + if (!RAPIDJSON_LIKELY(is.Tell() < length)) + return false; + + const char* p = is.src_; + const char* end = is.head_ + length; + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); + if (nextAligned > end) + return true; + + while (p != nextAligned) + if (*p < 0x20 || *p == '\"' || *p == '\\') { + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); + } + else + os_->PutUnsafe(*p++); + + // The rest of string using SIMD + static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; + static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; + static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; + const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); + const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); + const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); + + for (; p != endAligned; p += 16) { + const __m128i s = _mm_load_si128(reinterpret_cast(p)); + const __m128i t1 = _mm_cmpeq_epi8(s, dq); + const __m128i t2 = _mm_cmpeq_epi8(s, bs); + const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F + const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); + unsigned short r = static_cast(_mm_movemask_epi8(x)); + if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped + SizeType len; +#ifdef _MSC_VER // Find the index of first escaped + unsigned long offset; + _BitScanForward(&offset, r); + len = offset; +#else + len = static_cast(__builtin_ffs(r) - 1); +#endif + char* q = reinterpret_cast(os_->PushUnsafe(len)); + for (size_t i = 0; i < len; i++) + q[i] = p[i]; + + p += len; + break; + } + _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s); + } + + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); +} +#elif defined(RAPIDJSON_NEON) +template<> +inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { + if (length < 16) + return RAPIDJSON_LIKELY(is.Tell() < length); + + if (!RAPIDJSON_LIKELY(is.Tell() < length)) + return false; + + const char* p = is.src_; + const char* end = is.head_ + length; + const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); + const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); + if (nextAligned > end) + return true; + + while (p != nextAligned) + if (*p < 0x20 || *p == '\"' || *p == '\\') { + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); + } + else + os_->PutUnsafe(*p++); + + // The rest of string using SIMD + const uint8x16_t s0 = vmovq_n_u8('"'); + const uint8x16_t s1 = vmovq_n_u8('\\'); + const uint8x16_t s2 = vmovq_n_u8('\b'); + const uint8x16_t s3 = vmovq_n_u8(32); + + for (; p != endAligned; p += 16) { + const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); + uint8x16_t x = vceqq_u8(s, s0); + x = vorrq_u8(x, vceqq_u8(s, s1)); + x = vorrq_u8(x, vceqq_u8(s, s2)); + x = vorrq_u8(x, vcltq_u8(s, s3)); + + x = vrev64q_u8(x); // Rev in 64 + uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract + uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract + + SizeType len = 0; + bool escaped = false; + if (low == 0) { + if (high != 0) { + unsigned lz = (unsigned)__builtin_clzll(high); + len = 8 + (lz >> 3); + escaped = true; + } + } else { + unsigned lz = (unsigned)__builtin_clzll(low); + len = lz >> 3; + escaped = true; + } + if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped + char* q = reinterpret_cast(os_->PushUnsafe(len)); + for (size_t i = 0; i < len; i++) + q[i] = p[i]; + + p += len; + break; + } + vst1q_u8(reinterpret_cast(os_->PushUnsafe(16)), s); + } + + is.src_ = p; + return RAPIDJSON_LIKELY(is.Tell() < length); +} +#endif // RAPIDJSON_NEON + RAPIDJSON_NAMESPACE_END #ifdef _MSC_VER RAPIDJSON_DIAG_POP #endif +#ifdef __clang__ +RAPIDJSON_DIAG_POP +#endif + #endif // RAPIDJSON_RAPIDJSON_H_ diff --git a/contrib/rapidjson/license.txt b/contrib/rapidjson/license.txt index 879293afa..7ccc161c8 100644 --- a/contrib/rapidjson/license.txt +++ b/contrib/rapidjson/license.txt @@ -3,7 +3,7 @@ Tencent is pleased to support the open source community by making RapidJSON avai Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License. -If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. +If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. To avoid the problematic JSON license in your own projects, it's sufficient to exclude the bin/jsonchecker/ directory, as it's the only code under the JSON license. A copy of the MIT License is included in this file. Other dependencies and licenses: diff --git a/contrib/rapidjson/readme.md b/contrib/rapidjson/readme.md index 19da38667..b833a98e8 100644 --- a/contrib/rapidjson/readme.md +++ b/contrib/rapidjson/readme.md @@ -1,17 +1,17 @@ -![](doc/logo/rapidjson.png) +![RapidJSON logo](doc/logo/rapidjson.png) -![](https://img.shields.io/badge/release-v1.0.2-blue.png) +![Release version](https://img.shields.io/badge/release-v1.1.0-blue.svg) -## A fast JSON parser/generator for C++ with both SAX/DOM style API +## A fast JSON parser/generator for C++ with both SAX/DOM style API Tencent is pleased to support the open source community by making RapidJSON available. Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. -* [RapidJSON GitHub](https://github.com/miloyip/rapidjson/) +* [RapidJSON GitHub](https://github.com/Tencent/rapidjson/) * RapidJSON Documentation - * [English](http://miloyip.github.io/rapidjson/) - * [简体中文](http://miloyip.github.io/rapidjson/zh-cn/) + * [English](http://rapidjson.org/) + * [简体中文](http://rapidjson.org/zh-cn/) * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference. ## Build status @@ -20,33 +20,43 @@ Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights | :---------------: | :-----------------: | :-------------------: | | ![lin-badge] | ![win-badge] | ![cov-badge] | -[lin-badge]: https://travis-ci.org/miloyip/rapidjson.png?branch=master "Travis build status" -[lin-link]: https://travis-ci.org/miloyip/rapidjson "Travis build status" -[win-badge]: https://ci.appveyor.com/api/projects/status/u658dcuwxo14a8m9/branch/master "AppVeyor build status" -[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson/branch/master "AppVeyor build status" -[cov-badge]: https://coveralls.io/repos/miloyip/rapidjson/badge.png?branch=master -[cov-link]: https://coveralls.io/r/miloyip/rapidjson?branch=master +[lin-badge]: https://travis-ci.org/Tencent/rapidjson.svg?branch=master "Travis build status" +[lin-link]: https://travis-ci.org/Tencent/rapidjson "Travis build status" +[win-badge]: https://ci.appveyor.com/api/projects/status/l6qulgqahcayidrf/branch/master?svg=true "AppVeyor build status" +[win-link]: https://ci.appveyor.com/project/miloyip/rapidjson-0fdqj/branch/master "AppVeyor build status" +[cov-badge]: https://coveralls.io/repos/Tencent/rapidjson/badge.svg?branch=master "Coveralls coverage" +[cov-link]: https://coveralls.io/r/Tencent/rapidjson?branch=master "Coveralls coverage" ## Introduction RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml](http://rapidxml.sourceforge.net/). -* RapidJSON is small but complete. It supports both SAX and DOM style API. The SAX parser is only a half thousand lines of code. +* RapidJSON is **small** but **complete**. It supports both SAX and DOM style API. The SAX parser is only a half thousand lines of code. -* RapidJSON is fast. Its performance can be comparable to `strlen()`. It also optionally supports SSE2/SSE4.2 for acceleration. +* RapidJSON is **fast**. Its performance can be comparable to `strlen()`. It also optionally supports SSE2/SSE4.2 for acceleration. -* RapidJSON is self-contained. It does not depend on external libraries such as BOOST. It even does not depend on STL. +* RapidJSON is **self-contained** and **header-only**. It does not depend on external libraries such as BOOST. It even does not depend on STL. -* RapidJSON is memory friendly. Each JSON value occupies exactly 16/20 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing. +* RapidJSON is **memory-friendly**. Each JSON value occupies exactly 16 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing. -* RapidJSON is Unicode friendly. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validation and transcoding internally. For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character). +* RapidJSON is **Unicode-friendly**. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validation and transcoding internally. For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character). More features can be read [here](doc/features.md). -JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in fully compliance with RFC7159/ECMA-404. More information about JSON can be obtained at +JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in fully compliance with RFC7159/ECMA-404, with optional support of relaxed syntax. More information about JSON can be obtained at * [Introducing JSON](http://json.org/) -* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](http://www.ietf.org/rfc/rfc7159.txt) -* [Standard ECMA-404: The JSON Data Interchange Format](http://www.ecma-international.org/publications/standards/Ecma-404.htm) +* [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc7159) +* [Standard ECMA-404: The JSON Data Interchange Format](https://www.ecma-international.org/publications/standards/Ecma-404.htm) + +## Highlights in v1.1 (2016-8-25) + +* Added [JSON Pointer](doc/pointer.md) +* Added [JSON Schema](doc/schema.md) +* Added [relaxed JSON syntax](doc/dom.md) (comment, trailing comma, NaN/Infinity) +* Iterating array/object with [C++11 Range-based for loop](doc/tutorial.md) +* Reduce memory overhead of each `Value` from 24 bytes to 16 bytes in x86-64 architecture. + +For other changes please refer to [change log](CHANGELOG.md). ## Compatibility @@ -63,9 +73,9 @@ Users can build and run the unit tests on their platform/compiler. RapidJSON is a header-only C++ library. Just copy the `include/rapidjson` folder to system or project's include path. RapidJSON uses following software as its dependencies: -* [CMake](http://www.cmake.org) as a general build tool -* (optional)[Doxygen](http://www.doxygen.org) to build documentation -* (optional)[googletest](https://code.google.com/p/googletest/) for unit and performance testing +* [CMake](https://cmake.org/) as a general build tool +* (optional) [Doxygen](http://www.doxygen.org) to build documentation +* (optional) [googletest](https://github.com/google/googletest) for unit and performance testing To generate user documentation and run tests please proceed with the steps below: @@ -74,7 +84,7 @@ To generate user documentation and run tests please proceed with the steps below 3. Change to `build` directory and run `cmake ..` command to configure your build. Windows users can do the same with cmake-gui application. 4. On Windows, build the solution found in the build directory. On Linux, run `make` from the build directory. -On successfull build you will find compiled test and example binaries in `bin` +On successful build you will find compiled test and example binaries in `bin` directory. The generated documentation will be available in `doc/html` directory of the build tree. To run tests after finished build please run `make test` or `ctest` from your build tree. You can get detailed output using `ctest @@ -126,4 +136,25 @@ The following diagram shows the process. ![simpledom](doc/diagram/simpledom.png) -More [examples](https://github.com/miloyip/rapidjson/tree/master/example) are available. +More [examples](https://github.com/Tencent/rapidjson/tree/master/example) are available: + +* DOM API + * [tutorial](https://github.com/Tencent/rapidjson/blob/master/example/tutorial/tutorial.cpp): Basic usage of DOM API. + +* SAX API + * [simplereader](https://github.com/Tencent/rapidjson/blob/master/example/simplereader/simplereader.cpp): Dumps all SAX events while parsing a JSON by `Reader`. + * [condense](https://github.com/Tencent/rapidjson/blob/master/example/condense/condense.cpp): A command line tool to rewrite a JSON, with all whitespaces removed. + * [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp): A command line tool to rewrite a JSON with indents and newlines by `PrettyWriter`. + * [capitalize](https://github.com/Tencent/rapidjson/blob/master/example/capitalize/capitalize.cpp): A command line tool to capitalize strings in JSON. + * [messagereader](https://github.com/Tencent/rapidjson/blob/master/example/messagereader/messagereader.cpp): Parse a JSON message with SAX API. + * [serialize](https://github.com/Tencent/rapidjson/blob/master/example/serialize/serialize.cpp): Serialize a C++ object into JSON with SAX API. + * [jsonx](https://github.com/Tencent/rapidjson/blob/master/example/jsonx/jsonx.cpp): Implements a `JsonxWriter` which stringify SAX events into [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html) (a kind of XML) format. The example is a command line tool which converts input JSON into JSONx format. + +* Schema + * [schemavalidator](https://github.com/Tencent/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp) : A command line tool to validate a JSON with a JSON schema. + +* Advanced + * [prettyauto](https://github.com/Tencent/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): A modified version of [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp) to automatically handle JSON with any UTF encodings. + * [parsebyparts](https://github.com/Tencent/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): Implements an `AsyncDocumentParser` which can parse JSON in parts, using C++11 thread. + * [filterkey](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): A command line tool to remove all values with user-specified key. + * [filterkeydom](https://github.com/Tencent/rapidjson/blob/master/example/filterkeydom/filterkeydom.cpp): Same tool as above, but it demonstrates how to use a generator to populate a `Document`. diff --git a/contrib/unzip/crypt.h b/contrib/unzip/crypt.h index 622f4bc2e..2aa99c284 100644 --- a/contrib/unzip/crypt.h +++ b/contrib/unzip/crypt.h @@ -32,7 +32,7 @@ /*********************************************************************** * Return the next byte in the pseudo-random sequence */ -static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) +static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab) { unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an * unpredictable manner on 16-bit systems; not a problem @@ -45,7 +45,7 @@ static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) /*********************************************************************** * Update the encryption keys with the next byte of plain text */ -static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) +static int update_keys(unsigned long* pkeys,const z_crc_t* pcrc_32_tab,int c) { (*(pkeys+0)) = CRC32((*(pkeys+0)), c); (*(pkeys+1)) += (*(pkeys+0)) & 0xff; @@ -62,7 +62,7 @@ static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int * Initialize the encryption keys and the random header according to * the given password. */ -static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) +static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t* pcrc_32_tab) { *(pkeys+0) = 305419896L; *(pkeys+1) = 591751049L; diff --git a/contrib/unzip/ioapi.c b/contrib/unzip/ioapi.c index b7200df75..f1bee23e6 100644 --- a/contrib/unzip/ioapi.c +++ b/contrib/unzip/ioapi.c @@ -10,11 +10,7 @@ #include #include -# ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include -# else -# include "../zlib/zlib.h" -# endif +#include "zlib.h" #include "ioapi.h" @@ -33,40 +29,40 @@ #define SEEK_SET 0 #endif -voidpf ZCALLBACK fopen_file_func ( +voidpf ZCALLBACK fopen_file_func OF(( voidpf opaque, const char* filename, - int mode); + int mode)); -uLong ZCALLBACK fread_file_func ( +uLong ZCALLBACK fread_file_func OF(( voidpf opaque, voidpf stream, void* buf, - uLong size); + uLong size)); -uLong ZCALLBACK fwrite_file_func ( +uLong ZCALLBACK fwrite_file_func OF(( voidpf opaque, voidpf stream, const void* buf, - uLong size); + uLong size)); -long ZCALLBACK ftell_file_func ( +long ZCALLBACK ftell_file_func OF(( voidpf opaque, - voidpf stream); + voidpf stream)); -long ZCALLBACK fseek_file_func ( +long ZCALLBACK fseek_file_func OF(( voidpf opaque, voidpf stream, uLong offset, - int origin); + int origin)); -int ZCALLBACK fclose_file_func ( +int ZCALLBACK fclose_file_func OF(( voidpf opaque, - voidpf stream); + voidpf stream)); -int ZCALLBACK ferror_file_func ( +int ZCALLBACK ferror_file_func OF(( voidpf opaque, - voidpf stream); + voidpf stream)); voidpf ZCALLBACK fopen_file_func (opaque, filename, mode) diff --git a/contrib/unzip/ioapi.h b/contrib/unzip/ioapi.h index 06fdd15e9..7d457baab 100644 --- a/contrib/unzip/ioapi.h +++ b/contrib/unzip/ioapi.h @@ -35,13 +35,13 @@ extern "C" { #endif -typedef voidpf (ZCALLBACK *open_file_func) (voidpf opaque, const char* filename, int mode); -typedef uLong (ZCALLBACK *read_file_func) (voidpf opaque, voidpf stream, void* buf, uLong size); -typedef uLong (ZCALLBACK *write_file_func)(voidpf opaque, voidpf stream, const void* buf, uLong size); -typedef long (ZCALLBACK *tell_file_func) (voidpf opaque, voidpf stream); -typedef long (ZCALLBACK *seek_file_func) (voidpf opaque, voidpf stream, uLong offset, int origin); -typedef int (ZCALLBACK *close_file_func) (voidpf opaque, voidpf stream); -typedef int (ZCALLBACK *testerror_file_func) (voidpf opaque, voidpf stream); +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); typedef struct zlib_filefunc_def_s { @@ -57,7 +57,7 @@ typedef struct zlib_filefunc_def_s -void fill_fopen_filefunc (zlib_filefunc_def* pzlib_filefunc_def); +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); #define ZREAD(filefunc,filestream,buf,size) ((*((filefunc).zread_file))((filefunc).opaque,filestream,buf,size)) #define ZWRITE(filefunc,filestream,buf,size) ((*((filefunc).zwrite_file))((filefunc).opaque,filestream,buf,size)) diff --git a/contrib/unzip/unzip.c b/contrib/unzip/unzip.c index af00f7d6f..085d79a02 100644 --- a/contrib/unzip/unzip.c +++ b/contrib/unzip/unzip.c @@ -38,7 +38,8 @@ woven in by Terry Thorsen 1/2003. #include #include #include -#include "./unzip.h" +#include "zlib.h" +#include "unzip.h" #ifdef STDC # include @@ -146,7 +147,7 @@ typedef struct int encrypted; # ifndef NOUNCRYPT unsigned long keys[3]; /* keys defining the pseudo-random sequence */ - const unsigned long* pcrc_32_tab; + const z_crc_t* pcrc_32_tab; # endif } unz_s; @@ -162,10 +163,10 @@ typedef struct */ -local int unzlocal_getByte ( +local int unzlocal_getByte OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, - int *pi); + int *pi)); local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi) const zlib_filefunc_def* pzlib_filefunc_def; @@ -192,10 +193,10 @@ local int unzlocal_getByte(pzlib_filefunc_def,filestream,pi) /* =========================================================================== Reads a long in LSB order from the given gz_stream. Sets */ -local int unzlocal_getShort ( +local int unzlocal_getShort OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, - uLong *pX); + uLong *pX)); local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX) const zlib_filefunc_def* pzlib_filefunc_def; @@ -220,10 +221,10 @@ local int unzlocal_getShort (pzlib_filefunc_def,filestream,pX) return err; } -local int unzlocal_getLong ( +local int unzlocal_getLong OF(( const zlib_filefunc_def* pzlib_filefunc_def, voidpf filestream, - uLong *pX); + uLong *pX)); local int unzlocal_getLong (pzlib_filefunc_def,filestream,pX) const zlib_filefunc_def* pzlib_filefunc_def; @@ -323,9 +324,9 @@ extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivit Locate the Central directory of a zipfile (at the end, just before the global comment) */ -local uLong unzlocal_SearchCentralDir ( +local uLong unzlocal_SearchCentralDir OF(( const zlib_filefunc_def* pzlib_filefunc_def, - voidpf filestream); + voidpf filestream)); local uLong unzlocal_SearchCentralDir(pzlib_filefunc_def,filestream) const zlib_filefunc_def* pzlib_filefunc_def; @@ -562,7 +563,7 @@ local void unzlocal_DosDateToTmuDate (ulDosDate, ptm) /* Get Info about the current file in the zipfile, with internal only info */ -local int unzlocal_GetCurrentFileInfoInternal (unzFile file, +local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file, unz_file_info *pfile_info, unz_file_info_internal *pfile_info_internal, @@ -571,7 +572,7 @@ local int unzlocal_GetCurrentFileInfoInternal (unzFile file, void *extraField, uLong extraFieldBufferSize, char *szComment, - uLong commentBufferSize); + uLong commentBufferSize)); local int unzlocal_GetCurrentFileInfoInternal (file, pfile_info, @@ -609,9 +610,13 @@ local int unzlocal_GetCurrentFileInfoInternal (file, if (err==UNZ_OK) { if (unzlocal_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + { err=UNZ_ERRNO; + } else if (uMagic!=0x02014b50) + { err=UNZ_BADZIPFILE; + } } if (unzlocal_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) @@ -701,8 +706,9 @@ local int unzlocal_GetCurrentFileInfoInternal (file, lSeek += file_info.size_file_extra - uSizeRead; } else + { lSeek+=file_info.size_file_extra; - + } if ((err==UNZ_OK) && (szComment!=NULL)) { @@ -713,7 +719,9 @@ local int unzlocal_GetCurrentFileInfoInternal (file, uSizeRead = file_info.size_file_comment; } else + { uSizeRead = commentBufferSize; + } if (lSeek!=0) { @@ -728,7 +736,9 @@ local int unzlocal_GetCurrentFileInfoInternal (file, lSeek+=file_info.size_file_comment - uSizeRead; } else + { lSeek+=file_info.size_file_comment; + } if ((err==UNZ_OK) && (pfile_info!=NULL)) *pfile_info=file_info; @@ -988,7 +998,7 @@ local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar, else if (uMagic!=0x04034b50) err=UNZ_BADZIPFILE; } - + if (unzlocal_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) err=UNZ_ERRNO; /* @@ -1541,6 +1551,7 @@ extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf) char *szComment; uLong uSizeBuf; { + int err=UNZ_OK; unz_s* s; uLong uReadThis ; if (file==NULL) diff --git a/contrib/unzip/unzip.h b/contrib/unzip/unzip.h index e3b7f24ee..b247937c8 100644 --- a/contrib/unzip/unzip.h +++ b/contrib/unzip/unzip.h @@ -50,11 +50,7 @@ extern "C" { #endif #ifndef _ZLIB_H -# ifdef ASSIMP_BUILD_NO_OWN_ZLIB -# include -# else -# include "../zlib/zlib.h" -# endif +#include "zlib.h" #endif #ifndef _ZLIBIOAPI_H @@ -123,9 +119,9 @@ typedef struct unz_file_info_s tm_unz tmu_date; } unz_file_info; -extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, const char* fileName2, - int iCaseSensitivity); + int iCaseSensitivity)); /* Compare two filename (fileName1,fileName2). If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) @@ -136,7 +132,7 @@ extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, */ -extern unzFile ZEXPORT unzOpen (const char *path); +extern unzFile ZEXPORT unzOpen OF((const char *path)); /* Open a Zip file. path contain the full pathname (by example, on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer @@ -147,31 +143,31 @@ extern unzFile ZEXPORT unzOpen (const char *path); of this unzip package. */ -extern unzFile ZEXPORT unzOpen2 (const char *path, - zlib_filefunc_def* pzlib_filefunc_def); +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); /* Open a Zip file, like unzOpen, but provide a set of file low level API for read/write the zip file (see ioapi.h) */ -extern int ZEXPORT unzClose (unzFile file); +extern int ZEXPORT unzClose OF((unzFile file)); /* Close a ZipFile opened with unzipOpen. If there is files inside the .Zip opened with unzOpenCurrentFile (see later), these files MUST be closed with unzipCloseCurrentFile before call unzipClose. return UNZ_OK if there is no problem. */ -extern int ZEXPORT unzGetGlobalInfo (unzFile file, - unz_global_info *pglobal_info); +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); /* Write info about the ZipFile in the *pglobal_info structure. No preparation of the structure is needed return UNZ_OK if there is no problem. */ -extern int ZEXPORT unzGetGlobalComment (unzFile file, +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, char *szComment, - uLong uSizeBuf); + uLong uSizeBuf)); /* Get the global comment string of the ZipFile, in the szComment buffer. uSizeBuf is the size of the szComment buffer. @@ -182,22 +178,22 @@ extern int ZEXPORT unzGetGlobalComment (unzFile file, /***************************************************************************/ /* Unzip package allow you browse the directory of the zipfile */ -extern int ZEXPORT unzGoToFirstFile (unzFile file); +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); /* Set the current file of the zipfile to the first file. return UNZ_OK if there is no problem */ -extern int ZEXPORT unzGoToNextFile (unzFile file); +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); /* Set the current file of the zipfile to the next file. return UNZ_OK if there is no problem return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. */ -extern int ZEXPORT unzLocateFile (unzFile file, +extern int ZEXPORT unzLocateFile OF((unzFile file, const char *szFileName, - int iCaseSensitivity); + int iCaseSensitivity)); /* Try locate the file szFileName in the zipfile. For the iCaseSensitivity signification, see unzStringFileNameCompare @@ -227,14 +223,14 @@ extern int ZEXPORT unzGoToFilePos( /* ****************************************** */ -extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, unz_file_info *pfile_info, char *szFileName, uLong fileNameBufferSize, void *extraField, uLong extraFieldBufferSize, char *szComment, - uLong commentBufferSize); + uLong commentBufferSize)); /* Get Info about the current file if pfile_info!=NULL, the *pfile_info structure will contain somes info about @@ -253,24 +249,24 @@ extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, from it, and close it (you can close it before reading all the file) */ -extern int ZEXPORT unzOpenCurrentFile (unzFile file); +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); /* Open for reading data the current file in the zipfile. If there is no error, the return value is UNZ_OK. */ -extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, - const char* password); +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); /* Open for reading data the current file in the zipfile. password is a crypting password If there is no error, the return value is UNZ_OK. */ -extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, int* method, int* level, - int raw); + int raw)); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 @@ -280,11 +276,11 @@ extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, but you CANNOT set method parameter as NULL */ -extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, int* method, int* level, int raw, - const char* password); + const char* password)); /* Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) if raw==1 @@ -295,15 +291,15 @@ extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, */ -extern int ZEXPORT unzCloseCurrentFile (unzFile file); +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); /* Close the file in zip opened with unzOpenCurrentFile Return UNZ_CRCERROR if all the file was read but the CRC is not good */ -extern int ZEXPORT unzReadCurrentFile (unzFile file, +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, voidp buf, - unsigned len); + unsigned len)); /* Read bytes from the current file (opened by unzOpenCurrentFile) buf contain buffer where data must be copied @@ -315,19 +311,19 @@ extern int ZEXPORT unzReadCurrentFile (unzFile file, (UNZ_ERRNO for IO error, or zLib error for uncompress error) */ -extern z_off_t ZEXPORT unztell (unzFile file); +extern z_off_t ZEXPORT unztell OF((unzFile file)); /* Give the current position in uncompressed data */ -extern int ZEXPORT unzeof (unzFile file); +extern int ZEXPORT unzeof OF((unzFile file)); /* return 1 if the end of file was reached, 0 elsewhere */ -extern int ZEXPORT unzGetLocalExtrafield (unzFile file, +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, voidp buf, - unsigned len); + unsigned len)); /* Read extra field from the current file (opened by unzOpenCurrentFile) This is the local-header version of the extra field (sometimes, there is diff --git a/contrib/utf8cpp/doc/ReleaseNotes b/contrib/utf8cpp/doc/ReleaseNotes new file mode 100644 index 000000000..364411a23 --- /dev/null +++ b/contrib/utf8cpp/doc/ReleaseNotes @@ -0,0 +1,12 @@ +utf8 cpp library +Release 2.3.4 + +A minor bug fix release. Thanks to all who reported bugs. + +Note: Version 2.3.3 contained a regression, and therefore was removed. + +Changes from version 2.3.2 +- Bug fix [39]: checked.h Line 273 and unchecked.h Line 182 have an extra ';' +- Bug fix [36]: replace_invalid() only works with back_inserter + +Files included in the release: utf8.h, core.h, checked.h, unchecked.h, utf8cpp.html, ReleaseNotes diff --git a/contrib/utf8cpp/doc/utf8cpp.html b/contrib/utf8cpp/doc/utf8cpp.html new file mode 100644 index 000000000..6f2aacbe7 --- /dev/null +++ b/contrib/utf8cpp/doc/utf8cpp.html @@ -0,0 +1,1789 @@ + + + + + + + + + UTF8-CPP: UTF-8 with C++ in a Portable Way + + + + +

+ UTF8-CPP: UTF-8 with C++ in a Portable Way +

+

+ The Sourceforge project page +

+ +

+ Introduction +

+

+ Many C++ developers miss an easy and portable way of handling Unicode encoded + strings. The original C++ Standard (known as C++98 or C++03) is Unicode agnostic. + C++11 provides some support for Unicode on core language and library level: + u8, u, and U character and string literals, char16_t and char32_t character types, + u16string and u32string library classes, and codecvt support for conversions + between Unicode encoding forms. + In the meantime, developers use third party libraries like ICU, OS specific capabilities, or simply + roll out their own solutions. +

+

+ In order to easily handle UTF-8 encoded Unicode strings, I came up with a small + generic library. For anybody used to work with STL algorithms and iterators, it should be + easy and natural to use. The code is freely available for any purpose - check out + the license at the beginning of the utf8.h file. If you run into + bugs or performance issues, please let me know and I'll do my best to address them. +

+

+ The purpose of this article is not to offer an introduction to Unicode in general, + and UTF-8 in particular. If you are not familiar with Unicode, be sure to check out + Unicode Home Page or some other source of + information for Unicode. Also, it is not my aim to advocate the use of UTF-8 + encoded strings in C++ programs; if you want to handle UTF-8 encoded strings from + C++, I am sure you have good reasons for it. +

+

+ Examples of use +

+

+ Introductionary Sample +

+

+ To illustrate the use of the library, let's start with a small but complete program + that opens a file containing UTF-8 encoded text, reads it line by line, checks each line + for invalid UTF-8 byte sequences, and converts it to UTF-16 encoding and back to UTF-8: +

+
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+#include "utf8.h"
+using namespace std;
+int main(int argc, char** argv)
+{
+    if (argc != 2) {
+        cout << "\nUsage: docsample filename\n";
+        return 0;
+    }
+
+    const char* test_file_path = argv[1];
+    // Open the test file (contains UTF-8 encoded text)
+    ifstream fs8(test_file_path);
+    if (!fs8.is_open()) {
+    cout << "Could not open " << test_file_path << endl;
+    return 0;
+    }
+
+    unsigned line_count = 1;
+    string line;
+    // Play with all the lines in the file
+    while (getline(fs8, line)) {
+       // check for invalid utf-8 (for a simple yes/no check, there is also utf8::is_valid function)
+        string::iterator end_it = utf8::find_invalid(line.begin(), line.end());
+        if (end_it != line.end()) {
+            cout << "Invalid UTF-8 encoding detected at line " << line_count << "\n";
+            cout << "This part is fine: " << string(line.begin(), end_it) << "\n";
+        }
+
+        // Get the line length (at least for the valid part)
+        int length = utf8::distance(line.begin(), end_it);
+        cout << "Length of line " << line_count << " is " << length <<  "\n";
+
+        // Convert it to utf-16
+        vector<unsigned short> utf16line;
+        utf8::utf8to16(line.begin(), end_it, back_inserter(utf16line));
+
+        // And back to utf-8
+        string utf8line; 
+        utf8::utf16to8(utf16line.begin(), utf16line.end(), back_inserter(utf8line));
+
+        // Confirm that the conversion went OK:
+        if (utf8line != string(line.begin(), end_it))
+            cout << "Error in UTF-16 conversion at line: " << line_count << "\n";        
+
+        line_count++;
+    }
+    return 0;
+}
+
+

+ In the previous code sample, for each line we performed + a detection of invalid UTF-8 sequences with find_invalid; the number + of characters (more precisely - the number of Unicode code points, including the end + of line and even BOM if there is one) in each line was + determined with a use of utf8::distance; finally, we have converted + each line to UTF-16 encoding with utf8to16 and back to UTF-8 with + utf16to8. +

+

Checking if a file contains valid UTF-8 text

+

+Here is a function that checks whether the content of a file is valid UTF-8 encoded text without +reading the content into the memory: +

+
    
+bool valid_utf8_file(iconst char* file_name)
+{
+    ifstream ifs(file_name);
+    if (!ifs)
+        return false; // even better, throw here
+
+    istreambuf_iterator<char> it(ifs.rdbuf());
+    istreambuf_iterator<char> eos;
+
+    return utf8::is_valid(it, eos);
+}
+
+

+Because the function utf8::is_valid() works with input iterators, we were able +to pass an istreambuf_iterator to it and read the content of the file directly +without loading it to the memory first.

+

+Note that other functions that take input iterator arguments can be used in a similar way. For +instance, to read the content of a UTF-8 encoded text file and convert the text to UTF-16, just +do something like: +

+
+    utf8::utf8to16(it, eos, back_inserter(u16string));
+
+

Ensure that a string contains valid UTF-8 text

+

+If we have some text that "probably" contains UTF-8 encoded text and we want to +replace any invalid UTF-8 sequence with a replacement character, something like +the following function may be used: +

+
+void fix_utf8_string(std::string& str)
+{
+    std::string temp;
+    utf8::replace_invalid(str.begin(), str.end(), back_inserter(temp));
+    str = temp;
+}
+
+

The function will replace any invalid UTF-8 sequence with a Unicode replacement character. +There is an overloaded function that enables the caller to supply their own replacement character. +

+

+ Reference +

+

+ Functions From utf8 Namespace +

+

+ utf8::append +

+

+ Available in version 1.0 and later. +

+

+ Encodes a 32 bit code point as a UTF-8 sequence of octets and appends the sequence + to a UTF-8 string. +

+
+template <typename octet_iterator>
+octet_iterator append(uint32_t cp, octet_iterator result);
+   
+
+

+ octet_iterator: an output iterator.
+ cp: a 32 bit integer representing a code point to append to the + sequence.
+ result: an output iterator to the place in the sequence where to + append the code point.
+ Return value: an iterator pointing to the place + after the newly appended sequence. +

+

+ Example of use: +

+
+unsigned char u[5] = {0,0,0,0,0};
+unsigned char* end = append(0x0448, u);
+assert (u[0] == 0xd1 && u[1] == 0x88 && u[2] == 0 && u[3] == 0 && u[4] == 0);
+
+

+ Note that append does not allocate any memory - it is the burden of + the caller to make sure there is enough memory allocated for the operation. To make + things more interesting, append can add anywhere between 1 and 4 + octets to the sequence. In practice, you would most often want to use + std::back_inserter to ensure that the necessary memory is allocated. +

+

+ In case of an invalid code point, a utf8::invalid_code_point exception + is thrown. +

+

+ utf8::next +

+

+ Available in version 1.0 and later. +

+

+ Given the iterator to the beginning of the UTF-8 sequence, it returns the code + point and moves the iterator to the next position. +

+
+template <typename octet_iterator> 
+uint32_t next(octet_iterator& it, octet_iterator end);
+   
+
+

+ octet_iterator: an input iterator.
+ it: a reference to an iterator pointing to the beginning of an UTF-8 + encoded code point. After the function returns, it is incremented to point to the + beginning of the next code point.
+ end: end of the UTF-8 sequence to be processed. If it + gets equal to end during the extraction of a code point, an + utf8::not_enough_room exception is thrown.
+ Return value: the 32 bit representation of the + processed UTF-8 code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars;
+int cp = next(w, twochars + 6);
+assert (cp == 0x65e5);
+assert (w == twochars + 3);
+
+

+ This function is typically used to iterate through a UTF-8 encoded string. +

+

+ In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is + thrown. +

+

+ utf8::peek_next +

+

+ Available in version 2.1 and later. +

+

+ Given the iterator to the beginning of the UTF-8 sequence, it returns the code + point for the following sequence without changing the value of the iterator. +

+
+template <typename octet_iterator> 
+uint32_t peek_next(octet_iterator it, octet_iterator end);
+   
+
+

+ octet_iterator: an input iterator.
+ it: an iterator pointing to the beginning of an UTF-8 + encoded code point.
+ end: end of the UTF-8 sequence to be processed. If it + gets equal to end during the extraction of a code point, an + utf8::not_enough_room exception is thrown.
+ Return value: the 32 bit representation of the + processed UTF-8 code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars;
+int cp = peek_next(w, twochars + 6);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is + thrown. +

+

+ utf8::prior +

+

+ Available in version 1.02 and later. +

+

+ Given a reference to an iterator pointing to an octet in a UTF-8 sequence, it + decreases the iterator until it hits the beginning of the previous UTF-8 encoded + code point and returns the 32 bits representation of the code point. +

+
+template <typename octet_iterator> 
+uint32_t prior(octet_iterator& it, octet_iterator start);
+   
+
+

+ octet_iterator: a bidirectional iterator.
+ it: a reference pointing to an octet within a UTF-8 encoded string. + After the function returns, it is decremented to point to the beginning of the + previous code point.
+ start: an iterator to the beginning of the sequence where the search + for the beginning of a code point is performed. It is a + safety measure to prevent passing the beginning of the string in the search for a + UTF-8 lead octet.
+ Return value: the 32 bit representation of the + previous code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+unsigned char* w = twochars + 3;
+int cp = prior (w, twochars);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ This function has two purposes: one is two iterate backwards through a UTF-8 + encoded string. Note that it is usually a better idea to iterate forward instead, + since utf8::next is faster. The second purpose is to find a beginning + of a UTF-8 sequence if we have a random position within a string. Note that in that + case utf8::prior may not detect an invalid UTF-8 sequence in some scenarios: + for instance if there are superfluous trail octets, it will just skip them. +

+

+ it will typically point to the beginning of + a code point, and start will point to the + beginning of the string to ensure we don't go backwards too far. it is + decreased until it points to a lead UTF-8 octet, and then the UTF-8 sequence + beginning with that octet is decoded to a 32 bit representation and returned. +

+

+ In case start is reached before a UTF-8 lead octet is hit, or if an + invalid UTF-8 sequence is started by the lead octet, an invalid_utf8 + exception is thrown. +

+

In case start equals it, a not_enough_room + exception is thrown. +

+ utf8::previous +

+

+ Deprecated in version 1.02 and later. +

+

+ Given a reference to an iterator pointing to an octet in a UTF-8 seqence, it + decreases the iterator until it hits the beginning of the previous UTF-8 encoded + code point and returns the 32 bits representation of the code point. +

+
+template <typename octet_iterator> 
+uint32_t previous(octet_iterator& it, octet_iterator pass_start);
+   
+
+

+ octet_iterator: a random access iterator.
+ it: a reference pointing to an octet within a UTF-8 encoded string. + After the function returns, it is decremented to point to the beginning of the + previous code point.
+ pass_start: an iterator to the point in the sequence where the search + for the beginning of a code point is aborted if no result was reached. It is a + safety measure to prevent passing the beginning of the string in the search for a + UTF-8 lead octet.
+ Return value: the 32 bit representation of the + previous code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+unsigned char* w = twochars + 3;
+int cp = previous (w, twochars - 1);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ utf8::previous is deprecated, and utf8::prior should + be used instead, although the existing code can continue using this function. + The problem is the parameter pass_start that points to the position + just before the beginning of the sequence. Standard containers don't have the + concept of "pass start" and the function can not be used with their iterators. +

+

+ it will typically point to the beginning of + a code point, and pass_start will point to the octet just before the + beginning of the string to ensure we don't go backwards too far. it is + decreased until it points to a lead UTF-8 octet, and then the UTF-8 sequence + beginning with that octet is decoded to a 32 bit representation and returned. +

+

+ In case pass_start is reached before a UTF-8 lead octet is hit, or if an + invalid UTF-8 sequence is started by the lead octet, an invalid_utf8 + exception is thrown +

+

+ utf8::advance +

+

+ Available in version 1.0 and later. +

+

+ Advances an iterator by the specified number of code points within an UTF-8 + sequence. +

+
+template <typename octet_iterator, typename distance_type> 
+void advance (octet_iterator& it, distance_type n, octet_iterator end);
+   
+
+

+ octet_iterator: an input iterator.
+ distance_type: an integral type convertible to octet_iterator's difference type.
+ it: a reference to an iterator pointing to the beginning of an UTF-8 + encoded code point. After the function returns, it is incremented to point to the + nth following code point.
+ n: a positive integer that shows how many code points we want to + advance.
+ end: end of the UTF-8 sequence to be processed. If it + gets equal to end during the extraction of a code point, an + utf8::not_enough_room exception is thrown.
+

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+unsigned char* w = twochars;
+advance (w, 2, twochars + 6);
+assert (w == twochars + 5);
+
+

+ This function works only "forward". In case of a negative n, there is + no effect. +

+

+ In case of an invalid code point, a utf8::invalid_code_point exception + is thrown. +

+

+ utf8::distance +

+

+ Available in version 1.0 and later. +

+

+ Given the iterators to two UTF-8 encoded code points in a seqence, returns the + number of code points between them. +

+
+template <typename octet_iterator> 
+typename std::iterator_traits<octet_iterator>::difference_type distance (octet_iterator first, octet_iterator last);
+   
+
+

+ octet_iterator: an input iterator.
+ first: an iterator to a beginning of a UTF-8 encoded code point.
+ last: an iterator to a "post-end" of the last UTF-8 encoded code + point in the sequence we are trying to determine the length. It can be the + beginning of a new code point, or not.
+ Return value the distance between the iterators, + in code points. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+size_t dist = utf8::distance(twochars, twochars + 5);
+assert (dist == 2);
+
+

+ This function is used to find the length (in code points) of a UTF-8 encoded + string. The reason it is called distance, rather than, say, + length is mainly because developers are used that length is an + O(1) function. Computing the length of an UTF-8 string is a linear operation, and + it looked better to model it after std::distance algorithm. +

+

+ In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is + thrown. If last does not point to the past-of-end of a UTF-8 seqence, + a utf8::not_enough_room exception is thrown. +

+

+ utf8::utf16to8 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-16 encoded string to UTF-8. +

+
+template <typename u16bit_iterator, typename octet_iterator>
+octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result);
+   
+
+

+ u16bit_iterator: an input iterator.
+ octet_iterator: an output iterator.
+ start: an iterator pointing to the beginning of the UTF-16 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-16 encoded + string to convert.
+ result: an output iterator to the place in the UTF-8 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-8 string. +

+

+ Example of use: +

+
+unsigned short utf16string[] = {0x41, 0x0448, 0x65e5, 0xd834, 0xdd1e};
+vector<unsigned char> utf8result;
+utf16to8(utf16string, utf16string + 5, back_inserter(utf8result));
+assert (utf8result.size() == 10);    
+
+

+ In case of invalid UTF-16 sequence, a utf8::invalid_utf16 exception is + thrown. +

+

+ utf8::utf8to16 +

+

+ Available in version 1.0 and later. +

+

+ Converts an UTF-8 encoded string to UTF-16 +

+
+template <typename u16bit_iterator, typename octet_iterator>
+u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result);
+   
+
+

+ octet_iterator: an input iterator.
+ u16bit_iterator: an output iterator.
+ start: an iterator pointing to the beginning of the UTF-8 encoded + string to convert. < br /> end: an iterator pointing to + pass-the-end of the UTF-8 encoded string to convert.
+ result: an output iterator to the place in the UTF-16 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-16 string. +

+

+ Example of use: +

+
+char utf8_with_surrogates[] = "\xe6\x97\xa5\xd1\x88\xf0\x9d\x84\x9e";
+vector <unsigned short> utf16result;
+utf8to16(utf8_with_surrogates, utf8_with_surrogates + 9, back_inserter(utf16result));
+assert (utf16result.size() == 4);
+assert (utf16result[2] == 0xd834);
+assert (utf16result[3] == 0xdd1e);
+
+

+ In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is + thrown. If end does not point to the past-of-end of a UTF-8 seqence, a + utf8::not_enough_room exception is thrown. +

+

+ utf8::utf32to8 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-32 encoded string to UTF-8. +

+
+template <typename octet_iterator, typename u32bit_iterator>
+octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result);
+   
+
+

+ octet_iterator: an output iterator.
+ u32bit_iterator: an input iterator.
+ start: an iterator pointing to the beginning of the UTF-32 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-32 encoded + string to convert.
+ result: an output iterator to the place in the UTF-8 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-8 string. +

+

+ Example of use: +

+
+int utf32string[] = {0x448, 0x65E5, 0x10346, 0};
+vector<unsigned char> utf8result;
+utf32to8(utf32string, utf32string + 3, back_inserter(utf8result));
+assert (utf8result.size() == 9);
+
+

+ In case of invalid UTF-32 string, a utf8::invalid_code_point exception + is thrown. +

+

+ utf8::utf8to32 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-8 encoded string to UTF-32. +

+
+template <typename octet_iterator, typename u32bit_iterator>
+u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result);
+   
+
+

+ octet_iterator: an input iterator.
+ u32bit_iterator: an output iterator.
+ start: an iterator pointing to the beginning of the UTF-8 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-8 encoded string + to convert.
+ result: an output iterator to the place in the UTF-32 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-32 string. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+vector<int> utf32result;
+utf8to32(twochars, twochars + 5, back_inserter(utf32result));
+assert (utf32result.size() == 2);
+
+

+ In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is + thrown. If end does not point to the past-of-end of a UTF-8 seqence, a + utf8::not_enough_room exception is thrown. +

+

+ utf8::find_invalid +

+

+ Available in version 1.0 and later. +

+

+ Detects an invalid sequence within a UTF-8 string. +

+
+template <typename octet_iterator> 
+octet_iterator find_invalid(octet_iterator start, octet_iterator end);
+
+

+ octet_iterator: an input iterator.
+ start: an iterator pointing to the beginning of the UTF-8 string to + test for validity.
+ end: an iterator pointing to pass-the-end of the UTF-8 string to test + for validity.
+ Return value: an iterator pointing to the first + invalid octet in the UTF-8 string. In case none were found, equals + end. +

+

+ Example of use: +

+
+char utf_invalid[] = "\xe6\x97\xa5\xd1\x88\xfa";
+char* invalid = find_invalid(utf_invalid, utf_invalid + 6);
+assert (invalid == utf_invalid + 5);
+
+

+ This function is typically used to make sure a UTF-8 string is valid before + processing it with other functions. It is especially important to call it if before + doing any of the unchecked operations on it. +

+

+ utf8::is_valid +

+

+ Available in version 1.0 and later. +

+

+ Checks whether a sequence of octets is a valid UTF-8 string. +

+
+template <typename octet_iterator> 
+bool is_valid(octet_iterator start, octet_iterator end);
+   
+
+

+ octet_iterator: an input iterator.
+ start: an iterator pointing to the beginning of the UTF-8 string to + test for validity.
+ end: an iterator pointing to pass-the-end of the UTF-8 string to test + for validity.
+ Return value: true if the sequence + is a valid UTF-8 string; false if not. +

+ Example of use: +
+char utf_invalid[] = "\xe6\x97\xa5\xd1\x88\xfa";
+bool bvalid = is_valid(utf_invalid, utf_invalid + 6);
+assert (bvalid == false);
+
+

+ is_valid is a shorthand for find_invalid(start, end) == + end;. You may want to use it to make sure that a byte seqence is a valid + UTF-8 string without the need to know where it fails if it is not valid. +

+

+ utf8::replace_invalid +

+

+ Available in version 2.0 and later. +

+

+ Replaces all invalid UTF-8 sequences within a string with a replacement marker. +

+
+template <typename octet_iterator, typename output_iterator>
+output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement);
+template <typename octet_iterator, typename output_iterator>
+output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out);
+   
+
+

+ octet_iterator: an input iterator.
+ output_iterator: an output iterator.
+ start: an iterator pointing to the beginning of the UTF-8 string to + look for invalid UTF-8 sequences.
+ end: an iterator pointing to pass-the-end of the UTF-8 string to look + for invalid UTF-8 sequences.
+ out: An output iterator to the range where the result of replacement + is stored.
+ replacement: A Unicode code point for the replacement marker. The + version without this parameter assumes the value 0xfffd
+ Return value: An iterator pointing to the place + after the UTF-8 string with replaced invalid sequences. +

+

+ Example of use: +

+
+char invalid_sequence[] = "a\x80\xe0\xa0\xc0\xaf\xed\xa0\x80z";
+vector<char> replace_invalid_result;
+replace_invalid (invalid_sequence, invalid_sequence + sizeof(invalid_sequence), back_inserter(replace_invalid_result), '?');
+bvalid = is_valid(replace_invalid_result.begin(), replace_invalid_result.end());
+assert (bvalid);
+char* fixed_invalid_sequence = "a????z";
+assert (std::equal(replace_invalid_result.begin(), replace_invalid_result.end(), fixed_invalid_sequence));
+
+

+ replace_invalid does not perform in-place replacement of invalid + sequences. Rather, it produces a copy of the original string with the invalid + sequences replaced with a replacement marker. Therefore, out must not + be in the [start, end] range. +

+

+ If end does not point to the past-of-end of a UTF-8 sequence, a + utf8::not_enough_room exception is thrown. +

+

+ utf8::starts_with_bom +

+

+ Available in version 2.3 and later. Relaces deprecated is_bom() function. +

+

+ Checks whether an octet sequence starts with a UTF-8 byte order mark (BOM) +

+
+template <typename octet_iterator> 
+bool starts_with_bom (octet_iterator it, octet_iterator end);
+
+

+ octet_iterator: an input iterator.
+ it: beginning of the octet sequence to check
+ end: pass-end of the sequence to check
+ Return value: true if the sequence + starts with a UTF-8 byte order mark; false if not. +

+

+ Example of use: +

+
+unsigned char byte_order_mark[] = {0xef, 0xbb, 0xbf};
+bool bbom = starts_with_bom(byte_order_mark, byte_order_mark + sizeof(byte_order_mark));
+assert (bbom == true);
+
+

+ The typical use of this function is to check the first three bytes of a file. If + they form the UTF-8 BOM, we want to skip them before processing the actual UTF-8 + encoded text. +

+

+ utf8::is_bom +

+

+ Available in version 1.0 and later. Deprecated in version 2.3. starts_with_bom() should be used + instead. +

+

+ Checks whether a sequence of three octets is a UTF-8 byte order mark (BOM) +

+
+template <typename octet_iterator> 
+bool is_bom (octet_iterator it);  // Deprecated
+
+

+ octet_iterator: an input iterator.
+ it: beginning of the 3-octet sequence to check
+ Return value: true if the sequence + is UTF-8 byte order mark; false if not. +

+

+ Example of use: +

+
+unsigned char byte_order_mark[] = {0xef, 0xbb, 0xbf};
+bool bbom = is_bom(byte_order_mark);
+assert (bbom == true);
+
+

+ The typical use of this function is to check the first three bytes of a file. If + they form the UTF-8 BOM, we want to skip them before processing the actual UTF-8 + encoded text. +

+

+ If a sequence is + shorter than three bytes, an invalid iterator will be dereferenced. Therefore, this function is deprecated + in favor of starts_with_bom()that takes the end of sequence as an argument. +

+

+ Types From utf8 Namespace +

+

utf8::exception +

+

+ Available in version 2.3 and later. +

+

+ Base class for the exceptions thrown by UTF CPP library functions. +

+
+class exception : public std::exception {};
+
+

+ Example of use: +

+
+try {
+  code_that_uses_utf_cpp_library();
+}
+catch(const utf8::exception& utfcpp_ex) {
+  cerr << utfcpp_ex.what();
+}
+
+ +

utf8::invalid_code_point +

+

+ Available in version 1.0 and later. +

+

+ Thrown by UTF8 CPP functions such as advance and next if an UTF-8 sequence represents and invalid code point. +

+ +
+class invalid_code_point : public exception {
+public: 
+    uint32_t code_point() const;
+};
+
+
+

+ Member function code_point() can be used to determine the invalid code point that + caused the exception to be thrown. +

+

utf8::invalid_utf8 +

+

+ Available in version 1.0 and later. +

+

+ Thrown by UTF8 CPP functions such as next and prior if an invalid UTF-8 sequence + is detected during decoding. +

+ +
+class invalid_utf8 : public exception {
+public: 
+    uint8_t utf8_octet() const;
+};
+
+ +

+ Member function utf8_octet() can be used to determine the beginning of the byte + sequence that caused the exception to be thrown. +

+ +

utf8::invalid_utf16 +

+

+ Available in version 1.0 and later. +

+

+ Thrown by UTF8 CPP function utf16to8 if an invalid UTF-16 sequence + is detected during decoding. +

+ +
+class invalid_utf16 : public exception {
+public: 
+    uint16_t utf16_word() const;
+};
+
+ +

+ Member function utf16_word() can be used to determine the UTF-16 code unit + that caused the exception to be thrown. +

+

utf8::not_enough_room +

+

+ Available in version 1.0 and later. +

+

+ Thrown by UTF8 CPP functions such as next if the end of the decoded UTF-8 sequence + was reached before the code point was decoded. +

+ +
+class not_enough_room : public exception {};
+
+

+ utf8::iterator +

+

+ Available in version 2.0 and later. +

+

+ Adapts the underlying octet iterator to iterate over the sequence of code points, + rather than raw octets. +

+
+template <typename octet_iterator>
+class iterator;
+
+ +
Member functions
+
+
iterator();
the deafult constructor; the underlying octet_iterator is + constructed with its default constructor. +
explicit iterator (const octet_iterator& octet_it, + const octet_iterator& range_start, + const octet_iterator& range_end);
a constructor + that initializes the underlying octet_iterator with octet_it + and sets the range in which the iterator is considered valid. +
octet_iterator base () const;
returns the + underlying octet_iterator. +
uint32_t operator * () const;
decodes the utf-8 sequence + the underlying octet_iterator is pointing to and returns the code point. +
bool operator == (const iterator& rhs) + const;
returns true + if the two underlaying iterators are equal. +
bool operator != (const iterator& rhs) + const;
returns true + if the two underlaying iterators are not equal. +
iterator& operator ++ ();
the prefix increment - moves + the iterator to the next UTF-8 encoded code point. +
iterator operator ++ (int);
+ the postfix increment - moves the iterator to the next UTF-8 encoded code point and returns the current one. +
iterator& operator -- ();
the prefix decrement - moves + the iterator to the previous UTF-8 encoded code point. +
iterator operator -- (int);
+ the postfix decrement - moves the iterator to the previous UTF-8 encoded code point and returns the current one. +
+

+ Example of use: +

+
+char* threechars = "\xf0\x90\x8d\x86\xe6\x97\xa5\xd1\x88";
+utf8::iterator<char*> it(threechars, threechars, threechars + 9);
+utf8::iterator<char*> it2 = it;
+assert (it2 == it);
+assert (*it == 0x10346);
+assert (*(++it) == 0x65e5);
+assert ((*it++) == 0x65e5);
+assert (*it == 0x0448);
+assert (it != it2);
+utf8::iterator<char*> endit (threechars + 9, threechars, threechars + 9);  
+assert (++it == endit);
+assert (*(--it) == 0x0448);
+assert ((*it--) == 0x0448);
+assert (*it == 0x65e5);
+assert (--it == utf8::iterator<char*>(threechars, threechars, threechars + 9));
+assert (*it == 0x10346);
+
+

+ The purpose of utf8::iterator adapter is to enable easy iteration as well as the use of STL + algorithms with UTF-8 encoded strings. Increment and decrement operators are implemented in terms of + utf8::next() and utf8::prior() functions. +

+

+ Note that utf8::iterator adapter is a checked iterator. It operates on the range specified in + the constructor; any attempt to go out of that range will result in an exception. Even the comparison operators + require both iterator object to be constructed against the same range - otherwise an exception is thrown. Typically, + the range will be determined by sequence container functions begin and end, i.e.: +

+
+std::string s = "example";
+utf8::iterator i (s.begin(), s.begin(), s.end());
+
+

+ Functions From utf8::unchecked Namespace +

+

+ utf8::unchecked::append +

+

+ Available in version 1.0 and later. +

+

+ Encodes a 32 bit code point as a UTF-8 sequence of octets and appends the sequence + to a UTF-8 string. +

+
+template <typename octet_iterator>
+octet_iterator append(uint32_t cp, octet_iterator result);
+   
+
+

+ cp: A 32 bit integer representing a code point to append to the + sequence.
+ result: An output iterator to the place in the sequence where to + append the code point.
+ Return value: An iterator pointing to the place + after the newly appended sequence. +

+

+ Example of use: +

+
+unsigned char u[5] = {0,0,0,0,0};
+unsigned char* end = unchecked::append(0x0448, u);
+assert (u[0] == 0xd1 && u[1] == 0x88 && u[2] == 0 && u[3] == 0 && u[4] == 0);
+
+

+ This is a faster but less safe version of utf8::append. It does not + check for validity of the supplied code point, and may produce an invalid UTF-8 + sequence. +

+

+ utf8::unchecked::next +

+

+ Available in version 1.0 and later. +

+

+ Given the iterator to the beginning of a UTF-8 sequence, it returns the code point + and moves the iterator to the next position. +

+
+template <typename octet_iterator>
+uint32_t next(octet_iterator& it);
+   
+
+

+ it: a reference to an iterator pointing to the beginning of an UTF-8 + encoded code point. After the function returns, it is incremented to point to the + beginning of the next code point.
+ Return value: the 32 bit representation of the + processed UTF-8 code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars;
+int cp = unchecked::next(w);
+assert (cp == 0x65e5);
+assert (w == twochars + 3);
+
+

+ This is a faster but less safe version of utf8::next. It does not + check for validity of the supplied UTF-8 sequence. +

+

+ utf8::unchecked::peek_next +

+

+ Available in version 2.1 and later. +

+

+ Given the iterator to the beginning of a UTF-8 sequence, it returns the code point. +

+
+template <typename octet_iterator>
+uint32_t peek_next(octet_iterator it);
+   
+
+

+ it: an iterator pointing to the beginning of an UTF-8 + encoded code point.
+ Return value: the 32 bit representation of the + processed UTF-8 code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars;
+int cp = unchecked::peek_next(w);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ This is a faster but less safe version of utf8::peek_next. It does not + check for validity of the supplied UTF-8 sequence. +

+

+ utf8::unchecked::prior +

+

+ Available in version 1.02 and later. +

+

+ Given a reference to an iterator pointing to an octet in a UTF-8 seqence, it + decreases the iterator until it hits the beginning of the previous UTF-8 encoded + code point and returns the 32 bits representation of the code point. +

+
+template <typename octet_iterator>
+uint32_t prior(octet_iterator& it);
+   
+
+

+ it: a reference pointing to an octet within a UTF-8 encoded string. + After the function returns, it is decremented to point to the beginning of the + previous code point.
+ Return value: the 32 bit representation of the + previous code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars + 3;
+int cp = unchecked::prior (w);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ This is a faster but less safe version of utf8::prior. It does not + check for validity of the supplied UTF-8 sequence and offers no boundary checking. +

+

+ utf8::unchecked::previous (deprecated, see utf8::unchecked::prior) +

+

+ Deprecated in version 1.02 and later. +

+

+ Given a reference to an iterator pointing to an octet in a UTF-8 seqence, it + decreases the iterator until it hits the beginning of the previous UTF-8 encoded + code point and returns the 32 bits representation of the code point. +

+
+template <typename octet_iterator>
+uint32_t previous(octet_iterator& it);
+   
+
+

+ it: a reference pointing to an octet within a UTF-8 encoded string. + After the function returns, it is decremented to point to the beginning of the + previous code point.
+ Return value: the 32 bit representation of the + previous code point. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars + 3;
+int cp = unchecked::previous (w);
+assert (cp == 0x65e5);
+assert (w == twochars);
+
+

+ The reason this function is deprecated is just the consistency with the "checked" + versions, where prior should be used instead of previous. + In fact, unchecked::previous behaves exactly the same as + unchecked::prior +

+

+ This is a faster but less safe version of utf8::previous. It does not + check for validity of the supplied UTF-8 sequence and offers no boundary checking. +

+

+ utf8::unchecked::advance +

+

+ Available in version 1.0 and later. +

+

+ Advances an iterator by the specified number of code points within an UTF-8 + sequence. +

+
+template <typename octet_iterator, typename distance_type>
+void advance (octet_iterator& it, distance_type n);
+   
+
+

+ it: a reference to an iterator pointing to the beginning of an UTF-8 + encoded code point. After the function returns, it is incremented to point to the + nth following code point.
+ n: a positive integer that shows how many code points we want to + advance.
+

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+char* w = twochars;
+unchecked::advance (w, 2);
+assert (w == twochars + 5);
+
+

+ This function works only "forward". In case of a negative n, there is + no effect. +

+

+ This is a faster but less safe version of utf8::advance. It does not + check for validity of the supplied UTF-8 sequence and offers no boundary checking. +

+

+ utf8::unchecked::distance +

+

+ Available in version 1.0 and later. +

+

+ Given the iterators to two UTF-8 encoded code points in a seqence, returns the + number of code points between them. +

+
+template <typename octet_iterator>
+typename std::iterator_traits<octet_iterator>::difference_type distance (octet_iterator first, octet_iterator last);
+
+

+ first: an iterator to a beginning of a UTF-8 encoded code point.
+ last: an iterator to a "post-end" of the last UTF-8 encoded code + point in the sequence we are trying to determine the length. It can be the + beginning of a new code point, or not.
+ Return value the distance between the iterators, + in code points. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+size_t dist = utf8::unchecked::distance(twochars, twochars + 5);
+assert (dist == 2);
+
+

+ This is a faster but less safe version of utf8::distance. It does not + check for validity of the supplied UTF-8 sequence. +

+

+ utf8::unchecked::utf16to8 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-16 encoded string to UTF-8. +

+
+template <typename u16bit_iterator, typename octet_iterator>
+octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result);
+   
+
+

+ start: an iterator pointing to the beginning of the UTF-16 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-16 encoded + string to convert.
+ result: an output iterator to the place in the UTF-8 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-8 string. +

+

+ Example of use: +

+
+unsigned short utf16string[] = {0x41, 0x0448, 0x65e5, 0xd834, 0xdd1e};
+vector<unsigned char> utf8result;
+unchecked::utf16to8(utf16string, utf16string + 5, back_inserter(utf8result));
+assert (utf8result.size() == 10);    
+
+

+ This is a faster but less safe version of utf8::utf16to8. It does not + check for validity of the supplied UTF-16 sequence. +

+

+ utf8::unchecked::utf8to16 +

+

+ Available in version 1.0 and later. +

+

+ Converts an UTF-8 encoded string to UTF-16 +

+
+template <typename u16bit_iterator, typename octet_iterator>
+u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result);
+   
+
+

+ start: an iterator pointing to the beginning of the UTF-8 encoded + string to convert. < br /> end: an iterator pointing to + pass-the-end of the UTF-8 encoded string to convert.
+ result: an output iterator to the place in the UTF-16 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-16 string. +

+

+ Example of use: +

+
+char utf8_with_surrogates[] = "\xe6\x97\xa5\xd1\x88\xf0\x9d\x84\x9e";
+vector <unsigned short> utf16result;
+unchecked::utf8to16(utf8_with_surrogates, utf8_with_surrogates + 9, back_inserter(utf16result));
+assert (utf16result.size() == 4);
+assert (utf16result[2] == 0xd834);
+assert (utf16result[3] == 0xdd1e);
+
+

+ This is a faster but less safe version of utf8::utf8to16. It does not + check for validity of the supplied UTF-8 sequence. +

+

+ utf8::unchecked::utf32to8 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-32 encoded string to UTF-8. +

+
+template <typename octet_iterator, typename u32bit_iterator>
+octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result);
+   
+
+

+ start: an iterator pointing to the beginning of the UTF-32 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-32 encoded + string to convert.
+ result: an output iterator to the place in the UTF-8 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-8 string. +

+

+ Example of use: +

+
+int utf32string[] = {0x448, 0x65e5, 0x10346, 0};
+vector<unsigned char> utf8result;
+utf32to8(utf32string, utf32string + 3, back_inserter(utf8result));
+assert (utf8result.size() == 9);
+
+

+ This is a faster but less safe version of utf8::utf32to8. It does not + check for validity of the supplied UTF-32 sequence. +

+

+ utf8::unchecked::utf8to32 +

+

+ Available in version 1.0 and later. +

+

+ Converts a UTF-8 encoded string to UTF-32. +

+
+template <typename octet_iterator, typename u32bit_iterator>
+u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result);
+   
+
+

+ start: an iterator pointing to the beginning of the UTF-8 encoded + string to convert.
+ end: an iterator pointing to pass-the-end of the UTF-8 encoded string + to convert.
+ result: an output iterator to the place in the UTF-32 string where to + append the result of conversion.
+ Return value: An iterator pointing to the place + after the appended UTF-32 string. +

+

+ Example of use: +

+
+char* twochars = "\xe6\x97\xa5\xd1\x88";
+vector<int> utf32result;
+unchecked::utf8to32(twochars, twochars + 5, back_inserter(utf32result));
+assert (utf32result.size() == 2);
+
+

+ This is a faster but less safe version of utf8::utf8to32. It does not + check for validity of the supplied UTF-8 sequence. +

+

+ Types From utf8::unchecked Namespace +

+

+ utf8::iterator +

+

+ Available in version 2.0 and later. +

+

+ Adapts the underlying octet iterator to iterate over the sequence of code points, + rather than raw octets. +

+
+template <typename octet_iterator>
+class iterator;
+
+ +
Member functions
+
+
iterator();
the deafult constructor; the underlying octet_iterator is + constructed with its default constructor. +
explicit iterator (const octet_iterator& octet_it); +
a constructor + that initializes the underlying octet_iterator with octet_it +
octet_iterator base () const;
returns the + underlying octet_iterator. +
uint32_t operator * () const;
decodes the utf-8 sequence + the underlying octet_iterator is pointing to and returns the code point. +
bool operator == (const iterator& rhs) + const;
returns true + if the two underlaying iterators are equal. +
bool operator != (const iterator& rhs) + const;
returns true + if the two underlaying iterators are not equal. +
iterator& operator ++ ();
the prefix increment - moves + the iterator to the next UTF-8 encoded code point. +
iterator operator ++ (int);
+ the postfix increment - moves the iterator to the next UTF-8 encoded code point and returns the current one. +
iterator& operator -- ();
the prefix decrement - moves + the iterator to the previous UTF-8 encoded code point. +
iterator operator -- (int);
+ the postfix decrement - moves the iterator to the previous UTF-8 encoded code point and returns the current one. +
+

+ Example of use: +

+
+char* threechars = "\xf0\x90\x8d\x86\xe6\x97\xa5\xd1\x88";
+utf8::unchecked::iterator<char*> un_it(threechars);
+utf8::unchecked::iterator<char*> un_it2 = un_it;
+assert (un_it2 == un_it);
+assert (*un_it == 0x10346);
+assert (*(++un_it) == 0x65e5);
+assert ((*un_it++) == 0x65e5);
+assert (*un_it == 0x0448);
+assert (un_it != un_it2);
+utf8::::unchecked::iterator<char*> un_endit (threechars + 9);  
+assert (++un_it == un_endit);
+assert (*(--un_it) == 0x0448);
+assert ((*un_it--) == 0x0448);
+assert (*un_it == 0x65e5);
+assert (--un_it == utf8::unchecked::iterator<char*>(threechars));
+assert (*un_it == 0x10346);
+
+

+ This is an unchecked version of utf8::iterator. It is faster in many cases, but offers + no validity or range checks. +

+

+ Points of interest +

+

+ Design goals and decisions +

+

+ The library was designed to be: +

+
    +
  1. + Generic: for better or worse, there are many C++ string classes out there, and + the library should work with as many of them as possible. +
  2. +
  3. + Portable: the library should be portable both accross different platforms and + compilers. The only non-portable code is a small section that declares unsigned + integers of different sizes: three typedefs. They can be changed by the users of + the library if they don't match their platform. The default setting should work + for Windows (both 32 and 64 bit), and most 32 bit and 64 bit Unix derivatives. +
  4. +
  5. + Lightweight: follow the "pay only for what you use" guideline. +
  6. +
  7. + Unintrusive: avoid forcing any particular design or even programming style on the + user. This is a library, not a framework. +
  8. +
+

+ Alternatives +

+

+ In case you want to look into other means of working with UTF-8 strings from C++, + here is the list of solutions I am aware of: +

+
    +
  1. + ICU Library. It is very powerful, + complete, feature-rich, mature, and widely used. Also big, intrusive, + non-generic, and doesn't play well with the Standard Library. I definitelly + recommend looking at ICU even if you don't plan to use it. +
  2. +
  3. + C++11 language and library features. Still far from complete, and not widely + supported by compiler vendors. +
  4. +
  5. + Glib::ustring. + A class specifically made to work with UTF-8 strings, and also feel like + std::string. If you prefer to have yet another string class in your + code, it may be worth a look. Be aware of the licensing issues, though. +
  6. +
  7. + Platform dependent solutions: Windows and POSIX have functions to convert strings + from one encoding to another. That is only a subset of what my library offers, + but if that is all you need it may be good enough. +
  8. +
+ +
    +
  1. + The Unicode Consortium. +
  2. +
  3. + ICU Library. +
  4. +
  5. + UTF-8 at Wikipedia +
  6. +
  7. + UTF-8 and Unicode FAQ for + Unix/Linux +
  8. +
+ + diff --git a/contrib/utf8cpp/source/utf8.h b/contrib/utf8cpp/source/utf8.h new file mode 100644 index 000000000..82b13f59f --- /dev/null +++ b/contrib/utf8cpp/source/utf8.h @@ -0,0 +1,34 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "utf8/checked.h" +#include "utf8/unchecked.h" + +#endif // header guard diff --git a/contrib/utf8cpp/source/utf8/checked.h b/contrib/utf8cpp/source/utf8/checked.h new file mode 100644 index 000000000..133115513 --- /dev/null +++ b/contrib/utf8cpp/source/utf8/checked.h @@ -0,0 +1,327 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "core.h" +#include + +namespace utf8 +{ + // Base for the exceptions that may be thrown from the library + class exception : public ::std::exception { + }; + + // Exceptions that may be thrown from the library functions. + class invalid_code_point : public exception { + uint32_t cp; + public: + invalid_code_point(uint32_t cp) : cp(cp) {} + virtual const char* what() const throw() { return "Invalid code point"; } + uint32_t code_point() const {return cp;} + }; + + class invalid_utf8 : public exception { + uint8_t u8; + public: + invalid_utf8 (uint8_t u) : u8(u) {} + virtual const char* what() const throw() { return "Invalid UTF-8"; } + uint8_t utf8_octet() const {return u8;} + }; + + class invalid_utf16 : public exception { + uint16_t u16; + public: + invalid_utf16 (uint16_t u) : u16(u) {} + virtual const char* what() const throw() { return "Invalid UTF-16"; } + uint16_t utf16_word() const {return u16;} + }; + + class not_enough_room : public exception { + public: + virtual const char* what() const throw() { return "Not enough space"; } + }; + + /// The library API - functions intended to be called by the users + + template + octet_iterator append(uint32_t cp, octet_iterator result) + { + if (!utf8::internal::is_code_point_valid(cp)) + throw invalid_code_point(cp); + + if (cp < 0x80) // one octet + *(result++) = static_cast(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast((cp >> 6) | 0xc0); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast((cp >> 12) | 0xe0); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast((cp >> 18) | 0xf0); + *(result++) = static_cast(((cp >> 12) & 0x3f) | 0x80); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + return result; + } + + template + output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement) + { + while (start != end) { + octet_iterator sequence_start = start; + internal::utf_error err_code = utf8::internal::validate_next(start, end); + switch (err_code) { + case internal::UTF8_OK : + for (octet_iterator it = sequence_start; it != start; ++it) + *out++ = *it; + break; + case internal::NOT_ENOUGH_ROOM: + throw not_enough_room(); + case internal::INVALID_LEAD: + out = utf8::append (replacement, out); + ++start; + break; + case internal::INCOMPLETE_SEQUENCE: + case internal::OVERLONG_SEQUENCE: + case internal::INVALID_CODE_POINT: + out = utf8::append (replacement, out); + ++start; + // just one replacement mark for the sequence + while (start != end && utf8::internal::is_trail(*start)) + ++start; + break; + } + } + return out; + } + + template + inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) + { + static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd); + return utf8::replace_invalid(start, end, out, replacement_marker); + } + + template + uint32_t next(octet_iterator& it, octet_iterator end) + { + uint32_t cp = 0; + internal::utf_error err_code = utf8::internal::validate_next(it, end, cp); + switch (err_code) { + case internal::UTF8_OK : + break; + case internal::NOT_ENOUGH_ROOM : + throw not_enough_room(); + case internal::INVALID_LEAD : + case internal::INCOMPLETE_SEQUENCE : + case internal::OVERLONG_SEQUENCE : + throw invalid_utf8(*it); + case internal::INVALID_CODE_POINT : + throw invalid_code_point(cp); + } + return cp; + } + + template + uint32_t peek_next(octet_iterator it, octet_iterator end) + { + return utf8::next(it, end); + } + + template + uint32_t prior(octet_iterator& it, octet_iterator start) + { + // can't do much if it == start + if (it == start) + throw not_enough_room(); + + octet_iterator end = it; + // Go back until we hit either a lead octet or start + while (utf8::internal::is_trail(*(--it))) + if (it == start) + throw invalid_utf8(*it); // error - no lead byte in the sequence + return utf8::peek_next(it, end); + } + + /// Deprecated in versions that include "prior" + template + uint32_t previous(octet_iterator& it, octet_iterator pass_start) + { + octet_iterator end = it; + while (utf8::internal::is_trail(*(--it))) + if (it == pass_start) + throw invalid_utf8(*it); // error - no lead byte in the sequence + octet_iterator temp = it; + return utf8::next(temp, end); + } + + template + void advance (octet_iterator& it, distance_type n, octet_iterator end) + { + for (distance_type i = 0; i < n; ++i) + utf8::next(it, end); + } + + template + typename std::iterator_traits::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits::difference_type dist; + for (dist = 0; first < last; ++dist) + utf8::next(first, last); + return dist; + } + + template + octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) + { + while (start != end) { + uint32_t cp = utf8::internal::mask16(*start++); + // Take care of surrogate pairs first + if (utf8::internal::is_lead_surrogate(cp)) { + if (start != end) { + uint32_t trail_surrogate = utf8::internal::mask16(*start++); + if (utf8::internal::is_trail_surrogate(trail_surrogate)) + cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; + else + throw invalid_utf16(static_cast(trail_surrogate)); + } + else + throw invalid_utf16(static_cast(cp)); + + } + // Lone trail surrogate + else if (utf8::internal::is_trail_surrogate(cp)) + throw invalid_utf16(static_cast(cp)); + + result = utf8::append(cp, result); + } + return result; + } + + template + u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) + { + while (start != end) { + uint32_t cp = utf8::next(start, end); + if (cp > 0xffff) { //make a surrogate pair + *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast(cp); + } + return result; + } + + template + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = utf8::append(*(start++), result); + + return result; + } + + template + u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) + { + while (start != end) + (*result++) = utf8::next(start, end); + + return result; + } + + // The iterator class + template + class iterator : public std::iterator { + octet_iterator it; + octet_iterator range_start; + octet_iterator range_end; + public: + iterator () {} + explicit iterator (const octet_iterator& octet_it, + const octet_iterator& range_start, + const octet_iterator& range_end) : + it(octet_it), range_start(range_start), range_end(range_end) + { + if (it < range_start || it > range_end) + throw std::out_of_range("Invalid utf-8 iterator position"); + } + // the default "big three" are OK + octet_iterator base () const { return it; } + uint32_t operator * () const + { + octet_iterator temp = it; + return utf8::next(temp, range_end); + } + bool operator == (const iterator& rhs) const + { + if (range_start != rhs.range_start || range_end != rhs.range_end) + throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const + { + return !(operator == (rhs)); + } + iterator& operator ++ () + { + utf8::next(it, range_end); + return *this; + } + iterator operator ++ (int) + { + iterator temp = *this; + utf8::next(it, range_end); + return temp; + } + iterator& operator -- () + { + utf8::prior(it, range_start); + return *this; + } + iterator operator -- (int) + { + iterator temp = *this; + utf8::prior(it, range_start); + return temp; + } + }; // class iterator + +} // namespace utf8 + +#endif //header guard + + diff --git a/contrib/utf8cpp/source/utf8/core.h b/contrib/utf8cpp/source/utf8/core.h new file mode 100644 index 000000000..693d388c0 --- /dev/null +++ b/contrib/utf8cpp/source/utf8/core.h @@ -0,0 +1,329 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include + +namespace utf8 +{ + // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers + // You may need to change them to match your system. + // These typedefs have the same names as ones from cstdint, or boost/cstdint + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; + +// Helper code - not intended to be directly called by the library users. May be changed at any time +namespace internal +{ + // Unicode constants + // Leading (high) surrogates: 0xd800 - 0xdbff + // Trailing (low) surrogates: 0xdc00 - 0xdfff + const uint16_t LEAD_SURROGATE_MIN = 0xd800u; + const uint16_t LEAD_SURROGATE_MAX = 0xdbffu; + const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u; + const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu; + const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10); + const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN; + + // Maximum valid value for a Unicode code point + const uint32_t CODE_POINT_MAX = 0x0010ffffu; + + template + inline uint8_t mask8(octet_type oc) + { + return static_cast(0xff & oc); + } + template + inline uint16_t mask16(u16_type oc) + { + return static_cast(0xffff & oc); + } + template + inline bool is_trail(octet_type oc) + { + return ((utf8::internal::mask8(oc) >> 6) == 0x2); + } + + template + inline bool is_lead_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX); + } + + template + inline bool is_trail_surrogate(u16 cp) + { + return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template + inline bool is_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template + inline bool is_code_point_valid(u32 cp) + { + return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp)); + } + + template + inline typename std::iterator_traits::difference_type + sequence_length(octet_iterator lead_it) + { + uint8_t lead = utf8::internal::mask8(*lead_it); + if (lead < 0x80) + return 1; + else if ((lead >> 5) == 0x6) + return 2; + else if ((lead >> 4) == 0xe) + return 3; + else if ((lead >> 3) == 0x1e) + return 4; + else + return 0; + } + + template + inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length) + { + if (cp < 0x80) { + if (length != 1) + return true; + } + else if (cp < 0x800) { + if (length != 2) + return true; + } + else if (cp < 0x10000) { + if (length != 3) + return true; + } + + return false; + } + + enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; + + /// Helper for get_sequence_x + template + utf_error increase_safely(octet_iterator& it, octet_iterator end) + { + if (++it == end) + return NOT_ENOUGH_ROOM; + + if (!utf8::internal::is_trail(*it)) + return INCOMPLETE_SEQUENCE; + + return UTF8_OK; + } + + #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;} + + /// get_sequence_x functions decode utf-8 sequences of the length x + template + utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + code_point = utf8::internal::mask8(*it); + + return UTF8_OK; + } + + template + utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + code_point = utf8::internal::mask8(*it); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f); + + return UTF8_OK; + } + + template + utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + code_point = utf8::internal::mask8(*it); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point += (*it) & 0x3f; + + return UTF8_OK; + } + + template + utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + if (it == end) + return NOT_ENOUGH_ROOM; + + code_point = utf8::internal::mask8(*it); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point += (utf8::internal::mask8(*it) << 6) & 0xfff; + + UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) + + code_point += (*it) & 0x3f; + + return UTF8_OK; + } + + #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR + + template + utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point) + { + // Save the original value of it so we can go back in case of failure + // Of course, it does not make much sense with i.e. stream iterators + octet_iterator original_it = it; + + uint32_t cp = 0; + // Determine the sequence length based on the lead octet + typedef typename std::iterator_traits::difference_type octet_difference_type; + const octet_difference_type length = utf8::internal::sequence_length(it); + + // Get trail octets and calculate the code point + utf_error err = UTF8_OK; + switch (length) { + case 0: + return INVALID_LEAD; + case 1: + err = utf8::internal::get_sequence_1(it, end, cp); + break; + case 2: + err = utf8::internal::get_sequence_2(it, end, cp); + break; + case 3: + err = utf8::internal::get_sequence_3(it, end, cp); + break; + case 4: + err = utf8::internal::get_sequence_4(it, end, cp); + break; + } + + if (err == UTF8_OK) { + // Decoding succeeded. Now, security checks... + if (utf8::internal::is_code_point_valid(cp)) { + if (!utf8::internal::is_overlong_sequence(cp, length)){ + // Passed! Return here. + code_point = cp; + ++it; + return UTF8_OK; + } + else + err = OVERLONG_SEQUENCE; + } + else + err = INVALID_CODE_POINT; + } + + // Failure branch - restore the original value of the iterator + it = original_it; + return err; + } + + template + inline utf_error validate_next(octet_iterator& it, octet_iterator end) { + uint32_t ignored; + return utf8::internal::validate_next(it, end, ignored); + } + +} // namespace internal + + /// The library API - functions intended to be called by the users + + // Byte order mark + const uint8_t bom[] = {0xef, 0xbb, 0xbf}; + + template + octet_iterator find_invalid(octet_iterator start, octet_iterator end) + { + octet_iterator result = start; + while (result != end) { + utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end); + if (err_code != internal::UTF8_OK) + return result; + } + return result; + } + + template + inline bool is_valid(octet_iterator start, octet_iterator end) + { + return (utf8::find_invalid(start, end) == end); + } + + template + inline bool starts_with_bom (octet_iterator it, octet_iterator end) + { + return ( + ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) && + ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) && + ((it != end) && (utf8::internal::mask8(*it)) == bom[2]) + ); + } + + //Deprecated in release 2.3 + template + inline bool is_bom (octet_iterator it) + { + return ( + (utf8::internal::mask8(*it++)) == bom[0] && + (utf8::internal::mask8(*it++)) == bom[1] && + (utf8::internal::mask8(*it)) == bom[2] + ); + } +} // namespace utf8 + +#endif // header guard + + diff --git a/contrib/utf8cpp/source/utf8/unchecked.h b/contrib/utf8cpp/source/utf8/unchecked.h new file mode 100644 index 000000000..cb2427166 --- /dev/null +++ b/contrib/utf8cpp/source/utf8/unchecked.h @@ -0,0 +1,228 @@ +// Copyright 2006 Nemanja Trifunovic + +/* +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. +*/ + + +#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 +#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 + +#include "core.h" + +namespace utf8 +{ + namespace unchecked + { + template + octet_iterator append(uint32_t cp, octet_iterator result) + { + if (cp < 0x80) // one octet + *(result++) = static_cast(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast((cp >> 6) | 0xc0); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast((cp >> 12) | 0xe0); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast((cp >> 18) | 0xf0); + *(result++) = static_cast(((cp >> 12) & 0x3f)| 0x80); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + return result; + } + + template + uint32_t next(octet_iterator& it) + { + uint32_t cp = utf8::internal::mask8(*it); + typename std::iterator_traits::difference_type length = utf8::internal::sequence_length(it); + switch (length) { + case 1: + break; + case 2: + it++; + cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); + break; + case 3: + ++it; + cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); + ++it; + cp += (*it) & 0x3f; + break; + case 4: + ++it; + cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); + ++it; + cp += (utf8::internal::mask8(*it) << 6) & 0xfff; + ++it; + cp += (*it) & 0x3f; + break; + } + ++it; + return cp; + } + + template + uint32_t peek_next(octet_iterator it) + { + return utf8::unchecked::next(it); + } + + template + uint32_t prior(octet_iterator& it) + { + while (utf8::internal::is_trail(*(--it))) ; + octet_iterator temp = it; + return utf8::unchecked::next(temp); + } + + // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous) + template + inline uint32_t previous(octet_iterator& it) + { + return utf8::unchecked::prior(it); + } + + template + void advance (octet_iterator& it, distance_type n) + { + for (distance_type i = 0; i < n; ++i) + utf8::unchecked::next(it); + } + + template + typename std::iterator_traits::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits::difference_type dist; + for (dist = 0; first < last; ++dist) + utf8::unchecked::next(first); + return dist; + } + + template + octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) + { + while (start != end) { + uint32_t cp = utf8::internal::mask16(*start++); + // Take care of surrogate pairs first + if (utf8::internal::is_lead_surrogate(cp)) { + uint32_t trail_surrogate = utf8::internal::mask16(*start++); + cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; + } + result = utf8::unchecked::append(cp, result); + } + return result; + } + + template + u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) + { + while (start < end) { + uint32_t cp = utf8::unchecked::next(start); + if (cp > 0xffff) { //make a surrogate pair + *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast(cp); + } + return result; + } + + template + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = utf8::unchecked::append(*(start++), result); + + return result; + } + + template + u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) + { + while (start < end) + (*result++) = utf8::unchecked::next(start); + + return result; + } + + // The iterator class + template + class iterator : public std::iterator { + octet_iterator it; + public: + iterator () {} + explicit iterator (const octet_iterator& octet_it): it(octet_it) {} + // the default "big three" are OK + octet_iterator base () const { return it; } + uint32_t operator * () const + { + octet_iterator temp = it; + return utf8::unchecked::next(temp); + } + bool operator == (const iterator& rhs) const + { + return (it == rhs.it); + } + bool operator != (const iterator& rhs) const + { + return !(operator == (rhs)); + } + iterator& operator ++ () + { + ::std::advance(it, utf8::internal::sequence_length(it)); + return *this; + } + iterator operator ++ (int) + { + iterator temp = *this; + ::std::advance(it, utf8::internal::sequence_length(it)); + return temp; + } + iterator& operator -- () + { + utf8::unchecked::prior(it); + return *this; + } + iterator operator -- (int) + { + iterator temp = *this; + utf8::unchecked::prior(it); + return temp; + } + }; // class iterator + + } // namespace utf8::unchecked +} // namespace utf8 + + +#endif // header guard + diff --git a/contrib/zlib/CMakeLists.txt b/contrib/zlib/CMakeLists.txt index 022d3dfba..5f1368adb 100644 --- a/contrib/zlib/CMakeLists.txt +++ b/contrib/zlib/CMakeLists.txt @@ -10,10 +10,10 @@ endif() project(zlib C) cmake_policy(POP) -set(VERSION "1.2.8") +set(VERSION "1.2.11.1") -option(ASM686 "Enable building i686 assembly implementation for zlib") -option(AMD64 "Enable building amd64 assembly implementation for zlib") +option(ASM686 "Enable building i686 assembly implementation") +option(AMD64 "Enable building amd64 assembly implementation") #set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables") #set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries") @@ -90,7 +90,6 @@ configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zlib.pc.cmakein ${ZLIB_PC} @ONLY) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.cmakein ${CMAKE_CURRENT_BINARY_DIR}/zconf.h @ONLY) - include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR}) @@ -191,7 +190,11 @@ if(MINGW) set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj) endif(MINGW) +add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS}) +set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL) +set_target_properties(zlib PROPERTIES SOVERSION 1) + INSTALL( TARGETS zlibstatic LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} diff --git a/contrib/zlib/README b/contrib/zlib/README index 5ca9d127e..41777d06d 100644 --- a/contrib/zlib/README +++ b/contrib/zlib/README @@ -1,6 +1,6 @@ ZLIB DATA COMPRESSION LIBRARY -zlib 1.2.8 is a general purpose data compression library. All the code is +zlib 1.2.11.1 is a general purpose data compression library. All the code is thread safe. The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and @@ -31,7 +31,7 @@ Mark Nelson wrote an article about zlib for the Jan. 1997 issue of Dr. Dobb's Journal; a copy of the article is available at http://marknelson.us/1997/01/01/zlib-engine/ . -The changes made in version 1.2.8 are documented in the file ChangeLog. +The changes made in version 1.2.11.1 are documented in the file ChangeLog. Unsupported third party contributions are provided in directory contrib/ . @@ -84,7 +84,7 @@ Acknowledgments: Copyright notice: - (C) 1995-2013 Jean-loup Gailly and Mark Adler + (C) 1995-2017 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/contrib/zlib/adler32.c b/contrib/zlib/adler32.c index a868f073d..d0be4380a 100644 --- a/contrib/zlib/adler32.c +++ b/contrib/zlib/adler32.c @@ -1,5 +1,5 @@ /* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2011 Mark Adler + * Copyright (C) 1995-2011, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -7,11 +7,9 @@ #include "zutil.h" -#define local static - local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); -#define BASE 65521 /* largest prime smaller than 65536 */ +#define BASE 65521U /* largest prime smaller than 65536 */ #define NMAX 5552 /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ @@ -62,10 +60,10 @@ local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); #endif /* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) +uLong ZEXPORT adler32_z(adler, buf, len) uLong adler; const Bytef *buf; - uInt len; + z_size_t len; { unsigned long sum2; unsigned n; @@ -132,6 +130,15 @@ uLong ZEXPORT adler32(adler, buf, len) return adler | (sum2 << 16); } +/* ========================================================================= */ +uLong ZEXPORT adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + return adler32_z(adler, buf, len); +} + /* ========================================================================= */ local uLong adler32_combine_(adler1, adler2, len2) uLong adler1; @@ -156,7 +163,7 @@ local uLong adler32_combine_(adler1, adler2, len2) sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; if (sum1 >= BASE) sum1 -= BASE; if (sum1 >= BASE) sum1 -= BASE; - if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1); + if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); if (sum2 >= BASE) sum2 -= BASE; return sum1 | (sum2 << 16); } diff --git a/contrib/zlib/compress.c b/contrib/zlib/compress.c index 6e9762676..e2db404ab 100644 --- a/contrib/zlib/compress.c +++ b/contrib/zlib/compress.c @@ -1,5 +1,5 @@ /* compress.c -- compress a memory buffer - * Copyright (C) 1995-2005 Jean-loup Gailly. + * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -28,16 +28,11 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) { z_stream stream; int err; + const uInt max = (uInt)-1; + uLong left; - stream.next_in = (z_const Bytef *)source; - stream.avail_in = (uInt)sourceLen; -#ifdef MAXSEG_64K - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; -#endif - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + left = *destLen; + *destLen = 0; stream.zalloc = (alloc_func)0; stream.zfree = (free_func)0; @@ -46,15 +41,26 @@ int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) err = deflateInit(&stream, level); if (err != Z_OK) return err; - err = deflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - deflateEnd(&stream); - return err == Z_OK ? Z_BUF_ERROR : err; - } - *destLen = stream.total_out; + stream.next_out = dest; + stream.avail_out = 0; + stream.next_in = (z_const Bytef *)source; + stream.avail_in = 0; - err = deflateEnd(&stream); - return err; + do { + if (stream.avail_out == 0) { + stream.avail_out = left > (uLong)max ? max : (uInt)left; + left -= stream.avail_out; + } + if (stream.avail_in == 0) { + stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen; + sourceLen -= stream.avail_in; + } + err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH); + } while (err == Z_OK); + + *destLen = stream.total_out; + deflateEnd(&stream); + return err == Z_STREAM_END ? Z_OK : err; } /* =========================================================================== diff --git a/contrib/zlib/crc32.c b/contrib/zlib/crc32.c index 979a7190a..e72636a50 100644 --- a/contrib/zlib/crc32.c +++ b/contrib/zlib/crc32.c @@ -1,5 +1,5 @@ /* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2006, 2010, 2011, 2012 Mark Adler + * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h * * Thanks to Rodney Brown for his contribution of faster @@ -30,17 +30,15 @@ #include "zutil.h" /* for STDC and FAR definitions */ -#define local static - /* Definitions for doing the crc four data bytes at a time. */ #if !defined(NOBYFOUR) && defined(Z_U4) # define BYFOUR #endif #ifdef BYFOUR local unsigned long crc32_little OF((unsigned long, - const unsigned char FAR *, unsigned)); + const unsigned char FAR *, z_size_t)); local unsigned long crc32_big OF((unsigned long, - const unsigned char FAR *, unsigned)); + const unsigned char FAR *, z_size_t)); # define TBLS 8 #else # define TBLS 1 @@ -201,10 +199,10 @@ const z_crc_t FAR * ZEXPORT get_crc_table() #define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 /* ========================================================================= */ -unsigned long ZEXPORT crc32(crc, buf, len) +unsigned long ZEXPORT crc32_z(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; - uInt len; + z_size_t len; { if (buf == Z_NULL) return 0UL; @@ -214,7 +212,7 @@ unsigned long ZEXPORT crc32(crc, buf, len) #endif /* DYNAMIC_CRC_TABLE */ #ifdef BYFOUR - if (sizeof(void *) == sizeof(ptrdiff_t)) { + if (sizeof(void *) == sizeof(z_size_t)) { z_crc_t endian; endian = 1; @@ -235,8 +233,29 @@ unsigned long ZEXPORT crc32(crc, buf, len) return crc ^ 0xffffffffUL; } +/* ========================================================================= */ +unsigned long ZEXPORT crc32(crc, buf, len) + unsigned long crc; + const unsigned char FAR *buf; + uInt len; +{ + return crc32_z(crc, buf, len); +} + #ifdef BYFOUR +/* + This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit + integer pointer type. This violates the strict aliasing rule, where a + compiler can assume, for optimization purposes, that two pointers to + fundamentally different types won't ever point to the same memory. This can + manifest as a problem only if one of the pointers is written to. This code + only reads from those pointers. So long as this code remains isolated in + this compilation unit, there won't be a problem. For this reason, this code + should not be copied and pasted into a compilation unit in which other code + writes to the buffer that is passed to these routines. + */ + /* ========================================================================= */ #define DOLIT4 c ^= *buf4++; \ c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ @@ -247,14 +266,14 @@ unsigned long ZEXPORT crc32(crc, buf, len) local unsigned long crc32_little(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; - unsigned len; + z_size_t len; { register z_crc_t c; register const z_crc_t FAR *buf4; c = (z_crc_t)crc; c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { + while (len && ((z_size_t)buf & 3)) { c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); len--; } @@ -278,7 +297,7 @@ local unsigned long crc32_little(crc, buf, len) } /* ========================================================================= */ -#define DOBIG4 c ^= *++buf4; \ +#define DOBIG4 c ^= *buf4++; \ c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] #define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 @@ -287,20 +306,19 @@ local unsigned long crc32_little(crc, buf, len) local unsigned long crc32_big(crc, buf, len) unsigned long crc; const unsigned char FAR *buf; - unsigned len; + z_size_t len; { register z_crc_t c; register const z_crc_t FAR *buf4; c = ZSWAP32((z_crc_t)crc); c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { + while (len && ((z_size_t)buf & 3)) { c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); len--; } buf4 = (const z_crc_t FAR *)(const void FAR *)buf; - buf4--; while (len >= 32) { DOBIG32; len -= 32; @@ -309,7 +327,6 @@ local unsigned long crc32_big(crc, buf, len) DOBIG4; len -= 4; } - buf4++; buf = (const unsigned char FAR *)buf4; if (len) do { diff --git a/contrib/zlib/deflate.c b/contrib/zlib/deflate.c index 696957705..568eaddbe 100644 --- a/contrib/zlib/deflate.c +++ b/contrib/zlib/deflate.c @@ -1,5 +1,5 @@ /* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + * Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -52,7 +52,7 @@ #include "deflate.h" const char deflate_copyright[] = - " deflate 1.2.8 Copyright 1995-2013 Jean-loup Gailly and Mark Adler "; + " deflate 1.2.11.1 Copyright 1995-2017 Jean-loup Gailly and Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -73,6 +73,8 @@ typedef enum { typedef block_state (*compress_func) OF((deflate_state *s, int flush)); /* Compression function. Returns the block state after the call. */ +local int deflateStateCheck OF((z_streamp strm)); +local void slide_hash OF((deflate_state *s)); local void fill_window OF((deflate_state *s)); local block_state deflate_stored OF((deflate_state *s, int flush)); local block_state deflate_fast OF((deflate_state *s, int flush)); @@ -84,15 +86,16 @@ local block_state deflate_huff OF((deflate_state *s, int flush)); local void lm_init OF((deflate_state *s)); local void putShortMSB OF((deflate_state *s, uInt b)); local void flush_pending OF((z_streamp strm)); -local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); +local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); #ifdef ASMV +# pragma message("Assembler code may have bugs -- use at your own risk") void match_init OF((void)); /* asm code initialization */ uInt longest_match OF((deflate_state *s, IPos cur_match)); #else local uInt longest_match OF((deflate_state *s, IPos cur_match)); #endif -#ifdef DEBUG +#ifdef ZLIB_DEBUG local void check_match OF((deflate_state *s, IPos start, IPos match, int length)); #endif @@ -148,21 +151,14 @@ local const config configuration_table[10] = { * meaning. */ -#define EQUAL 0 -/* result of memcmp for equal strings */ - -#ifndef NO_DUMMY_DECL -struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ -#endif - /* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ -#define RANK(f) (((f) << 1) - ((f) > 4 ? 9 : 0)) +#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0)) /* =========================================================================== * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. + * IN assertion: all calls to UPDATE_HASH are made with consecutive input + * characters, so that a running hash key can be computed from the previous + * key instead of complete recalculation each time. */ #define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) @@ -173,9 +169,9 @@ struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ * the previous length of the hash chain. * If this file is compiled with -DFASTEST, the compression level is forced * to 1, and no hash chains are maintained. - * IN assertion: all calls to to INSERT_STRING are made with consecutive - * input characters and the first MIN_MATCH bytes of str are valid - * (except for the last MIN_MATCH-1 bytes of the input file). + * IN assertion: all calls to INSERT_STRING are made with consecutive input + * characters and the first MIN_MATCH bytes of str are valid (except for + * the last MIN_MATCH-1 bytes of the input file). */ #ifdef FASTEST #define INSERT_STRING(s, str, match_head) \ @@ -194,8 +190,42 @@ struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ * prev[] will be initialized on the fly. */ #define CLEAR_HASH(s) \ - s->head[s->hash_size-1] = NIL; \ - zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + do { \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((Bytef *)s->head, \ + (unsigned)(s->hash_size-1)*sizeof(*s->head)); \ + } while (0) + +/* =========================================================================== + * Slide the hash table when sliding the window down (could be avoided with 32 + * bit values at the expense of memory usage). We slide even when level == 0 to + * keep the hash table consistent if we switch back to level > 0 later. + */ +local void slide_hash(s) + deflate_state *s; +{ + unsigned n, m; + Posf *p; + uInt wsize = s->w_size; + + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m - wsize : NIL); + } while (--n); + n = wsize; +#ifndef FASTEST + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m - wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); +#endif +} /* ========================================================================= */ int ZEXPORT deflateInit_(strm, level, version, stream_size) @@ -270,7 +300,7 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, #endif if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_FIXED) { + strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) { return Z_STREAM_ERROR; } if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ @@ -278,14 +308,15 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, if (s == Z_NULL) return Z_MEM_ERROR; strm->state = (struct internal_state FAR *)s; s->strm = strm; + s->status = INIT_STATE; /* to pass state test in deflateReset() */ s->wrap = wrap; s->gzhead = Z_NULL; - s->w_bits = windowBits; + s->w_bits = (uInt)windowBits; s->w_size = 1 << s->w_bits; s->w_mask = s->w_size - 1; - s->hash_bits = memLevel + 7; + s->hash_bits = (uInt)memLevel + 7; s->hash_size = 1 << s->hash_bits; s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); @@ -319,6 +350,31 @@ int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, return deflateReset(strm); } +/* ========================================================================= + * Check for a valid deflate stream state. Return 0 if ok, 1 if not. + */ +local int deflateStateCheck (strm) + z_streamp strm; +{ + deflate_state *s; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + s = strm->state; + if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE && +#ifdef GZIP + s->status != GZIP_STATE && +#endif + s->status != EXTRA_STATE && + s->status != NAME_STATE && + s->status != COMMENT_STATE && + s->status != HCRC_STATE && + s->status != BUSY_STATE && + s->status != FINISH_STATE)) + return 1; + return 0; +} + /* ========================================================================= */ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) z_streamp strm; @@ -331,7 +387,7 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) unsigned avail; z_const unsigned char *next; - if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) + if (deflateStateCheck(strm) || dictionary == Z_NULL) return Z_STREAM_ERROR; s = strm->state; wrap = s->wrap; @@ -388,14 +444,35 @@ int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) return Z_OK; } +/* ========================================================================= */ +int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) + z_streamp strm; + Bytef *dictionary; + uInt *dictLength; +{ + deflate_state *s; + uInt len; + + if (deflateStateCheck(strm)) + return Z_STREAM_ERROR; + s = strm->state; + len = s->strstart + s->lookahead; + if (len > s->w_size) + len = s->w_size; + if (dictionary != Z_NULL && len) + zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len); + if (dictLength != Z_NULL) + *dictLength = len; + return Z_OK; +} + /* ========================================================================= */ int ZEXPORT deflateResetKeep (strm) z_streamp strm; { deflate_state *s; - if (strm == Z_NULL || strm->state == Z_NULL || - strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) { + if (deflateStateCheck(strm)) { return Z_STREAM_ERROR; } @@ -410,13 +487,17 @@ int ZEXPORT deflateResetKeep (strm) if (s->wrap < 0) { s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ } - s->status = s->wrap ? INIT_STATE : BUSY_STATE; + s->status = +#ifdef GZIP + s->wrap == 2 ? GZIP_STATE : +#endif + s->wrap ? INIT_STATE : BUSY_STATE; strm->adler = #ifdef GZIP s->wrap == 2 ? crc32(0L, Z_NULL, 0) : #endif adler32(0L, Z_NULL, 0); - s->last_flush = Z_NO_FLUSH; + s->last_flush = -2; _tr_init(s); @@ -440,8 +521,8 @@ int ZEXPORT deflateSetHeader (strm, head) z_streamp strm; gz_headerp head; { - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; - if (strm->state->wrap != 2) return Z_STREAM_ERROR; + if (deflateStateCheck(strm) || strm->state->wrap != 2) + return Z_STREAM_ERROR; strm->state->gzhead = head; return Z_OK; } @@ -452,7 +533,7 @@ int ZEXPORT deflatePending (strm, pending, bits) int *bits; z_streamp strm; { - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; if (pending != Z_NULL) *pending = strm->state->pending; if (bits != Z_NULL) @@ -469,7 +550,7 @@ int ZEXPORT deflatePrime (strm, bits, value) deflate_state *s; int put; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) return Z_BUF_ERROR; @@ -494,9 +575,8 @@ int ZEXPORT deflateParams(strm, level, strategy) { deflate_state *s; compress_func func; - int err = Z_OK; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; #ifdef FASTEST @@ -510,13 +590,22 @@ int ZEXPORT deflateParams(strm, level, strategy) func = configuration_table[s->level].func; if ((strategy != s->strategy || func != configuration_table[level].func) && - strm->total_in != 0) { + s->last_flush != -2) { /* Flush the last buffer: */ - err = deflate(strm, Z_BLOCK); - if (err == Z_BUF_ERROR && s->pending == 0) - err = Z_OK; + int err = deflate(strm, Z_BLOCK); + if (err == Z_STREAM_ERROR) + return err; + if (strm->avail_in || (s->strstart - s->block_start) + s->lookahead) + return Z_BUF_ERROR; } if (s->level != level) { + if (s->level == 0 && s->matches != 0) { + if (s->matches == 1) + slide_hash(s); + else + CLEAR_HASH(s); + s->matches = 0; + } s->level = level; s->max_lazy_match = configuration_table[level].max_lazy; s->good_match = configuration_table[level].good_length; @@ -524,7 +613,7 @@ int ZEXPORT deflateParams(strm, level, strategy) s->max_chain_length = configuration_table[level].max_chain; } s->strategy = strategy; - return err; + return Z_OK; } /* ========================================================================= */ @@ -537,12 +626,12 @@ int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) { deflate_state *s; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; s = strm->state; - s->good_match = good_length; - s->max_lazy_match = max_lazy; + s->good_match = (uInt)good_length; + s->max_lazy_match = (uInt)max_lazy; s->nice_match = nice_length; - s->max_chain_length = max_chain; + s->max_chain_length = (uInt)max_chain; return Z_OK; } @@ -569,14 +658,13 @@ uLong ZEXPORT deflateBound(strm, sourceLen) { deflate_state *s; uLong complen, wraplen; - Bytef *str; /* conservative upper bound for compressed data */ complen = sourceLen + ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; /* if can't get parameters, return conservative bound plus zlib wrapper */ - if (strm == Z_NULL || strm->state == Z_NULL) + if (deflateStateCheck(strm)) return complen + 6; /* compute wrapper length */ @@ -588,9 +676,11 @@ uLong ZEXPORT deflateBound(strm, sourceLen) case 1: /* zlib wrapper */ wraplen = 6 + (s->strstart ? 4 : 0); break; +#ifdef GZIP case 2: /* gzip wrapper */ wraplen = 18; if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ + Bytef *str; if (s->gzhead->extra != Z_NULL) wraplen += 2 + s->gzhead->extra_len; str = s->gzhead->name; @@ -607,6 +697,7 @@ uLong ZEXPORT deflateBound(strm, sourceLen) wraplen += 2; } break; +#endif default: /* for compiler happiness */ wraplen = 6; } @@ -634,10 +725,10 @@ local void putShortMSB (s, b) } /* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->next_out buffer and copying into it. - * (See also read_buf()). + * Flush as much pending output as possible. All deflate() output, except for + * some deflate_stored() output, goes through this function so some + * applications may wish to modify it to avoid allocating a large + * strm->next_out buffer and copying into it. (See also read_buf()). */ local void flush_pending(strm) z_streamp strm; @@ -654,13 +745,23 @@ local void flush_pending(strm) strm->next_out += len; s->pending_out += len; strm->total_out += len; - strm->avail_out -= len; - s->pending -= len; + strm->avail_out -= len; + s->pending -= len; if (s->pending == 0) { s->pending_out = s->pending_buf; } } +/* =========================================================================== + * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1]. + */ +#define HCRC_UPDATE(beg) \ + do { \ + if (s->gzhead->hcrc && s->pending > (beg)) \ + strm->adler = crc32(strm->adler, s->pending_buf + (beg), \ + s->pending - (beg)); \ + } while (0) + /* ========================================================================= */ int ZEXPORT deflate (strm, flush) z_streamp strm; @@ -669,203 +770,21 @@ int ZEXPORT deflate (strm, flush) int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; - if (strm == Z_NULL || strm->state == Z_NULL || - flush > Z_BLOCK || flush < 0) { + if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) { return Z_STREAM_ERROR; } s = strm->state; if (strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0) || + (strm->avail_in != 0 && strm->next_in == Z_NULL) || (s->status == FINISH_STATE && flush != Z_FINISH)) { ERR_RETURN(strm, Z_STREAM_ERROR); } if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); - s->strm = strm; /* just in case */ old_flush = s->last_flush; s->last_flush = flush; - /* Write the header */ - if (s->status == INIT_STATE) { -#ifdef GZIP - if (s->wrap == 2) { - strm->adler = crc32(0L, Z_NULL, 0); - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - if (s->gzhead == Z_NULL) { - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, OS_CODE); - s->status = BUSY_STATE; - } - else { - put_byte(s, (s->gzhead->text ? 1 : 0) + - (s->gzhead->hcrc ? 2 : 0) + - (s->gzhead->extra == Z_NULL ? 0 : 4) + - (s->gzhead->name == Z_NULL ? 0 : 8) + - (s->gzhead->comment == Z_NULL ? 0 : 16) - ); - put_byte(s, (Byte)(s->gzhead->time & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, s->gzhead->os & 0xff); - if (s->gzhead->extra != Z_NULL) { - put_byte(s, s->gzhead->extra_len & 0xff); - put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); - } - if (s->gzhead->hcrc) - strm->adler = crc32(strm->adler, s->pending_buf, - s->pending); - s->gzindex = 0; - s->status = EXTRA_STATE; - } - } - else -#endif - { - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags; - - if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) - level_flags = 0; - else if (s->level < 6) - level_flags = 1; - else if (s->level == 6) - level_flags = 2; - else - level_flags = 3; - header |= (level_flags << 6); - if (s->strstart != 0) header |= PRESET_DICT; - header += 31 - (header % 31); - - s->status = BUSY_STATE; - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - strm->adler = adler32(0L, Z_NULL, 0); - } - } -#ifdef GZIP - if (s->status == EXTRA_STATE) { - if (s->gzhead->extra != Z_NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - - while (s->gzindex < (s->gzhead->extra_len & 0xffff)) { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) - break; - } - put_byte(s, s->gzhead->extra[s->gzindex]); - s->gzindex++; - } - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (s->gzindex == s->gzhead->extra_len) { - s->gzindex = 0; - s->status = NAME_STATE; - } - } - else - s->status = NAME_STATE; - } - if (s->status == NAME_STATE) { - if (s->gzhead->name != Z_NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - int val; - - do { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) { - val = 1; - break; - } - } - val = s->gzhead->name[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (val == 0) { - s->gzindex = 0; - s->status = COMMENT_STATE; - } - } - else - s->status = COMMENT_STATE; - } - if (s->status == COMMENT_STATE) { - if (s->gzhead->comment != Z_NULL) { - uInt beg = s->pending; /* start of bytes to update crc */ - int val; - - do { - if (s->pending == s->pending_buf_size) { - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - flush_pending(strm); - beg = s->pending; - if (s->pending == s->pending_buf_size) { - val = 1; - break; - } - } - val = s->gzhead->comment[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - if (s->gzhead->hcrc && s->pending > beg) - strm->adler = crc32(strm->adler, s->pending_buf + beg, - s->pending - beg); - if (val == 0) - s->status = HCRC_STATE; - } - else - s->status = HCRC_STATE; - } - if (s->status == HCRC_STATE) { - if (s->gzhead->hcrc) { - if (s->pending + 2 > s->pending_buf_size) - flush_pending(strm); - if (s->pending + 2 <= s->pending_buf_size) { - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - strm->adler = crc32(0L, Z_NULL, 0); - s->status = BUSY_STATE; - } - } - else - s->status = BUSY_STATE; - } -#endif - /* Flush as much pending output as possible */ if (s->pending != 0) { flush_pending(strm); @@ -894,15 +813,197 @@ int ZEXPORT deflate (strm, flush) ERR_RETURN(strm, Z_BUF_ERROR); } + /* Write the header */ + if (s->status == INIT_STATE) { + /* zlib header */ + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags; + + if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) + level_flags = 0; + else if (s->level < 6) + level_flags = 1; + else if (s->level == 6) + level_flags = 2; + else + level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = adler32(0L, Z_NULL, 0); + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } +#ifdef GZIP + if (s->status == GZIP_STATE) { + /* gzip header */ + strm->adler = crc32(0L, Z_NULL, 0); + put_byte(s, 31); + put_byte(s, 139); + put_byte(s, 8); + if (s->gzhead == Z_NULL) { + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, 0); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, OS_CODE); + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } + else { + put_byte(s, (s->gzhead->text ? 1 : 0) + + (s->gzhead->hcrc ? 2 : 0) + + (s->gzhead->extra == Z_NULL ? 0 : 4) + + (s->gzhead->name == Z_NULL ? 0 : 8) + + (s->gzhead->comment == Z_NULL ? 0 : 16) + ); + put_byte(s, (Byte)(s->gzhead->time & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); + put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); + put_byte(s, s->level == 9 ? 2 : + (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? + 4 : 0)); + put_byte(s, s->gzhead->os & 0xff); + if (s->gzhead->extra != Z_NULL) { + put_byte(s, s->gzhead->extra_len & 0xff); + put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); + } + if (s->gzhead->hcrc) + strm->adler = crc32(strm->adler, s->pending_buf, + s->pending); + s->gzindex = 0; + s->status = EXTRA_STATE; + } + } + if (s->status == EXTRA_STATE) { + if (s->gzhead->extra != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex; + while (s->pending + left > s->pending_buf_size) { + uInt copy = s->pending_buf_size - s->pending; + zmemcpy(s->pending_buf + s->pending, + s->gzhead->extra + s->gzindex, copy); + s->pending = s->pending_buf_size; + HCRC_UPDATE(beg); + s->gzindex += copy; + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + left -= copy; + } + zmemcpy(s->pending_buf + s->pending, + s->gzhead->extra + s->gzindex, left); + s->pending += left; + HCRC_UPDATE(beg); + s->gzindex = 0; + } + s->status = NAME_STATE; + } + if (s->status == NAME_STATE) { + if (s->gzhead->name != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + int val; + do { + if (s->pending == s->pending_buf_size) { + HCRC_UPDATE(beg); + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + } + val = s->gzhead->name[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + HCRC_UPDATE(beg); + s->gzindex = 0; + } + s->status = COMMENT_STATE; + } + if (s->status == COMMENT_STATE) { + if (s->gzhead->comment != Z_NULL) { + ulg beg = s->pending; /* start of bytes to update crc */ + int val; + do { + if (s->pending == s->pending_buf_size) { + HCRC_UPDATE(beg); + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + beg = 0; + } + val = s->gzhead->comment[s->gzindex++]; + put_byte(s, val); + } while (val != 0); + HCRC_UPDATE(beg); + } + s->status = HCRC_STATE; + } + if (s->status == HCRC_STATE) { + if (s->gzhead->hcrc) { + if (s->pending + 2 > s->pending_buf_size) { + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } + put_byte(s, (Byte)(strm->adler & 0xff)); + put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); + strm->adler = crc32(0L, Z_NULL, 0); + } + s->status = BUSY_STATE; + + /* Compression must start with an empty pending buffer */ + flush_pending(strm); + if (s->pending != 0) { + s->last_flush = -1; + return Z_OK; + } + } +#endif + /* Start a new block or continue the current one. */ if (strm->avail_in != 0 || s->lookahead != 0 || (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { block_state bstate; - bstate = s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : - (s->strategy == Z_RLE ? deflate_rle(s, flush) : - (*(configuration_table[s->level].func))(s, flush)); + bstate = s->level == 0 ? deflate_stored(s, flush) : + s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : + s->strategy == Z_RLE ? deflate_rle(s, flush) : + (*(configuration_table[s->level].func))(s, flush); if (bstate == finish_started || bstate == finish_done) { s->status = FINISH_STATE; @@ -944,7 +1045,6 @@ int ZEXPORT deflate (strm, flush) } } } - Assert(strm->avail_out > 0, "bug2"); if (flush != Z_FINISH) return Z_OK; if (s->wrap <= 0) return Z_STREAM_END; @@ -981,18 +1081,9 @@ int ZEXPORT deflateEnd (strm) { int status; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (deflateStateCheck(strm)) return Z_STREAM_ERROR; status = strm->state->status; - if (status != INIT_STATE && - status != EXTRA_STATE && - status != NAME_STATE && - status != COMMENT_STATE && - status != HCRC_STATE && - status != BUSY_STATE && - status != FINISH_STATE) { - return Z_STREAM_ERROR; - } /* Deallocate in reverse order of allocations: */ TRY_FREE(strm, strm->state->pending_buf); @@ -1023,7 +1114,7 @@ int ZEXPORT deflateCopy (dest, source) ushf *overlay; - if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + if (deflateStateCheck(source) || dest == Z_NULL) { return Z_STREAM_ERROR; } @@ -1073,7 +1164,7 @@ int ZEXPORT deflateCopy (dest, source) * allocating a large strm->next_in buffer and copying from it. * (See also flush_pending()). */ -local int read_buf(strm, buf, size) +local unsigned read_buf(strm, buf, size) z_streamp strm; Bytef *buf; unsigned size; @@ -1097,7 +1188,7 @@ local int read_buf(strm, buf, size) strm->next_in += len; strm->total_in += len; - return (int)len; + return len; } /* =========================================================================== @@ -1151,9 +1242,9 @@ local uInt longest_match(s, cur_match) { unsigned chain_length = s->max_chain_length;/* max hash chain length */ register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ + register Bytef *match; /* matched string */ register int len; /* length of current match */ - int best_len = s->prev_length; /* best match length so far */ + int best_len = (int)s->prev_length; /* best match length so far */ int nice_match = s->nice_match; /* stop if match long enough */ IPos limit = s->strstart > (IPos)MAX_DIST(s) ? s->strstart - (IPos)MAX_DIST(s) : NIL; @@ -1188,7 +1279,7 @@ local uInt longest_match(s, cur_match) /* Do not look for matches beyond the end of the input. This is necessary * to make deflate deterministic. */ - if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); @@ -1349,7 +1440,11 @@ local uInt longest_match(s, cur_match) #endif /* FASTEST */ -#ifdef DEBUG +#ifdef ZLIB_DEBUG + +#define EQUAL 0 +/* result of memcmp for equal strings */ + /* =========================================================================== * Check that the match at match_start is indeed a match. */ @@ -1375,7 +1470,7 @@ local void check_match(s, start, match, length) } #else # define check_match(s, start, match, length) -#endif /* DEBUG */ +#endif /* ZLIB_DEBUG */ /* =========================================================================== * Fill the window when the lookahead becomes insufficient. @@ -1390,8 +1485,7 @@ local void check_match(s, start, match, length) local void fill_window(s) deflate_state *s; { - register unsigned n, m; - register Posf *p; + unsigned n; unsigned more; /* Amount of free space at the end of the window. */ uInt wsize = s->w_size; @@ -1418,35 +1512,13 @@ local void fill_window(s) */ if (s->strstart >= wsize+MAX_DIST(s)) { - zmemcpy(s->window, s->window+wsize, (unsigned)wsize); + zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ s->block_start -= (long) wsize; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - } while (--n); - - n = wsize; -#ifndef FASTEST - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); -#endif + if (s->insert > s->strstart) + s->insert = s->strstart; + slide_hash(s); more += wsize; } if (s->strm->avail_in == 0) break; @@ -1552,70 +1624,205 @@ local void fill_window(s) if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ } +/* Maximum stored block length in deflate format (not including header). */ +#define MAX_STORED 65535 + +/* Minimum of a and b. */ +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + /* =========================================================================== * Copy without compression as much as possible from the input stream, return * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. + * + * In case deflateParams() is used to later switch to a non-zero compression + * level, s->matches (otherwise unused when storing) keeps track of the number + * of hash table slides to perform. If s->matches is 1, then one hash table + * slide will be done when switching. If s->matches is 2, the maximum value + * allowed here, then the hash table will be cleared, since two or more slides + * is the same as a clear. + * + * deflate_stored() is written to minimize the number of times an input byte is + * copied. It is most efficient with large input and output buffers, which + * maximizes the opportunites to have a single copy from next_in to next_out. */ local block_state deflate_stored(s, flush) deflate_state *s; int flush; { - /* Stored blocks are limited to 0xffff bytes, pending_buf is limited - * to pending_buf_size, and each stored block has a 5 byte header: + /* Smallest worthy block size when not flushing or finishing. By default + * this is 32K. This can be as small as 507 bytes for memLevel == 1. For + * large input and output buffers, the stored block size will be larger. */ - ulg max_block_size = 0xffff; - ulg max_start; + unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size); - if (max_block_size > s->pending_buf_size - 5) { - max_block_size = s->pending_buf_size - 5; - } - - /* Copy as much as possible from input to output: */ - for (;;) { - /* Fill the window as much as possible: */ - if (s->lookahead <= 1) { - - Assert(s->strstart < s->w_size+MAX_DIST(s) || - s->block_start >= (long)s->w_size, "slide too late"); - - fill_window(s); - if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; - - if (s->lookahead == 0) break; /* flush the current block */ - } - Assert(s->block_start >= 0L, "block gone"); - - s->strstart += s->lookahead; - s->lookahead = 0; - - /* Emit a stored block if pending_buf will be full: */ - max_start = s->block_start + max_block_size; - if (s->strstart == 0 || (ulg)s->strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s->lookahead = (uInt)(s->strstart - max_start); - s->strstart = (uInt)max_start; - FLUSH_BLOCK(s, 0); - } - /* Flush if we may have to slide, otherwise block_start may become - * negative and the data will be gone: + /* Copy as many min_block or larger stored blocks directly to next_out as + * possible. If flushing, copy the remaining available input to next_out as + * stored blocks, if there is enough space. + */ + unsigned len, left, have, last = 0; + unsigned used = s->strm->avail_in; + do { + /* Set len to the maximum size block that we can copy directly with the + * available input data and output space. Set left to how much of that + * would be copied from what's left in the window. */ - if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { - FLUSH_BLOCK(s, 0); + len = MAX_STORED; /* maximum deflate stored block length */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + if (s->strm->avail_out < have) /* need room for header */ + break; + /* maximum stored block length that will fit in avail_out: */ + have = s->strm->avail_out - have; + left = s->strstart - s->block_start; /* bytes left in window */ + if (len > (ulg)left + s->strm->avail_in) + len = left + s->strm->avail_in; /* limit len to the input */ + if (len > have) + len = have; /* limit len to the output */ + + /* If the stored block would be less than min_block in length, or if + * unable to copy all of the available input when flushing, then try + * copying to the window and the pending buffer instead. Also don't + * write an empty block when flushing -- deflate() does that. + */ + if (len < min_block && ((len == 0 && flush != Z_FINISH) || + flush == Z_NO_FLUSH || + len != left + s->strm->avail_in)) + break; + + /* Make a dummy stored block in pending to get the header bytes, + * including any pending bits. This also updates the debugging counts. + */ + last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; + _tr_stored_block(s, (char *)0, 0L, last); + + /* Replace the lengths in the dummy stored block with len. */ + s->pending_buf[s->pending - 4] = len; + s->pending_buf[s->pending - 3] = len >> 8; + s->pending_buf[s->pending - 2] = ~len; + s->pending_buf[s->pending - 1] = ~len >> 8; + + /* Write the stored block header bytes. */ + flush_pending(s->strm); + +#ifdef ZLIB_DEBUG + /* Update debugging counts for the data about to be copied. */ + s->compressed_len += len << 3; + s->bits_sent += len << 3; +#endif + + /* Copy uncompressed bytes from the window to next_out. */ + if (left) { + if (left > len) + left = len; + zmemcpy(s->strm->next_out, s->window + s->block_start, left); + s->strm->next_out += left; + s->strm->avail_out -= left; + s->strm->total_out += left; + s->block_start += left; + len -= left; } + + /* Copy uncompressed bytes directly from next_in to next_out, updating + * the check value. + */ + if (len) { + read_buf(s->strm, s->strm->next_out, len); + s->strm->next_out += len; + s->strm->avail_out -= len; + s->strm->total_out += len; + } + } while (last == 0); + + /* Update the sliding window with the last s->w_size bytes of the copied + * data, or append all of the copied data to the existing window if less + * than s->w_size bytes were copied. Also update the number of bytes to + * insert in the hash tables, in the event that deflateParams() switches to + * a non-zero compression level. + */ + used -= s->strm->avail_in; /* number of input bytes directly copied */ + if (used) { + /* If any input was used, then no unused input remains in the window, + * therefore s->block_start == s->strstart. + */ + if (used >= s->w_size) { /* supplant the previous history */ + s->matches = 2; /* clear hash */ + zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); + s->strstart = s->w_size; + s->insert = s->strstart; + } + else { + if (s->window_size - s->strstart <= used) { + /* Slide the window down. */ + s->strstart -= s->w_size; + zmemcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + if (s->insert > s->strstart) + s->insert = s->strstart; + } + zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); + s->strstart += used; + s->insert += MIN(used, s->w_size - s->insert); + } + s->block_start = s->strstart; } - s->insert = 0; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); + if (s->high_water < s->strstart) + s->high_water = s->strstart; + + /* If the last block was written to next_out, then done. */ + if (last) return finish_done; + + /* If flushing and all input has been consumed, then done. */ + if (flush != Z_NO_FLUSH && flush != Z_FINISH && + s->strm->avail_in == 0 && (long)s->strstart == s->block_start) + return block_done; + + /* Fill the window with any remaining input. */ + have = s->window_size - s->strstart; + if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) { + /* Slide the window down. */ + s->block_start -= s->w_size; + s->strstart -= s->w_size; + zmemcpy(s->window, s->window + s->w_size, s->strstart); + if (s->matches < 2) + s->matches++; /* add a pending slide_hash() */ + have += s->w_size; /* more space now */ + if (s->insert > s->strstart) + s->insert = s->strstart; } - if ((long)s->strstart > s->block_start) - FLUSH_BLOCK(s, 0); - return block_done; + if (have > s->strm->avail_in) + have = s->strm->avail_in; + if (have) { + read_buf(s->strm, s->window + s->strstart, have); + s->strstart += have; + s->insert += MIN(have, s->w_size - s->insert); + } + if (s->high_water < s->strstart) + s->high_water = s->strstart; + + /* There was not enough avail_out to write a complete worthy or flushed + * stored block to next_out. Write a stored block to pending instead, if we + * have enough input for a worthy block, or if flushing and there is enough + * room for the remaining input as a stored block in the pending buffer. + */ + have = (s->bi_valid + 42) >> 3; /* number of header bytes */ + /* maximum stored block length that will fit in pending: */ + have = MIN(s->pending_buf_size - have, MAX_STORED); + min_block = MIN(have, s->w_size); + left = s->strstart - s->block_start; + if (left >= min_block || + ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && + s->strm->avail_in == 0 && left <= have)) { + len = MIN(left, have); + last = flush == Z_FINISH && s->strm->avail_in == 0 && + len == left ? 1 : 0; + _tr_stored_block(s, (charf *)s->window + s->block_start, len, last); + s->block_start += len; + flush_pending(s->strm); + } + + /* We've done all we can with the available input and output. */ + return last ? finish_started : need_more; } /* =========================================================================== @@ -1892,7 +2099,7 @@ local block_state deflate_rle(s, flush) prev == *++scan && prev == *++scan && prev == *++scan && prev == *++scan && scan < strend); - s->match_length = MAX_MATCH - (int)(strend - scan); + s->match_length = MAX_MATCH - (uInt)(strend - scan); if (s->match_length > s->lookahead) s->match_length = s->lookahead; } diff --git a/contrib/zlib/deflate.h b/contrib/zlib/deflate.h index ce0299edd..23ecdd312 100644 --- a/contrib/zlib/deflate.h +++ b/contrib/zlib/deflate.h @@ -1,5 +1,5 @@ /* deflate.h -- internal compression state - * Copyright (C) 1995-2012 Jean-loup Gailly + * Copyright (C) 1995-2016 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -51,13 +51,16 @@ #define Buf_size 16 /* size of bit buffer in bi_buf */ -#define INIT_STATE 42 -#define EXTRA_STATE 69 -#define NAME_STATE 73 -#define COMMENT_STATE 91 -#define HCRC_STATE 103 -#define BUSY_STATE 113 -#define FINISH_STATE 666 +#define INIT_STATE 42 /* zlib header -> BUSY_STATE */ +#ifdef GZIP +# define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */ +#endif +#define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */ +#define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */ +#define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */ +#define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */ +#define BUSY_STATE 113 /* deflate -> FINISH_STATE */ +#define FINISH_STATE 666 /* stream complete */ /* Stream status */ @@ -83,7 +86,7 @@ typedef struct static_tree_desc_s static_tree_desc; typedef struct tree_desc_s { ct_data *dyn_tree; /* the dynamic tree */ int max_code; /* largest code with non zero frequency */ - static_tree_desc *stat_desc; /* the corresponding static tree */ + const static_tree_desc *stat_desc; /* the corresponding static tree */ } FAR tree_desc; typedef ush Pos; @@ -100,10 +103,10 @@ typedef struct internal_state { Bytef *pending_buf; /* output still pending */ ulg pending_buf_size; /* size of pending_buf */ Bytef *pending_out; /* next pending byte to output to the stream */ - uInt pending; /* nb of bytes in the pending buffer */ + ulg pending; /* nb of bytes in the pending buffer */ int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ gz_headerp gzhead; /* gzip header information to write */ - uInt gzindex; /* where in extra, name, or comment */ + ulg gzindex; /* where in extra, name, or comment */ Byte method; /* can only be DEFLATED */ int last_flush; /* value of flush param for previous deflate call */ @@ -249,7 +252,7 @@ typedef struct internal_state { uInt matches; /* number of string matches in current block */ uInt insert; /* bytes at end of window left to insert */ -#ifdef DEBUG +#ifdef ZLIB_DEBUG ulg compressed_len; /* total bit length of compressed file mod 2^32 */ ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ #endif @@ -275,7 +278,7 @@ typedef struct internal_state { /* Output a byte on the stream. * IN assertion: there is enough room in pending_buf. */ -#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} +#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);} #define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) @@ -309,7 +312,7 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, * used. */ -#ifndef DEBUG +#ifndef ZLIB_DEBUG /* Inline versions of _tr_tally for speed: */ #if defined(GEN_TREES_H) || !defined(STDC) @@ -328,8 +331,8 @@ void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, flush = (s->last_lit == s->lit_bufsize-1); \ } # define _tr_tally_dist(s, distance, length, flush) \ - { uch len = (length); \ - ush dist = (distance); \ + { uch len = (uch)(length); \ + ush dist = (ush)(distance); \ s->d_buf[s->last_lit] = dist; \ s->l_buf[s->last_lit++] = len; \ dist--; \ diff --git a/contrib/zlib/gzguts.h b/contrib/zlib/gzguts.h index d87659d03..6378d468a 100644 --- a/contrib/zlib/gzguts.h +++ b/contrib/zlib/gzguts.h @@ -1,5 +1,5 @@ /* gzguts.h -- zlib internal header definitions for gz* operations - * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -25,6 +25,10 @@ # include # include #endif + +#ifndef _POSIX_SOURCE +# define _POSIX_SOURCE +#endif #include #ifdef _WIN32 @@ -35,6 +39,10 @@ # include #endif +#if defined(_WIN32) +# define WIDECHAR +#endif + #ifdef WINAPI_FAMILY # define open _open # define read _read @@ -95,18 +103,19 @@ # endif #endif -/* unlike snprintf (which is required in C99, yet still not supported by - Microsoft more than a decade later!), _snprintf does not guarantee null - termination of the result -- however this is only used in gzlib.c where +/* unlike snprintf (which is required in C99), _snprintf does not guarantee + null termination of the result -- however this is only used in gzlib.c where the result is assured to fit in the space provided */ -#ifdef _MSC_VER +#if defined(_MSC_VER) && _MSC_VER < 1900 # define snprintf _snprintf #endif #ifndef local # define local static #endif -/* compile with -Dlocal if your debugger can't find static symbols */ +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ /* gz* functions always use library allocation functions */ #ifndef STDC @@ -170,7 +179,7 @@ typedef struct { char *path; /* path or fd for error messages */ unsigned size; /* buffer size, zero if not allocated yet */ unsigned want; /* requested buffer size, default is GZBUFSIZE */ - unsigned char *in; /* input buffer */ + unsigned char *in; /* input buffer (double-sized when writing) */ unsigned char *out; /* output buffer (double-sized when reading) */ int direct; /* 0 if processing gzip, 1 if transparent */ /* just for reading */ diff --git a/contrib/zlib/gzlib.c b/contrib/zlib/gzlib.c index fae202ef8..4838bf047 100644 --- a/contrib/zlib/gzlib.c +++ b/contrib/zlib/gzlib.c @@ -1,5 +1,5 @@ /* gzlib.c -- zlib functions common to reading and writing gzip files - * Copyright (C) 2004, 2010, 2011, 2012, 2013 Mark Adler + * Copyright (C) 2004-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -94,7 +94,7 @@ local gzFile gz_open(path, fd, mode) const char *mode; { gz_statep state; - size_t len; + z_size_t len; int oflag; #ifdef O_CLOEXEC int cloexec = 0; @@ -188,10 +188,10 @@ local gzFile gz_open(path, fd, mode) } /* save the path name for error messages */ -#ifdef _WIN32 +#ifdef WIDECHAR if (fd == -2) { len = wcstombs(NULL, path, 0); - if (len == (size_t)-1) + if (len == (z_size_t)-1) len = 0; } else @@ -202,7 +202,7 @@ local gzFile gz_open(path, fd, mode) free(state); return NULL; } -#ifdef _WIN32 +#ifdef WIDECHAR if (fd == -2) if (len) wcstombs(state->path, path, len + 1); @@ -211,7 +211,7 @@ local gzFile gz_open(path, fd, mode) else #endif #if !defined(NO_snprintf) && !defined(NO_vsnprintf) - snprintf(state->path, len + 1, "%s", (const char *)path); + (void)snprintf(state->path, len + 1, "%s", (const char *)path); #else strcpy(state->path, path); #endif @@ -239,7 +239,7 @@ local gzFile gz_open(path, fd, mode) /* open the file with the appropriate flags (or just use fd) */ state->fd = fd > -1 ? fd : ( -#ifdef _WIN32 +#ifdef WIDECHAR fd == -2 ? _wopen(path, oflag, 0666) : #endif open((const char *)path, oflag, 0666)); @@ -248,8 +248,10 @@ local gzFile gz_open(path, fd, mode) free(state); return NULL; } - if (state->mode == GZ_APPEND) + if (state->mode == GZ_APPEND) { + LSEEK(state->fd, 0, SEEK_END); /* so gzoffset() is correct */ state->mode = GZ_WRITE; /* simplify later checks */ + } /* save the current position for rewinding (only if reading) */ if (state->mode == GZ_READ) { @@ -291,7 +293,7 @@ gzFile ZEXPORT gzdopen(fd, mode) if (fd == -1 || (path = (char *)malloc(7 + 3 * sizeof(int))) == NULL) return NULL; #if !defined(NO_snprintf) && !defined(NO_vsnprintf) - snprintf(path, 7 + 3 * sizeof(int), "", fd); /* for debugging */ + (void)snprintf(path, 7 + 3 * sizeof(int), "", fd); #else sprintf(path, "", fd); /* for debugging */ #endif @@ -301,7 +303,7 @@ gzFile ZEXPORT gzdopen(fd, mode) } /* -- see zlib.h -- */ -#ifdef _WIN32 +#ifdef WIDECHAR gzFile ZEXPORT gzopen_w(path, mode) const wchar_t *path; const char *mode; @@ -329,6 +331,8 @@ int ZEXPORT gzbuffer(file, size) return -1; /* check and set requested size */ + if ((size << 1) < size) + return -1; /* need to be able to double it */ if (size < 2) size = 2; /* need two bytes to check magic header */ state->want = size; @@ -393,7 +397,7 @@ z_off64_t ZEXPORT gzseek64(file, offset, whence) /* if within raw area while reading, just go there */ if (state->mode == GZ_READ && state->how == COPY && state->x.pos + offset >= 0) { - ret = LSEEK(state->fd, offset - state->x.have, SEEK_CUR); + ret = LSEEK(state->fd, offset - (z_off64_t)state->x.have, SEEK_CUR); if (ret == -1) return -1; state->x.have = 0; @@ -604,14 +608,13 @@ void ZLIB_INTERNAL gz_error(state, err, msg) return; } #if !defined(NO_snprintf) && !defined(NO_vsnprintf) - snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, - "%s%s%s", state->path, ": ", msg); + (void)snprintf(state->msg, strlen(state->path) + strlen(msg) + 3, + "%s%s%s", state->path, ": ", msg); #else strcpy(state->msg, state->path); strcat(state->msg, ": "); strcat(state->msg, msg); #endif - return; } #ifndef INT_MAX diff --git a/contrib/zlib/gzread.c b/contrib/zlib/gzread.c index bf4538eb2..f94abfed3 100644 --- a/contrib/zlib/gzread.c +++ b/contrib/zlib/gzread.c @@ -1,5 +1,5 @@ /* gzread.c -- zlib functions for reading gzip files - * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler + * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -12,6 +12,7 @@ local int gz_look OF((gz_statep)); local int gz_decomp OF((gz_statep)); local int gz_fetch OF((gz_statep)); local int gz_skip OF((gz_statep, z_off64_t)); +local z_size_t gz_read OF((gz_statep, voidp, z_size_t)); /* Use read() to load a buffer -- return -1 on error, otherwise 0. Read from state->fd, and update state->eof, state->err, and state->msg as appropriate. @@ -24,13 +25,17 @@ local int gz_load(state, buf, len, have) unsigned *have; { int ret; + unsigned get, max = ((unsigned)-1 >> 2) + 1; *have = 0; do { - ret = read(state->fd, buf + *have, len - *have); + get = len - *have; + if (get > max) + get = max; + ret = read(state->fd, buf + *have, get); if (ret <= 0) break; - *have += ret; + *have += (unsigned)ret; } while (*have < len); if (ret < 0) { gz_error(state, Z_ERRNO, zstrerror()); @@ -94,10 +99,8 @@ local int gz_look(state) state->in = (unsigned char *)malloc(state->want); state->out = (unsigned char *)malloc(state->want << 1); if (state->in == NULL || state->out == NULL) { - if (state->out != NULL) - free(state->out); - if (state->in != NULL) - free(state->in); + free(state->out); + free(state->in); gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } @@ -284,33 +287,17 @@ local int gz_skip(state, len) return 0; } -/* -- see zlib.h -- */ -int ZEXPORT gzread(file, buf, len) - gzFile file; - voidp buf; - unsigned len; -{ - unsigned got, n; +/* Read len bytes into buf from file, or less than len up to the end of the + input. Return the number of bytes read. If zero is returned, either the + end of file was reached, or there was an error. state->err must be + consulted in that case to determine which. */ +local z_size_t gz_read(state, buf, len) gz_statep state; - z_streamp strm; - - /* get internal structure */ - if (file == NULL) - return -1; - state = (gz_statep)file; - strm = &(state->strm); - - /* check that we're reading and that there's no (serious) error */ - if (state->mode != GZ_READ || - (state->err != Z_OK && state->err != Z_BUF_ERROR)) - return -1; - - /* since an int is returned, make sure len fits in one, otherwise return - with an error (this avoids the flaw in the interface) */ - if ((int)len < 0) { - gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); - return -1; - } + voidp buf; + z_size_t len; +{ + z_size_t got; + unsigned n; /* if len is zero, avoid unnecessary operations */ if (len == 0) @@ -320,32 +307,38 @@ int ZEXPORT gzread(file, buf, len) if (state->seek) { state->seek = 0; if (gz_skip(state, state->skip) == -1) - return -1; + return 0; } /* get len bytes to buf, or less than len if at the end */ got = 0; do { + /* set n to the maximum amount of len that fits in an unsigned int */ + n = (unsigned)-1; + if (n > len) + n = (unsigned)len; + /* first just try copying data from the output buffer */ if (state->x.have) { - n = state->x.have > len ? len : state->x.have; + if (state->x.have < n) + n = state->x.have; memcpy(buf, state->x.next, n); state->x.next += n; state->x.have -= n; } /* output buffer empty -- return if we're at the end of the input */ - else if (state->eof && strm->avail_in == 0) { + else if (state->eof && state->strm.avail_in == 0) { state->past = 1; /* tried to read past end */ break; } /* need output data -- for small len or new stream load up our output buffer */ - else if (state->how == LOOK || len < (state->size << 1)) { + else if (state->how == LOOK || n < (state->size << 1)) { /* get more output, looking for header if required */ if (gz_fetch(state) == -1) - return -1; + return 0; continue; /* no progress yet -- go back to copy above */ /* the copy above assures that we will leave with space in the output buffer, allowing at least one gzungetc() to succeed */ @@ -353,16 +346,16 @@ int ZEXPORT gzread(file, buf, len) /* large len -- read directly into user buffer */ else if (state->how == COPY) { /* read directly */ - if (gz_load(state, (unsigned char *)buf, len, &n) == -1) - return -1; + if (gz_load(state, (unsigned char *)buf, n, &n) == -1) + return 0; } /* large len -- decompress directly into user buffer */ else { /* state->how == GZIP */ - strm->avail_out = len; - strm->next_out = (unsigned char *)buf; + state->strm.avail_out = n; + state->strm.next_out = (unsigned char *)buf; if (gz_decomp(state) == -1) - return -1; + return 0; n = state->x.have; state->x.have = 0; } @@ -374,8 +367,75 @@ int ZEXPORT gzread(file, buf, len) state->x.pos += n; } while (len); - /* return number of bytes read into user buffer (will fit in int) */ - return (int)got; + /* return number of bytes read into user buffer */ + return got; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzread(file, buf, len) + gzFile file; + voidp buf; + unsigned len; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return -1; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids a flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in an int"); + return -1; + } + + /* read len or fewer bytes to buf */ + len = (unsigned)gz_read(state, buf, len); + + /* check for an error */ + if (len == 0 && state->err != Z_OK && state->err != Z_BUF_ERROR) + return -1; + + /* return the number of bytes read (this is assured to fit in an int) */ + return (int)len; +} + +/* -- see zlib.h -- */ +z_size_t ZEXPORT gzfread(buf, size, nitems, file) + voidp buf; + z_size_t size; + z_size_t nitems; + gzFile file; +{ + z_size_t len; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're reading and that there's no (serious) error */ + if (state->mode != GZ_READ || + (state->err != Z_OK && state->err != Z_BUF_ERROR)) + return 0; + + /* compute bytes to read -- error on overflow */ + len = nitems * size; + if (size && len / size != nitems) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); + return 0; + } + + /* read len or fewer bytes to buf, return the number of full items read */ + return len ? gz_read(state, buf, len) / size : 0; } /* -- see zlib.h -- */ @@ -387,7 +447,6 @@ int ZEXPORT gzread(file, buf, len) int ZEXPORT gzgetc(file) gzFile file; { - int ret; unsigned char buf[1]; gz_statep state; @@ -408,9 +467,8 @@ int ZEXPORT gzgetc(file) return *(state->x.next)++; } - /* nothing there -- try gzread() */ - ret = gzread(file, buf, 1); - return ret < 1 ? -1 : buf[0]; + /* nothing there -- try gz_read() */ + return gz_read(state, buf, 1) < 1 ? -1 : buf[0]; } int ZEXPORT gzgetc_(file) @@ -451,7 +509,7 @@ int ZEXPORT gzungetc(c, file) if (state->x.have == 0) { state->x.have = 1; state->x.next = state->out + (state->size << 1) - 1; - state->x.next[0] = c; + state->x.next[0] = (unsigned char)c; state->x.pos--; state->past = 0; return c; @@ -473,7 +531,7 @@ int ZEXPORT gzungetc(c, file) } state->x.have++; state->x.next--; - state->x.next[0] = c; + state->x.next[0] = (unsigned char)c; state->x.pos--; state->past = 0; return c; diff --git a/contrib/zlib/gzwrite.c b/contrib/zlib/gzwrite.c index 3ed161f44..3560193b8 100644 --- a/contrib/zlib/gzwrite.c +++ b/contrib/zlib/gzwrite.c @@ -1,5 +1,5 @@ /* gzwrite.c -- zlib functions for writing gzip files - * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013 Mark Adler + * Copyright (C) 2004-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,17 +9,19 @@ local int gz_init OF((gz_statep)); local int gz_comp OF((gz_statep, int)); local int gz_zero OF((gz_statep, z_off64_t)); +local z_size_t gz_write OF((gz_statep, voidpc, z_size_t)); /* Initialize state for writing a gzip file. Mark initialization by setting - state->size to non-zero. Return -1 on failure or 0 on success. */ + state->size to non-zero. Return -1 on a memory allocation failure, or 0 on + success. */ local int gz_init(state) gz_statep state; { int ret; z_streamp strm = &(state->strm); - /* allocate input buffer */ - state->in = (unsigned char *)malloc(state->want); + /* allocate input buffer (double size for gzprintf) */ + state->in = (unsigned char *)malloc(state->want << 1); if (state->in == NULL) { gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; @@ -47,6 +49,7 @@ local int gz_init(state) gz_error(state, Z_MEM_ERROR, "out of memory"); return -1; } + strm->next_in = NULL; } /* mark state as initialized */ @@ -62,17 +65,17 @@ local int gz_init(state) } /* Compress whatever is at avail_in and next_in and write to the output file. - Return -1 if there is an error writing to the output file, otherwise 0. - flush is assumed to be a valid deflate() flush value. If flush is Z_FINISH, - then the deflate() state is reset to start a new gzip stream. If gz->direct - is true, then simply write to the output file without compressing, and - ignore flush. */ + Return -1 if there is an error writing to the output file or if gz_init() + fails to allocate memory, otherwise 0. flush is assumed to be a valid + deflate() flush value. If flush is Z_FINISH, then the deflate() state is + reset to start a new gzip stream. If gz->direct is true, then simply write + to the output file without compressing, and ignore flush. */ local int gz_comp(state, flush) gz_statep state; int flush; { - int ret, got; - unsigned have; + int ret, writ; + unsigned have, put, max = ((unsigned)-1 >> 2) + 1; z_streamp strm = &(state->strm); /* allocate memory if this is the first time through */ @@ -81,12 +84,16 @@ local int gz_comp(state, flush) /* write directly if requested */ if (state->direct) { - got = write(state->fd, strm->next_in, strm->avail_in); - if (got < 0 || (unsigned)got != strm->avail_in) { - gz_error(state, Z_ERRNO, zstrerror()); - return -1; + while (strm->avail_in) { + put = strm->avail_in > max ? max : strm->avail_in; + writ = write(state->fd, strm->next_in, put); + if (writ < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + strm->avail_in -= (unsigned)writ; + strm->next_in += writ; } - strm->avail_in = 0; return 0; } @@ -97,17 +104,21 @@ local int gz_comp(state, flush) doing Z_FINISH then don't write until we get to Z_STREAM_END */ if (strm->avail_out == 0 || (flush != Z_NO_FLUSH && (flush != Z_FINISH || ret == Z_STREAM_END))) { - have = (unsigned)(strm->next_out - state->x.next); - if (have && ((got = write(state->fd, state->x.next, have)) < 0 || - (unsigned)got != have)) { - gz_error(state, Z_ERRNO, zstrerror()); - return -1; + while (strm->next_out > state->x.next) { + put = strm->next_out - state->x.next > (int)max ? max : + (unsigned)(strm->next_out - state->x.next); + writ = write(state->fd, state->x.next, put); + if (writ < 0) { + gz_error(state, Z_ERRNO, zstrerror()); + return -1; + } + state->x.next += writ; } if (strm->avail_out == 0) { strm->avail_out = state->size; strm->next_out = state->out; + state->x.next = state->out; } - state->x.next = strm->next_out; } /* compress */ @@ -129,7 +140,8 @@ local int gz_comp(state, flush) return 0; } -/* Compress len zeros to output. Return -1 on error, 0 on success. */ +/* Compress len zeros to output. Return -1 on a write error or memory + allocation failure by gz_comp(), or 0 on success. */ local int gz_zero(state, len) gz_statep state; z_off64_t len; @@ -161,32 +173,14 @@ local int gz_zero(state, len) return 0; } -/* -- see zlib.h -- */ -int ZEXPORT gzwrite(file, buf, len) - gzFile file; - voidpc buf; - unsigned len; -{ - unsigned put = len; +/* Write len bytes from buf to file. Return the number of bytes written. If + the returned value is less than len, then there was an error. */ +local z_size_t gz_write(state, buf, len) gz_statep state; - z_streamp strm; - - /* get internal structure */ - if (file == NULL) - return 0; - state = (gz_statep)file; - strm = &(state->strm); - - /* check that we're writing and that there's no error */ - if (state->mode != GZ_WRITE || state->err != Z_OK) - return 0; - - /* since an int is returned, make sure len fits in one, otherwise return - with an error (this avoids the flaw in the interface) */ - if ((int)len < 0) { - gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); - return 0; - } + voidpc buf; + z_size_t len; +{ + z_size_t put = len; /* if len is zero, avoid unnecessary operations */ if (len == 0) @@ -209,14 +203,15 @@ int ZEXPORT gzwrite(file, buf, len) do { unsigned have, copy; - if (strm->avail_in == 0) - strm->next_in = state->in; - have = (unsigned)((strm->next_in + strm->avail_in) - state->in); + if (state->strm.avail_in == 0) + state->strm.next_in = state->in; + have = (unsigned)((state->strm.next_in + state->strm.avail_in) - + state->in); copy = state->size - have; if (copy > len) - copy = len; + copy = (unsigned)len; memcpy(state->in + have, buf, copy); - strm->avail_in += copy; + state->strm.avail_in += copy; state->x.pos += copy; buf = (const char *)buf + copy; len -= copy; @@ -226,19 +221,83 @@ int ZEXPORT gzwrite(file, buf, len) } else { /* consume whatever's left in the input buffer */ - if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) + if (state->strm.avail_in && gz_comp(state, Z_NO_FLUSH) == -1) return 0; /* directly compress user buffer to file */ - strm->avail_in = len; - strm->next_in = (z_const Bytef *)buf; - state->x.pos += len; - if (gz_comp(state, Z_NO_FLUSH) == -1) - return 0; + state->strm.next_in = (z_const Bytef *)buf; + do { + unsigned n = (unsigned)-1; + if (n > len) + n = (unsigned)len; + state->strm.avail_in = n; + state->x.pos += n; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return 0; + len -= n; + } while (len); } - /* input was all buffered or compressed (put will fit in int) */ - return (int)put; + /* input was all buffered or compressed */ + return put; +} + +/* -- see zlib.h -- */ +int ZEXPORT gzwrite(file, buf, len) + gzFile file; + voidpc buf; + unsigned len; +{ + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* since an int is returned, make sure len fits in one, otherwise return + with an error (this avoids a flaw in the interface) */ + if ((int)len < 0) { + gz_error(state, Z_DATA_ERROR, "requested length does not fit in int"); + return 0; + } + + /* write len bytes from buf (the return value will fit in an int) */ + return (int)gz_write(state, buf, len); +} + +/* -- see zlib.h -- */ +z_size_t ZEXPORT gzfwrite(buf, size, nitems, file) + voidpc buf; + z_size_t size; + z_size_t nitems; + gzFile file; +{ + z_size_t len; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return 0; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return 0; + + /* compute bytes to read -- error on overflow */ + len = nitems * size; + if (size && len / size != nitems) { + gz_error(state, Z_STREAM_ERROR, "request does not fit in a size_t"); + return 0; + } + + /* write len bytes to buf, return the number of full items written */ + return len ? gz_write(state, buf, len) / size : 0; } /* -- see zlib.h -- */ @@ -275,7 +334,7 @@ int ZEXPORT gzputc(file, c) strm->next_in = state->in; have = (unsigned)((strm->next_in + strm->avail_in) - state->in); if (have < state->size) { - state->in[have] = c; + state->in[have] = (unsigned char)c; strm->avail_in++; state->x.pos++; return c & 0xff; @@ -283,8 +342,8 @@ int ZEXPORT gzputc(file, c) } /* no room in buffer or not initialized, use gz_write() */ - buf[0] = c; - if (gzwrite(file, buf, 1) != 1) + buf[0] = (unsigned char)c; + if (gz_write(state, buf, 1) != 1) return -1; return c & 0xff; } @@ -294,13 +353,26 @@ int ZEXPORT gzputs(file, str) gzFile file; const char *str; { - int ret; - unsigned len; + z_size_t len, put; + gz_statep state; + + /* get internal structure */ + if (file == NULL) + return -1; + state = (gz_statep)file; + + /* check that we're writing and that there's no error */ + if (state->mode != GZ_WRITE || state->err != Z_OK) + return -1; /* write string */ - len = (unsigned)strlen(str); - ret = gzwrite(file, str, len); - return ret == 0 && len != 0 ? -1 : ret; + len = strlen(str); + if ((int)len < 0 || (unsigned)len != len) { + gz_error(state, Z_STREAM_ERROR, "string length does not fit in int"); + return -1; + } + put = gz_write(state, str, len); + return put < len ? -1 : (int)len; } #if defined(STDC) || defined(Z_HAVE_STDARG_H) @@ -309,63 +381,73 @@ int ZEXPORT gzputs(file, str) /* -- see zlib.h -- */ int ZEXPORTVA gzvprintf(gzFile file, const char *format, va_list va) { - int size, len; + int len; + unsigned left; + char *next; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) - return -1; + return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) - return 0; + return Z_STREAM_ERROR; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) - return 0; + return state->err; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) - return 0; + return state->err; } - /* consume whatever's left in the input buffer */ - if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) - return 0; - - /* do the printf() into the input buffer, put length in len */ - size = (int)(state->size); - state->in[size - 1] = 0; + /* do the printf() into the input buffer, put length in len -- the input + buffer is double-sized just for this function, so there is guaranteed to + be state->size bytes available after the current contents */ + if (strm->avail_in == 0) + strm->next_in = state->in; + next = (char *)(state->in + (strm->next_in - state->in) + strm->avail_in); + next[state->size - 1] = 0; #ifdef NO_vsnprintf # ifdef HAS_vsprintf_void - (void)vsprintf((char *)(state->in), format, va); - for (len = 0; len < size; len++) - if (state->in[len] == 0) break; + (void)vsprintf(next, format, va); + for (len = 0; len < state->size; len++) + if (next[len] == 0) break; # else - len = vsprintf((char *)(state->in), format, va); + len = vsprintf(next, format, va); # endif #else # ifdef HAS_vsnprintf_void - (void)vsnprintf((char *)(state->in), size, format, va); - len = strlen((char *)(state->in)); + (void)vsnprintf(next, state->size, format, va); + len = strlen(next); # else - len = vsnprintf((char *)(state->in), size, format, va); + len = vsnprintf(next, state->size, format, va); # endif #endif /* check that printf() results fit in buffer */ - if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) + if (len == 0 || (unsigned)len >= state->size || next[state->size - 1] != 0) return 0; - /* update buffer and position, defer compression until needed */ - strm->avail_in = (unsigned)len; - strm->next_in = state->in; + /* update buffer and position, compress first half if past that */ + strm->avail_in += (unsigned)len; state->x.pos += len; + if (strm->avail_in >= state->size) { + left = strm->avail_in - state->size; + strm->avail_in = state->size; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return state->err; + memcpy(state->in, state->in + state->size, left); + strm->next_in = state->in; + strm->avail_in = left; + } return len; } @@ -390,73 +472,82 @@ int ZEXPORTVA gzprintf (file, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, int a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20; { - int size, len; + unsigned len, left; + char *next; gz_statep state; z_streamp strm; /* get internal structure */ if (file == NULL) - return -1; + return Z_STREAM_ERROR; state = (gz_statep)file; strm = &(state->strm); /* check that can really pass pointer in ints */ if (sizeof(int) != sizeof(void *)) - return 0; + return Z_STREAM_ERROR; /* check that we're writing and that there's no error */ if (state->mode != GZ_WRITE || state->err != Z_OK) - return 0; + return Z_STREAM_ERROR; /* make sure we have some buffer space */ if (state->size == 0 && gz_init(state) == -1) - return 0; + return state->error; /* check for seek request */ if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) - return 0; + return state->error; } - /* consume whatever's left in the input buffer */ - if (strm->avail_in && gz_comp(state, Z_NO_FLUSH) == -1) - return 0; - - /* do the printf() into the input buffer, put length in len */ - size = (int)(state->size); - state->in[size - 1] = 0; + /* do the printf() into the input buffer, put length in len -- the input + buffer is double-sized just for this function, so there is guaranteed to + be state->size bytes available after the current contents */ + if (strm->avail_in == 0) + strm->next_in = state->in; + next = (char *)(strm->next_in + strm->avail_in); + next[state->size - 1] = 0; #ifdef NO_snprintf # ifdef HAS_sprintf_void - sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, + a13, a14, a15, a16, a17, a18, a19, a20); for (len = 0; len < size; len++) - if (state->in[len] == 0) break; + if (next[len] == 0) + break; # else - len = sprintf((char *)(state->in), format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = sprintf(next, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, + a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #else # ifdef HAS_snprintf_void - snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, a7, a8, - a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); - len = strlen((char *)(state->in)); + snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, a9, + a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); + len = strlen(next); # else - len = snprintf((char *)(state->in), size, format, a1, a2, a3, a4, a5, a6, - a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, - a19, a20); + len = snprintf(next, state->size, format, a1, a2, a3, a4, a5, a6, a7, a8, + a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19, a20); # endif #endif /* check that printf() results fit in buffer */ - if (len <= 0 || len >= (int)size || state->in[size - 1] != 0) + if (len == 0 || len >= state->size || next[state->size - 1] != 0) return 0; - /* update buffer and position, defer compression until needed */ - strm->avail_in = (unsigned)len; - strm->next_in = state->in; + /* update buffer and position, compress first half if past that */ + strm->avail_in += len; state->x.pos += len; - return len; + if (strm->avail_in >= state->size) { + left = strm->avail_in - state->size; + strm->avail_in = state->size; + if (gz_comp(state, Z_NO_FLUSH) == -1) + return state->err; + memcpy(state->in, state->in + state->size, left); + strm->next_in = state->in; + strm->avail_in = left; + } + return (int)len; } #endif @@ -470,7 +561,7 @@ int ZEXPORT gzflush(file, flush) /* get internal structure */ if (file == NULL) - return -1; + return Z_STREAM_ERROR; state = (gz_statep)file; /* check that we're writing and that there's no error */ @@ -485,11 +576,11 @@ int ZEXPORT gzflush(file, flush) if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) - return -1; + return state->err; } /* compress remaining data with requested flush */ - gz_comp(state, flush); + (void)gz_comp(state, flush); return state->err; } @@ -520,13 +611,13 @@ int ZEXPORT gzsetparams(file, level, strategy) if (state->seek) { state->seek = 0; if (gz_zero(state, state->skip) == -1) - return -1; + return state->err; } /* change compression parameters for subsequent input */ if (state->size) { /* flush previous input with previous parameters before changing */ - if (strm->avail_in && gz_comp(state, Z_PARTIAL_FLUSH) == -1) + if (strm->avail_in && gz_comp(state, Z_BLOCK) == -1) return state->err; deflateParams(strm, level, strategy); } diff --git a/contrib/zlib/infback.c b/contrib/zlib/infback.c index f3833c2e4..59679ecbf 100644 --- a/contrib/zlib/infback.c +++ b/contrib/zlib/infback.c @@ -1,5 +1,5 @@ /* infback.c -- inflate using a call-back interface - * Copyright (C) 1995-2011 Mark Adler + * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -61,7 +61,7 @@ int stream_size; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; state->dmax = 32768U; - state->wbits = windowBits; + state->wbits = (uInt)windowBits; state->wsize = 1U << windowBits; state->window = window; state->wnext = 0; diff --git a/contrib/zlib/inffast.c b/contrib/zlib/inffast.c index bda59ceb6..1fec7f363 100644 --- a/contrib/zlib/inffast.c +++ b/contrib/zlib/inffast.c @@ -1,5 +1,5 @@ /* inffast.c -- fast decoding - * Copyright (C) 1995-2008, 2010, 2013 Mark Adler + * Copyright (C) 1995-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -8,26 +8,9 @@ #include "inflate.h" #include "inffast.h" -#ifndef ASMINF - -/* Allow machine dependent optimization for post-increment or pre-increment. - Based on testing to date, - Pre-increment preferred for: - - PowerPC G3 (Adler) - - MIPS R5000 (Randers-Pehrson) - Post-increment preferred for: - - none - No measurable difference: - - Pentium III (Anderson) - - M68060 (Nikl) - */ -#ifdef POSTINC -# define OFF 0 -# define PUP(a) *(a)++ +#ifdef ASMINF +# pragma message("Assembler code may have bugs -- use at your own risk") #else -# define OFF 1 -# define PUP(a) *++(a) -#endif /* Decode literal, length, and distance codes and write out the resulting @@ -87,7 +70,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ code const FAR *dcode; /* local strm->distcode */ unsigned lmask; /* mask for first level of length codes */ unsigned dmask; /* mask for first level of distance codes */ - code here; /* retrieved table entry */ + code const *here; /* retrieved table entry */ unsigned op; /* code bits, operation, extra bits, or */ /* window position, window bytes to copy */ unsigned len; /* match length, unused bytes */ @@ -96,9 +79,9 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ /* copy state to local variables */ state = (struct inflate_state FAR *)strm->state; - in = strm->next_in - OFF; + in = strm->next_in; last = in + (strm->avail_in - 5); - out = strm->next_out - OFF; + out = strm->next_out; beg = out - (start - strm->avail_out); end = out + (strm->avail_out - 257); #ifdef INFLATE_STRICT @@ -119,29 +102,29 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ input data or output space */ do { if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; + hold += (unsigned long)(*in++) << bits; bits += 8; - hold += (unsigned long)(PUP(in)) << bits; + hold += (unsigned long)(*in++) << bits; bits += 8; } - here = lcode[hold & lmask]; + here = lcode + (hold & lmask); dolen: - op = (unsigned)(here.bits); + op = (unsigned)(here->bits); hold >>= op; bits -= op; - op = (unsigned)(here.op); + op = (unsigned)(here->op); if (op == 0) { /* literal */ - Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? + Tracevv((stderr, here->val >= 0x20 && here->val < 0x7f ? "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", here.val)); - PUP(out) = (unsigned char)(here.val); + "inflate: literal 0x%02x\n", here->val)); + *out++ = (unsigned char)(here->val); } else if (op & 16) { /* length base */ - len = (unsigned)(here.val); + len = (unsigned)(here->val); op &= 15; /* number of extra bits */ if (op) { if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; + hold += (unsigned long)(*in++) << bits; bits += 8; } len += (unsigned)hold & ((1U << op) - 1); @@ -150,25 +133,25 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ } Tracevv((stderr, "inflate: length %u\n", len)); if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; + hold += (unsigned long)(*in++) << bits; bits += 8; - hold += (unsigned long)(PUP(in)) << bits; + hold += (unsigned long)(*in++) << bits; bits += 8; } - here = dcode[hold & dmask]; + here = dcode + (hold & dmask); dodist: - op = (unsigned)(here.bits); + op = (unsigned)(here->bits); hold >>= op; bits -= op; - op = (unsigned)(here.op); + op = (unsigned)(here->op); if (op & 16) { /* distance base */ - dist = (unsigned)(here.val); + dist = (unsigned)(here->val); op &= 15; /* number of extra bits */ if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; + hold += (unsigned long)(*in++) << bits; bits += 8; if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; + hold += (unsigned long)(*in++) << bits; bits += 8; } } @@ -196,30 +179,30 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR if (len <= op - whave) { do { - PUP(out) = 0; + *out++ = 0; } while (--len); continue; } len -= op - whave; do { - PUP(out) = 0; + *out++ = 0; } while (--op > whave); if (op == 0) { from = out - dist; do { - PUP(out) = PUP(from); + *out++ = *from++; } while (--len); continue; } #endif } - from = window - OFF; + from = window; if (wnext == 0) { /* very common case */ from += wsize - op; if (op < len) { /* some from window */ len -= op; do { - PUP(out) = PUP(from); + *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } @@ -230,14 +213,14 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ if (op < len) { /* some from end of window */ len -= op; do { - PUP(out) = PUP(from); + *out++ = *from++; } while (--op); - from = window - OFF; + from = window; if (wnext < len) { /* some from start of window */ op = wnext; len -= op; do { - PUP(out) = PUP(from); + *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } @@ -248,40 +231,40 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ if (op < len) { /* some from window */ len -= op; do { - PUP(out) = PUP(from); + *out++ = *from++; } while (--op); from = out - dist; /* rest from output */ } } while (len > 2) { - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; len -= 3; } if (len) { - PUP(out) = PUP(from); + *out++ = *from++; if (len > 1) - PUP(out) = PUP(from); + *out++ = *from++; } } else { from = out - dist; /* copy direct from output */ do { /* minimum length is three */ - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); + *out++ = *from++; + *out++ = *from++; + *out++ = *from++; len -= 3; } while (len > 2); if (len) { - PUP(out) = PUP(from); + *out++ = *from++; if (len > 1) - PUP(out) = PUP(from); + *out++ = *from++; } } } else if ((op & 64) == 0) { /* 2nd level distance code */ - here = dcode[here.val + (hold & ((1U << op) - 1))]; + here = dcode + here->val + (hold & ((1U << op) - 1)); goto dodist; } else { @@ -291,7 +274,7 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ } } else if ((op & 64) == 0) { /* 2nd level length code */ - here = lcode[here.val + (hold & ((1U << op) - 1))]; + here = lcode + here->val + (hold & ((1U << op) - 1)); goto dolen; } else if (op & 32) { /* end-of-block */ @@ -313,8 +296,8 @@ unsigned start; /* inflate()'s starting value for strm->avail_out */ hold &= (1U << bits) - 1; /* update state and return */ - strm->next_in = in + OFF; - strm->next_out = out + OFF; + strm->next_in = in; + strm->next_out = out; strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); strm->avail_out = (unsigned)(out < end ? 257 + (end - out) : 257 - (out - end)); diff --git a/contrib/zlib/inflate.c b/contrib/zlib/inflate.c index 870f89bb4..575fcdf82 100644 --- a/contrib/zlib/inflate.c +++ b/contrib/zlib/inflate.c @@ -1,5 +1,5 @@ /* inflate.c -- zlib decompression - * Copyright (C) 1995-2012 Mark Adler + * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -92,6 +92,7 @@ #endif /* function prototypes */ +local int inflateStateCheck OF((z_streamp strm)); local void fixedtables OF((struct inflate_state FAR *state)); local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, unsigned copy)); @@ -101,12 +102,26 @@ local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, unsigned len)); +local int inflateStateCheck(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (strm == Z_NULL || + strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) + return 1; + state = (struct inflate_state FAR *)strm->state; + if (state == Z_NULL || state->strm != strm || + state->mode < HEAD || state->mode > SYNC) + return 1; + return 0; +} + int ZEXPORT inflateResetKeep(strm) z_streamp strm; { struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; strm->total_in = strm->total_out = state->total = 0; strm->msg = Z_NULL; @@ -131,7 +146,7 @@ z_streamp strm; { struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; state->wsize = 0; state->whave = 0; @@ -147,7 +162,7 @@ int windowBits; struct inflate_state FAR *state; /* get the state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* extract wrap request from windowBits parameter */ @@ -156,7 +171,7 @@ int windowBits; windowBits = -windowBits; } else { - wrap = (windowBits >> 4) + 1; + wrap = (windowBits >> 4) + 5; #ifdef GUNZIP if (windowBits < 48) windowBits &= 15; @@ -210,7 +225,9 @@ int stream_size; if (state == Z_NULL) return Z_MEM_ERROR; Tracev((stderr, "inflate: allocated\n")); strm->state = (struct internal_state FAR *)state; + state->strm = strm; state->window = Z_NULL; + state->mode = HEAD; /* to pass state test in inflateReset2() */ ret = inflateReset2(strm, windowBits); if (ret != Z_OK) { ZFREE(strm, state); @@ -234,17 +251,17 @@ int value; { struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (bits < 0) { state->hold = 0; state->bits = 0; return Z_OK; } - if (bits > 16 || state->bits + bits > 32) return Z_STREAM_ERROR; + if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; value &= (1L << bits) - 1; - state->hold += value << state->bits; - state->bits += bits; + state->hold += (unsigned)value << state->bits; + state->bits += (uInt)bits; return Z_OK; } @@ -625,7 +642,7 @@ int flush; static const unsigned short order[19] = /* permutation of code lengths */ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - if (strm == Z_NULL || strm->state == Z_NULL || strm->next_out == Z_NULL || + if (inflateStateCheck(strm) || strm->next_out == Z_NULL || (strm->next_in == Z_NULL && strm->avail_in != 0)) return Z_STREAM_ERROR; @@ -645,6 +662,8 @@ int flush; NEEDBITS(16); #ifdef GUNZIP if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ + if (state->wbits == 0) + state->wbits = 15; state->check = crc32(0L, Z_NULL, 0); CRC2(state->check, hold); INITBITS(); @@ -672,7 +691,7 @@ int flush; len = BITS(4) + 8; if (state->wbits == 0) state->wbits = len; - else if (len > state->wbits) { + if (len > 15 || len > state->wbits) { strm->msg = (char *)"invalid window size"; state->mode = BAD; break; @@ -699,14 +718,16 @@ int flush; } if (state->head != Z_NULL) state->head->text = (int)((hold >> 8) & 1); - if (state->flags & 0x0200) CRC2(state->check, hold); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); INITBITS(); state->mode = TIME; case TIME: NEEDBITS(32); if (state->head != Z_NULL) state->head->time = hold; - if (state->flags & 0x0200) CRC4(state->check, hold); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC4(state->check, hold); INITBITS(); state->mode = OS; case OS: @@ -715,7 +736,8 @@ int flush; state->head->xflags = (int)(hold & 0xff); state->head->os = (int)(hold >> 8); } - if (state->flags & 0x0200) CRC2(state->check, hold); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); INITBITS(); state->mode = EXLEN; case EXLEN: @@ -724,7 +746,8 @@ int flush; state->length = (unsigned)(hold); if (state->head != Z_NULL) state->head->extra_len = (unsigned)hold; - if (state->flags & 0x0200) CRC2(state->check, hold); + if ((state->flags & 0x0200) && (state->wrap & 4)) + CRC2(state->check, hold); INITBITS(); } else if (state->head != Z_NULL) @@ -742,7 +765,7 @@ int flush; len + copy > state->head->extra_max ? state->head->extra_max - len : copy); } - if (state->flags & 0x0200) + if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; @@ -761,9 +784,9 @@ int flush; if (state->head != Z_NULL && state->head->name != Z_NULL && state->length < state->head->name_max) - state->head->name[state->length++] = len; + state->head->name[state->length++] = (Bytef)len; } while (len && copy < have); - if (state->flags & 0x0200) + if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; @@ -782,9 +805,9 @@ int flush; if (state->head != Z_NULL && state->head->comment != Z_NULL && state->length < state->head->comm_max) - state->head->comment[state->length++] = len; + state->head->comment[state->length++] = (Bytef)len; } while (len && copy < have); - if (state->flags & 0x0200) + if ((state->flags & 0x0200) && (state->wrap & 4)) state->check = crc32(state->check, next, copy); have -= copy; next += copy; @@ -796,7 +819,7 @@ int flush; case HCRC: if (state->flags & 0x0200) { NEEDBITS(16); - if (hold != (state->check & 0xffff)) { + if ((state->wrap & 4) && hold != (state->check & 0xffff)) { strm->msg = (char *)"header crc mismatch"; state->mode = BAD; break; @@ -1177,11 +1200,11 @@ int flush; out -= left; strm->total_out += out; state->total += out; - if (out) + if ((state->wrap & 4) && out) strm->adler = state->check = UPDATE(state->check, put - out, out); out = left; - if (( + if ((state->wrap & 4) && ( #ifdef GUNZIP state->flags ? hold : #endif @@ -1240,10 +1263,10 @@ int flush; strm->total_in += in; strm->total_out += out; state->total += out; - if (state->wrap && out) + if ((state->wrap & 4) && out) strm->adler = state->check = UPDATE(state->check, strm->next_out - out, out); - strm->data_type = state->bits + (state->last ? 64 : 0) + + strm->data_type = (int)state->bits + (state->last ? 64 : 0) + (state->mode == TYPE ? 128 : 0) + (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) @@ -1255,7 +1278,7 @@ int ZEXPORT inflateEnd(strm) z_streamp strm; { struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0) + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->window != Z_NULL) ZFREE(strm, state->window); @@ -1273,7 +1296,7 @@ uInt *dictLength; struct inflate_state FAR *state; /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; /* copy dictionary */ @@ -1298,7 +1321,7 @@ uInt dictLength; int ret; /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (state->wrap != 0 && state->mode != DICT) return Z_STREAM_ERROR; @@ -1330,7 +1353,7 @@ gz_headerp head; struct inflate_state FAR *state; /* check state */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; @@ -1383,7 +1406,7 @@ z_streamp strm; struct inflate_state FAR *state; /* check parameters */ - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; @@ -1410,6 +1433,8 @@ z_streamp strm; /* return no joy or set up to restart inflate() on a new block */ if (state->have != 4) return Z_DATA_ERROR; + if (state->mode == HEAD) + state->wrap = 0; /* never processed header, so assume raw */ in = strm->total_in; out = strm->total_out; inflateReset(strm); strm->total_in = in; strm->total_out = out; @@ -1430,7 +1455,7 @@ z_streamp strm; { struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; return state->mode == STORED && state->bits == 0; } @@ -1445,8 +1470,7 @@ z_streamp source; unsigned wsize; /* check input */ - if (dest == Z_NULL || source == Z_NULL || source->state == Z_NULL || - source->zalloc == (alloc_func)0 || source->zfree == (free_func)0) + if (inflateStateCheck(source) || dest == Z_NULL) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)source->state; @@ -1467,6 +1491,7 @@ z_streamp source; /* copy state */ zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); + copy->strm = dest; if (state->lencode >= state->codes && state->lencode <= state->codes + ENOUGH - 1) { copy->lencode = copy->codes + (state->lencode - state->codes); @@ -1488,25 +1513,51 @@ int subvert; { struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; state = (struct inflate_state FAR *)strm->state; - state->sane = !subvert; #ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR + state->sane = !subvert; return Z_OK; #else + (void)subvert; state->sane = 1; return Z_DATA_ERROR; #endif } +int ZEXPORT inflateValidate(strm, check) +z_streamp strm; +int check; +{ + struct inflate_state FAR *state; + + if (inflateStateCheck(strm)) return Z_STREAM_ERROR; + state = (struct inflate_state FAR *)strm->state; + if (check && state->wrap) + state->wrap |= 4; + else + state->wrap &= ~4; + return Z_OK; +} + long ZEXPORT inflateMark(strm) z_streamp strm; { struct inflate_state FAR *state; - if (strm == Z_NULL || strm->state == Z_NULL) return -1L << 16; + if (inflateStateCheck(strm)) + return -(1L << 16); state = (struct inflate_state FAR *)strm->state; - return ((long)(state->back) << 16) + + return (long)(((unsigned long)((long)state->back)) << 16) + (state->mode == COPY ? state->length : (state->mode == MATCH ? state->was - state->length : 0)); } + +unsigned long ZEXPORT inflateCodesUsed(strm) +z_streamp strm; +{ + struct inflate_state FAR *state; + if (inflateStateCheck(strm)) return (unsigned long)-1; + state = (struct inflate_state FAR *)strm->state; + return (unsigned long)(state->next - state->codes); +} diff --git a/contrib/zlib/inflate.h b/contrib/zlib/inflate.h index 95f4986d4..a46cce6b6 100644 --- a/contrib/zlib/inflate.h +++ b/contrib/zlib/inflate.h @@ -1,5 +1,5 @@ /* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2009 Mark Adler + * Copyright (C) 1995-2016 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -18,7 +18,7 @@ /* Possible inflate modes between inflate() calls */ typedef enum { - HEAD, /* i: waiting for magic header */ + HEAD = 16180, /* i: waiting for magic header */ FLAGS, /* i: waiting for method and flags (gzip) */ TIME, /* i: waiting for modification time (gzip) */ OS, /* i: waiting for extra flags and operating system (gzip) */ @@ -77,11 +77,14 @@ typedef enum { CHECK -> LENGTH -> DONE */ -/* state maintained between inflate() calls. Approximately 10K bytes. */ +/* State maintained between inflate() calls -- approximately 7K bytes, not + including the allocated sliding window, which is up to 32K bytes. */ struct inflate_state { + z_streamp strm; /* pointer back to this zlib stream */ inflate_mode mode; /* current inflate mode */ int last; /* true if processing last block */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ + int wrap; /* bit 0 true for zlib, bit 1 true for gzip, + bit 2 true to validate check value */ int havedict; /* true if dictionary provided */ int flags; /* gzip header method and flags (0 if zlib) */ unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ diff --git a/contrib/zlib/inftrees.c b/contrib/zlib/inftrees.c index 44d89cf24..716c98842 100644 --- a/contrib/zlib/inftrees.c +++ b/contrib/zlib/inftrees.c @@ -1,5 +1,5 @@ /* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2013 Mark Adler + * Copyright (C) 1995-2017 Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,7 +9,7 @@ #define MAXBITS 15 const char inflate_copyright[] = - " inflate 1.2.8 Copyright 1995-2013 Mark Adler "; + " inflate 1.2.11.1 Copyright 1995-2017 Mark Adler "; /* If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot @@ -54,7 +54,7 @@ unsigned short FAR *work; code FAR *next; /* next available space in table */ const unsigned short FAR *base; /* base value table to use */ const unsigned short FAR *extra; /* extra bits table to use */ - int end; /* use base and extra for symbol > end */ + unsigned match; /* use base and extra for symbol >= match */ unsigned short count[MAXBITS+1]; /* number of codes of each length */ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ static const unsigned short lbase[31] = { /* Length codes 257..285 base */ @@ -62,7 +62,7 @@ unsigned short FAR *work; 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; static const unsigned short lext[31] = { /* Length codes 257..285 extra */ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78}; + 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 198, 196}; static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ 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, @@ -181,19 +181,17 @@ unsigned short FAR *work; switch (type) { case CODES: base = extra = work; /* dummy value--not used */ - end = 19; + match = 20; break; case LENS: base = lbase; - base -= 257; extra = lext; - extra -= 257; - end = 256; + match = 257; break; - default: /* DISTS */ + default: /* DISTS */ base = dbase; extra = dext; - end = -1; + match = 0; } /* initialize state for loop */ @@ -216,13 +214,13 @@ unsigned short FAR *work; for (;;) { /* create table entry */ here.bits = (unsigned char)(len - drop); - if ((int)(work[sym]) < end) { + if (work[sym] + 1U < match) { here.op = (unsigned char)0; here.val = work[sym]; } - else if ((int)(work[sym]) > end) { - here.op = (unsigned char)(extra[work[sym]]); - here.val = base[work[sym]]; + else if (work[sym] >= match) { + here.op = (unsigned char)(extra[work[sym] - match]); + here.val = base[work[sym] - match]; } else { here.op = (unsigned char)(32 + 64); /* end of block */ diff --git a/contrib/zlib/trees.c b/contrib/zlib/trees.c index 1fd7759ef..50cf4b457 100644 --- a/contrib/zlib/trees.c +++ b/contrib/zlib/trees.c @@ -1,5 +1,5 @@ /* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2012 Jean-loup Gailly + * Copyright (C) 1995-2017 Jean-loup Gailly * detect_data_type() function provided freely by Cosmin Truta, 2006 * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -36,7 +36,7 @@ #include "deflate.h" -#ifdef DEBUG +#ifdef ZLIB_DEBUG # include #endif @@ -122,13 +122,13 @@ struct static_tree_desc_s { int max_length; /* max bit length for the codes */ }; -local static_tree_desc static_l_desc = +local const static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; -local static_tree_desc static_d_desc = +local const static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; -local static_tree_desc static_bl_desc = +local const static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== @@ -152,18 +152,16 @@ local int detect_data_type OF((deflate_state *s)); local unsigned bi_reverse OF((unsigned value, int length)); local void bi_windup OF((deflate_state *s)); local void bi_flush OF((deflate_state *s)); -local void copy_block OF((deflate_state *s, charf *buf, unsigned len, - int header)); #ifdef GEN_TREES_H local void gen_trees_header OF((void)); #endif -#ifndef DEBUG +#ifndef ZLIB_DEBUG # define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) /* Send a code of the given tree. c and tree must not have side effects */ -#else /* DEBUG */ +#else /* !ZLIB_DEBUG */ # define send_code(s, c, tree) \ { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ send_bits(s, tree[c].Code, tree[c].Len); } @@ -182,7 +180,7 @@ local void gen_trees_header OF((void)); * Send a value on a given number of bits. * IN assertion: length <= 16 and value fits in length bits. */ -#ifdef DEBUG +#ifdef ZLIB_DEBUG local void send_bits OF((deflate_state *s, int value, int length)); local void send_bits(s, value, length) @@ -208,12 +206,12 @@ local void send_bits(s, value, length) s->bi_valid += length; } } -#else /* !DEBUG */ +#else /* !ZLIB_DEBUG */ #define send_bits(s, value, length) \ { int len = length;\ if (s->bi_valid > (int)Buf_size - len) {\ - int val = value;\ + int val = (int)value;\ s->bi_buf |= (ush)val << s->bi_valid;\ put_short(s, s->bi_buf);\ s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ @@ -223,7 +221,7 @@ local void send_bits(s, value, length) s->bi_valid += len;\ }\ } -#endif /* DEBUG */ +#endif /* ZLIB_DEBUG */ /* the arguments must not have side effects */ @@ -317,7 +315,7 @@ local void tr_static_init() * Genererate the file trees.h describing the static trees. */ #ifdef GEN_TREES_H -# ifndef DEBUG +# ifndef ZLIB_DEBUG # include # endif @@ -394,7 +392,7 @@ void ZLIB_INTERNAL _tr_init(s) s->bi_buf = 0; s->bi_valid = 0; -#ifdef DEBUG +#ifdef ZLIB_DEBUG s->compressed_len = 0L; s->bits_sent = 0L; #endif @@ -522,12 +520,12 @@ local void gen_bitlen(s, desc) xbits = 0; if (n >= base) xbits = extra[n-base]; f = tree[n].Freq; - s->opt_len += (ulg)f * (bits + xbits); - if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + s->opt_len += (ulg)f * (unsigned)(bits + xbits); + if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); } if (overflow == 0) return; - Trace((stderr,"\nbit length overflow\n")); + Tracev((stderr,"\nbit length overflow\n")); /* This happens for example on obj2 and pic of the Calgary corpus */ /* Find the first bit length which could increase: */ @@ -554,9 +552,8 @@ local void gen_bitlen(s, desc) m = s->heap[--h]; if (m > max_code) continue; if ((unsigned) tree[m].Len != (unsigned) bits) { - Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s->opt_len += ((long)bits - (long)tree[m].Len) - *(long)tree[m].Freq; + Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq; tree[m].Len = (ush)bits; } n--; @@ -578,7 +575,7 @@ local void gen_codes (tree, max_code, bl_count) ushf *bl_count; /* number of codes at each bit length */ { ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ + unsigned code = 0; /* running code value */ int bits; /* bit index */ int n; /* code index */ @@ -586,7 +583,8 @@ local void gen_codes (tree, max_code, bl_count) * without bit reversal. */ for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits-1]) << 1; + code = (code + bl_count[bits-1]) << 1; + next_code[bits] = (ush)code; } /* Check that the bit counts in bl_count are consistent. The last code * must be all ones. @@ -599,7 +597,7 @@ local void gen_codes (tree, max_code, bl_count) int len = tree[n].Len; if (len == 0) continue; /* Now reverse the bits */ - tree[n].Code = bi_reverse(next_code[len]++, len); + tree[n].Code = (ush)bi_reverse(next_code[len]++, len); Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1)); @@ -821,7 +819,7 @@ local int build_bl_tree(s) if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; } /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*(max_blindex+1) + 5+5+4; + s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4; Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", s->opt_len, s->static_len)); @@ -869,11 +867,17 @@ void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) int last; /* one if this is the last block for a file */ { send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ -#ifdef DEBUG + bi_windup(s); /* align on byte boundary */ + put_short(s, (ush)stored_len); + put_short(s, (ush)~stored_len); + zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len); + s->pending += stored_len; +#ifdef ZLIB_DEBUG s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; s->compressed_len += (stored_len + 4) << 3; + s->bits_sent += 2*16; + s->bits_sent += stored_len<<3; #endif - copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ } /* =========================================================================== @@ -894,7 +898,7 @@ void ZLIB_INTERNAL _tr_align(s) { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); -#ifdef DEBUG +#ifdef ZLIB_DEBUG s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ #endif bi_flush(s); @@ -902,7 +906,7 @@ void ZLIB_INTERNAL _tr_align(s) /* =========================================================================== * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. + * trees or store, and write out the encoded block. */ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) deflate_state *s; @@ -974,7 +978,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) send_bits(s, (STATIC_TREES<<1)+last, 3); compress_block(s, (const ct_data *)static_ltree, (const ct_data *)static_dtree); -#ifdef DEBUG +#ifdef ZLIB_DEBUG s->compressed_len += 3 + s->static_len; #endif } else { @@ -983,7 +987,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) max_blindex+1); compress_block(s, (const ct_data *)s->dyn_ltree, (const ct_data *)s->dyn_dtree); -#ifdef DEBUG +#ifdef ZLIB_DEBUG s->compressed_len += 3 + s->opt_len; #endif } @@ -995,7 +999,7 @@ void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) if (last) { bi_windup(s); -#ifdef DEBUG +#ifdef ZLIB_DEBUG s->compressed_len += 7; /* align on byte boundary */ #endif } @@ -1090,7 +1094,7 @@ local void compress_block(s, ltree, dtree) send_code(s, code, dtree); /* send the distance code */ extra = extra_dbits[code]; if (extra != 0) { - dist -= base_dist[code]; + dist -= (unsigned)base_dist[code]; send_bits(s, dist, extra); /* send the extra distance bits */ } } /* literal or match pair ? */ @@ -1193,34 +1197,7 @@ local void bi_windup(s) } s->bi_buf = 0; s->bi_valid = 0; -#ifdef DEBUG +#ifdef ZLIB_DEBUG s->bits_sent = (s->bits_sent+7) & ~7; #endif } - -/* =========================================================================== - * Copy a stored block, storing first the length and its - * one's complement if requested. - */ -local void copy_block(s, buf, len, header) - deflate_state *s; - charf *buf; /* the input data */ - unsigned len; /* its length */ - int header; /* true if block header must be written */ -{ - bi_windup(s); /* align on byte boundary */ - - if (header) { - put_short(s, (ush)len); - put_short(s, (ush)~len); -#ifdef DEBUG - s->bits_sent += 2*16; -#endif - } -#ifdef DEBUG - s->bits_sent += (ulg)len<<3; -#endif - while (len--) { - put_byte(s, *buf++); - } -} diff --git a/contrib/zlib/uncompr.c b/contrib/zlib/uncompr.c index 242e9493d..f03a1a865 100644 --- a/contrib/zlib/uncompr.c +++ b/contrib/zlib/uncompr.c @@ -1,5 +1,5 @@ /* uncompr.c -- decompress a memory buffer - * Copyright (C) 1995-2003, 2010 Jean-loup Gailly. + * Copyright (C) 1995-2003, 2010, 2014, 2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -9,51 +9,85 @@ #include "zlib.h" /* =========================================================================== - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total - size of the destination buffer, which must be large enough to hold the - entire uncompressed data. (The size of the uncompressed data must have - been saved previously by the compressor and transmitted to the decompressor - by some mechanism outside the scope of this compression library.) - Upon exit, destLen is the actual size of the compressed buffer. + Decompresses the source buffer into the destination buffer. *sourceLen is + the byte length of the source buffer. Upon entry, *destLen is the total size + of the destination buffer, which must be large enough to hold the entire + uncompressed data. (The size of the uncompressed data must have been saved + previously by the compressor and transmitted to the decompressor by some + mechanism outside the scope of this compression library.) Upon exit, + *destLen is the size of the decompressed data and *sourceLen is the number + of source bytes consumed. Upon return, source + *sourceLen points to the + first unused input byte. - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted. + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, or + Z_DATA_ERROR if the input data was corrupted, including if the input data is + an incomplete zlib stream. */ +int ZEXPORT uncompress2 (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong *sourceLen; +{ + z_stream stream; + int err; + const uInt max = (uInt)-1; + uLong len, left; + Byte buf[1]; /* for detection of incomplete stream when *destLen == 0 */ + + len = *sourceLen; + if (*destLen) { + left = *destLen; + *destLen = 0; + } + else { + left = 1; + dest = buf; + } + + stream.next_in = (z_const Bytef *)source; + stream.avail_in = 0; + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + stream.next_out = dest; + stream.avail_out = 0; + + do { + if (stream.avail_out == 0) { + stream.avail_out = left > (uLong)max ? max : (uInt)left; + left -= stream.avail_out; + } + if (stream.avail_in == 0) { + stream.avail_in = len > (uLong)max ? max : (uInt)len; + len -= stream.avail_in; + } + err = inflate(&stream, Z_NO_FLUSH); + } while (err == Z_OK); + + *sourceLen -= len + stream.avail_in; + if (dest != buf) + *destLen = stream.total_out; + else if (stream.total_out && err == Z_BUF_ERROR) + left = 1; + + inflateEnd(&stream); + return err == Z_STREAM_END ? Z_OK : + err == Z_NEED_DICT ? Z_DATA_ERROR : + err == Z_BUF_ERROR && left + stream.avail_out ? Z_DATA_ERROR : + err; +} + int ZEXPORT uncompress (dest, destLen, source, sourceLen) Bytef *dest; uLongf *destLen; const Bytef *source; uLong sourceLen; { - z_stream stream; - int err; - - stream.next_in = (z_const Bytef *)source; - stream.avail_in = (uInt)sourceLen; - /* Check for source > 64K on 16-bit machine: */ - if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; - - stream.next_out = dest; - stream.avail_out = (uInt)*destLen; - if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - - err = inflateInit(&stream); - if (err != Z_OK) return err; - - err = inflate(&stream, Z_FINISH); - if (err != Z_STREAM_END) { - inflateEnd(&stream); - if (err == Z_NEED_DICT || (err == Z_BUF_ERROR && stream.avail_in == 0)) - return Z_DATA_ERROR; - return err; - } - *destLen = stream.total_out; - - err = inflateEnd(&stream); - return err; + return uncompress2(dest, destLen, source, &sourceLen); } diff --git a/contrib/zlib/win32/Makefile.gcc b/contrib/zlib/win32/Makefile.gcc index 6d1ded622..305be50af 100644 --- a/contrib/zlib/win32/Makefile.gcc +++ b/contrib/zlib/win32/Makefile.gcc @@ -39,7 +39,7 @@ IMPLIB = libz.dll.a SHARED_MODE=0 #LOC = -DASMV -#LOC = -DDEBUG -g +#LOC = -DZLIB_DEBUG -g PREFIX = CC = $(PREFIX)gcc diff --git a/contrib/zlib/win32/Makefile.msc b/contrib/zlib/win32/Makefile.msc index 67b773171..6831882de 100644 --- a/contrib/zlib/win32/Makefile.msc +++ b/contrib/zlib/win32/Makefile.msc @@ -1,5 +1,5 @@ # Makefile for zlib using Microsoft (Visual) C -# zlib is copyright (C) 1995-2006 Jean-loup Gailly and Mark Adler +# zlib is copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler # # Usage: # nmake -f win32/Makefile.msc (standard build) diff --git a/contrib/zlib/win32/README-WIN32.txt b/contrib/zlib/win32/README-WIN32.txt index 3d77d521e..a1de359a3 100644 --- a/contrib/zlib/win32/README-WIN32.txt +++ b/contrib/zlib/win32/README-WIN32.txt @@ -1,6 +1,6 @@ ZLIB DATA COMPRESSION LIBRARY -zlib 1.2.8 is a general purpose data compression library. All the code is +zlib 1.2.11.1 is a general purpose data compression library. All the code is thread safe. The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) @@ -22,7 +22,7 @@ before asking for help. Manifest: -The package zlib-1.2.8-win32-x86.zip will contain the following files: +The package zlib-1.2.11.1-win32-x86.zip will contain the following files: README-WIN32.txt This document ChangeLog Changes since previous zlib packages @@ -72,7 +72,7 @@ are too numerous to cite here. Copyright notice: - (C) 1995-2012 Jean-loup Gailly and Mark Adler + (C) 1995-2017 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/contrib/zlib/win32/VisualC.txt b/contrib/zlib/win32/VisualC.txt index 579a5fc9e..1005b2194 100644 --- a/contrib/zlib/win32/VisualC.txt +++ b/contrib/zlib/win32/VisualC.txt @@ -1,3 +1,3 @@ To build zlib using the Microsoft Visual C++ environment, -use the appropriate project from the projects/ directory. +use the appropriate project from the contrib/vstudio/ directory. diff --git a/contrib/zlib/win32/zlib.def b/contrib/zlib/win32/zlib.def index face65518..a2188b000 100644 --- a/contrib/zlib/win32/zlib.def +++ b/contrib/zlib/win32/zlib.def @@ -8,6 +8,7 @@ EXPORTS inflateEnd ; advanced functions deflateSetDictionary + deflateGetDictionary deflateCopy deflateReset deflateParams @@ -33,12 +34,15 @@ EXPORTS compress2 compressBound uncompress + uncompress2 gzopen gzdopen gzbuffer gzsetparams gzread + gzfread gzwrite + gzfwrite gzprintf gzvprintf gzputs @@ -67,7 +71,9 @@ EXPORTS crc32_combine64 ; checksum functions adler32 + adler32_z crc32 + crc32_z adler32_combine crc32_combine ; various hacks, don't look :) @@ -81,6 +87,8 @@ EXPORTS inflateSyncPoint get_crc_table inflateUndermine + inflateValidate + inflateCodesUsed inflateResetKeep deflateResetKeep gzopen_w diff --git a/contrib/zlib/win32/zlib1.rc b/contrib/zlib/win32/zlib1.rc index 5c0feed1b..234e641c3 100644 --- a/contrib/zlib/win32/zlib1.rc +++ b/contrib/zlib/win32/zlib1.rc @@ -26,7 +26,7 @@ BEGIN VALUE "FileDescription", "zlib data compression library\0" VALUE "FileVersion", ZLIB_VERSION "\0" VALUE "InternalName", "zlib1.dll\0" - VALUE "LegalCopyright", "(C) 1995-2013 Jean-loup Gailly & Mark Adler\0" + VALUE "LegalCopyright", "(C) 1995-2017 Jean-loup Gailly & Mark Adler\0" VALUE "OriginalFilename", "zlib1.dll\0" VALUE "ProductName", "zlib\0" VALUE "ProductVersion", ZLIB_VERSION "\0" diff --git a/contrib/zlib/zconf.h.cmakein b/contrib/zlib/zconf.h.cmakein index 043019cda..a7f24cce6 100644 --- a/contrib/zlib/zconf.h.cmakein +++ b/contrib/zlib/zconf.h.cmakein @@ -1,5 +1,5 @@ /* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2013 Jean-loup Gailly. + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -19,7 +19,7 @@ #ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ # define Z_PREFIX_SET -/* all linked symbols */ +/* all linked symbols and init macros */ # define _dist_code z__dist_code # define _length_code z__length_code # define _tr_align z__tr_align @@ -31,6 +31,7 @@ # define adler32 z_adler32 # define adler32_combine z_adler32_combine # define adler32_combine64 z_adler32_combine64 +# define adler32_z z_adler32_z # ifndef Z_SOLO # define compress z_compress # define compress2 z_compress2 @@ -39,10 +40,14 @@ # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 +# define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd +# define deflateGetDictionary z_deflateGetDictionary +# define deflateInit z_deflateInit +# define deflateInit2 z_deflateInit2 # define deflateInit2_ z_deflateInit2_ # define deflateInit_ z_deflateInit_ # define deflateParams z_deflateParams @@ -69,6 +74,8 @@ # define gzeof z_gzeof # define gzerror z_gzerror # define gzflush z_gzflush +# define gzfread z_gzfread +# define gzfwrite z_gzfwrite # define gzgetc z_gzgetc # define gzgetc_ z_gzgetc_ # define gzgets z_gzgets @@ -80,7 +87,6 @@ # define gzopen_w z_gzopen_w # endif # define gzprintf z_gzprintf -# define gzvprintf z_gzvprintf # define gzputc z_gzputc # define gzputs z_gzputs # define gzread z_gzread @@ -91,32 +97,39 @@ # define gztell z_gztell # define gztell64 z_gztell64 # define gzungetc z_gzungetc +# define gzvprintf z_gzvprintf # define gzwrite z_gzwrite # endif # define inflate z_inflate # define inflateBack z_inflateBack # define inflateBackEnd z_inflateBackEnd +# define inflateBackInit z_inflateBackInit # define inflateBackInit_ z_inflateBackInit_ +# define inflateCodesUsed z_inflateCodesUsed # define inflateCopy z_inflateCopy # define inflateEnd z_inflateEnd +# define inflateGetDictionary z_inflateGetDictionary # define inflateGetHeader z_inflateGetHeader +# define inflateInit z_inflateInit +# define inflateInit2 z_inflateInit2 # define inflateInit2_ z_inflateInit2_ # define inflateInit_ z_inflateInit_ # define inflateMark z_inflateMark # define inflatePrime z_inflatePrime # define inflateReset z_inflateReset # define inflateReset2 z_inflateReset2 +# define inflateResetKeep z_inflateResetKeep # define inflateSetDictionary z_inflateSetDictionary -# define inflateGetDictionary z_inflateGetDictionary # define inflateSync z_inflateSync # define inflateSyncPoint z_inflateSyncPoint # define inflateUndermine z_inflateUndermine -# define inflateResetKeep z_inflateResetKeep +# define inflateValidate z_inflateValidate # define inflate_copyright z_inflate_copyright # define inflate_fast z_inflate_fast # define inflate_table z_inflate_table # ifndef Z_SOLO # define uncompress z_uncompress +# define uncompress2 z_uncompress2 # endif # define zError z_zError # ifndef Z_SOLO @@ -226,9 +239,19 @@ # define z_const #endif -/* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) -# define NO_DUMMY_DECL +#ifdef Z_SOLO + typedef unsigned long z_size_t; +#else +# define z_longlong long long +# if defined(NO_SIZE_T) + typedef unsigned NO_SIZE_T z_size_t; +# elif defined(STDC) +# include + typedef size_t z_size_t; +# else + typedef unsigned long z_size_t; +# endif +# undef z_longlong #endif /* Maximum value for memLevel in deflateInit2 */ @@ -258,7 +281,7 @@ Of course this will generally degrade compression (there's no free lunch). The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes for small objects. */ diff --git a/contrib/zlib/zconf.in.h b/contrib/zlib/zconf.h.in similarity index 50% rename from contrib/zlib/zconf.in.h rename to contrib/zlib/zconf.h.in index 03a9431c8..5e1d68a00 100644 --- a/contrib/zlib/zconf.in.h +++ b/contrib/zlib/zconf.h.in @@ -1,5 +1,5 @@ /* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2005 Jean-loup Gailly. + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -11,52 +11,158 @@ /* * If you *really* need a unique prefix for all types and library functions, * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + * Even better than compiling with -DZ_PREFIX would be to use configure to set + * this permanently in zconf.h using "./configure --zprefix". */ -#ifdef Z_PREFIX -# define deflateInit_ z_deflateInit_ +#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ +# define Z_PREFIX_SET + +/* all linked symbols and init macros */ +# define _dist_code z__dist_code +# define _length_code z__length_code +# define _tr_align z__tr_align +# define _tr_flush_bits z__tr_flush_bits +# define _tr_flush_block z__tr_flush_block +# define _tr_init z__tr_init +# define _tr_stored_block z__tr_stored_block +# define _tr_tally z__tr_tally +# define adler32 z_adler32 +# define adler32_combine z_adler32_combine +# define adler32_combine64 z_adler32_combine64 +# define adler32_z z_adler32_z +# ifndef Z_SOLO +# define compress z_compress +# define compress2 z_compress2 +# define compressBound z_compressBound +# endif +# define crc32 z_crc32 +# define crc32_combine z_crc32_combine +# define crc32_combine64 z_crc32_combine64 +# define crc32_z z_crc32_z # define deflate z_deflate -# define deflateEnd z_deflateEnd -# define inflateInit_ z_inflateInit_ -# define inflate z_inflate -# define inflateEnd z_inflateEnd -# define deflateInit2_ z_deflateInit2_ -# define deflateSetDictionary z_deflateSetDictionary -# define deflateCopy z_deflateCopy -# define deflateReset z_deflateReset -# define deflateParams z_deflateParams # define deflateBound z_deflateBound +# define deflateCopy z_deflateCopy +# define deflateEnd z_deflateEnd +# define deflateGetDictionary z_deflateGetDictionary +# define deflateInit z_deflateInit +# define deflateInit2 z_deflateInit2 +# define deflateInit2_ z_deflateInit2_ +# define deflateInit_ z_deflateInit_ +# define deflateParams z_deflateParams +# define deflatePending z_deflatePending # define deflatePrime z_deflatePrime +# define deflateReset z_deflateReset +# define deflateResetKeep z_deflateResetKeep +# define deflateSetDictionary z_deflateSetDictionary +# define deflateSetHeader z_deflateSetHeader +# define deflateTune z_deflateTune +# define deflate_copyright z_deflate_copyright +# define get_crc_table z_get_crc_table +# ifndef Z_SOLO +# define gz_error z_gz_error +# define gz_intmax z_gz_intmax +# define gz_strwinerror z_gz_strwinerror +# define gzbuffer z_gzbuffer +# define gzclearerr z_gzclearerr +# define gzclose z_gzclose +# define gzclose_r z_gzclose_r +# define gzclose_w z_gzclose_w +# define gzdirect z_gzdirect +# define gzdopen z_gzdopen +# define gzeof z_gzeof +# define gzerror z_gzerror +# define gzflush z_gzflush +# define gzfread z_gzfread +# define gzfwrite z_gzfwrite +# define gzgetc z_gzgetc +# define gzgetc_ z_gzgetc_ +# define gzgets z_gzgets +# define gzoffset z_gzoffset +# define gzoffset64 z_gzoffset64 +# define gzopen z_gzopen +# define gzopen64 z_gzopen64 +# ifdef _WIN32 +# define gzopen_w z_gzopen_w +# endif +# define gzprintf z_gzprintf +# define gzputc z_gzputc +# define gzputs z_gzputs +# define gzread z_gzread +# define gzrewind z_gzrewind +# define gzseek z_gzseek +# define gzseek64 z_gzseek64 +# define gzsetparams z_gzsetparams +# define gztell z_gztell +# define gztell64 z_gztell64 +# define gzungetc z_gzungetc +# define gzvprintf z_gzvprintf +# define gzwrite z_gzwrite +# endif +# define inflate z_inflate +# define inflateBack z_inflateBack +# define inflateBackEnd z_inflateBackEnd +# define inflateBackInit z_inflateBackInit +# define inflateBackInit_ z_inflateBackInit_ +# define inflateCodesUsed z_inflateCodesUsed +# define inflateCopy z_inflateCopy +# define inflateEnd z_inflateEnd +# define inflateGetDictionary z_inflateGetDictionary +# define inflateGetHeader z_inflateGetHeader +# define inflateInit z_inflateInit +# define inflateInit2 z_inflateInit2 # define inflateInit2_ z_inflateInit2_ +# define inflateInit_ z_inflateInit_ +# define inflateMark z_inflateMark +# define inflatePrime z_inflatePrime +# define inflateReset z_inflateReset +# define inflateReset2 z_inflateReset2 +# define inflateResetKeep z_inflateResetKeep # define inflateSetDictionary z_inflateSetDictionary # define inflateSync z_inflateSync # define inflateSyncPoint z_inflateSyncPoint -# define inflateCopy z_inflateCopy -# define inflateReset z_inflateReset -# define inflateBack z_inflateBack -# define inflateBackEnd z_inflateBackEnd -# define compress z_compress -# define compress2 z_compress2 -# define compressBound z_compressBound -# define uncompress z_uncompress -# define adler32 z_adler32 -# define crc32 z_crc32 -# define get_crc_table z_get_crc_table +# define inflateUndermine z_inflateUndermine +# define inflateValidate z_inflateValidate +# define inflate_copyright z_inflate_copyright +# define inflate_fast z_inflate_fast +# define inflate_table z_inflate_table +# ifndef Z_SOLO +# define uncompress z_uncompress +# define uncompress2 z_uncompress2 +# endif # define zError z_zError +# ifndef Z_SOLO +# define zcalloc z_zcalloc +# define zcfree z_zcfree +# endif +# define zlibCompileFlags z_zlibCompileFlags +# define zlibVersion z_zlibVersion -# define alloc_func z_alloc_func -# define free_func z_free_func -# define in_func z_in_func -# define out_func z_out_func +/* all zlib typedefs in zlib.h and zconf.h */ # define Byte z_Byte -# define uInt z_uInt -# define uLong z_uLong # define Bytef z_Bytef +# define alloc_func z_alloc_func # define charf z_charf +# define free_func z_free_func +# ifndef Z_SOLO +# define gzFile z_gzFile +# endif +# define gz_header z_gz_header +# define gz_headerp z_gz_headerp +# define in_func z_in_func # define intf z_intf +# define out_func z_out_func +# define uInt z_uInt # define uIntf z_uIntf +# define uLong z_uLong # define uLongf z_uLongf -# define voidpf z_voidpf # define voidp z_voidp +# define voidpc z_voidpc +# define voidpf z_voidpf + +/* all zlib structs in zlib.h and zconf.h */ +# define gz_header_s z_gz_header_s +# define internal_state z_internal_state + #endif #if defined(__MSDOS__) && !defined(MSDOS) @@ -125,9 +231,25 @@ # endif #endif -/* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) -# define NO_DUMMY_DECL +#if defined(ZLIB_CONST) && !defined(z_const) +# define z_const const +#else +# define z_const +#endif + +#ifdef Z_SOLO + typedef unsigned long z_size_t; +#else +# define z_longlong long long +# if defined(NO_SIZE_T) + typedef unsigned NO_SIZE_T z_size_t; +# elif defined(STDC) +# include + typedef size_t z_size_t; +# else + typedef unsigned long z_size_t; +# endif +# undef z_longlong #endif /* Maximum value for memLevel in deflateInit2 */ @@ -157,7 +279,7 @@ Of course this will generally degrade compression (there's no free lunch). The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes for small objects. */ @@ -171,6 +293,14 @@ # endif #endif +#ifndef Z_ARG /* function prototypes for stdarg */ +# if defined(STDC) || defined(Z_HAVE_STDARG_H) +# define Z_ARG(args) args +# else +# define Z_ARG(args) () +# endif +#endif + /* The following definitions for FAR are needed only for MSDOS mixed * model programming (small or medium model with some far allocations). * This was tested only with MSC; for other MSDOS compilers you may have @@ -284,49 +414,121 @@ typedef uLong FAR uLongf; typedef Byte *voidp; #endif -#if 0 /* HAVE_UNISTD_H -- this line is updated by ./configure */ -# include /* for off_t */ -# include /* for SEEK_* and off_t */ -# ifdef VMS -# include /* for off_t */ +#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) +# include +# if (UINT_MAX == 0xffffffffUL) +# define Z_U4 unsigned +# elif (ULONG_MAX == 0xffffffffUL) +# define Z_U4 unsigned long +# elif (USHRT_MAX == 0xffffffffUL) +# define Z_U4 unsigned short # endif -# define z_off_t off_t #endif -#ifndef SEEK_SET + +#ifdef Z_U4 + typedef Z_U4 z_crc_t; +#else + typedef unsigned long z_crc_t; +#endif + +#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_UNISTD_H +#endif + +#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +# define Z_HAVE_STDARG_H +#endif + +#ifdef STDC +# ifndef Z_SOLO +# include /* for off_t */ +# endif +#endif + +#if defined(STDC) || defined(Z_HAVE_STDARG_H) +# ifndef Z_SOLO +# include /* for va_list */ +# endif +#endif + +#ifdef _WIN32 +# ifndef Z_SOLO +# include /* for wchar_t */ +# endif +#endif + +/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and + * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even + * though the former does not conform to the LFS document), but considering + * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as + * equivalently requesting no 64-bit operations + */ +#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 +# undef _LARGEFILE64_SOURCE +#endif + +#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) +# define Z_HAVE_UNISTD_H +#endif +#ifndef Z_SOLO +# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) +# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ +# ifdef VMS +# include /* for off_t */ +# endif +# ifndef z_off_t +# define z_off_t off_t +# endif +# endif +#endif + +#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 +# define Z_LFS64 +#endif + +#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) +# define Z_LARGE64 +#endif + +#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) +# define Z_WANT64 +#endif + +#if !defined(SEEK_SET) && !defined(Z_SOLO) # define SEEK_SET 0 /* Seek from beginning of file. */ # define SEEK_CUR 1 /* Seek from current position. */ # define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ #endif + #ifndef z_off_t # define z_off_t long #endif -#if defined(__OS400__) -# define NO_vsnprintf -#endif - -#if defined(__MVS__) -# define NO_vsnprintf -# ifdef FAR -# undef FAR +#if !defined(_WIN32) && defined(Z_LARGE64) +# define z_off64_t off64_t +#else +# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) +# define z_off64_t __int64 +# else +# define z_off64_t z_off_t # endif #endif /* MVS linker does not support external names larger than 8 bytes */ #if defined(__MVS__) -# pragma map(deflateInit_,"DEIN") -# pragma map(deflateInit2_,"DEIN2") -# pragma map(deflateEnd,"DEEND") -# pragma map(deflateBound,"DEBND") -# pragma map(inflateInit_,"ININ") -# pragma map(inflateInit2_,"ININ2") -# pragma map(inflateEnd,"INEND") -# pragma map(inflateSync,"INSY") -# pragma map(inflateSetDictionary,"INSEDI") -# pragma map(compressBound,"CMBND") -# pragma map(inflate_table,"INTABL") -# pragma map(inflate_fast,"INFA") -# pragma map(inflate_copyright,"INCOPY") + #pragma map(deflateInit_,"DEIN") + #pragma map(deflateInit2_,"DEIN2") + #pragma map(deflateEnd,"DEEND") + #pragma map(deflateBound,"DEBND") + #pragma map(inflateInit_,"ININ") + #pragma map(inflateInit2_,"ININ2") + #pragma map(inflateEnd,"INEND") + #pragma map(inflateSync,"INSY") + #pragma map(inflateSetDictionary,"INSEDI") + #pragma map(compressBound,"CMBND") + #pragma map(inflate_table,"INTABL") + #pragma map(inflate_fast,"INFA") + #pragma map(inflate_copyright,"INCOPY") #endif #endif /* ZCONF_H */ diff --git a/contrib/zlib/zconf.h.included b/contrib/zlib/zconf.h.included index 9ccbb0a6f..5e1d68a00 100644 --- a/contrib/zlib/zconf.h.included +++ b/contrib/zlib/zconf.h.included @@ -1,5 +1,5 @@ /* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2013 Jean-loup Gailly. + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -7,8 +7,6 @@ #ifndef ZCONF_H #define ZCONF_H -/* #undef Z_PREFIX */ -/* #undef Z_HAVE_UNISTD_H */ /* * If you *really* need a unique prefix for all types and library functions, @@ -19,7 +17,7 @@ #ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ # define Z_PREFIX_SET -/* all linked symbols */ +/* all linked symbols and init macros */ # define _dist_code z__dist_code # define _length_code z__length_code # define _tr_align z__tr_align @@ -31,6 +29,7 @@ # define adler32 z_adler32 # define adler32_combine z_adler32_combine # define adler32_combine64 z_adler32_combine64 +# define adler32_z z_adler32_z # ifndef Z_SOLO # define compress z_compress # define compress2 z_compress2 @@ -39,10 +38,14 @@ # define crc32 z_crc32 # define crc32_combine z_crc32_combine # define crc32_combine64 z_crc32_combine64 +# define crc32_z z_crc32_z # define deflate z_deflate # define deflateBound z_deflateBound # define deflateCopy z_deflateCopy # define deflateEnd z_deflateEnd +# define deflateGetDictionary z_deflateGetDictionary +# define deflateInit z_deflateInit +# define deflateInit2 z_deflateInit2 # define deflateInit2_ z_deflateInit2_ # define deflateInit_ z_deflateInit_ # define deflateParams z_deflateParams @@ -69,6 +72,8 @@ # define gzeof z_gzeof # define gzerror z_gzerror # define gzflush z_gzflush +# define gzfread z_gzfread +# define gzfwrite z_gzfwrite # define gzgetc z_gzgetc # define gzgetc_ z_gzgetc_ # define gzgets z_gzgets @@ -80,7 +85,6 @@ # define gzopen_w z_gzopen_w # endif # define gzprintf z_gzprintf -# define gzvprintf z_gzvprintf # define gzputc z_gzputc # define gzputs z_gzputs # define gzread z_gzread @@ -91,32 +95,39 @@ # define gztell z_gztell # define gztell64 z_gztell64 # define gzungetc z_gzungetc +# define gzvprintf z_gzvprintf # define gzwrite z_gzwrite # endif # define inflate z_inflate # define inflateBack z_inflateBack # define inflateBackEnd z_inflateBackEnd +# define inflateBackInit z_inflateBackInit # define inflateBackInit_ z_inflateBackInit_ +# define inflateCodesUsed z_inflateCodesUsed # define inflateCopy z_inflateCopy # define inflateEnd z_inflateEnd +# define inflateGetDictionary z_inflateGetDictionary # define inflateGetHeader z_inflateGetHeader +# define inflateInit z_inflateInit +# define inflateInit2 z_inflateInit2 # define inflateInit2_ z_inflateInit2_ # define inflateInit_ z_inflateInit_ # define inflateMark z_inflateMark # define inflatePrime z_inflatePrime # define inflateReset z_inflateReset # define inflateReset2 z_inflateReset2 +# define inflateResetKeep z_inflateResetKeep # define inflateSetDictionary z_inflateSetDictionary -# define inflateGetDictionary z_inflateGetDictionary # define inflateSync z_inflateSync # define inflateSyncPoint z_inflateSyncPoint # define inflateUndermine z_inflateUndermine -# define inflateResetKeep z_inflateResetKeep +# define inflateValidate z_inflateValidate # define inflate_copyright z_inflate_copyright # define inflate_fast z_inflate_fast # define inflate_table z_inflate_table # ifndef Z_SOLO # define uncompress z_uncompress +# define uncompress2 z_uncompress2 # endif # define zError z_zError # ifndef Z_SOLO @@ -226,9 +237,19 @@ # define z_const #endif -/* Some Mac compilers merge all .h files incorrectly: */ -#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__) -# define NO_DUMMY_DECL +#ifdef Z_SOLO + typedef unsigned long z_size_t; +#else +# define z_longlong long long +# if defined(NO_SIZE_T) + typedef unsigned NO_SIZE_T z_size_t; +# elif defined(STDC) +# include + typedef size_t z_size_t; +# else + typedef unsigned long z_size_t; +# endif +# undef z_longlong #endif /* Maximum value for memLevel in deflateInit2 */ @@ -258,7 +279,7 @@ Of course this will generally degrade compression (there's no free lunch). The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes + that is, 32K for windowBits=15 (default value) plus about 7 kilobytes for small objects. */ diff --git a/contrib/zlib/zlib.h b/contrib/zlib/zlib.h index 3e0c7672a..577d81e3b 100644 --- a/contrib/zlib/zlib.h +++ b/contrib/zlib/zlib.h @@ -1,7 +1,7 @@ /* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.8, April 28th, 2013 + version 1.2.11.1, January xxth, 2017 - Copyright (C) 1995-2013 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -37,12 +37,12 @@ extern "C" { #endif -#define ZLIB_VERSION "1.2.8" -#define ZLIB_VERNUM 0x1280 +#define ZLIB_VERSION "1.2.11.1-motley" +#define ZLIB_VERNUM 0x12b1 #define ZLIB_VER_MAJOR 1 #define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 8 -#define ZLIB_VER_SUBREVISION 0 +#define ZLIB_VER_REVISION 11 +#define ZLIB_VER_SUBREVISION 1 /* The 'zlib' compression library provides in-memory compression and @@ -65,7 +65,8 @@ extern "C" { with "gz". The gzip format is different from the zlib format. gzip is a gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. - This library can optionally read and write gzip streams in memory as well. + This library can optionally read and write gzip and raw deflate streams in + memory as well. The zlib format was designed to be compact and fast for use in memory and on communications channels. The gzip format was designed for single- @@ -74,7 +75,7 @@ extern "C" { The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash - even in case of corrupted input. + even in the case of corrupted input. */ typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); @@ -87,7 +88,7 @@ typedef struct z_stream_s { uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total number of input bytes read so far */ - Bytef *next_out; /* next output byte should be put there */ + Bytef *next_out; /* next output byte will go here */ uInt avail_out; /* remaining free space at next_out */ uLong total_out; /* total number of bytes output so far */ @@ -98,8 +99,9 @@ typedef struct z_stream_s { free_func zfree; /* used to free the internal state */ voidpf opaque; /* private data object passed to zalloc and zfree */ - int data_type; /* best guess about the data type: binary or text */ - uLong adler; /* adler32 value of the uncompressed data */ + int data_type; /* best guess about the data type: binary or text + for deflate, or the decoding state for inflate */ + uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ uLong reserved; /* reserved for future use */ } z_stream; @@ -142,7 +144,9 @@ typedef gz_header FAR *gz_headerp; zalloc must return Z_NULL if there is not enough memory for the object. If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. + thread safe. In that case, zlib is thread-safe. When zalloc and zfree are + Z_NULL on entry to the initialization function, they are set to internal + routines that use the standard library functions malloc() and free(). On 16-bit systems, the functions zalloc and zfree must be able to allocate exactly 65536 bytes, but will not be required to allocate more than this if @@ -155,7 +159,7 @@ typedef gz_header FAR *gz_headerp; The fields total_in and total_out can be used for statistics or progress reports. After compression, total_in holds the total size of the - uncompressed data and may be saved for use in the decompressor (particularly + uncompressed data and may be saved for use by the decompressor (particularly if the decompressor wants to decompress everything in a single step). */ @@ -200,7 +204,7 @@ typedef gz_header FAR *gz_headerp; #define Z_TEXT 1 #define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ #define Z_UNKNOWN 2 -/* Possible values of the data_type field (though see inflate()) */ +/* Possible values of the data_type field for deflate() */ #define Z_DEFLATED 8 /* The deflate compression method (the only one supported in this version) */ @@ -258,11 +262,11 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); enough room in the output buffer), next_in and avail_in are updated and processing will resume at this point for the next call of deflate(). - - Provide more output starting at next_out and update next_out and avail_out + - Generate more output starting at next_out and update next_out and avail_out accordingly. This action is forced if the parameter flush is non zero. Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). Some - output may be provided even if flush is not set. + should be set only when necessary. Some output may be provided even if + flush is zero. Before the call of deflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more @@ -271,7 +275,9 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output - buffer because there might be more output pending. + buffer because there might be more output pending. See deflatePending(), + which can be used if desired to determine whether or not there is more ouput + in that case. Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to decide how much data to accumulate before producing output, in order to @@ -292,8 +298,8 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. This completes the current deflate block and follows it with an empty fixed codes block that is 10 bits long. This assures that enough bytes are output - in order for the decompressor to finish the block before the empty fixed code - block. + in order for the decompressor to finish the block before the empty fixed + codes block. If flush is set to Z_BLOCK, a deflate block is completed and emitted, as for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to @@ -319,34 +325,38 @@ ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); If the parameter flush is set to Z_FINISH, pending input is processed, pending output is flushed and deflate returns with Z_STREAM_END if there was - enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the stream - are deflateReset or deflateEnd. + enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this + function must be called again with Z_FINISH and more output space (updated + avail_out) but no more input data, until it returns with Z_STREAM_END or an + error. After deflate has returned Z_STREAM_END, the only possible operations + on the stream are deflateReset or deflateEnd. - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least the - value returned by deflateBound (see below). Then deflate is guaranteed to - return Z_STREAM_END. If not enough output space is provided, deflate will - not return Z_STREAM_END, and it must be called again as described above. + Z_FINISH can be used in the first deflate call after deflateInit if all the + compression is to be done in a single step. In order to complete in one + call, avail_out must be at least the value returned by deflateBound (see + below). Then deflate is guaranteed to return Z_STREAM_END. If not enough + output space is provided, deflate will not return Z_STREAM_END, and it must + be called again as described above. - deflate() sets strm->adler to the adler32 checksum of all input read - so far (that is, total_in bytes). + deflate() sets strm->adler to the Adler-32 checksum of all input read + so far (that is, total_in bytes). If a gzip stream is being generated, then + strm->adler will be the CRC-32 checksum of the input read so far. (See + deflateInit2 below.) deflate() may update strm->data_type if it can make a good guess about - the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered - binary. This field is only for information purposes and does not affect the - compression algorithm in any manner. + the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is + considered binary. This field is only for information purposes and does not + affect the compression algorithm in any manner. deflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if all input has been consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not - fatal, and deflate() can be called again with more input and more output - space to continue compressing. + if next_in or next_out was Z_NULL or the state was inadvertently written over + by the application), or Z_BUF_ERROR if no progress is possible (for example + avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and + deflate() can be called again with more input and more output space to + continue compressing. */ @@ -369,23 +379,21 @@ ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); Initializes the internal stream state for decompression. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. If next_in is not Z_NULL and avail_in is large enough (the - exact value depends on the compression method), inflateInit determines the - compression method from the zlib header and allocates all data structures - accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to - use default allocation functions. + the caller. In the current version of inflate, the provided input is not + read or consumed. The allocation of a sliding window will be deferred to + the first call of inflate (if the decompression does not complete on the + first call). If zalloc and zfree are set to Z_NULL, inflateInit updates + them to use default allocation functions. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller, or Z_STREAM_ERROR if the parameters are invalid, such as a null pointer to the structure. msg is set to null if - there is no error message. inflateInit does not perform any decompression - apart from possibly reading the zlib header if present: actual decompression - will be done by inflate(). (So next_in and avail_in may be modified, but - next_out and avail_out are unused and unchanged.) The current implementation - of inflateInit() does not process any header information -- that is deferred - until inflate() is called. + there is no error message. inflateInit does not perform any decompression. + Actual decompression will be done by inflate(). So next_in, and avail_in, + next_out, and avail_out are unused and unchanged. The current + implementation of inflateInit() does not process any header information -- + that is deferred until inflate() is called. */ @@ -401,17 +409,20 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); - Decompress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing will - resume at this point for the next call of inflate(). + enough room in the output buffer), then next_in and avail_in are updated + accordingly, and processing will resume at this point for the next call of + inflate(). - - Provide more output starting at next_out and update next_out and avail_out + - Generate more output starting at next_out and update next_out and avail_out accordingly. inflate() provides as much output as possible, until there is no more input data or no more space in the output buffer (see below about the flush parameter). Before the call of inflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more - output, and updating the next_* and avail_* values accordingly. The + output, and updating the next_* and avail_* values accordingly. If the + caller of inflate() does not provide both available input and available + output space, it is possible that there will be no progress made. The application can consume the uncompressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of inflate(). If inflate returns Z_OK and with zero avail_out, it must be @@ -428,7 +439,7 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); gets to the end of that block, or when it runs out of data. The Z_BLOCK option assists in appending to or combining deflate streams. - Also to assist in this, on return inflate() will set strm->data_type to the + To assist in this, on return inflate() always sets strm->data_type to the number of unused bits in the last byte taken from strm->next_in, plus 64 if inflate() is currently decoding the last block in the deflate stream, plus 128 if inflate() returned immediately after decoding an end-of-block code or @@ -454,7 +465,7 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); this case all pending input is processed and all pending output is flushed; avail_out must be large enough to hold all of the uncompressed data for the operation to complete. (The size of the uncompressed data may have been - saved by the compressor for this purpose.) The use of Z_FINISH is not + saved by the compressor for this purpose.) The use of Z_FINISH is not required to perform an inflation in one step. However it may be used to inform inflate that a faster approach can be used for the single inflate() call. Z_FINISH also informs inflate to not maintain a sliding window if the @@ -476,32 +487,33 @@ ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); chosen by the compressor and returns Z_NEED_DICT; otherwise it sets strm->adler to the Adler-32 checksum of all output produced so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described - below. At the end of the stream, inflate() checks that its computed adler32 + below. At the end of the stream, inflate() checks that its computed Adler-32 checksum is equal to that saved by the compressor and returns Z_STREAM_END only if the checksum is correct. inflate() can decompress and check either zlib-wrapped or gzip-wrapped deflate data. The header type is detected automatically, if requested when initializing with inflateInit2(). Any information contained in the gzip - header is not retained, so applications that need that information should - instead use raw inflate, see inflateInit2() below, or inflateBack() and - perform their own processing of the gzip header and trailer. When processing + header is not retained unless inflateGetHeader() is used. When processing gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output - producted so far. The CRC-32 is checked against the gzip trailer. + produced so far. The CRC-32 is checked against the gzip trailer, as is the + uncompressed length, modulo 2^32. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was corrupted (input stream not conforming to the zlib format or incorrect check - value), Z_STREAM_ERROR if the stream structure was inconsistent (for example - next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory, - Z_BUF_ERROR if no progress is possible or if there was not enough room in the - output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and + value, in which case strm->msg points to a string with a more specific + error), Z_STREAM_ERROR if the stream structure was inconsistent (for example + next_in or next_out was Z_NULL, or the state was inadvertently written over + by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR + if no progress was possible or if there was not enough room in the output + buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and inflate() can be called again with more input and more output space to continue decompressing. If Z_DATA_ERROR is returned, the application may then call inflateSync() to look for a good compression block if a partial - recovery of the data is desired. + recovery of the data is to be attempted. */ @@ -511,9 +523,8 @@ ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); This function discards any unprocessed input and does not flush any pending output. - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). + inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state + was inconsistent. */ @@ -544,16 +555,29 @@ ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, compression at the expense of memory usage. The default value is 15 if deflateInit is used instead. + For the current implementation of deflate(), a windowBits value of 8 (a + window size of 256 bytes) is not supported. As a result, a request for 8 + will result in 9 (a 512-byte window). In that case, providing 8 to + inflateInit2() will result in an error when the zlib header with 9 is + checked against the initialization of inflate(). The remedy is to not use 8 + with deflateInit2() with this initialization, or at least in that case use 9 + with inflateInit2(). + windowBits can also be -8..-15 for raw deflate. In this case, -windowBits determines the window size. deflate() will then generate raw deflate data - with no zlib header or trailer, and will not compute an adler32 check value. + with no zlib header or trailer, and will not compute a check value. windowBits can also be greater than 15 for optional gzip encoding. Add 16 to windowBits to write a simple gzip header and trailer around the compressed data instead of a zlib wrapper. The gzip header will have no file name, no extra data, no comment, no modification time (set to zero), no - header crc, and the operating system will be set to 255 (unknown). If a - gzip stream is being written, strm->adler is a crc32 instead of an adler32. + header crc, and the operating system will be set to the appropriate value, + if the operating system was determined at compile time. If a gzip stream is + being written, strm->adler is a CRC-32 instead of an Adler-32. + + For raw deflate or gzip encoding, a request for a 256-byte window is + rejected as invalid, since only the zlib header provides a means of + transmitting the window size to the decompressor. The memLevel parameter specifies how much memory should be allocated for the internal compression state. memLevel=1 uses minimum memory but is @@ -614,12 +638,12 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, addition, the current implementation of deflate will use at most the window size minus 262 bytes of the provided dictionary. - Upon return of this function, strm->adler is set to the adler32 value + Upon return of this function, strm->adler is set to the Adler-32 value of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The adler32 value + which dictionary has been used by the compressor. (The Adler-32 value applies to the whole dictionary even if only a subset of the dictionary is actually used by the compressor.) If a raw deflate was requested, then the - adler32 value is not computed and strm->adler is not set. + Adler-32 value is not computed and strm->adler is not set. deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is @@ -628,6 +652,28 @@ ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, not perform any compression: this will be done by deflate(). */ +ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, + Bytef *dictionary, + uInt *dictLength)); +/* + Returns the sliding dictionary being maintained by deflate. dictLength is + set to the number of bytes in the dictionary, and that many bytes are copied + to dictionary. dictionary must have enough space, where 32768 bytes is + always enough. If deflateGetDictionary() is called with dictionary equal to + Z_NULL, then only the dictionary length is returned, and nothing is copied. + Similary, if dictLength is Z_NULL, then it is not set. + + deflateGetDictionary() may return a length less than the window size, even + when more than the window size in input has been provided. It may return up + to 258 bytes less in that case, due to how zlib's implementation of deflate + manages the sliding window and lookahead for matches, where matches can be + up to 258 bytes long. If the application needs the last window-size bytes of + input, then that would need to be saved by the application outside of zlib. + + deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the + stream state is inconsistent. +*/ + ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, z_streamp source)); /* @@ -648,10 +694,10 @@ ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); /* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. The - stream will keep the same compression level and any other attributes that - may have been set by deflateInit2. + This function is equivalent to deflateEnd followed by deflateInit, but + does not free and reallocate the internal compression state. The stream + will leave the compression level and any other attributes that may have been + set unchanged. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL). @@ -662,20 +708,37 @@ ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, int strategy)); /* Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2. This can be + interpretation of level and strategy is as in deflateInit2(). This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. - If the compression level is changed, the input available so far is - compressed with the old level (and may be flushed); the new level will take - effect only at the next call of deflate(). + If the compression approach (which is a function of the level) or the + strategy is changed, and if there have been any deflate() calls since the + state was initialized or reset, then the input available so far is + compressed with the old level and strategy using deflate(strm, Z_BLOCK). + There are three approaches for the compression levels 0, 1..3, and 4..9 + respectively. The new level and strategy will take effect at the next call + of deflate(). - Before the call of deflateParams, the stream state must be set as for - a call of deflate(), since the currently available input may have to be - compressed and flushed. In particular, strm->avail_out must be non-zero. + If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does + not have enough output space to complete, then the parameter change will not + take effect. In this case, deflateParams() can be called again with the + same parameters and more output space to try again. - deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source - stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if - strm->avail_out was zero. + In order to assure a change in the parameters on the first try, the + deflate stream should be flushed using deflate() with Z_BLOCK or other flush + request until strm.avail_out is not zero, before calling deflateParams(). + Then no more input data should be provided before the deflateParams() call. + If this is done, the old level and strategy will be applied to the data + compressed before deflateParams(), and the new level and strategy will be + applied to the the data compressed after deflateParams(). + + deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream + state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if + there was not enough output space to complete the compression of the + available input data before a change in the strategy or approach. Note that + in the case of a Z_BUF_ERROR, the parameters are not changed. A return + value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be + retried with more output space. */ ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, @@ -793,7 +856,7 @@ ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, is for use with other formats that use the deflate compressed data format such as zip. Those formats provide their own check values. If a custom format is developed using the raw deflate format for compressed data, it is - recommended that a check value such as an adler32 or a crc32 be applied to + recommended that a check value such as an Adler-32 or a CRC-32 be applied to the uncompressed data as is done in the zlib, gzip, and zip formats. For most applications, the zlib format should be used as is. Note that comments above on the use in deflateInit2() applies to the magnitude of windowBits. @@ -802,7 +865,10 @@ ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, 32 to windowBits to enable zlib and gzip decoding with automatic header detection, or add 16 to decode only the gzip format (the zlib format will return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a - crc32 instead of an adler32. + CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see + below), inflate() will not automatically decode concatenated gzip streams. + inflate() will return Z_STREAM_END at the end of the gzip stream. The state + would need to be reset to continue decoding a subsequent gzip stream. inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the @@ -823,7 +889,7 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate, if that call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the adler32 value returned by that call of inflate. + can be determined from the Adler-32 value returned by that call of inflate. The compressor and decompressor must use exactly the same dictionary (see deflateSetDictionary). For raw inflate, this function can be called at any time to set the dictionary. If the provided dictionary is smaller than the @@ -834,7 +900,7 @@ ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect adler32 value). inflateSetDictionary does not + expected one (incorrect Adler-32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). */ @@ -892,7 +958,7 @@ ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); /* This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. The + but does not free and reallocate the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source @@ -904,7 +970,9 @@ ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, /* This function is the same as inflateReset, but it also permits changing the wrap and window size requests. The windowBits parameter is interpreted - the same as it is for inflateInit2. + the same as it is for inflateInit2. If the window size is changed, then the + memory allocated for the window is freed, and the window will be reallocated + by inflate() if needed. inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being Z_NULL), or if @@ -956,7 +1024,7 @@ ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); location in the input stream can be determined from avail_in and data_type as noted in the description for the Z_BLOCK flush parameter for inflate. - inflateMark returns the value noted above or -1 << 16 if the provided + inflateMark returns the value noted above, or -65536 if the provided source stream state was inconsistent. */ @@ -1048,9 +1116,9 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, This routine would normally be used in a utility that reads zip or gzip files and writes out uncompressed files. The utility would decode the header and process the trailer on its own, hence this routine expects only - the raw deflate stream to decompress. This is different from the normal - behavior of inflate(), which expects either a zlib or gzip header and - trailer around the deflate stream. + the raw deflate stream to decompress. This is different from the default + behavior of inflate(), which expects a zlib header and trailer around the + deflate stream. inflateBack() uses two subroutines supplied by the caller that are then called by inflateBack() for input and output. inflateBack() calls those @@ -1059,12 +1127,12 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, parameters and return types are defined above in the in_func and out_func typedefs. inflateBack() will call in(in_desc, &buf) which should return the number of bytes of provided input, and a pointer to that input in buf. If - there is no input available, in() must return zero--buf is ignored in that - case--and inflateBack() will return a buffer error. inflateBack() will call - out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out() - should return zero on success, or non-zero on failure. If out() returns - non-zero, inflateBack() will return with an error. Neither in() nor out() - are permitted to change the contents of the window provided to + there is no input available, in() must return zero -- buf is ignored in that + case -- and inflateBack() will return a buffer error. inflateBack() will + call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. + out() should return zero on success, or non-zero on failure. If out() + returns non-zero, inflateBack() will return with an error. Neither in() nor + out() are permitted to change the contents of the window provided to inflateBackInit(), which is also the buffer that out() uses to write from. The length written by out() will be at most the window size. Any non-zero amount of input may be provided by in(). @@ -1092,7 +1160,7 @@ ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, using strm->next_in which will be Z_NULL only if in() returned an error. If strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning non-zero. (in() will always be called before out(), so strm->next_in is - assured to be defined if out() returns non-zero.) Note that inflateBack() + assured to be defined if out() returns non-zero.) Note that inflateBack() cannot return Z_OK. */ @@ -1114,7 +1182,7 @@ ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); 7.6: size of z_off_t Compiler, assembler, and debug options: - 8: DEBUG + 8: ZLIB_DEBUG 9: ASMV or ASMINF -- use ASM code 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention 11: 0 (reserved) @@ -1164,7 +1232,8 @@ ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, the byte length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. + compressed data. compress() is equivalent to compress2() with a level + parameter of Z_DEFAULT_COMPRESSION. compress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output @@ -1180,7 +1249,7 @@ ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, length of the source buffer. Upon entry, destLen is the total size of the destination buffer, which must be at least the value returned by compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed buffer. + compressed data. compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output buffer, @@ -1203,7 +1272,7 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, uncompressed data. (The size of the uncompressed data must have been saved previously by the compressor and transmitted to the decompressor by some mechanism outside the scope of this compression library.) Upon exit, destLen - is the actual size of the uncompressed buffer. + is the actual size of the uncompressed data. uncompress returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if there was not enough room in the output @@ -1212,6 +1281,14 @@ ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, buffer with the uncompressed data up to that point. */ +ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong *sourceLen)); +/* + Same as uncompress, except that sourceLen is a pointer, where the + length of the source is *sourceLen. On return, *sourceLen is the number of + source bytes consumed. +*/ + /* gzip file access functions */ /* @@ -1290,10 +1367,9 @@ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); default buffer size is 8192 bytes. This function must be called after gzopen() or gzdopen(), and before any other calls that read or write the file. The buffer memory allocation is always deferred to the first read or - write. Two buffers are allocated, either both of the specified size when - writing, or one of the specified size and the other twice that size when - reading. A larger buffer size of, for example, 64K or 128K bytes will - noticeably increase the speed of decompression (reading). + write. Three times that size in buffer space is allocated. A larger buffer + size of, for example, 64K or 128K bytes will noticeably increase the speed + of decompression (reading). The new buffer size also affects the maximum length for gzprintf(). @@ -1304,10 +1380,12 @@ ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); /* Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. + of deflateInit2 for the meaning of these parameters. Previously provided + data is flushed before the parameter change. - gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not - opened for writing. + gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not + opened for writing, Z_ERRNO if there is an error writing the flushed data, + or Z_MEM_ERROR if there is a memory allocation error. */ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); @@ -1335,7 +1413,35 @@ ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); case. gzread returns the number of uncompressed bytes actually read, less than - len for end of file, or -1 for error. + len for end of file, or -1 for error. If len is too large to fit in an int, + then nothing is read, -1 is returned, and the error state is set to + Z_STREAM_ERROR. +*/ + +ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, + gzFile file)); +/* + Read up to nitems items of size size from file to buf, otherwise operating + as gzread() does. This duplicates the interface of stdio's fread(), with + size_t request and return types. If the library defines size_t, then + z_size_t is identical to size_t. If not, then z_size_t is an unsigned + integer type that can contain a pointer. + + gzfread() returns the number of full items read of size size, or zero if + the end of the file was reached and a full item could not be read, or if + there was an error. gzerror() must be consulted if zero is returned in + order to determine if there was an error. If the multiplication of size and + nitems overflows, i.e. the product does not fit in a z_size_t, then nothing + is read, zero is returned, and the error state is set to Z_STREAM_ERROR. + + In the event that the end of file is reached and only a partial item is + available at the end, i.e. the remaining uncompressed data length is not a + multiple of size, then the final partial item is nevetheless read into buf + and the end-of-file flag is set. The length of the partial item read is not + provided, but could be inferred from the result of gztell(). This behavior + is the same as the behavior of fread() implementations in common libraries, + but it prevents the direct use of gzfread() to read a concurrently written + file, reseting and retrying on end-of-file, when size is not 1. */ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, @@ -1346,19 +1452,33 @@ ZEXTERN int ZEXPORT gzwrite OF((gzFile file, error. */ +ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, + z_size_t nitems, gzFile file)); +/* + gzfwrite() writes nitems items of size size from buf to file, duplicating + the interface of stdio's fwrite(), with size_t request and return types. If + the library defines size_t, then z_size_t is identical to size_t. If not, + then z_size_t is an unsigned integer type that can contain a pointer. + + gzfwrite() returns the number of full items written of size size, or zero + if there was an error. If the multiplication of size and nitems overflows, + i.e. the product does not fit in a z_size_t, then nothing is written, zero + is returned, and the error state is set to Z_STREAM_ERROR. +*/ + ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); /* Converts, formats, and writes the arguments to the compressed file under control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written, or 0 in case of error. The number of - uncompressed bytes written is limited to 8191, or one less than the buffer - size given to gzbuffer(). The caller should assure that this limit is not - exceeded. If it is exceeded, then gzprintf() will return an error (0) with - nothing written. In this case, there may also be a buffer overflow with - unpredictable consequences, which is possible only if zlib was compiled with - the insecure functions sprintf() or vsprintf() because the secure snprintf() - or vsnprintf() functions were not available. This can be determined using - zlibCompileFlags(). + uncompressed bytes actually written, or a negative zlib error code in case + of error. The number of uncompressed bytes written is limited to 8191, or + one less than the buffer size given to gzbuffer(). The caller should assure + that this limit is not exceeded. If it is exceeded, then gzprintf() will + return an error (0) with nothing written. In this case, there may also be a + buffer overflow with unpredictable consequences, which is possible only if + zlib was compiled with the insecure functions sprintf() or vsprintf() + because the secure snprintf() or vsnprintf() functions were not available. + This can be determined using zlibCompileFlags(). */ ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); @@ -1418,7 +1538,7 @@ ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); If the flush parameter is Z_FINISH, the remaining data is written and the gzip stream is completed in the output. If gzwrite() is called again, a new gzip stream will be started in the output. gzread() is able to read such - concatented gzip streams. + concatenated gzip streams. gzflush should be called only when strictly necessary because it will degrade compression if called too often. @@ -1572,7 +1692,7 @@ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); return the updated checksum. If buf is Z_NULL, this function returns the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed much faster. Usage example: @@ -1585,6 +1705,12 @@ ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); if (adler != original_adler) error(); */ +ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, + z_size_t len)); +/* + Same as adler32(), but with a size_t length. +*/ + /* ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, z_off_t len2)); @@ -1614,6 +1740,12 @@ ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); if (crc != original_crc) error(); */ +ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf, + z_size_t len)); +/* + Same as crc32(), but with a size_t length. +*/ + /* ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); @@ -1644,19 +1776,35 @@ ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, unsigned char FAR *window, const char *version, int stream_size)); -#define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) -#define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) -#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) -#define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ - (int)sizeof(z_stream)) -#define inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, (int)sizeof(z_stream)) +#ifdef Z_PREFIX_SET +# define z_deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define z_inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define z_inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#else +# define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) +# define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) +# define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ + (int)sizeof(z_stream)) +# define inflateBackInit(strm, windowBits, window) \ + inflateBackInit_((strm), (windowBits), (window), \ + ZLIB_VERSION, (int)sizeof(z_stream)) +#endif #ifndef Z_SOLO @@ -1676,10 +1824,10 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ #ifdef Z_PREFIX_SET # undef z_gzgetc # define z_gzgetc(g) \ - ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) #else # define gzgetc(g) \ - ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : gzgetc(g)) + ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) #endif /* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or @@ -1737,16 +1885,13 @@ ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ #endif /* !Z_SOLO */ -/* hack for buggy compilers */ -#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL) - struct internal_state {int dummy;}; -#endif - /* undocumented functions */ ZEXTERN const char * ZEXPORT zError OF((int)); ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); +ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); +ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); #if defined(_WIN32) && !defined(Z_SOLO) diff --git a/contrib/zlib/zutil.c b/contrib/zlib/zutil.c index 23d2ebef0..dcab28a0d 100644 --- a/contrib/zlib/zutil.c +++ b/contrib/zlib/zutil.c @@ -1,5 +1,5 @@ /* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-2005, 2010, 2011, 2012 Jean-loup Gailly. + * Copyright (C) 1995-2017 Jean-loup Gailly * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -10,21 +10,18 @@ # include "gzguts.h" #endif -#ifndef NO_DUMMY_DECL -struct internal_state {int dummy;}; /* for buggy compilers */ -#endif - z_const char * const z_errmsg[10] = { -"need dictionary", /* Z_NEED_DICT 2 */ -"stream end", /* Z_STREAM_END 1 */ -"", /* Z_OK 0 */ -"file error", /* Z_ERRNO (-1) */ -"stream error", /* Z_STREAM_ERROR (-2) */ -"data error", /* Z_DATA_ERROR (-3) */ -"insufficient memory", /* Z_MEM_ERROR (-4) */ -"buffer error", /* Z_BUF_ERROR (-5) */ -"incompatible version",/* Z_VERSION_ERROR (-6) */ -""}; + (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ + (z_const char *)"stream end", /* Z_STREAM_END 1 */ + (z_const char *)"", /* Z_OK 0 */ + (z_const char *)"file error", /* Z_ERRNO (-1) */ + (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ + (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ + (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ + (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ + (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ + (z_const char *)"" +}; const char * ZEXPORT zlibVersion() @@ -61,7 +58,7 @@ uLong ZEXPORT zlibCompileFlags() case 8: flags += 2 << 6; break; default: flags += 3 << 6; } -#ifdef DEBUG +#ifdef ZLIB_DEBUG flags += 1 << 8; #endif #if defined(ASMV) || defined(ASMINF) @@ -115,8 +112,8 @@ uLong ZEXPORT zlibCompileFlags() return flags; } -#ifdef DEBUG - +#ifdef ZLIB_DEBUG +#include # ifndef verbose # define verbose 0 # endif @@ -139,8 +136,8 @@ const char * ZEXPORT zError(err) return ERR_MSG(err); } -#if defined(_WIN32_WCE) - /* The Microsoft C Run-Time Library for Windows CE doesn't have +#if defined(_WIN32_WCE) && _WIN32_WCE < 0x800 + /* The older Microsoft C Run-Time Library for Windows CE doesn't have * errno. We define it as a global variable to simplify porting. * Its value is always 0 and should not be used. */ @@ -219,9 +216,11 @@ local ptr_table table[MAX_PTR]; voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) { - voidpf buf = opaque; /* just to make some compilers happy */ + voidpf buf; ulg bsize = (ulg)items*size; + (void)opaque; + /* If we allocate less than 65520 bytes, we assume that farmalloc * will return a usable pointer which doesn't have to be normalized. */ @@ -244,6 +243,9 @@ voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { int n; + + (void)opaque; + if (*(ush*)&ptr != 0) { /* object < 64K */ farfree(ptr); return; @@ -259,7 +261,6 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) next_ptr--; return; } - ptr = opaque; /* just to make some compilers happy */ Assert(0, "zcfree: ptr not found"); } @@ -278,13 +279,13 @@ void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) { - if (opaque) opaque = 0; /* to make compiler happy */ + (void)opaque; return _halloc((long)items, size); } void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) { - if (opaque) opaque = 0; /* to make compiler happy */ + (void)opaque; _hfree(ptr); } @@ -306,7 +307,7 @@ voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) unsigned items; unsigned size; { - if (opaque) items += size - size; /* make compiler happy */ + (void)opaque; return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : (voidpf)calloc(items, size); } @@ -315,8 +316,8 @@ void ZLIB_INTERNAL zcfree (opaque, ptr) voidpf opaque; voidpf ptr; { + (void)opaque; free(ptr); - if (opaque) return; /* make compiler happy */ } #endif /* MY_ZCALLOC */ diff --git a/contrib/zlib/zutil.h b/contrib/zlib/zutil.h index 24ab06b1c..60a0bca79 100644 --- a/contrib/zlib/zutil.h +++ b/contrib/zlib/zutil.h @@ -1,5 +1,5 @@ /* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2013 Jean-loup Gailly. + * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler * For conditions of distribution and use, see copyright notice in zlib.h */ @@ -29,14 +29,12 @@ # include #endif -#ifdef Z_SOLO - typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ -#endif - #ifndef local # define local static #endif -/* compile with -Dlocal if your debugger can't find static symbols */ +/* since "static" is used to mean two completely different things in C, we + define "local" for the non-static meaning of "static", for readability + (compile with -Dlocal if your debugger can't find static symbols) */ typedef unsigned char uch; typedef uch FAR uchf; @@ -98,28 +96,38 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ #endif #ifdef AMIGA -# define OS_CODE 0x01 +# define OS_CODE 1 #endif #if defined(VAXC) || defined(VMS) -# define OS_CODE 0x02 +# define OS_CODE 2 # define F_OPEN(name, mode) \ fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") #endif +#ifdef __370__ +# if __TARGET_LIB__ < 0x20000000 +# define OS_CODE 4 +# elif __TARGET_LIB__ < 0x40000000 +# define OS_CODE 11 +# else +# define OS_CODE 8 +# endif +#endif + #if defined(ATARI) || defined(atarist) -# define OS_CODE 0x05 +# define OS_CODE 5 #endif #ifdef OS2 -# define OS_CODE 0x06 +# define OS_CODE 6 # if defined(M_I86) && !defined(Z_SOLO) # include # endif #endif #if defined(MACOS) || defined(TARGET_OS_MAC) -# define OS_CODE 0x07 +# define OS_CODE 7 # ifndef Z_SOLO # if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os # include /* for fdopen */ @@ -131,18 +139,24 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # endif #endif -#ifdef TOPS20 -# define OS_CODE 0x0a +#ifdef __acorn +# define OS_CODE 13 #endif -#ifdef WIN32 -# ifndef __CYGWIN__ /* Cygwin is Unix, not Win32 */ -# define OS_CODE 0x0b -# endif +#if defined(WIN32) && !defined(__CYGWIN__) +# define OS_CODE 10 #endif -#ifdef __50SERIES /* Prime/PRIMOS */ -# define OS_CODE 0x0f +#ifdef _BEOS_ +# define OS_CODE 16 +#endif + +#ifdef __TOS_OS400__ +# define OS_CODE 18 +#endif + +#ifdef __APPLE__ +# define OS_CODE 19 #endif #if defined(_BEOS_) || defined(RISCOS) @@ -152,10 +166,6 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ #if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX # if defined(_WIN32_WCE) # define fdopen(fd,mode) NULL /* No fdopen() */ -# ifndef _PTRDIFF_T_DEFINED - typedef int ptrdiff_t; -# define _PTRDIFF_T_DEFINED -# endif # else # define fdopen(fd,type) _fdopen(fd,type) # endif @@ -177,7 +187,7 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ /* common defaults */ #ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ +# define OS_CODE 3 /* assume Unix */ #endif #ifndef F_OPEN @@ -216,7 +226,7 @@ extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ #endif /* Diagnostic functions */ -#ifdef DEBUG +#ifdef ZLIB_DEBUG # include extern int ZLIB_INTERNAL z_verbose; extern void ZLIB_INTERNAL z_error OF((char *m)); diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt new file mode 100644 index 000000000..f7ce7b726 --- /dev/null +++ b/doc/CMakeLists.txt @@ -0,0 +1,42 @@ +find_package( Doxygen REQUIRED ) + +set( HTML_OUTPUT "AssimpDoc_Html" CACHE STRING "Output directory for generated HTML documentation. Defaults to AssimpDoc_Html." ) + +# Enable Microsoft CHM help style only on Windows +set( MICROSOFT_HELP_WORKSHOP "NO") +if( MSVC ) + set( MICROSOFT_HELP_WORKSHOP "YES" ) +endif( MSVC ) + +configure_file( + ${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in + ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile + @ONLY +) + +add_custom_target( + docs ALL + DEPENDS docs.done +) + +add_custom_command( + OUTPUT docs.done + COMMAND ${DOXYGEN_EXECUTABLE} + COMMAND ${CMAKE_COMMAND} -E touch docs.done + COMMENT "Generating assimp documentation" + VERBATIM + ) + +if( DEFINED CMAKE_INSTALL_DOCDIR ) + install( + DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${HTML_OUTPUT} + DESTINATION ${CMAKE_INSTALL_DOCDIR} + ) + install(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/AssimpDoc_Html/AnimationOverview.png + ${CMAKE_CURRENT_SOURCE_DIR}/AssimpDoc_Html/AnimationOverview.svg + ${CMAKE_CURRENT_SOURCE_DIR}/AssimpDoc_Html/dragonsplash.png + DESTINATION ${CMAKE_INSTALL_DOCDIR}/${HTML_OUTPUT} + ) +endif( DEFINED CMAKE_INSTALL_DOCDIR ) + diff --git a/doc/Doxyfile b/doc/Doxyfile.in similarity index 98% rename from doc/Doxyfile rename to doc/Doxyfile.in index 64dd5d2cc..ebb6b72b8 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile.in @@ -140,7 +140,8 @@ FULL_PATH_NAMES = NO # relative paths, which will be relative from the directory where doxygen is # started. -STRIP_FROM_PATH = +STRIP_FROM_PATH = @PROJECT_SOURCE_DIR@ \ + @PROJECT_BINARY_DIR@ # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of # the path mentioned in the documentation of a class, which tells @@ -339,22 +340,6 @@ INLINE_SIMPLE_STRUCTS = NO TYPEDEF_HIDES_STRUCT = YES -# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to -# determine which symbols to keep in memory and which to flush to disk. -# When the cache is full, less often used symbols will be written to disk. -# For small to medium size projects (<1000 input files) the default value is -# probably good enough. For larger projects a too small cache size can cause -# doxygen to be busy swapping symbols to and from disk most of the time -# causing a significant performance penalty. -# If the system has enough physical memory increasing the cache will improve the -# performance by keeping more symbols in memory. Note that the value works on -# a logarithmic scale so increasing the size by one will roughly double the -# memory usage. The cache size is given by this formula: -# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, -# corresponding to a cache size of 2^16 = 65536 symbols. - -SYMBOL_CACHE_SIZE = 0 - # Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be # set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given # their name and scope. Since this can be an expensive process and often the @@ -677,9 +662,12 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ../include/ \ - ../doc/dox.h \ - ../code/BaseImporter.h +INPUT = @doxy_main_page@ \ + @PROJECT_SOURCE_DIR@ \ + @PROJECT_BINARY_DIR@ \ + @PROJECT_SOURCE_DIR@/include/ \ + @PROJECT_SOURCE_DIR@/doc/dox.h \ + @PROJECT_SOURCE_DIR@/code/BaseImporter.h # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is @@ -919,7 +907,7 @@ GENERATE_HTML = YES # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. -HTML_OUTPUT = AssimpDoc_Html +HTML_OUTPUT = @HTML_OUTPUT@ # The HTML_FILE_EXTENSION tag can be used to specify the file extension for # each generated HTML page (for example: .htm,.php,.asp). If it is left blank @@ -953,7 +941,7 @@ HTML_FOOTER = # HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this # tag will in the future become obsolete. -HTML_STYLESHEET = style.css +# HTML_STYLESHEET = @CMAKE_CURRENT_SOURCE_DIR@/style.css # The HTML_EXTRA_STYLESHEET tag can be used to specify an additional # user-defined cascading style sheet that is included after the standard @@ -1064,7 +1052,7 @@ DOCSET_PUBLISHER_NAME = Publisher # Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. -GENERATE_HTMLHELP = YES +GENERATE_HTMLHELP = @MICROSOFT_HELP_WORKSHOP@ # If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can # be used to specify the file name of the resulting .chm file. You @@ -1504,18 +1492,6 @@ GENERATE_XML = NO XML_OUTPUT = xml -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - # If the XML_PROGRAMLISTING tag is set to YES Doxygen will # dump the program listings (including syntax highlighting # and cross-referencing information) to the XML output. Note that diff --git a/doc/Preamble.txt b/doc/Preamble.txt index 0722a48e1..102b2792d 100644 --- a/doc/Preamble.txt +++ b/doc/Preamble.txt @@ -3,12 +3,12 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2012, assimp team +Copyright (c) 2006-2017, 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,16 +25,16 @@ 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. --------------------------------------------------------------------------- -*/ \ No newline at end of file +*/ diff --git a/doc/dox.h b/doc/dox.h index f051e5c00..46ca23251 100644 --- a/doc/dox.h +++ b/doc/dox.h @@ -453,7 +453,7 @@ by calling it as a singleton with the requested logging-type. To see how this wo using namespace Assimp; // Create a logger instance -DefaultLogger::create("",Logger::VERBOSE); +DefaultLogger::create("", Logger::VERBOSE); // Now I am ready for logging my stuff DefaultLogger::get()->info("this is my info-call"); @@ -472,22 +472,9 @@ Just derivate your own logger from the abstract base class LogStream and overwri @code // Example stream -class myStream : - public LogStream +class myStream : public LogStream { public: - // Constructor - myStream() - { - // empty - } - - // Destructor - ~myStream() - { - // empty - } - // Write womethink using your own functionality void write(const char* message) { @@ -496,10 +483,10 @@ public: }; // Select the kinds of messages you want to receive on this log stream -const unsigned int severity = Logger::DEBUGGING|Logger::INFO|Logger::ERR|Logger::WARN; +const unsigned int severity = Logger::Debugging|Logger::Info|Logger::Err|Logger::Warn; // Attaching it to the default logger -Assimp::DefaultLogger::get()->attachStream( new myStream(), severity ); +Assimp::DefaultLogger::get()->attachStream( new myStream, severity ); @endcode @@ -512,10 +499,10 @@ flag set: @code unsigned int severity = 0; -severity |= Logger::DEBUGGING; +severity |= Logger::Debugging; // Detach debug messages from you self defined stream -Assimp::DefaultLogger::get()->attachStream( new myStream(), severity ); +Assimp::DefaultLogger::get()->attachStream( new myStream, severity ); @endcode @@ -743,6 +730,8 @@ need them at all. Normally textures used by assets are stored in separate files, however, there are file formats embedding their textures directly into the model file. Such textures are loaded into an aiTexture structure. +For embedded textures, the value of `AI_MATKEY_TEXTURE(textureType, index)` will be `*` where +`` is the index of the texture in aiScene::mTextures.
There are two cases:
@@ -930,7 +919,7 @@ All material key constants start with 'AI_MATKEY' (it's an ugly macro for histor TEXTURE(t,n) aiString n/a - Defines the path to the n'th texture on the stack 't', where 'n' is any value >= 0 and 't' is one of the #aiTextureType enumerated values. + Defines the path of the n'th texture on the stack 't', where 'n' is any value >= 0 and 't' is one of the #aiTextureType enumerated values. Either a filepath or `*`, where `` is the index of an embedded texture in aiScene::mTextures. See the 'Textures' section above. diff --git a/include/assimp/DefaultIOStream.h b/include/assimp/DefaultIOStream.h index f4c9af85d..3668b27ec 100644 --- a/include/assimp/DefaultIOStream.h +++ b/include/assimp/DefaultIOStream.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/include/assimp/DefaultIOSystem.h b/include/assimp/DefaultIOSystem.h index b4986b330..d7cf031cf 100644 --- a/include/assimp/DefaultIOSystem.h +++ b/include/assimp/DefaultIOSystem.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/include/assimp/DefaultLogger.hpp b/include/assimp/DefaultLogger.hpp index 52574d5ea..4f1a7e1f4 100644 --- a/include/assimp/DefaultLogger.hpp +++ b/include/assimp/DefaultLogger.hpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/include/assimp/Exporter.hpp b/include/assimp/Exporter.hpp index 72224da3c..2c141ded2 100644 --- a/include/assimp/Exporter.hpp +++ b/include/assimp/Exporter.hpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/IOStream.hpp b/include/assimp/IOStream.hpp index b0bc5ebb6..ce5907a47 100644 --- a/include/assimp/IOStream.hpp +++ b/include/assimp/IOStream.hpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/IOSystem.hpp b/include/assimp/IOSystem.hpp index 83d927453..e7a216e4e 100644 --- a/include/assimp/IOSystem.hpp +++ b/include/assimp/IOSystem.hpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/Importer.hpp b/include/assimp/Importer.hpp index 6b8c6ac46..f42a2deaf 100644 --- a/include/assimp/Importer.hpp +++ b/include/assimp/Importer.hpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/LogStream.hpp b/include/assimp/LogStream.hpp index 03e77dba4..1052f1fda 100644 --- a/include/assimp/LogStream.hpp +++ b/include/assimp/LogStream.hpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -63,12 +64,11 @@ class ASSIMP_API LogStream { protected: /** @brief Default constructor */ - LogStream() { - } + LogStream(); + public: /** @brief Virtual destructor */ - virtual ~LogStream() { - } + virtual ~LogStream(); // ------------------------------------------------------------------- /** @brief Overwrite this for your own output methods @@ -93,6 +93,17 @@ public: IOSystem* io = NULL); }; // !class LogStream + +inline +LogStream::LogStream() { + // empty +} + +inline +LogStream::~LogStream() { + // empty +} + // ------------------------------------------------------------------------------------ } // Namespace Assimp diff --git a/include/assimp/Logger.hpp b/include/assimp/Logger.hpp index 655957bab..0875b6d7d 100644 --- a/include/assimp/Logger.hpp +++ b/include/assimp/Logger.hpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/include/assimp/NullLogger.hpp b/include/assimp/NullLogger.hpp index 357ffc499..191db1aaa 100644 --- a/include/assimp/NullLogger.hpp +++ b/include/assimp/NullLogger.hpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/include/assimp/ProgressHandler.hpp b/include/assimp/ProgressHandler.hpp index 1ac016efb..2c5b2f4c5 100644 --- a/include/assimp/ProgressHandler.hpp +++ b/include/assimp/ProgressHandler.hpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/code/SceneCombiner.h b/include/assimp/SceneCombiner.h similarity index 98% rename from code/SceneCombiner.h rename to include/assimp/SceneCombiner.h index 64c1ea48e..ebb5dda00 100644 --- a/code/SceneCombiner.h +++ b/include/assimp/SceneCombiner.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, @@ -142,7 +143,6 @@ struct NodeAttachmentInfo */ #define AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY 0x10 - typedef std::pair BoneSrcIndex; // --------------------------------------------------------------------------- @@ -152,7 +152,6 @@ struct BoneWithHash : public std::pair { std::vector pSrcBones; }; - // --------------------------------------------------------------------------- /** @brief Utility for SceneCombiner */ @@ -218,10 +217,9 @@ public: static void MergeScenes(aiScene** dest,std::vector& src, unsigned int flags = 0); - // ------------------------------------------------------------------- - /** Merges two or more scenes and attaches all sceenes to a specific - * position in the node graph of the masteer scene. + /** Merges two or more scenes and attaches all scenes to a specific + * position in the node graph of the master scene. * * @param dest Receives a pointer to the destination scene. If the * pointer doesn't point to NULL when the function is called, the @@ -237,7 +235,6 @@ public: std::vector& src, unsigned int flags = 0); - // ------------------------------------------------------------------- /** Merges two or more meshes * @@ -256,7 +253,6 @@ public: std::vector::const_iterator begin, std::vector::const_iterator end); - // ------------------------------------------------------------------- /** Merges two or more bones * diff --git a/include/assimp/ai_assert.h b/include/assimp/ai_assert.h index fa63c329c..d8dbac8d2 100644 --- a/include/assimp/ai_assert.h +++ b/include/assimp/ai_assert.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/anim.h b/include/assimp/anim.h index 4fac3e4d8..f8774b8fd 100644 --- a/include/assimp/anim.h +++ b/include/assimp/anim.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/camera.h b/include/assimp/camera.h index 6b9fbbea5..7b7bd0922 100644 --- a/include/assimp/camera.h +++ b/include/assimp/camera.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/cfileio.h b/include/assimp/cfileio.h index 5f46f7c4c..63eeb59b0 100644 --- a/include/assimp/cfileio.h +++ b/include/assimp/cfileio.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/cimport.h b/include/assimp/cimport.h index 8bb47750a..8aa125c67 100644 --- a/include/assimp/cimport.h +++ b/include/assimp/cimport.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -416,7 +417,7 @@ ASSIMP_API void aiSetImportPropertyInteger( ASSIMP_API void aiSetImportPropertyFloat( C_STRUCT aiPropertyStore* store, const char* szName, - float value); + ai_real value); // -------------------------------------------------------------------------------- /** Set a string property. diff --git a/include/assimp/color4.h b/include/assimp/color4.h index 889669e4b..48e7aad30 100644 --- a/include/assimp/color4.h +++ b/include/assimp/color4.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/color4.inl b/include/assimp/color4.inl index e171d9d44..b242c4e77 100644 --- a/include/assimp/color4.inl +++ b/include/assimp/color4.inl @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -76,7 +77,6 @@ AI_FORCE_INLINE const aiColor4t& aiColor4t::operator /= (TReal f) // ------------------------------------------------------------------------------------------------ template AI_FORCE_INLINE TReal aiColor4t::operator[](unsigned int i) const { - //return *(&r + i); switch ( i ) { case 0: return r; @@ -92,7 +92,6 @@ AI_FORCE_INLINE TReal aiColor4t::operator[](unsigned int i) const { // ------------------------------------------------------------------------------------------------ template AI_FORCE_INLINE TReal& aiColor4t::operator[](unsigned int i) { -// return *(&r + i); switch ( i ) { case 0: return r; diff --git a/include/assimp/config.h.in b/include/assimp/config.h.in index db197822e..00fe7b593 100644 --- a/include/assimp/config.h.in +++ b/include/assimp/config.h.in @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team All rights reserved. @@ -632,8 +632,15 @@ enum aiComponent #define AI_CONFIG_IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES \ "IMPORT_FBX_OPTIMIZE_EMPTY_ANIMATION_CURVES" - - +// --------------------------------------------------------------------------- +/** @brief Set whether the fbx importer will search for embedded loaded textures, where no embedded texture data is provided. +* +* The default value is false (0) +* Property type: bool +*/ +#define AI_CONFIG_IMPORT_FBX_SEARCH_EMBEDDED_TEXTURES \ + "IMPORT_FBX_SEARCH_EMBEDDED_TEXTURES" + // --------------------------------------------------------------------------- /** @brief Set the vertex animation keyframe to be imported * diff --git a/include/assimp/defs.h b/include/assimp/defs.h index cfe69984a..20b234f90 100644 --- a/include/assimp/defs.h +++ b/include/assimp/defs.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/importerdesc.h b/include/assimp/importerdesc.h index 455f83cce..6b83b8aa2 100644 --- a/include/assimp/importerdesc.h +++ b/include/assimp/importerdesc.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/light.h b/include/assimp/light.h index 9a7893b52..324339a97 100644 --- a/include/assimp/light.h +++ b/include/assimp/light.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/material.h b/include/assimp/material.h index 23a45878e..a12e7d076 100644 --- a/include/assimp/material.h +++ b/include/assimp/material.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/material.inl b/include/assimp/material.inl index cd610fd58..2c31fd571 100644 --- a/include/assimp/material.inl +++ b/include/assimp/material.inl @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -47,6 +48,18 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef AI_MATERIAL_INL_INC #define AI_MATERIAL_INL_INC +// --------------------------------------------------------------------------- +inline aiPropertyTypeInfo ai_real_to_property_type_info(float) +{ + return aiPTI_Float; +} + +inline aiPropertyTypeInfo ai_real_to_property_type_info(double) +{ + return aiPTI_Double; +} +// --------------------------------------------------------------------------- + //! @cond never // --------------------------------------------------------------------------- @@ -222,7 +235,7 @@ inline aiReturn aiMaterial::AddProperty(const aiUVTransform* pInput, { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiUVTransform), - pKey,type,index,aiPTI_Float); //TODO could be Double ... + pKey,type,index,ai_real_to_property_type_info(pInput->mRotation)); } // --------------------------------------------------------------------------- @@ -234,7 +247,7 @@ inline aiReturn aiMaterial::AddProperty(const aiColor4D* pInput, { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiColor4D), - pKey,type,index,aiPTI_Float); //TODO could be Double ... + pKey,type,index,ai_real_to_property_type_info(pInput->a)); } // --------------------------------------------------------------------------- @@ -246,7 +259,7 @@ inline aiReturn aiMaterial::AddProperty(const aiColor3D* pInput, { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiColor3D), - pKey,type,index,aiPTI_Float); //TODO could be Double ... + pKey,type,index,ai_real_to_property_type_info(pInput->b)); } // --------------------------------------------------------------------------- @@ -258,7 +271,7 @@ inline aiReturn aiMaterial::AddProperty(const aiVector3D* pInput, { return AddBinaryProperty((const void*)pInput, pNumValues * sizeof(aiVector3D), - pKey,type,index,aiPTI_Float); //TODO could be Double ... + pKey,type,index,ai_real_to_property_type_info(pInput->x)); } // --------------------------------------------------------------------------- diff --git a/include/assimp/matrix3x3.h b/include/assimp/matrix3x3.h index c34e3c8b3..3cf575e38 100644 --- a/include/assimp/matrix3x3.h +++ b/include/assimp/matrix3x3.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/matrix3x3.inl b/include/assimp/matrix3x3.inl index dce5aa00e..14f2cd2fc 100644 --- a/include/assimp/matrix3x3.inl +++ b/include/assimp/matrix3x3.inl @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/matrix4x4.h b/include/assimp/matrix4x4.h index 9f87efca7..4311fa118 100644 --- a/include/assimp/matrix4x4.h +++ b/include/assimp/matrix4x4.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -223,7 +224,7 @@ public: * @return Reference to the output matrix */ static aiMatrix4x4t& Rotation(TReal a, const aiVector3t& axis, - aiMatrix4x4t& out); + aiMatrix4x4t& out); // ------------------------------------------------------------------- /** @brief Returns a translation matrix @@ -231,7 +232,8 @@ public: * @param out Receives the output matrix * @return Reference to the output matrix */ - static aiMatrix4x4t& Translation( const aiVector3t& v, aiMatrix4x4t& out); + static aiMatrix4x4t& Translation( const aiVector3t& v, + aiMatrix4x4t& out); // ------------------------------------------------------------------- /** @brief Returns a scaling matrix @@ -251,7 +253,7 @@ public: * Journal of Graphics Tools, 4(4):1-4, 1999 */ static aiMatrix4x4t& FromToMatrix(const aiVector3t& from, - const aiVector3t& to, aiMatrix4x4t& out); + const aiVector3t& to, aiMatrix4x4t& out); public: TReal a1, a2, a3, a4; diff --git a/include/assimp/matrix4x4.inl b/include/assimp/matrix4x4.inl index c36c893ce..b15d50a09 100644 --- a/include/assimp/matrix4x4.inl +++ b/include/assimp/matrix4x4.inl @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/mesh.h b/include/assimp/mesh.h index ef2c8838b..c8648c778 100644 --- a/include/assimp/mesh.h +++ b/include/assimp/mesh.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team All rights reserved. @@ -377,8 +377,10 @@ struct aiAnimMesh * from language bindings. */ unsigned int mNumVertices; - -/** Weight of the AnimMesh. */ + + /** + * Weight of the AnimMesh. + */ float mWeight; #ifdef __cplusplus @@ -389,6 +391,7 @@ struct aiAnimMesh , mTangents( NULL ) , mBitangents( NULL ) , mNumVertices( 0 ) + , mWeight( 0.0f ) { // fixme consider moving this to the ctor initializer list as well for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++){ @@ -633,7 +636,9 @@ struct aiMesh * Note! Currently only works with Collada loader.*/ C_STRUCT aiAnimMesh** mAnimMeshes; - /** Method of morphing when animeshes are specified. */ + /** + * Method of morphing when animeshes are specified. + */ unsigned int mMethod; #ifdef __cplusplus @@ -653,6 +658,7 @@ struct aiMesh , mMaterialIndex( 0 ) , mNumAnimMeshes( 0 ) , mAnimMeshes( NULL ) + , mMethod( 0 ) { for( unsigned int a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; a++) { diff --git a/include/assimp/metadata.h b/include/assimp/metadata.h index fbf950c72..ded08d14b 100644 --- a/include/assimp/metadata.h +++ b/include/assimp/metadata.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -133,7 +134,6 @@ struct aiMetadata { // empty } - /** * @brief The destructor. */ @@ -198,6 +198,14 @@ struct aiMetadata { return data; } + /** + * @brief Deallocates property fields + keys. + */ + static inline + void Dealloc( aiMetadata *metadata ) { + delete metadata; + } + template inline void Add(const std::string& key, const T& value) { diff --git a/include/assimp/postprocess.h b/include/assimp/postprocess.h index 53c22da13..b35bc34f5 100644 --- a/include/assimp/postprocess.h +++ b/include/assimp/postprocess.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/include/assimp/quaternion.h b/include/assimp/quaternion.h index fdc4d266b..a5cb67a9a 100644 --- a/include/assimp/quaternion.h +++ b/include/assimp/quaternion.h @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) ---------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. Redistribution and use of this software in source and binary forms, diff --git a/include/assimp/quaternion.inl b/include/assimp/quaternion.inl index 68cb5a236..d0bf5831c 100644 --- a/include/assimp/quaternion.inl +++ b/include/assimp/quaternion.inl @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/scene.h b/include/assimp/scene.h index b52db9883..342c316d6 100644 --- a/include/assimp/scene.h +++ b/include/assimp/scene.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -59,6 +60,11 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. extern "C" { #endif +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wattributes" +#endif + // ------------------------------------------------------------------------------- /** * A node in the imported hierarchy. @@ -162,6 +168,9 @@ struct ASSIMP_API aiNode #endif // __cplusplus }; +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif // ------------------------------------------------------------------------------- /** diff --git a/include/assimp/texture.h b/include/assimp/texture.h index ab52c79a2..c09ef2cbe 100644 --- a/include/assimp/texture.h +++ b/include/assimp/texture.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/types.h b/include/assimp/types.h index 8f303f3af..0012a0bba 100644 --- a/include/assimp/types.h +++ b/include/assimp/types.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/vector2.h b/include/assimp/vector2.h index 4122273c5..564d1f8b5 100644 --- a/include/assimp/vector2.h +++ b/include/assimp/vector2.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/vector2.inl b/include/assimp/vector2.inl index ce6521139..5ce13eece 100644 --- a/include/assimp/vector2.inl +++ b/include/assimp/vector2.inl @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/vector3.h b/include/assimp/vector3.h index 1c2c187ce..946e36cc5 100644 --- a/include/assimp/vector3.h +++ b/include/assimp/vector3.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/vector3.inl b/include/assimp/vector3.inl index b5d743641..a074bb23a 100644 --- a/include/assimp/vector3.inl +++ b/include/assimp/vector3.inl @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/include/assimp/version.h b/include/assimp/version.h index a9b2beb5b..d1821fa2b 100644 --- a/include/assimp/version.h +++ b/include/assimp/version.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -104,3 +105,4 @@ ASSIMP_API unsigned int aiGetCompileFlags (void); #endif #endif // !! #ifndef AI_VERSION_H_INC + diff --git a/port/PyAssimp/README.md b/port/PyAssimp/README.md index 0000f9386..37ecdb65d 100644 --- a/port/PyAssimp/README.md +++ b/port/PyAssimp/README.md @@ -1,94 +1,94 @@ -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`: - -``` -$ 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: - -``` -$ 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. - +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`: + +``` +$ 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: + +``` +$ 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 ac3df9290..573ce27b1 100644 --- a/port/PyAssimp/pyassimp/core.py +++ b/port/PyAssimp/pyassimp/core.py @@ -119,7 +119,10 @@ def _init(self, target = None, parent = None): if m == 'mName': obj = self.mName - uni = unicode(obj.data, errors='ignore') + try: + uni = unicode(obj.data, errors='ignore') + except: + uni = str(obj.data, errors='ignore') target.name = str( uni ) target.__class__.__repr__ = lambda x: str(x.__class__) + "(" + x.name + ")" target.__class__.__str__ = lambda x: x.name @@ -440,7 +443,10 @@ def _get_properties(properties, length): for p in [properties[i] for i in range(length)]: #the name p = p.contents - uni = unicode(p.mKey.data, errors='ignore') + try: + uni = unicode(p.mKey.data, errors='ignore') + except: + uni = str(p.mKey.data, errors='ignore') key = (str(uni).split('.')[1], p.mSemantic) #the data @@ -449,7 +455,10 @@ def _get_properties(properties, length): 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 - uni = unicode(cast(p.mData, POINTER(structs.MaterialPropertyString)).contents.data, errors='ignore') + try: + uni = unicode(cast(p.mData, POINTER(structs.MaterialPropertyString)).contents.data, errors='ignore') + except: + uni = str(cast(p.mData, POINTER(structs.MaterialPropertyString)).contents.data, errors='ignore') value = uni elif p.mType == 4: @@ -476,3 +485,4 @@ def decompose_matrix(matrix): from ctypes import byref, pointer _assimp_lib.dll.aiDecomposeMatrix(pointer(matrix), byref(scaling), byref(rotation), byref(position)) return scaling._init(), rotation._init(), position._init() + diff --git a/port/PyAssimp/pyassimp/helper.py b/port/PyAssimp/pyassimp/helper.py index 99d0b1758..4fa01d51d 100644 --- a/port/PyAssimp/pyassimp/helper.py +++ b/port/PyAssimp/pyassimp/helper.py @@ -8,6 +8,9 @@ import os import ctypes from ctypes import POINTER import operator + +from distutils.sysconfig import get_python_lib +import re import sys try: import numpy @@ -27,7 +30,15 @@ if os.name=='posix': additional_dirs.append('/usr/lib/x86_64-linux-gnu') additional_dirs.append('/usr/local/lib/') - # note - this won't catch libassimp.so.N.n, but + # 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') @@ -41,8 +52,6 @@ elif os.name=='nt': if 'assimp' in dir_candidate.lower(): additional_dirs.append(dir_candidate) -additional_dirs += sys.path - #print(additional_dirs) def vec2tuple(x): """ Converts a VECTOR3D to a Tuple """ @@ -64,10 +73,10 @@ def transform(vector3, matrix4x4): 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] - \ @@ -80,7 +89,7 @@ def _inv(matrix4x4): 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, @@ -97,7 +106,7 @@ def _inv(matrix4x4): ( 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 @@ -132,7 +141,7 @@ def get_bounding_box_for_node(node, bb_min, bb_max, transformation): 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) @@ -152,25 +161,25 @@ def get_bounding_box_for_node(node, bb_min, bb_max, transformation): 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, + Tuple containing (library_path, load from filename function, load from memory function, export to filename function, - release function, + release function, ctypes handle to assimp library) ''' - + try: load = dll.aiImportFile release = dll.aiReleaseImport @@ -179,7 +188,7 @@ def try_load_functions(library_path, dll): except AttributeError: #OK, this is a library, but it doesn't have the functions we need return None - + # library found! from .structs import Scene load.restype = POINTER(Scene) @@ -188,13 +197,13 @@ def try_load_functions(library_path, dll): def search_library(): ''' - Loads the assimp library. + Loads the assimp library. Throws exception AssimpError if no library_path is found - - Returns: tuple, (load from filename function, + + Returns: tuple, (load from filename function, load from memory function, export to filename function, - release function, + release function, dll) ''' #this path @@ -204,7 +213,7 @@ def search_library(): try: ctypes.windll.kernel32.SetErrorMode(0x8007) except AttributeError: - pass + pass candidates = [] # test every file @@ -212,7 +221,7 @@ def search_library(): if os.path.isdir(curfolder): for filename in os.listdir(curfolder): # our minimum requirement for candidates is that - # they should contain 'assimp' somewhere in + # they should contain 'assimp' somewhere in # their name if filename.lower().find('assimp')==-1 or\ os.path.splitext(filename)[-1].lower() not in ext_whitelist: @@ -251,10 +260,10 @@ 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: diff --git a/port/PyAssimp/pyassimp/material.py b/port/PyAssimp/pyassimp/material.py new file mode 100644 index 000000000..97b143a62 --- /dev/null +++ b/port/PyAssimp/pyassimp/material.py @@ -0,0 +1,89 @@ +##
Dummy value. +# +# No texture, but the value to be used as 'texture semantic' +# (#aiMaterialProperty::mSemantic) for all material properties +# *not* related to textures. +# +aiTextureType_NONE = 0x0 + +##
The texture is combined with the result of the diffuse +# lighting equation. +# +aiTextureType_DIFFUSE = 0x1 + +##
The texture is combined with the result of the specular +# lighting equation. +# +aiTextureType_SPECULAR = 0x2 + +##
The texture is combined with the result of the ambient +# lighting equation. +# +aiTextureType_AMBIENT = 0x3 + +##
The texture is added to the result of the lighting +# calculation. It isn't influenced by incoming light. +# +aiTextureType_EMISSIVE = 0x4 + +##
The texture is a height map. +# +# By convention, higher gray-scale values stand for +# higher elevations from the base height. +# +aiTextureType_HEIGHT = 0x5 + +##
The texture is a (tangent space) normal-map. +# +# Again, there are several conventions for tangent-space +# normal maps. Assimp does (intentionally) not +# distinguish here. +# +aiTextureType_NORMALS = 0x6 + +##
The texture defines the glossiness of the material. +# +# The glossiness is in fact the exponent of the specular +# (phong) lighting equation. Usually there is a conversion +# function defined to map the linear color values in the +# texture to a suitable exponent. Have fun. +# +aiTextureType_SHININESS = 0x7 + +##
The texture defines per-pixel opacity. +# +# Usually 'white' means opaque and 'black' means +# 'transparency'. Or quite the opposite. Have fun. +# +aiTextureType_OPACITY = 0x8 + +##
Displacement texture +# +# The exact purpose and format is application-dependent. +# Higher color values stand for higher vertex displacements. +# +aiTextureType_DISPLACEMENT = 0x9 + +##
Lightmap texture (aka Ambient Occlusion) +# +# Both 'Lightmaps' and dedicated 'ambient occlusion maps' are +# covered by this material property. The texture contains a +# scaling value for the final color value of a pixel. Its +# intensity is not affected by incoming light. +# +aiTextureType_LIGHTMAP = 0xA + +##
Reflection texture +# +#Contains the color of a perfect mirror reflection. +#Rarely used, almost never for real-time applications. +# +aiTextureType_REFLECTION = 0xB + +##
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. +# +aiTextureType_UNKNOWN = 0xC diff --git a/port/PyAssimp/scripts/3d_viewer.py b/port/PyAssimp/scripts/3d_viewer.py index 3a579eb61..9aae25efe 100755 --- a/port/PyAssimp/scripts/3d_viewer.py +++ b/port/PyAssimp/scripts/3d_viewer.py @@ -679,7 +679,7 @@ class PyAssimp3DViewer: logger.info("Loading model:" + path + "...") if postprocess: - self.scene = pyassimp.load(path, postprocess) + self.scene = pyassimp.load(path, processing=postprocess) else: self.scene = pyassimp.load(path) logger.info("Done.") diff --git a/port/PyAssimp/scripts/3d_viewer_py3.py b/port/PyAssimp/scripts/3d_viewer_py3.py new file mode 100755 index 000000000..4e4ecebe8 --- /dev/null +++ b/port/PyAssimp/scripts/3d_viewer_py3.py @@ -0,0 +1,1320 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +""" This program loads a model with PyASSIMP, and display it. + +Based on: +- pygame code from http://3dengine.org/Spectator_%28PyOpenGL%29 +- http://www.lighthouse3d.com/tutorials +- http://www.songho.ca/opengl/gl_transform.html +- http://code.activestate.com/recipes/325391/ +- ASSIMP's C++ SimpleOpenGL viewer + +Authors: Séverin Lemaignan, 2012-2016 +""" +import sys +import logging + +from functools import reduce + +logger = logging.getLogger("pyassimp") +gllogger = logging.getLogger("OpenGL") +gllogger.setLevel(logging.WARNING) +logging.basicConfig(level=logging.INFO) + +import OpenGL + +OpenGL.ERROR_CHECKING = False +OpenGL.ERROR_LOGGING = False +# OpenGL.ERROR_ON_COPY = True +# OpenGL.FULL_LOGGING = True +from OpenGL.GL import * +from OpenGL.arrays import vbo +from OpenGL.GL import shaders + +import pygame +import pygame.font +import pygame.image + +import math, random +from numpy import linalg + +import pyassimp +from pyassimp.postprocess import * +from pyassimp.helper import * +import transformations + +ROTATION_180_X = numpy.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], dtype=numpy.float32) + +# rendering mode +BASE = "BASE" +COLORS = "COLORS" +SILHOUETTE = "SILHOUETTE" +HELPERS = "HELPERS" + +# Entities type +ENTITY = "entity" +CAMERA = "camera" +MESH = "mesh" + +FLAT_VERTEX_SHADER_120 = """ +#version 120 + +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelMatrix; + +uniform vec4 u_materialDiffuse; + +attribute vec3 a_vertex; + +varying vec4 v_color; + +void main(void) +{ + v_color = u_materialDiffuse; + gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); +} +""" + +FLAT_VERTEX_SHADER_130 = """ +#version 130 + +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelMatrix; + +uniform vec4 u_materialDiffuse; + +in vec3 a_vertex; + +out vec4 v_color; + +void main(void) +{ + v_color = u_materialDiffuse; + gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); +} +""" + +BASIC_VERTEX_SHADER_120 = """ +#version 120 + +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelMatrix; +uniform mat3 u_normalMatrix; +uniform vec3 u_lightPos; + +uniform vec4 u_materialDiffuse; + +attribute vec3 a_vertex; +attribute vec3 a_normal; + +varying vec4 v_color; + +void main(void) +{ + // Now the normal is in world space, as we pass the light in world space. + vec3 normal = u_normalMatrix * a_normal; + + float dist = distance(a_vertex, u_lightPos); + + // go to https://www.desmos.com/calculator/nmnaud1hrw to play with the parameters + // att is not used for now + float att=1.0/(1.0+0.8*dist*dist); + + vec3 surf2light = normalize(u_lightPos - a_vertex); + vec3 norm = normalize(normal); + float dcont=max(0.0,dot(norm,surf2light)); + + float ambient = 0.3; + float intensity = dcont + 0.3 + ambient; + + v_color = u_materialDiffuse * intensity; + + gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); +} +""" + +BASIC_VERTEX_SHADER_130 = """ +#version 130 + +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelMatrix; +uniform mat3 u_normalMatrix; +uniform vec3 u_lightPos; + +uniform vec4 u_materialDiffuse; + +in vec3 a_vertex; +in vec3 a_normal; + +out vec4 v_color; + +void main(void) +{ + // Now the normal is in world space, as we pass the light in world space. + vec3 normal = u_normalMatrix * a_normal; + + float dist = distance(a_vertex, u_lightPos); + + // go to https://www.desmos.com/calculator/nmnaud1hrw to play with the parameters + // att is not used for now + float att=1.0/(1.0+0.8*dist*dist); + + vec3 surf2light = normalize(u_lightPos - a_vertex); + vec3 norm = normalize(normal); + float dcont=max(0.0,dot(norm,surf2light)); + + float ambient = 0.3; + float intensity = dcont + 0.3 + ambient; + + v_color = u_materialDiffuse * intensity; + + gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); +} +""" + +BASIC_FRAGMENT_SHADER_120 = """ +#version 120 + +varying vec4 v_color; + +void main() { + gl_FragColor = v_color; +} +""" + +BASIC_FRAGMENT_SHADER_130 = """ +#version 130 + +in vec4 v_color; + +void main() { + gl_FragColor = v_color; +} +""" + +GOOCH_VERTEX_SHADER_120 = """ +#version 120 + +// attributes +attribute vec3 a_vertex; // xyz - position +attribute vec3 a_normal; // xyz - normal + +// uniforms +uniform mat4 u_modelMatrix; +uniform mat4 u_viewProjectionMatrix; +uniform mat3 u_normalMatrix; +uniform vec3 u_lightPos; +uniform vec3 u_camPos; + +// output data from vertex to fragment shader +varying vec3 o_normal; +varying vec3 o_lightVector; + +/////////////////////////////////////////////////////////////////// + +void main(void) +{ + // transform position and normal to world space + vec4 positionWorld = u_modelMatrix * vec4(a_vertex, 1.0); + vec3 normalWorld = u_normalMatrix * a_normal; + + // calculate and pass vectors required for lighting + o_lightVector = u_lightPos - positionWorld.xyz; + o_normal = normalWorld; + + // project world space position to the screen and output it + gl_Position = u_viewProjectionMatrix * positionWorld; +} +""" + +GOOCH_VERTEX_SHADER_130 = """ +#version 130 + +// attributes +in vec3 a_vertex; // xyz - position +in vec3 a_normal; // xyz - normal + +// uniforms +uniform mat4 u_modelMatrix; +uniform mat4 u_viewProjectionMatrix; +uniform mat3 u_normalMatrix; +uniform vec3 u_lightPos; +uniform vec3 u_camPos; + +// output data from vertex to fragment shader +out vec3 o_normal; +out vec3 o_lightVector; + +/////////////////////////////////////////////////////////////////// + +void main(void) +{ + // transform position and normal to world space + vec4 positionWorld = u_modelMatrix * vec4(a_vertex, 1.0); + vec3 normalWorld = u_normalMatrix * a_normal; + + // calculate and pass vectors required for lighting + o_lightVector = u_lightPos - positionWorld.xyz; + o_normal = normalWorld; + + // project world space position to the screen and output it + gl_Position = u_viewProjectionMatrix * positionWorld; +} +""" + +GOOCH_FRAGMENT_SHADER_120 = """ +#version 120 + +// data from vertex shader +varying vec3 o_normal; +varying vec3 o_lightVector; + +// diffuse color of the object +uniform vec4 u_materialDiffuse; +// cool color of gooch shading +uniform vec3 u_coolColor; +// warm color of gooch shading +uniform vec3 u_warmColor; +// how much to take from object color in final cool color +uniform float u_alpha; +// how much to take from object color in final warm color +uniform float u_beta; + +/////////////////////////////////////////////////////////// + +void main(void) +{ + // normlize vectors for lighting + vec3 normalVector = normalize(o_normal); + vec3 lightVector = normalize(o_lightVector); + // intensity of diffuse lighting [-1, 1] + float diffuseLighting = dot(lightVector, normalVector); + // map intensity of lighting from range [-1; 1] to [0, 1] + float interpolationValue = (1.0 + diffuseLighting)/2; + + ////////////////////////////////////////////////////////////////// + + // cool color mixed with color of the object + vec3 coolColorMod = u_coolColor + vec3(u_materialDiffuse) * u_alpha; + // warm color mixed with color of the object + vec3 warmColorMod = u_warmColor + vec3(u_materialDiffuse) * u_beta; + // interpolation of cool and warm colors according + // to lighting intensity. The lower the light intensity, + // the larger part of the cool color is used + vec3 colorOut = mix(coolColorMod, warmColorMod, interpolationValue); + + ////////////////////////////////////////////////////////////////// + + // save color + gl_FragColor.rgb = colorOut; + gl_FragColor.a = 1; +} +""" + +GOOCH_FRAGMENT_SHADER_130 = """ +#version 130 + +// data from vertex shader +in vec3 o_normal; +in vec3 o_lightVector; + +// diffuse color of the object +uniform vec4 u_materialDiffuse; +// cool color of gooch shading +uniform vec3 u_coolColor; +// warm color of gooch shading +uniform vec3 u_warmColor; +// how much to take from object color in final cool color +uniform float u_alpha; +// how much to take from object color in final warm color +uniform float u_beta; + +// output to framebuffer +out vec4 resultingColor; + +/////////////////////////////////////////////////////////// + +void main(void) +{ + // normlize vectors for lighting + vec3 normalVector = normalize(o_normal); + vec3 lightVector = normalize(o_lightVector); + // intensity of diffuse lighting [-1, 1] + float diffuseLighting = dot(lightVector, normalVector); + // map intensity of lighting from range [-1; 1] to [0, 1] + float interpolationValue = (1.0 + diffuseLighting)/2; + + ////////////////////////////////////////////////////////////////// + + // cool color mixed with color of the object + vec3 coolColorMod = u_coolColor + vec3(u_materialDiffuse) * u_alpha; + // warm color mixed with color of the object + vec3 warmColorMod = u_warmColor + vec3(u_materialDiffuse) * u_beta; + // interpolation of cool and warm colors according + // to lighting intensity. The lower the light intensity, + // the larger part of the cool color is used + vec3 colorOut = mix(coolColorMod, warmColorMod, interpolationValue); + + ////////////////////////////////////////////////////////////////// + + // save color + resultingColor.rgb = colorOut; + resultingColor.a = 1; +} +""" + +SILHOUETTE_VERTEX_SHADER_120 = """ +#version 120 + +attribute vec3 a_vertex; // xyz - position +attribute vec3 a_normal; // xyz - normal + +uniform mat4 u_modelMatrix; +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelViewMatrix; +uniform vec4 u_materialDiffuse; +uniform float u_bordersize; // width of the border + +varying vec4 v_color; + +void main(void){ + v_color = u_materialDiffuse; + float distToCamera = -(u_modelViewMatrix * vec4(a_vertex, 1.0)).z; + vec4 tPos = vec4(a_vertex + a_normal * u_bordersize * distToCamera, 1.0); + gl_Position = u_viewProjectionMatrix * u_modelMatrix * tPos; +} +""" + +SILHOUETTE_VERTEX_SHADER_130 = """ +#version 130 + +in vec3 a_vertex; // xyz - position +in vec3 a_normal; // xyz - normal + +uniform mat4 u_modelMatrix; +uniform mat4 u_viewProjectionMatrix; +uniform mat4 u_modelViewMatrix; +uniform vec4 u_materialDiffuse; +uniform float u_bordersize; // width of the border + +out vec4 v_color; + +void main(void){ + v_color = u_materialDiffuse; + float distToCamera = -(u_modelViewMatrix * vec4(a_vertex, 1.0)).z; + vec4 tPos = vec4(a_vertex + a_normal * u_bordersize * distToCamera, 1.0); + gl_Position = u_viewProjectionMatrix * u_modelMatrix * tPos; +} +""" +DEFAULT_CLIP_PLANE_NEAR = 0.001 +DEFAULT_CLIP_PLANE_FAR = 1000.0 + + +def get_world_transform(scene, node): + if node == scene.rootnode: + return numpy.identity(4, dtype=numpy.float32) + + parents = reversed(_get_parent_chain(scene, node, [])) + parent_transform = reduce(numpy.dot, [p.transformation for p in parents]) + return numpy.dot(parent_transform, node.transformation) + + +def _get_parent_chain(scene, node, parents): + parent = node.parent + + parents.append(parent) + + if parent == scene.rootnode: + return parents + + return _get_parent_chain(scene, parent, parents) + + +class DefaultCamera: + def __init__(self, w, h, fov): + self.name = "default camera" + self.type = CAMERA + self.clipplanenear = DEFAULT_CLIP_PLANE_NEAR + self.clipplanefar = DEFAULT_CLIP_PLANE_FAR + self.aspect = w / h + self.horizontalfov = fov * math.pi / 180 + self.transformation = numpy.array([[0.68, -0.32, 0.65, 7.48], + [0.73, 0.31, -0.61, -6.51], + [-0.01, 0.89, 0.44, 5.34], + [0., 0., 0., 1.]], dtype=numpy.float32) + + self.transformation = numpy.dot(self.transformation, ROTATION_180_X) + + def __str__(self): + return self.name + + +class PyAssimp3DViewer: + base_name = "PyASSIMP 3D viewer" + + def __init__(self, model, w=1024, h=768): + + self.w = w + self.h = h + + pygame.init() + pygame.display.set_caption(self.base_name) + pygame.display.set_mode((w, h), pygame.OPENGL | pygame.DOUBLEBUF) + + glClearColor(0.18, 0.18, 0.18, 1.0) + + shader_compilation_succeeded = False + try: + self.set_shaders_v130() + self.prepare_shaders() + except RuntimeError, message: + sys.stderr.write("%s\n" % message) + sys.stdout.write("Could not compile shaders in version 1.30, trying version 1.20\n") + + if not shader_compilation_succeeded: + self.set_shaders_v120() + self.prepare_shaders() + + self.scene = None + self.meshes = {} # stores the OpenGL vertex/faces/normals buffers pointers + + self.node2colorid = {} # stores a color ID for each node. Useful for mouse picking and visibility checking + self.colorid2node = {} # reverse dict of node2colorid + + self.currently_selected = None + self.moving = False + self.moving_situation = None + + self.default_camera = DefaultCamera(self.w, self.h, fov=70) + self.cameras = [self.default_camera] + + self.current_cam_index = 0 + self.current_cam = self.default_camera + self.set_camera_projection() + + self.load_model(model) + + # user interactions + self.focal_point = [0, 0, 0] + self.is_rotating = False + self.is_panning = False + self.is_zooming = False + + def set_shaders_v120(self): + self.BASIC_VERTEX_SHADER = BASIC_VERTEX_SHADER_120 + self.FLAT_VERTEX_SHADER = FLAT_VERTEX_SHADER_120 + self.SILHOUETTE_VERTEX_SHADER = SILHOUETTE_VERTEX_SHADER_120 + self.GOOCH_VERTEX_SHADER = GOOCH_VERTEX_SHADER_120 + + self.BASIC_FRAGMENT_SHADER = BASIC_FRAGMENT_SHADER_120 + self.GOOCH_FRAGMENT_SHADER = GOOCH_FRAGMENT_SHADER_120 + + def set_shaders_v130(self): + self.BASIC_VERTEX_SHADER = BASIC_VERTEX_SHADER_130 + self.FLAT_VERTEX_SHADER = FLAT_VERTEX_SHADER_130 + self.SILHOUETTE_VERTEX_SHADER = SILHOUETTE_VERTEX_SHADER_130 + self.GOOCH_VERTEX_SHADER = GOOCH_VERTEX_SHADER_130 + + self.BASIC_FRAGMENT_SHADER = BASIC_FRAGMENT_SHADER_130 + self.GOOCH_FRAGMENT_SHADER = GOOCH_FRAGMENT_SHADER_130 + + def prepare_shaders(self): + + ### Base shader + vertex = shaders.compileShader(self.BASIC_VERTEX_SHADER, GL_VERTEX_SHADER) + fragment = shaders.compileShader(self.BASIC_FRAGMENT_SHADER, GL_FRAGMENT_SHADER) + + self.shader = shaders.compileProgram(vertex, fragment) + + self.set_shader_accessors(('u_modelMatrix', + 'u_viewProjectionMatrix', + 'u_normalMatrix', + 'u_lightPos', + 'u_materialDiffuse'), + ('a_vertex', + 'a_normal'), self.shader) + + ### Flat shader + flatvertex = shaders.compileShader(self.FLAT_VERTEX_SHADER, GL_VERTEX_SHADER) + self.flatshader = shaders.compileProgram(flatvertex, fragment) + + self.set_shader_accessors(('u_modelMatrix', + 'u_viewProjectionMatrix', + 'u_materialDiffuse',), + ('a_vertex',), self.flatshader) + + ### Silhouette shader + silh_vertex = shaders.compileShader(self.SILHOUETTE_VERTEX_SHADER, GL_VERTEX_SHADER) + self.silhouette_shader = shaders.compileProgram(silh_vertex, fragment) + + self.set_shader_accessors(('u_modelMatrix', + 'u_viewProjectionMatrix', + 'u_modelViewMatrix', + 'u_materialDiffuse', + 'u_bordersize' # width of the silhouette + ), + ('a_vertex', + 'a_normal'), self.silhouette_shader) + + ### Gooch shader + gooch_vertex = shaders.compileShader(self.GOOCH_VERTEX_SHADER, GL_VERTEX_SHADER) + gooch_fragment = shaders.compileShader(self.GOOCH_FRAGMENT_SHADER, GL_FRAGMENT_SHADER) + self.gooch_shader = shaders.compileProgram(gooch_vertex, gooch_fragment) + + self.set_shader_accessors(('u_modelMatrix', + 'u_viewProjectionMatrix', + 'u_normalMatrix', + 'u_lightPos', + 'u_materialDiffuse', + 'u_coolColor', + 'u_warmColor', + 'u_alpha', + 'u_beta' + ), + ('a_vertex', + 'a_normal'), self.gooch_shader) + + @staticmethod + def set_shader_accessors(uniforms, attributes, shader): + # add accessors to the shaders uniforms and attributes + for uniform in uniforms: + location = glGetUniformLocation(shader, uniform) + if location in (None, -1): + raise RuntimeError('No uniform: %s (maybe it is not used ' + 'anymore and has been optimized out by' + ' the shader compiler)' % uniform) + setattr(shader, uniform, location) + + for attribute in attributes: + location = glGetAttribLocation(shader, attribute) + if location in (None, -1): + raise RuntimeError('No attribute: %s' % attribute) + setattr(shader, attribute, location) + + @staticmethod + def prepare_gl_buffers(mesh): + + mesh.gl = {} + + # Fill the buffer for vertex and normals positions + v = numpy.array(mesh.vertices, 'f') + n = numpy.array(mesh.normals, 'f') + + mesh.gl["vbo"] = vbo.VBO(numpy.hstack((v, n))) + + # Fill the buffer for vertex positions + mesh.gl["faces"] = glGenBuffers(1) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["faces"]) + glBufferData(GL_ELEMENT_ARRAY_BUFFER, + numpy.array(mesh.faces, dtype=numpy.int32), + GL_STATIC_DRAW) + + mesh.gl["nbfaces"] = len(mesh.faces) + + # Unbind buffers + glBindBuffer(GL_ARRAY_BUFFER, 0) + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) + + @staticmethod + def get_rgb_from_colorid(colorid): + r = (colorid >> 0) & 0xff + g = (colorid >> 8) & 0xff + b = (colorid >> 16) & 0xff + + return r, g, b + + def get_color_id(self): + id = random.randint(0, 256 * 256 * 256) + if id not in self.colorid2node: + return id + else: + return self.get_color_id() + + def glize(self, scene, node): + + logger.info("Loading node <%s>" % node) + node.selected = True if self.currently_selected and self.currently_selected == node else False + + node.transformation = node.transformation.astype(numpy.float32) + + if node.meshes: + node.type = MESH + colorid = self.get_color_id() + self.colorid2node[colorid] = node + self.node2colorid[node.name] = colorid + + elif node.name in [c.name for c in scene.cameras]: + + # retrieve the ASSIMP camera object + [cam] = [c for c in scene.cameras if c.name == node.name] + node.type = CAMERA + logger.info("Added camera <%s>" % node.name) + logger.info("Camera position: %.3f, %.3f, %.3f" % tuple(node.transformation[:, 3][:3].tolist())) + self.cameras.append(node) + node.clipplanenear = cam.clipplanenear + node.clipplanefar = cam.clipplanefar + + if numpy.allclose(cam.lookat, [0, 0, -1]) and numpy.allclose(cam.up, [0, 1, 0]): # Cameras in .blend files + + # Rotate by 180deg around X to have Z pointing forward + node.transformation = numpy.dot(node.transformation, ROTATION_180_X) + else: + raise RuntimeError( + "I do not know how to normalize this camera orientation: lookat=%s, up=%s" % (cam.lookat, cam.up)) + + if cam.aspect == 0.0: + logger.warning("Camera aspect not set. Setting to default 4:3") + node.aspect = 1.333 + else: + node.aspect = cam.aspect + + node.horizontalfov = cam.horizontalfov + + else: + node.type = ENTITY + + for child in node.children: + self.glize(scene, child) + + def load_model(self, path, postprocess=aiProcessPreset_TargetRealtime_MaxQuality): + logger.info("Loading model:" + path + "...") + + if postprocess: + self.scene = pyassimp.load(path, processing=postprocess) + else: + self.scene = pyassimp.load(path) + logger.info("Done.") + + scene = self.scene + # log some statistics + logger.info(" meshes: %d" % len(scene.meshes)) + logger.info(" total faces: %d" % sum([len(mesh.faces) for mesh in scene.meshes])) + logger.info(" materials: %d" % len(scene.materials)) + self.bb_min, self.bb_max = get_bounding_box(self.scene) + logger.info(" bounding box:" + str(self.bb_min) + " - " + str(self.bb_max)) + + self.scene_center = [(a + b) / 2. for a, b in zip(self.bb_min, self.bb_max)] + + for index, mesh in enumerate(scene.meshes): + self.prepare_gl_buffers(mesh) + + self.glize(scene, scene.rootnode) + + # Finally release the model + pyassimp.release(scene) + logger.info("Ready for 3D rendering!") + + def cycle_cameras(self): + + self.current_cam_index = (self.current_cam_index + 1) % len(self.cameras) + self.current_cam = self.cameras[self.current_cam_index] + self.set_camera_projection(self.current_cam) + logger.info("Switched to camera <%s>" % self.current_cam) + + def set_overlay_projection(self): + glViewport(0, 0, self.w, self.h) + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + glOrtho(0.0, self.w - 1.0, 0.0, self.h - 1.0, -1.0, 1.0) + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + + def set_camera_projection(self, camera=None): + + if not camera: + camera = self.current_cam + + znear = camera.clipplanenear or DEFAULT_CLIP_PLANE_NEAR + zfar = camera.clipplanefar or DEFAULT_CLIP_PLANE_FAR + aspect = camera.aspect + fov = camera.horizontalfov + + glMatrixMode(GL_PROJECTION) + glLoadIdentity() + + # Compute gl frustrum + tangent = math.tan(fov / 2.) + h = znear * tangent + w = h * aspect + + # params: left, right, bottom, top, near, far + glFrustum(-w, w, -h, h, znear, zfar) + # equivalent to: + # gluPerspective(fov * 180/math.pi, aspect, znear, zfar) + + self.projection_matrix = glGetFloatv(GL_PROJECTION_MATRIX).transpose() + + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + + def render_colors(self): + + glEnable(GL_DEPTH_TEST) + glDepthFunc(GL_LEQUAL) + + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) + glEnable(GL_CULL_FACE) + + glUseProgram(self.flatshader) + + glUniformMatrix4fv(self.flatshader.u_viewProjectionMatrix, 1, GL_TRUE, + numpy.dot(self.projection_matrix, self.view_matrix)) + + self.recursive_render(self.scene.rootnode, self.flatshader, mode=COLORS) + + glUseProgram(0) + + def get_hovered_node(self, mousex, mousey): + """ + Attention: The performances of this method relies heavily on the size of the display! + """ + + # mouse out of the window? + if mousex < 0 or mousex >= self.w or mousey < 0 or mousey >= self.h: + return None + + self.render_colors() + # Capture image from the OpenGL buffer + buf = (GLubyte * (3 * self.w * self.h))(0) + glReadPixels(0, 0, self.w, self.h, GL_RGB, GL_UNSIGNED_BYTE, buf) + + # Reinterpret the RGB pixel buffer as a 1-D array of 24bits colors + a = numpy.ndarray(len(buf), numpy.dtype('>u1'), buf) + colors = numpy.zeros(len(buf) // 3, numpy.dtype('u1')[i::3] + + colorid = colors[mousex + mousey * self.w] + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + if colorid in self.colorid2node: + return self.colorid2node[colorid] + + def render(self, wireframe=False, twosided=False): + + glEnable(GL_DEPTH_TEST) + glDepthFunc(GL_LEQUAL) + + glPolygonMode(GL_FRONT_AND_BACK, GL_LINE if wireframe else GL_FILL) + glDisable(GL_CULL_FACE) if twosided else glEnable(GL_CULL_FACE) + + self.render_grid() + + self.recursive_render(self.scene.rootnode, None, mode=HELPERS) + + ### First, the silhouette + + if False: + shader = self.silhouette_shader + + # glDepthMask(GL_FALSE) + glCullFace(GL_FRONT) # cull front faces + + glUseProgram(shader) + glUniform1f(shader.u_bordersize, 0.01) + + glUniformMatrix4fv(shader.u_viewProjectionMatrix, 1, GL_TRUE, + numpy.dot(self.projection_matrix, self.view_matrix)) + + self.recursive_render(self.scene.rootnode, shader, mode=SILHOUETTE) + + glUseProgram(0) + + ### Then, inner shading + # glDepthMask(GL_TRUE) + glCullFace(GL_BACK) + + use_gooch = False + if use_gooch: + shader = self.gooch_shader + + glUseProgram(shader) + glUniform3f(shader.u_lightPos, -.5, -.5, .5) + + ##### GOOCH specific + glUniform3f(shader.u_coolColor, 159.0 / 255, 148.0 / 255, 255.0 / 255) + glUniform3f(shader.u_warmColor, 255.0 / 255, 75.0 / 255, 75.0 / 255) + glUniform1f(shader.u_alpha, .25) + glUniform1f(shader.u_beta, .25) + ######### + else: + shader = self.shader + glUseProgram(shader) + glUniform3f(shader.u_lightPos, -.5, -.5, .5) + + glUniformMatrix4fv(shader.u_viewProjectionMatrix, 1, GL_TRUE, + numpy.dot(self.projection_matrix, self.view_matrix)) + + self.recursive_render(self.scene.rootnode, shader) + + glUseProgram(0) + + def render_axis(self, + transformation=numpy.identity(4, dtype=numpy.float32), + label=None, + size=0.2, + selected=False): + m = transformation.transpose() # OpenGL row major + + glPushMatrix() + glMultMatrixf(m) + + glLineWidth(3 if selected else 1) + + size = 2 * size if selected else size + + glBegin(GL_LINES) + + # draw line for x axis + glColor3f(1.0, 0.0, 0.0) + glVertex3f(0.0, 0.0, 0.0) + glVertex3f(size, 0.0, 0.0) + + # draw line for y axis + glColor3f(0.0, 1.0, 0.0) + glVertex3f(0.0, 0.0, 0.0) + glVertex3f(0.0, size, 0.0) + + # draw line for Z axis + glColor3f(0.0, 0.0, 1.0) + glVertex3f(0.0, 0.0, 0.0) + glVertex3f(0.0, 0.0, size) + + glEnd() + + if label: + self.showtext(label) + + glPopMatrix() + + @staticmethod + def render_camera(camera, transformation): + + m = transformation.transpose() # OpenGL row major + + aspect = camera.aspect + + u = 0.1 # unit size (in m) + l = 3 * u # lenght of the camera cone + f = 3 * u # aperture of the camera cone + + glPushMatrix() + glMultMatrixf(m) + + glLineWidth(2) + glBegin(GL_LINE_STRIP) + + glColor3f(.2, .2, .2) + + glVertex3f(u, u, -u) + glVertex3f(u, -u, -u) + glVertex3f(-u, -u, -u) + glVertex3f(-u, u, -u) + glVertex3f(u, u, -u) + + glVertex3f(u, u, 0.0) + glVertex3f(u, -u, 0.0) + glVertex3f(-u, -u, 0.0) + glVertex3f(-u, u, 0.0) + glVertex3f(u, u, 0.0) + + glVertex3f(f * aspect, f, l) + glVertex3f(f * aspect, -f, l) + glVertex3f(-f * aspect, -f, l) + glVertex3f(-f * aspect, f, l) + glVertex3f(f * aspect, f, l) + + glEnd() + + glBegin(GL_LINE_STRIP) + glVertex3f(u, -u, -u) + glVertex3f(u, -u, 0.0) + glVertex3f(f * aspect, -f, l) + glEnd() + + glBegin(GL_LINE_STRIP) + glVertex3f(-u, -u, -u) + glVertex3f(-u, -u, 0.0) + glVertex3f(-f * aspect, -f, l) + glEnd() + + glBegin(GL_LINE_STRIP) + glVertex3f(-u, u, -u) + glVertex3f(-u, u, 0.0) + glVertex3f(-f * aspect, f, l) + glEnd() + + glPopMatrix() + + @staticmethod + def render_grid(): + + glLineWidth(1) + glColor3f(0.5, 0.5, 0.5) + glBegin(GL_LINES) + for i in range(-10, 11): + glVertex3f(i, -10.0, 0.0) + glVertex3f(i, 10.0, 0.0) + + for i in range(-10, 11): + glVertex3f(-10.0, i, 0.0) + glVertex3f(10.0, i, 0.0) + glEnd() + + def recursive_render(self, node, shader, mode=BASE, with_normals=True): + """ Main recursive rendering method. + """ + + normals = with_normals + + if mode == COLORS: + normals = False + + + if not hasattr(node, "selected"): + node.selected = False + + m = get_world_transform(self.scene, node) + + # HELPERS mode + ### + if mode == HELPERS: + # if node.type == ENTITY: + self.render_axis(m, + label=node.name if node != self.scene.rootnode else None, + selected=node.selected if hasattr(node, "selected") else False) + + if node.type == CAMERA: + self.render_camera(node, m) + + for child in node.children: + self.recursive_render(child, shader, mode) + + return + + # Mesh rendering modes + ### + if node.type == MESH: + + for mesh in node.meshes: + + stride = 24 # 6 * 4 bytes + + if node.selected and mode == SILHOUETTE: + glUniform4f(shader.u_materialDiffuse, 1.0, 0.0, 0.0, 1.0) + glUniformMatrix4fv(shader.u_modelViewMatrix, 1, GL_TRUE, + numpy.dot(self.view_matrix, m)) + + else: + if mode == COLORS: + colorid = self.node2colorid[node.name] + r, g, b = self.get_rgb_from_colorid(colorid) + glUniform4f(shader.u_materialDiffuse, r / 255.0, g / 255.0, b / 255.0, 1.0) + elif mode == SILHOUETTE: + glUniform4f(shader.u_materialDiffuse, .0, .0, .0, 1.0) + else: + if node.selected: + diffuse = (1.0, 0.0, 0.0, 1.0) # selected nodes in red + else: + diffuse = mesh.material.properties["diffuse"] + if len(diffuse) == 3: # RGB instead of expected RGBA + diffuse.append(1.0) + glUniform4f(shader.u_materialDiffuse, *diffuse) + # if ambient: + # glUniform4f( shader.Material_ambient, *mat["ambient"] ) + + if mode == BASE: # not in COLORS or SILHOUETTE + normal_matrix = linalg.inv(numpy.dot(self.view_matrix, m)[0:3, 0:3]).transpose() + glUniformMatrix3fv(shader.u_normalMatrix, 1, GL_TRUE, normal_matrix) + + glUniformMatrix4fv(shader.u_modelMatrix, 1, GL_TRUE, m) + + vbo = mesh.gl["vbo"] + vbo.bind() + + glEnableVertexAttribArray(shader.a_vertex) + if normals: + glEnableVertexAttribArray(shader.a_normal) + + glVertexAttribPointer( + shader.a_vertex, + 3, GL_FLOAT, False, stride, vbo + ) + + if normals: + glVertexAttribPointer( + shader.a_normal, + 3, GL_FLOAT, False, stride, vbo + 12 + ) + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["faces"]) + glDrawElements(GL_TRIANGLES, mesh.gl["nbfaces"] * 3, GL_UNSIGNED_INT, None) + + vbo.unbind() + glDisableVertexAttribArray(shader.a_vertex) + + if normals: + glDisableVertexAttribArray(shader.a_normal) + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) + + for child in node.children: + self.recursive_render(child, shader, mode) + + + def switch_to_overlay(self): + glPushMatrix() + self.set_overlay_projection() + + def switch_from_overlay(self): + self.set_camera_projection() + glPopMatrix() + + def select_node(self, node): + self.currently_selected = node + self.update_node_select(self.scene.rootnode) + + def update_node_select(self, node): + if node is self.currently_selected: + node.selected = True + else: + node.selected = False + + for child in node.children: + self.update_node_select(child) + + def loop(self): + + pygame.display.flip() + + if not self.process_events(): + return False # ESC has been pressed + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + return True + + def process_events(self): + + LEFT_BUTTON = 1 + MIDDLE_BUTTON = 2 + RIGHT_BUTTON = 3 + WHEEL_UP = 4 + WHEEL_DOWN = 5 + + dx, dy = pygame.mouse.get_rel() + mousex, mousey = pygame.mouse.get_pos() + + zooming_one_shot = False + + ok = True + + for evt in pygame.event.get(): + if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == LEFT_BUTTON: + hovered = self.get_hovered_node(mousex, self.h - mousey) + if hovered: + if self.currently_selected and self.currently_selected == hovered: + self.select_node(None) + else: + logger.info("Node %s selected" % hovered) + self.select_node(hovered) + else: + self.is_rotating = True + if evt.type == pygame.MOUSEBUTTONUP and evt.button == LEFT_BUTTON: + self.is_rotating = False + + if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == MIDDLE_BUTTON: + self.is_panning = True + if evt.type == pygame.MOUSEBUTTONUP and evt.button == MIDDLE_BUTTON: + self.is_panning = False + + if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == RIGHT_BUTTON: + self.is_zooming = True + if evt.type == pygame.MOUSEBUTTONUP and evt.button == RIGHT_BUTTON: + self.is_zooming = False + + if evt.type == pygame.MOUSEBUTTONDOWN and evt.button in [WHEEL_UP, WHEEL_DOWN]: + zooming_one_shot = True + self.is_zooming = True + dy = -10 if evt.button == WHEEL_UP else 10 + + if evt.type == pygame.KEYDOWN: + ok = (ok and self.process_keystroke(evt.key, evt.mod)) + + self.controls_3d(dx, dy, zooming_one_shot) + + return ok + + def process_keystroke(self, key, mod): + + # process arrow keys if an object is selected + if self.currently_selected: + up = 0 + strafe = 0 + + if key == pygame.K_UP: + up = 1 + if key == pygame.K_DOWN: + up = -1 + if key == pygame.K_LEFT: + strafe = -1 + if key == pygame.K_RIGHT: + strafe = 1 + + self.move_selected_node(up, strafe) + + if key == pygame.K_f: + pygame.display.toggle_fullscreen() + + if key == pygame.K_TAB: + self.cycle_cameras() + + if key in [pygame.K_ESCAPE, pygame.K_q]: + return False + + return True + + def controls_3d(self, dx, dy, zooming_one_shot=False): + + CAMERA_TRANSLATION_FACTOR = 0.01 + CAMERA_ROTATION_FACTOR = 0.01 + + if not (self.is_rotating or self.is_panning or self.is_zooming): + return + + current_pos = self.current_cam.transformation[:3, 3].copy() + 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) + cam_x_rotation = transformations.euler_matrix(rotation_camera_x, 0, 0) + + after_world_z_rotation = numpy.dot(world_z_rotation, self.current_cam.transformation) + + inverse_transformation = transformations.inverse_matrix(after_world_z_rotation) + + translation = transformations.translation_matrix( + transformations.decompose_matrix(inverse_transformation)[3]) + inverse_translation = transformations.inverse_matrix(translation) + + new_inverse = numpy.dot(inverse_translation, inverse_transformation) + new_inverse = numpy.dot(cam_x_rotation, new_inverse) + new_inverse = numpy.dot(translation, new_inverse) + + self.current_cam.transformation = transformations.inverse_matrix(new_inverse).astype(numpy.float32) + + if self.is_panning: + tx = -dx * CAMERA_TRANSLATION_FACTOR * distance + ty = dy * CAMERA_TRANSLATION_FACTOR * distance + cam_transform = transformations.translation_matrix((tx, ty, 0)).astype(numpy.float32) + self.current_cam.transformation = numpy.dot(self.current_cam.transformation, cam_transform) + + if self.is_zooming: + tz = dy * CAMERA_TRANSLATION_FACTOR * distance + cam_transform = transformations.translation_matrix((0, 0, tz)).astype(numpy.float32) + self.current_cam.transformation = numpy.dot(self.current_cam.transformation, cam_transform) + + if zooming_one_shot: + self.is_zooming = False + + self.update_view_camera() + + def update_view_camera(self): + + self.view_matrix = linalg.inv(self.current_cam.transformation) + + # Rotate by 180deg around X to have Z pointing backward (OpenGL convention) + self.view_matrix = numpy.dot(ROTATION_180_X, self.view_matrix) + + glMatrixMode(GL_MODELVIEW) + glLoadIdentity() + glMultMatrixf(self.view_matrix.transpose()) + + def move_selected_node(self, up, strafe): + self.currently_selected.transformation[0][3] += strafe + self.currently_selected.transformation[2][3] += up + + @staticmethod + def showtext(text, x=0, y=0, z=0, size=20): + + # TODO: alpha blending does not work... + # glEnable(GL_BLEND) + # glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) + + font = pygame.font.Font(None, size) + text_surface = font.render(text, True, (10, 10, 10, 255), + (255 * 0.18, 255 * 0.18, 255 * 0.18, 0)) + text_data = pygame.image.tostring(text_surface, "RGBA", True) + glRasterPos3d(x, y, z) + glDrawPixels(text_surface.get_width(), + text_surface.get_height(), + GL_RGBA, GL_UNSIGNED_BYTE, + text_data) + + # glDisable(GL_BLEND) + + +def main(model, width, height): + app = PyAssimp3DViewer(model, w=width, h=height) + + clock = pygame.time.Clock() + + while app.loop(): + + app.update_view_camera() + + ## Main rendering + app.render() + + ## GUI text display + app.switch_to_overlay() + app.showtext("Active camera: %s" % str(app.current_cam), 10, app.h - 30) + if app.currently_selected: + app.showtext("Selected node: %s" % app.currently_selected, 10, app.h - 50) + pos = app.h - 70 + + app.showtext("(%sm, %sm, %sm)" % (app.currently_selected.transformation[0, 3], + app.currently_selected.transformation[1, 3], + app.currently_selected.transformation[2, 3]), 30, pos) + + app.switch_from_overlay() + + # Make sure we do not go over 30fps + clock.tick(30) + + logger.info("Quitting! Bye bye!") + + +######################################################################### +######################################################################### + +if __name__ == '__main__': + if not len(sys.argv) > 1: + print("Usage: " + __file__ + " ") + sys.exit(2) + + main(model=sys.argv[1], width=1024, height=768) diff --git a/port/PyAssimp/scripts/fixed_pipeline_3d_viewer.py b/port/PyAssimp/scripts/fixed_pipeline_3d_viewer.py index 48c157917..7f98b9004 100755 --- a/port/PyAssimp/scripts/fixed_pipeline_3d_viewer.py +++ b/port/PyAssimp/scripts/fixed_pipeline_3d_viewer.py @@ -98,7 +98,7 @@ class GLRenderer(): logger.info("Loading model:" + path + "...") if postprocess: - self.scene = pyassimp.load(path, postprocess) + self.scene = pyassimp.load(path, processing=postprocess) else: self.scene = pyassimp.load(path) logger.info("Done.") diff --git a/port/PyAssimp/scripts/sample.py b/port/PyAssimp/scripts/sample.py index 5153a9bab..9012eb374 100755 --- a/port/PyAssimp/scripts/sample.py +++ b/port/PyAssimp/scripts/sample.py @@ -20,7 +20,7 @@ def recur_node(node,level = 0): def main(filename=None): - scene = pyassimp.load(filename, pyassimp.postprocess.aiProcess_Triangulate) + scene = pyassimp.load(filename, processing=pyassimp.postprocess.aiProcess_Triangulate) #the model we load print("MODEL:" + filename) diff --git a/port/PyAssimp/setup.py b/port/PyAssimp/setup.py index 8f3cdcae2..26cf9b400 100644 --- a/port/PyAssimp/setup.py +++ b/port/PyAssimp/setup.py @@ -8,8 +8,9 @@ setup(name='pyassimp', description='Python bindings for the Open Asset Import Library (ASSIMP)', url='https://github.com/assimp/assimp', packages=['pyassimp'], - data_files=[('share/pyassimp', ['README.md']), - ('share/examples/pyassimp', ['scripts/' + f for f in os.listdir('scripts/')]), - ('lib/', [f for f in os.listdir('../../lib') if os.path.isfile(f)])], + data_files=[ + ('share/pyassimp', ['README.md']), + ('share/examples/pyassimp', ['scripts/' + f for f in os.listdir('scripts/')]) + ], requires=['numpy'] ) diff --git a/port/iOS/IPHONEOS_ARM64_TOOLCHAIN.cmake b/port/iOS/IPHONEOS_ARM64_TOOLCHAIN.cmake index bd7199cc5..3aea8342e 100644 --- a/port/iOS/IPHONEOS_ARM64_TOOLCHAIN.cmake +++ b/port/iOS/IPHONEOS_ARM64_TOOLCHAIN.cmake @@ -7,8 +7,8 @@ SET (CMAKE_SYSTEM_PROCESSOR "arm64") SET (SDKVER "7.1") SET (DEVROOT "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain") SET (SDKROOT "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS${SDKVER}.sdk") -SET (CC "${DEVROOT}/usr/bin/llvm-gcc") -SET (CXX "${DEVROOT}/usr/bin/llvm-g++") +SET (CC "${DEVROOT}/usr/bin/clang") +SET (CXX "${DEVROOT}/usr/bin/clang++") CMAKE_FORCE_C_COMPILER (${CC} LLVM) CMAKE_FORCE_CXX_COMPILER (${CXX} LLVM) diff --git a/port/jassimp/jassimp-native/src/jassimp.h b/port/jassimp/jassimp-native/src/jassimp.h index 188a4e904..f448dc2c2 100644 --- a/port/jassimp/jassimp-native/src/jassimp.h +++ b/port/jassimp/jassimp-native/src/jassimp.h @@ -1,5 +1,6 @@ /* DO NOT EDIT THIS FILE - it is machine generated */ #include +#include /* Header for class jassimp_Jassimp */ #ifndef _Included_jassimp_Jassimp diff --git a/port/jassimp/jassimp/src/jassimp/AiMesh.java b/port/jassimp/jassimp/src/jassimp/AiMesh.java index c2ebcd307..b6a478d18 100644 --- a/port/jassimp/jassimp/src/jassimp/AiMesh.java +++ b/port/jassimp/jassimp/src/jassimp/AiMesh.java @@ -140,17 +140,17 @@ public final class AiMesh { /** * Number of bytes per float value. */ - private static final int SIZEOF_FLOAT = Jassimp.NATIVE_FLOAT_SIZE; + private final int SIZEOF_FLOAT = Jassimp.NATIVE_FLOAT_SIZE; /** * Number of bytes per int value. */ - private static final int SIZEOF_INT = Jassimp.NATIVE_INT_SIZE; + private final int SIZEOF_INT = Jassimp.NATIVE_INT_SIZE; /** * Size of an AiVector3D in the native world. */ - private static final int SIZEOF_V3D = Jassimp.NATIVE_AIVEKTOR3D_SIZE; + private final int SIZEOF_V3D = Jassimp.NATIVE_AIVEKTOR3D_SIZE; /** diff --git a/port/jassimp/jassimp/src/jassimp/AiNodeAnim.java b/port/jassimp/jassimp/src/jassimp/AiNodeAnim.java index cb1c6987c..fb317a5b1 100644 --- a/port/jassimp/jassimp/src/jassimp/AiNodeAnim.java +++ b/port/jassimp/jassimp/src/jassimp/AiNodeAnim.java @@ -70,17 +70,17 @@ public final class AiNodeAnim { /** * Size of one position key entry. */ - private static final int POS_KEY_SIZE = Jassimp.NATIVE_AIVEKTORKEY_SIZE; + private final int POS_KEY_SIZE = Jassimp.NATIVE_AIVEKTORKEY_SIZE; /** * Size of one rotation key entry. */ - private static final int ROT_KEY_SIZE = Jassimp.NATIVE_AIQUATKEY_SIZE; + private final int ROT_KEY_SIZE = Jassimp.NATIVE_AIQUATKEY_SIZE; /** * Size of one scaling key entry. */ - private static final int SCALE_KEY_SIZE = Jassimp.NATIVE_AIVEKTORKEY_SIZE; + private final int SCALE_KEY_SIZE = Jassimp.NATIVE_AIVEKTORKEY_SIZE; /** diff --git a/port/jassimp/jassimp/src/jassimp/Jassimp.java b/port/jassimp/jassimp/src/jassimp/Jassimp.java index eb4665f17..92f4864c7 100644 --- a/port/jassimp/jassimp/src/jassimp/Jassimp.java +++ b/port/jassimp/jassimp/src/jassimp/Jassimp.java @@ -59,7 +59,7 @@ import java.util.Set; * Pointer comparison will fail. */ public final class Jassimp { - + /** * The default wrapper provider using built in types. */ @@ -91,6 +91,8 @@ public final class Jassimp { public static AiScene importFile(String filename, Set postProcessing) throws IOException { + loadLibrary(); + return aiImportFile(filename, AiPostProcessSteps.toRawValue( postProcessing)); } @@ -177,6 +179,11 @@ public final class Jassimp { } + public static void setLibraryLoader(JassimpLibraryLoader libraryLoader) { + s_libraryLoader = libraryLoader; + } + + /** * Helper method for wrapping a matrix.

* @@ -264,6 +271,35 @@ public final class Jassimp { return s_wrapperProvider.wrapSceneNode(parent, matrix, meshRefs, name); } + /** + * Helper method to load the library using the provided JassimpLibraryLoader.

+ * + * Synchronized to avoid race conditions. + */ + private static void loadLibrary() + { + if(!s_libraryLoaded) + { + synchronized(s_libraryLoadingLock) + { + if(!s_libraryLoaded) + { + s_libraryLoader.loadLibrary(); + NATIVE_AIVEKTORKEY_SIZE = getVKeysize(); + NATIVE_AIQUATKEY_SIZE = getQKeysize(); + NATIVE_AIVEKTOR3D_SIZE = getV3Dsize(); + NATIVE_FLOAT_SIZE = getfloatsize(); + NATIVE_INT_SIZE = getintsize(); + NATIVE_UINT_SIZE = getuintsize(); + NATIVE_DOUBLE_SIZE = getdoublesize(); + NATIVE_LONG_SIZE = getlongsize(); + + s_libraryLoaded = true; + } + } + + } + } /** * The native interface. @@ -284,6 +320,25 @@ public final class Jassimp { 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. */ @@ -291,24 +346,13 @@ public final class Jassimp { /* nothing to do */ } - public static final int NATIVE_AIVEKTORKEY_SIZE; - public static final int NATIVE_AIQUATKEY_SIZE; - public static final int NATIVE_AIVEKTOR3D_SIZE; - public static final int NATIVE_FLOAT_SIZE; - public static final int NATIVE_INT_SIZE; - public static final int NATIVE_UINT_SIZE; - public static final int NATIVE_DOUBLE_SIZE; - public static final int NATIVE_LONG_SIZE; + public static int NATIVE_AIVEKTORKEY_SIZE; + public static int NATIVE_AIQUATKEY_SIZE; + public static int NATIVE_AIVEKTOR3D_SIZE; + public static int NATIVE_FLOAT_SIZE; + public static int NATIVE_INT_SIZE; + public static int NATIVE_UINT_SIZE; + public static int NATIVE_DOUBLE_SIZE; + public static int NATIVE_LONG_SIZE; - static { - System.loadLibrary("jassimp"); - NATIVE_AIVEKTORKEY_SIZE = getVKeysize(); - NATIVE_AIQUATKEY_SIZE = getQKeysize(); - NATIVE_AIVEKTOR3D_SIZE = getV3Dsize(); - NATIVE_FLOAT_SIZE = getfloatsize(); - NATIVE_INT_SIZE = getintsize(); - NATIVE_UINT_SIZE = getuintsize(); - NATIVE_DOUBLE_SIZE = getdoublesize(); - NATIVE_LONG_SIZE = getlongsize(); - } } diff --git a/port/jassimp/jassimp/src/jassimp/JassimpLibraryLoader.java b/port/jassimp/jassimp/src/jassimp/JassimpLibraryLoader.java new file mode 100644 index 000000000..c299706b7 --- /dev/null +++ b/port/jassimp/jassimp/src/jassimp/JassimpLibraryLoader.java @@ -0,0 +1,65 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library - Java Binding (jassimp) +--------------------------------------------------------------------------- + +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 +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. +--------------------------------------------------------------------------- +*/ +package jassimp; + +/** + * Library loader for the jassimp library.

+ * + * The default implementation uses "System.loadLibrary" to + * load the jassimp native library.

+ * + * Custom implementations should override the loadLibrary() + * function. + * + */ +public class JassimpLibraryLoader +{ + /** + * Function to load the native jassimp library. + * + * Called the first time Jassimp.importFile() is + * called. + */ + public void loadLibrary() + { + System.loadLibrary("jassimp"); + } +} diff --git a/samples/SimpleOpenGL/CMakeLists.txt b/samples/SimpleOpenGL/CMakeLists.txt index 52c994b63..455cbd8ca 100644 --- a/samples/SimpleOpenGL/CMakeLists.txt +++ b/samples/SimpleOpenGL/CMakeLists.txt @@ -16,6 +16,11 @@ IF ( NOT GLUT_FOUND ) ENDIF ( MSVC ) ENDIF ( NOT GLUT_FOUND ) +if ( MSVC ) + ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS ) + ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) +endif ( MSVC ) + INCLUDE_DIRECTORIES( ${Assimp_SOURCE_DIR}/include ${Assimp_SOURCE_DIR}/code diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln new file mode 100644 index 000000000..46b37e5ee --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26228.9 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimpleTexturedDirectx11", "SimpleTexturedDirectx11\SimpleTexturedDirectx11.vcxproj", "{E3B160B5-E71F-4F3F-9310-B8F156F736D8}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x64.ActiveCfg = Debug|x64 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x64.Build.0 = Debug|x64 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x86.ActiveCfg = Debug|Win32 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x86.Build.0 = Debug|Win32 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x64.ActiveCfg = Release|x64 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x64.Build.0 = Release|x64 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x86.ActiveCfg = Release|Win32 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h new file mode 100644 index 000000000..87433219f --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h @@ -0,0 +1,102 @@ +#ifndef MESH_H +#define MESH_H + +#include +#include +#include +#include +#include +using namespace std; + +#include +#include +#include +using namespace DirectX; + +struct VERTEX { + FLOAT X, Y, Z; + XMFLOAT2 texcoord; +}; + +struct Texture { + string type; + string path; + ID3D11ShaderResourceView *texture; +}; + +class Mesh { +public: + vector vertices; + vector indices; + vector textures; + ID3D11Device *dev; + + Mesh(ID3D11Device *dev, vector vertices, vector indices, vector textures) + { + this->vertices = vertices; + this->indices = indices; + this->textures = textures; + + this->dev = dev; + + this->setupMesh(dev); + } + + void Draw(ID3D11DeviceContext *devcon) + { + UINT stride = sizeof(VERTEX); + UINT offset = 0; + + devcon->IASetVertexBuffers(0, 1, &VertexBuffer, &stride, &offset); + devcon->IASetIndexBuffer(IndexBuffer, DXGI_FORMAT_R32_UINT, 0); + + devcon->PSSetShaderResources(0, 1, &textures[0].texture); + + devcon->DrawIndexed(indices.size(), 0, 0); + } + + void Close() + { + VertexBuffer->Release(); + IndexBuffer->Release(); + } +private: + /* Render data */ + ID3D11Buffer *VertexBuffer, *IndexBuffer; + + /* Functions */ + // Initializes all the buffer objects/arrays + bool setupMesh(ID3D11Device *dev) + { + HRESULT hr; + + D3D11_BUFFER_DESC vbd; + vbd.Usage = D3D11_USAGE_IMMUTABLE; + vbd.ByteWidth = sizeof(VERTEX) * vertices.size(); + vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vbd.CPUAccessFlags = 0; + vbd.MiscFlags = 0; + + D3D11_SUBRESOURCE_DATA initData; + initData.pSysMem = &vertices[0]; + + hr = dev->CreateBuffer(&vbd, &initData, &VertexBuffer); + if (FAILED(hr)) + return false; + + D3D11_BUFFER_DESC ibd; + ibd.Usage = D3D11_USAGE_IMMUTABLE; + ibd.ByteWidth = sizeof(UINT) * indices.size(); + ibd.BindFlags = D3D11_BIND_INDEX_BUFFER; + ibd.CPUAccessFlags = 0; + ibd.MiscFlags = 0; + + initData.pSysMem = &indices[0]; + + hr = dev->CreateBuffer(&ibd, &initData, &IndexBuffer); + if (FAILED(hr)) + return false; + } +}; + +#endif diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp new file mode 100644 index 000000000..a2d3faeb3 --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp @@ -0,0 +1,205 @@ +#include "ModelLoader.h" + +ModelLoader::ModelLoader() +{ +} + + +ModelLoader::~ModelLoader() +{ +} + +bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devcon, std::string filename) +{ + Assimp::Importer importer; + + const aiScene* pScene = importer.ReadFile(filename, + aiProcess_Triangulate | + aiProcess_ConvertToLeftHanded); + + if (pScene == NULL) + return false; + + this->directory = filename.substr(0, filename.find_last_of('/')); + + this->dev = dev; + this->hwnd = hwnd; + + processNode(pScene->mRootNode, pScene); + + return true; +} + +void ModelLoader::Draw(ID3D11DeviceContext * devcon) +{ + for (int i = 0; i < meshes.size(); i++) + { + meshes[i].Draw(devcon); + } +} + +string textype; + +Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene) +{ + // Data to fill + vector vertices; + vector indices; + vector textures; + + if (mesh->mMaterialIndex >= 0) + { + aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex]; + + if (textype.empty()) textype = determineTextureType(scene, mat); + } + + // Walk through each of the mesh's vertices + for (UINT i = 0; i < mesh->mNumVertices; i++) + { + VERTEX vertex; + + vertex.X = mesh->mVertices[i].x; + vertex.Y = mesh->mVertices[i].y; + vertex.Z = mesh->mVertices[i].z; + + if (mesh->mTextureCoords[0]) + { + vertex.texcoord.x = (float)mesh->mTextureCoords[0][i].x; + vertex.texcoord.y = (float)mesh->mTextureCoords[0][i].y; + } + + vertices.push_back(vertex); + } + + for (UINT i = 0; i < mesh->mNumFaces; i++) + { + aiFace face = mesh->mFaces[i]; + + for (UINT j = 0; j < face.mNumIndices; j++) + indices.push_back(face.mIndices[j]); + } + + if (mesh->mMaterialIndex >= 0) + { + aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; + + vector diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse", scene); + textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); + } + + return Mesh(dev, vertices, indices, textures); +} + +vector ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, string typeName, const aiScene * scene) +{ + vector textures; + for (UINT i = 0; i < mat->GetTextureCount(type); i++) + { + aiString str; + mat->GetTexture(type, i, &str); + // Check if texture was loaded before and if so, continue to next iteration: skip loading a new texture + bool skip = false; + for (UINT j = 0; j < textures_loaded.size(); j++) + { + if (std::strcmp(textures_loaded[j].path.c_str(), str.C_Str()) == 0) + { + textures.push_back(textures_loaded[j]); + skip = true; // A texture with the same filepath has already been loaded, continue to next one. (optimization) + break; + } + } + if (!skip) + { // If texture hasn't been loaded already, load it + HRESULT hr; + Texture texture; + if (textype == "embedded compressed texture") + { + int textureindex = getTextureIndex(&str); + texture.texture = getTextureFromModel(scene, textureindex); + } + else + { + string filename = string(str.C_Str()); + filename = directory + '/' + filename; + wstring filenamews = wstring(filename.begin(), filename.end()); + hr = CreateWICTextureFromFile(dev, devcon, filenamews.c_str(), nullptr, &texture.texture); + if (FAILED(hr)) + MessageBox(hwnd, "Texture couldn't be loaded", "Error!", MB_ICONERROR | MB_OK); + } + texture.type = typeName; + texture.path = str.C_Str(); + textures.push_back(texture); + this->textures_loaded.push_back(texture); // Store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures. + } + } + return textures; +} + +void ModelLoader::Close() +{ + for (int i = 0; i < meshes.size(); i++) + { + meshes[i].Close(); + } + + dev->Release(); +} + +void ModelLoader::processNode(aiNode * node, const aiScene * scene) +{ + for (UINT i = 0; i < node->mNumMeshes; i++) + { + aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; + meshes.push_back(this->processMesh(mesh, scene)); + } + + for (UINT i = 0; i < node->mNumChildren; i++) + { + this->processNode(node->mChildren[i], scene); + } +} + +string ModelLoader::determineTextureType(const aiScene * scene, aiMaterial * mat) +{ + aiString textypeStr; + mat->GetTexture(aiTextureType_DIFFUSE, 0, &textypeStr); + string textypeteststr = textypeStr.C_Str(); + if (textypeteststr == "*0" || textypeteststr == "*1" || textypeteststr == "*2" || textypeteststr == "*3" || textypeteststr == "*4" || textypeteststr == "*5") + { + if (scene->mTextures[0]->mHeight == 0) + { + return "embedded compressed texture"; + } + else + { + return "embedded non-compressed texture"; + } + } + if (textypeteststr.find('.') != string::npos) + { + return "textures are on disk"; + } +} + +int ModelLoader::getTextureIndex(aiString * str) +{ + string tistr; + tistr = str->C_Str(); + tistr = tistr.substr(1); + return stoi(tistr); +} + +ID3D11ShaderResourceView * ModelLoader::getTextureFromModel(const aiScene * scene, int textureindex) +{ + HRESULT hr; + ID3D11ShaderResourceView *texture; + + int* size = reinterpret_cast(&scene->mTextures[textureindex]->mWidth); + + hr = CreateWICTextureFromMemory(dev, devcon, reinterpret_cast(scene->mTextures[textureindex]->pcData), *size, nullptr, &texture); + if (FAILED(hr)) + MessageBox(hwnd, "Texture couldn't be created from memory!", "Error!", MB_ICONERROR | MB_OK); + + return texture; +} diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h new file mode 100644 index 000000000..9b4a53c27 --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h @@ -0,0 +1,44 @@ +#ifndef MODEL_LOADER_H +#define MODEL_LOADER_H + +#include +#include +#include + +#include +#include +#include + +#include "Mesh.h" +#include "TextureLoader.h" + +using namespace DirectX; + +class ModelLoader +{ +public: + ModelLoader(); + ~ModelLoader(); + + bool Load(HWND hwnd, ID3D11Device* dev, ID3D11DeviceContext* devcon, std::string filename); + void Draw(ID3D11DeviceContext* devcon); + + void Close(); +private: + ID3D11Device *dev; + ID3D11DeviceContext *devcon; + std::vector meshes; + string directory; + vector textures_loaded; + HWND hwnd; + + void processNode(aiNode* node, const aiScene* scene); + Mesh processMesh(aiMesh* mesh, const aiScene* scene); + vector loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName, const aiScene* scene); + string determineTextureType(const aiScene* scene, aiMaterial* mat); + int getTextureIndex(aiString* str); + ID3D11ShaderResourceView* getTextureFromModel(const aiScene* scene, int textureindex); +}; + +#endif // !MODEL_LOADER_H + diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/PixelShader.hlsl b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/PixelShader.hlsl new file mode 100644 index 000000000..2e8b4eeda --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/PixelShader.hlsl @@ -0,0 +1,9 @@ +Texture2D diffTexture; +SamplerState SampleType; + +float4 main(float4 pos : SV_POSITION, float2 texcoord : TEXCOORD) : SV_TARGET +{ + float4 textureColor = diffTexture.Sample(SampleType, texcoord); + + return textureColor; +} \ No newline at end of file diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj new file mode 100644 index 000000000..fc82bc18e --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj @@ -0,0 +1,146 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {E3B160B5-E71F-4F3F-9310-B8F156F736D8} + SimpleTexturedDirectx11 + 10.0.14393.0 + + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + $(IncludePath);E:\OpenGL VS Files\include + $(LibraryPath);E:\OpenGL VS Files\lib + + + + Level3 + Disabled + true + + + assimp-vc140-mt.lib;%(AdditionalDependencies) + + + + + Level3 + Disabled + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + Level3 + MaxSpeed + true + true + true + + + true + true + + + + + + + + + + Pixel + Pixel + Pixel + Pixel + + + Vertex + Vertex + Vertex + Vertex + + + + + + + + + + + \ No newline at end of file diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters new file mode 100644 index 000000000..271300ad8 --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filters @@ -0,0 +1,50 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {b6a86d3e-70a5-4d1e-ba05-c20902300206} + + + + + Source Files + + + Source Files + + + Source Files + + + + + Shaders + + + Shaders + + + + + Header Files + + + Header Files + + + Header Files + + + \ No newline at end of file diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp new file mode 100644 index 000000000..c3269d290 --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp @@ -0,0 +1,691 @@ +//-------------------------------------------------------------------------------------- +// File: WICTextureLoader.cpp +// +// Function for loading a WIC image and creating a Direct3D 11 runtime texture for it +// (auto-generating mipmaps if possible) +// +// Note: Assumes application has already called CoInitializeEx +// +// Warning: CreateWICTexture* functions are not thread-safe if given a d3dContext instance for +// auto-gen mipmap support. +// +// Note these functions are useful for images created as simple 2D textures. For +// more complex resources, DDSTextureLoader is an excellent light-weight runtime loader. +// For a full-featured DDS file reader, writer, and texture processing pipeline see +// the 'Texconv' sample and the 'DirectXTex' library. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// http://go.microsoft.com/fwlink/?LinkId=248926 +// http://go.microsoft.com/fwlink/?LinkId=248929 +//-------------------------------------------------------------------------------------- + +// We could load multi-frame images (TIFF/GIF) into a texture array. +// For now, we just load the first frame (note: DirectXTex supports multi-frame images) + +#include +#include + +#pragma warning(push) +#pragma warning(disable : 4005) +#include +#pragma warning(pop) + +#include + +#include "TextureLoader.h" + +#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) && !defined(DXGI_1_2_FORMATS) +#define DXGI_1_2_FORMATS +#endif + +//--------------------------------------------------------------------------------- +template class ScopedObject +{ +public: + explicit ScopedObject(T *p = 0) : _pointer(p) {} + ~ScopedObject() + { + if (_pointer) + { + _pointer->Release(); + _pointer = nullptr; + } + } + + bool IsNull() const { return (!_pointer); } + + T& operator*() { return *_pointer; } + T* operator->() { return _pointer; } + T** operator&() { return &_pointer; } + + void Reset(T *p = 0) { if (_pointer) { _pointer->Release(); } _pointer = p; } + + T* Get() const { return _pointer; } + +private: + ScopedObject(const ScopedObject&); + ScopedObject& operator=(const ScopedObject&); + + T* _pointer; +}; + +//------------------------------------------------------------------------------------- +// WIC Pixel Format Translation Data +//------------------------------------------------------------------------------------- +struct WICTranslate +{ + GUID wic; + DXGI_FORMAT format; +}; + +static WICTranslate g_WICFormats[] = +{ + { GUID_WICPixelFormat128bppRGBAFloat, DXGI_FORMAT_R32G32B32A32_FLOAT }, + + { GUID_WICPixelFormat64bppRGBAHalf, DXGI_FORMAT_R16G16B16A16_FLOAT }, + { GUID_WICPixelFormat64bppRGBA, DXGI_FORMAT_R16G16B16A16_UNORM }, + + { GUID_WICPixelFormat32bppRGBA, DXGI_FORMAT_R8G8B8A8_UNORM }, + { GUID_WICPixelFormat32bppBGRA, DXGI_FORMAT_B8G8R8A8_UNORM }, // DXGI 1.1 + { GUID_WICPixelFormat32bppBGR, DXGI_FORMAT_B8G8R8X8_UNORM }, // DXGI 1.1 + + { GUID_WICPixelFormat32bppRGBA1010102XR, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM }, // DXGI 1.1 + { GUID_WICPixelFormat32bppRGBA1010102, DXGI_FORMAT_R10G10B10A2_UNORM }, + { GUID_WICPixelFormat32bppRGBE, DXGI_FORMAT_R9G9B9E5_SHAREDEXP }, + +#ifdef DXGI_1_2_FORMATS + + { GUID_WICPixelFormat16bppBGRA5551, DXGI_FORMAT_B5G5R5A1_UNORM }, + { GUID_WICPixelFormat16bppBGR565, DXGI_FORMAT_B5G6R5_UNORM }, + +#endif // DXGI_1_2_FORMATS + + { GUID_WICPixelFormat32bppGrayFloat, DXGI_FORMAT_R32_FLOAT }, + { GUID_WICPixelFormat16bppGrayHalf, DXGI_FORMAT_R16_FLOAT }, + { GUID_WICPixelFormat16bppGray, DXGI_FORMAT_R16_UNORM }, + { GUID_WICPixelFormat8bppGray, DXGI_FORMAT_R8_UNORM }, + + { GUID_WICPixelFormat8bppAlpha, DXGI_FORMAT_A8_UNORM }, + +#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) + { GUID_WICPixelFormat96bppRGBFloat, DXGI_FORMAT_R32G32B32_FLOAT }, +#endif +}; + +//------------------------------------------------------------------------------------- +// WIC Pixel Format nearest conversion table +//------------------------------------------------------------------------------------- + +struct WICConvert +{ + GUID source; + GUID target; +}; + +static WICConvert g_WICConvert[] = +{ + // Note target GUID in this conversion table must be one of those directly supported formats (above). + + { GUID_WICPixelFormatBlackWhite, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM + + { GUID_WICPixelFormat1bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat2bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat4bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat8bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + + { GUID_WICPixelFormat2bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM + { GUID_WICPixelFormat4bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM + + { GUID_WICPixelFormat16bppGrayFixedPoint, GUID_WICPixelFormat16bppGrayHalf }, // DXGI_FORMAT_R16_FLOAT + { GUID_WICPixelFormat32bppGrayFixedPoint, GUID_WICPixelFormat32bppGrayFloat }, // DXGI_FORMAT_R32_FLOAT + +#ifdef DXGI_1_2_FORMATS + + { GUID_WICPixelFormat16bppBGR555, GUID_WICPixelFormat16bppBGRA5551 }, // DXGI_FORMAT_B5G5R5A1_UNORM + +#else + + { GUID_WICPixelFormat16bppBGR555, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat16bppBGRA5551, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat16bppBGR565, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + +#endif // DXGI_1_2_FORMATS + + { GUID_WICPixelFormat32bppBGR101010, GUID_WICPixelFormat32bppRGBA1010102 }, // DXGI_FORMAT_R10G10B10A2_UNORM + + { GUID_WICPixelFormat24bppBGR, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat24bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat32bppPBGRA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat32bppPRGBA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + + { GUID_WICPixelFormat48bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat48bppBGR, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat64bppBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat64bppPRGBA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat64bppPBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + + { GUID_WICPixelFormat48bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat48bppBGRFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat64bppRGBAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat64bppBGRAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat64bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat64bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + { GUID_WICPixelFormat48bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT + + { GUID_WICPixelFormat96bppRGBFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + { GUID_WICPixelFormat128bppPRGBAFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + { GUID_WICPixelFormat128bppRGBFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + { GUID_WICPixelFormat128bppRGBAFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + { GUID_WICPixelFormat128bppRGBFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT + + { GUID_WICPixelFormat32bppCMYK, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat64bppCMYK, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat40bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat80bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + +#if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) + { GUID_WICPixelFormat32bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM + { GUID_WICPixelFormat64bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM + { GUID_WICPixelFormat64bppPRGBAHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT +#endif + + // We don't support n-channel formats +}; + +//-------------------------------------------------------------------------------------- +static IWICImagingFactory* _GetWIC() +{ + static IWICImagingFactory* s_Factory = nullptr; + + if (s_Factory) + return s_Factory; + + HRESULT hr = CoCreateInstance( + CLSID_WICImagingFactory, + nullptr, + CLSCTX_INPROC_SERVER, + __uuidof(IWICImagingFactory), + (LPVOID*)&s_Factory + ); + + if (FAILED(hr)) + { + s_Factory = nullptr; + return nullptr; + } + + return s_Factory; +} + +//--------------------------------------------------------------------------------- +static DXGI_FORMAT _WICToDXGI(const GUID& guid) +{ + for (size_t i = 0; i < _countof(g_WICFormats); ++i) + { + if (memcmp(&g_WICFormats[i].wic, &guid, sizeof(GUID)) == 0) + return g_WICFormats[i].format; + } + + return DXGI_FORMAT_UNKNOWN; +} + +//--------------------------------------------------------------------------------- +static size_t _WICBitsPerPixel(REFGUID targetGuid) +{ + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return 0; + + ScopedObject cinfo; + if (FAILED(pWIC->CreateComponentInfo(targetGuid, &cinfo))) + return 0; + + WICComponentType type; + if (FAILED(cinfo->GetComponentType(&type))) + return 0; + + if (type != WICPixelFormat) + return 0; + + ScopedObject pfinfo; + if (FAILED(cinfo->QueryInterface(__uuidof(IWICPixelFormatInfo), reinterpret_cast(&pfinfo)))) + return 0; + + UINT bpp; + if (FAILED(pfinfo->GetBitsPerPixel(&bpp))) + return 0; + + return bpp; +} + +//--------------------------------------------------------------------------------- +static HRESULT CreateTextureFromWIC(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, + _In_ IWICBitmapFrameDecode *frame, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize) +{ + UINT width, height; + HRESULT hr = frame->GetSize(&width, &height); + if (FAILED(hr)) + return hr; + + assert(width > 0 && height > 0); + + if (!maxsize) + { + // This is a bit conservative because the hardware could support larger textures than + // the Feature Level defined minimums, but doing it this way is much easier and more + // performant for WIC than the 'fail and retry' model used by DDSTextureLoader + + switch (d3dDevice->GetFeatureLevel()) + { + case D3D_FEATURE_LEVEL_9_1: + case D3D_FEATURE_LEVEL_9_2: + maxsize = 2048 /*D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; + break; + + case D3D_FEATURE_LEVEL_9_3: + maxsize = 4096 /*D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; + break; + + case D3D_FEATURE_LEVEL_10_0: + case D3D_FEATURE_LEVEL_10_1: + maxsize = 8192 /*D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; + break; + + default: + maxsize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; + break; + } + } + + assert(maxsize > 0); + + UINT twidth, theight; + if (width > maxsize || height > maxsize) + { + float ar = static_cast(height) / static_cast(width); + if (width > height) + { + twidth = static_cast(maxsize); + theight = static_cast(static_cast(maxsize) * ar); + } + else + { + theight = static_cast(maxsize); + twidth = static_cast(static_cast(maxsize) / ar); + } + assert(twidth <= maxsize && theight <= maxsize); + } + else + { + twidth = width; + theight = height; + } + + // Determine format + WICPixelFormatGUID pixelFormat; + hr = frame->GetPixelFormat(&pixelFormat); + if (FAILED(hr)) + return hr; + + WICPixelFormatGUID convertGUID; + memcpy(&convertGUID, &pixelFormat, sizeof(WICPixelFormatGUID)); + + size_t bpp = 0; + + DXGI_FORMAT format = _WICToDXGI(pixelFormat); + if (format == DXGI_FORMAT_UNKNOWN) + { + for (size_t i = 0; i < _countof(g_WICConvert); ++i) + { + if (memcmp(&g_WICConvert[i].source, &pixelFormat, sizeof(WICPixelFormatGUID)) == 0) + { + memcpy(&convertGUID, &g_WICConvert[i].target, sizeof(WICPixelFormatGUID)); + + format = _WICToDXGI(g_WICConvert[i].target); + assert(format != DXGI_FORMAT_UNKNOWN); + bpp = _WICBitsPerPixel(convertGUID); + break; + } + } + + if (format == DXGI_FORMAT_UNKNOWN) + return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); + } + else + { + bpp = _WICBitsPerPixel(pixelFormat); + } + + if (!bpp) + return E_FAIL; + + // Verify our target format is supported by the current device + // (handles WDDM 1.0 or WDDM 1.1 device driver cases as well as DirectX 11.0 Runtime without 16bpp format support) + UINT support = 0; + hr = d3dDevice->CheckFormatSupport(format, &support); + if (FAILED(hr) || !(support & D3D11_FORMAT_SUPPORT_TEXTURE2D)) + { + // Fallback to RGBA 32-bit format which is supported by all devices + memcpy(&convertGUID, &GUID_WICPixelFormat32bppRGBA, sizeof(WICPixelFormatGUID)); + format = DXGI_FORMAT_R8G8B8A8_UNORM; + bpp = 32; + } + + // Allocate temporary memory for image + size_t rowPitch = (twidth * bpp + 7) / 8; + size_t imageSize = rowPitch * theight; + + std::unique_ptr temp(new uint8_t[imageSize]); + + // Load image data + if (memcmp(&convertGUID, &pixelFormat, sizeof(GUID)) == 0 + && twidth == width + && theight == height) + { + // No format conversion or resize needed + hr = frame->CopyPixels(0, static_cast(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + else if (twidth != width || theight != height) + { + // Resize + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return E_NOINTERFACE; + + ScopedObject scaler; + hr = pWIC->CreateBitmapScaler(&scaler); + if (FAILED(hr)) + return hr; + + hr = scaler->Initialize(frame, twidth, theight, WICBitmapInterpolationModeFant); + if (FAILED(hr)) + return hr; + + WICPixelFormatGUID pfScaler; + hr = scaler->GetPixelFormat(&pfScaler); + if (FAILED(hr)) + return hr; + + if (memcmp(&convertGUID, &pfScaler, sizeof(GUID)) == 0) + { + // No format conversion needed + hr = scaler->CopyPixels(0, static_cast(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + else + { + ScopedObject FC; + hr = pWIC->CreateFormatConverter(&FC); + if (FAILED(hr)) + return hr; + + hr = FC->Initialize(scaler.Get(), convertGUID, WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom); + if (FAILED(hr)) + return hr; + + hr = FC->CopyPixels(0, static_cast(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + } + else + { + // Format conversion but no resize + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return E_NOINTERFACE; + + ScopedObject FC; + hr = pWIC->CreateFormatConverter(&FC); + if (FAILED(hr)) + return hr; + + hr = FC->Initialize(frame, convertGUID, WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom); + if (FAILED(hr)) + return hr; + + hr = FC->CopyPixels(0, static_cast(rowPitch), static_cast(imageSize), temp.get()); + if (FAILED(hr)) + return hr; + } + + // See if format is supported for auto-gen mipmaps (varies by feature level) + bool autogen = false; + if (d3dContext != 0 && textureView != 0) // Must have context and shader-view to auto generate mipmaps + { + UINT fmtSupport = 0; + hr = d3dDevice->CheckFormatSupport(format, &fmtSupport); + if (SUCCEEDED(hr) && (fmtSupport & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN)) + { + autogen = true; + } + } + + // Create texture + D3D11_TEXTURE2D_DESC desc; + desc.Width = twidth; + desc.Height = theight; + desc.MipLevels = (autogen) ? 0 : 1; + desc.ArraySize = 1; + desc.Format = format; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = (autogen) ? (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET) : (D3D11_BIND_SHADER_RESOURCE); + desc.CPUAccessFlags = 0; + desc.MiscFlags = (autogen) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0; + + D3D11_SUBRESOURCE_DATA initData; + initData.pSysMem = temp.get(); + initData.SysMemPitch = static_cast(rowPitch); + initData.SysMemSlicePitch = static_cast(imageSize); + + ID3D11Texture2D* tex = nullptr; + hr = d3dDevice->CreateTexture2D(&desc, (autogen) ? nullptr : &initData, &tex); + if (SUCCEEDED(hr) && tex != 0) + { + if (textureView != 0) + { + D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc; + memset(&SRVDesc, 0, sizeof(SRVDesc)); + SRVDesc.Format = format; + SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; + SRVDesc.Texture2D.MipLevels = (autogen) ? -1 : 1; + + hr = d3dDevice->CreateShaderResourceView(tex, &SRVDesc, textureView); + if (FAILED(hr)) + { + tex->Release(); + return hr; + } + + if (autogen) + { + assert(d3dContext != 0); + d3dContext->UpdateSubresource(tex, 0, nullptr, temp.get(), static_cast(rowPitch), static_cast(imageSize)); + d3dContext->GenerateMips(*textureView); + } + } + + if (texture != 0) + { + *texture = tex; + } + else + { +#if defined(_DEBUG) || defined(PROFILE) + tex->SetPrivateData(WKPDID_D3DDebugObjectName, + sizeof("WICTextureLoader") - 1, + "WICTextureLoader" + ); +#endif + tex->Release(); + } + } + + return hr; +} + +//-------------------------------------------------------------------------------------- +HRESULT CreateWICTextureFromMemory(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, + _In_bytecount_(wicDataSize) const uint8_t* wicData, + _In_ size_t wicDataSize, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize +) +{ + if (!d3dDevice || !wicData || (!texture && !textureView)) + { + return E_INVALIDARG; + } + + if (!wicDataSize) + { + return E_FAIL; + } + +#ifdef _M_AMD64 + if (wicDataSize > 0xFFFFFFFF) + return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE); +#endif + + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return E_NOINTERFACE; + + // Create input stream for memory + ScopedObject stream; + HRESULT hr = pWIC->CreateStream(&stream); + if (FAILED(hr)) + return hr; + + hr = stream->InitializeFromMemory(const_cast(wicData), static_cast(wicDataSize)); + if (FAILED(hr)) + return hr; + + // Initialize WIC + ScopedObject decoder; + hr = pWIC->CreateDecoderFromStream(stream.Get(), 0, WICDecodeMetadataCacheOnDemand, &decoder); + if (FAILED(hr)) + return hr; + + ScopedObject frame; + hr = decoder->GetFrame(0, &frame); + if (FAILED(hr)) + return hr; + + hr = CreateTextureFromWIC(d3dDevice, d3dContext, frame.Get(), texture, textureView, maxsize); + if (FAILED(hr)) + return hr; + +#if defined(_DEBUG) || defined(PROFILE) + if (texture != 0 && *texture != 0) + { + (*texture)->SetPrivateData(WKPDID_D3DDebugObjectName, + sizeof("WICTextureLoader") - 1, + "WICTextureLoader" + ); + } + + if (textureView != 0 && *textureView != 0) + { + (*textureView)->SetPrivateData(WKPDID_D3DDebugObjectName, + sizeof("WICTextureLoader") - 1, + "WICTextureLoader" + ); + } +#endif + + return hr; +} + +//-------------------------------------------------------------------------------------- +HRESULT CreateWICTextureFromFile(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, + _In_z_ const wchar_t* fileName, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize) +{ + if (!d3dDevice || !fileName || (!texture && !textureView)) + { + return E_INVALIDARG; + } + + IWICImagingFactory* pWIC = _GetWIC(); + if (!pWIC) + return E_NOINTERFACE; + + // Initialize WIC + ScopedObject decoder; + HRESULT hr = pWIC->CreateDecoderFromFilename(fileName, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &decoder); + if (FAILED(hr)) + return hr; + + ScopedObject frame; + hr = decoder->GetFrame(0, &frame); + if (FAILED(hr)) + return hr; + + hr = CreateTextureFromWIC(d3dDevice, d3dContext, frame.Get(), texture, textureView, maxsize); + if (FAILED(hr)) + return hr; + +#if defined(_DEBUG) || defined(PROFILE) + if (texture != 0 || textureView != 0) + { + CHAR strFileA[MAX_PATH]; + WideCharToMultiByte(CP_ACP, + WC_NO_BEST_FIT_CHARS, + fileName, + -1, + strFileA, + MAX_PATH, + nullptr, + FALSE + ); + const CHAR* pstrName = strrchr(strFileA, '\\'); + if (!pstrName) + { + pstrName = strFileA; + } + else + { + pstrName++; + } + + if (texture != 0 && *texture != 0) + { + (*texture)->SetPrivateData(WKPDID_D3DDebugObjectName, + static_cast(strnlen_s(pstrName, MAX_PATH)), + pstrName + ); + } + + if (textureView != 0 && *textureView != 0) + { + (*textureView)->SetPrivateData(WKPDID_D3DDebugObjectName, + static_cast(strnlen_s(pstrName, MAX_PATH)), + pstrName + ); + } + } +#endif + + return hr; +} diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h new file mode 100644 index 000000000..c2e0b5214 --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h @@ -0,0 +1,55 @@ +//-------------------------------------------------------------------------------------- +// File: WICTextureLoader.h +// +// Function for loading a WIC image and creating a Direct3D 11 runtime texture for it +// (auto-generating mipmaps if possible) +// +// Note: Assumes application has already called CoInitializeEx +// +// Warning: CreateWICTexture* functions are not thread-safe if given a d3dContext instance for +// auto-gen mipmap support. +// +// Note these functions are useful for images created as simple 2D textures. For +// more complex resources, DDSTextureLoader is an excellent light-weight runtime loader. +// For a full-featured DDS file reader, writer, and texture processing pipeline see +// the 'Texconv' sample and the 'DirectXTex' library. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A +// PARTICULAR PURPOSE. +// +// Copyright (c) Microsoft Corporation. All rights reserved. +// +// http://go.microsoft.com/fwlink/?LinkId=248926 +// http://go.microsoft.com/fwlink/?LinkId=248929 +//-------------------------------------------------------------------------------------- + +#ifdef _MSC_VER +#pragma once +#endif + +#include + +#pragma warning(push) +#pragma warning(disable : 4005) +#include +#pragma warning(pop) + +HRESULT CreateWICTextureFromMemory(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, + _In_bytecount_(wicDataSize) const uint8_t* wicData, + _In_ size_t wicDataSize, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize = 0 +); + +HRESULT CreateWICTextureFromFile(_In_ ID3D11Device* d3dDevice, + _In_opt_ ID3D11DeviceContext* d3dContext, + _In_z_ const wchar_t* szFileName, + _Out_opt_ ID3D11Resource** texture, + _Out_opt_ ID3D11ShaderResourceView** textureView, + _In_ size_t maxsize = 0 +); + diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/VertexShader.hlsl b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/VertexShader.hlsl new file mode 100644 index 000000000..cf7ee16ac --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/VertexShader.hlsl @@ -0,0 +1,23 @@ +cbuffer ConstantBuffer : register(b0) +{ + matrix World; + matrix View; + matrix Projection; +} + +struct VOut { + float4 pos : SV_POSITION; + float2 texcoord : TEXCOORD; +}; + +VOut main(float4 pos : POSITION, float2 texcoord : TEXCOORD) +{ + VOut output; + + output.pos = mul(pos, World); + output.pos = mul(output.pos, View); + output.pos = mul(output.pos, Projection); + output.texcoord = texcoord; + + return output; +} \ No newline at end of file diff --git a/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp new file mode 100644 index 000000000..2d847095a --- /dev/null +++ b/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp @@ -0,0 +1,518 @@ +// --------------------------------------------------------------------------- +// Simple Assimp Directx11 Sample +// This is a very basic sample and only reads diffuse texture +// but this can load both embedded textures in fbx and non-embedded textures +// +// +// Replace ourModel->Load(hwnd, dev, devcon, "Models/myModel.fbx") this with your +// model name (line 480) +// If your model isn't a fbx with embedded textures make sure your model's +// textures are in same directory as your model +// +// +// Written by IAS. :) +// --------------------------------------------------------------------------- + +#include +#include +#include +#include +#include +#include +#include "ModelLoader.h" + +#pragma comment (lib, "d3d11.lib") +#pragma comment (lib, "Dxgi.lib") +#pragma comment(lib,"d3dcompiler.lib") +#pragma comment (lib, "dxguid.lib") + +using namespace DirectX; + +// ------------------------------------------------------------ +// Structs +// ------------------------------------------------------------ +struct ConstantBuffer { + XMMATRIX mWorld; + XMMATRIX mView; + XMMATRIX mProjection; +}; + +// ------------------------------------------------------------ +// Window Variables +// ------------------------------------------------------------ +#define SCREEN_WIDTH 800 +#define SCREEN_HEIGHT 600 + +const char g_szClassName[] = "directxWindowClass"; + + +UINT width, height; +HWND hwnd; + +// ------------------------------------------------------------ +// DirectX Variables +// ------------------------------------------------------------ +D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL; +D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0; +ID3D11Device *dev; +ID3D11Device1 *dev1; +ID3D11DeviceContext *devcon; +ID3D11DeviceContext1 *devcon1; +IDXGISwapChain *swapchain; +IDXGISwapChain1 *swapchain1; +ID3D11RenderTargetView *backbuffer; +ID3D11VertexShader *pVS; +ID3D11PixelShader *pPS; +ID3D11InputLayout *pLayout; +ID3D11Buffer *pConstantBuffer; +ID3D11Texture2D *g_pDepthStencil; +ID3D11DepthStencilView *g_pDepthStencilView; +ID3D11SamplerState *TexSamplerState; + +XMMATRIX m_World; +XMMATRIX m_View; +XMMATRIX m_Projection; + +// ------------------------------------------------------------ +// Function identifiers +// ------------------------------------------------------------ + +void InitD3D(HINSTANCE hinstance, HWND hWnd); +void CleanD3D(void); +void RenderFrame(void); + +void InitPipeline(); +void InitGraphics(); + +HRESULT CompileShaderFromFile(LPCWSTR pFileName, const D3D_SHADER_MACRO* pDefines, LPCSTR pEntryPoint, LPCSTR pShaderModel, ID3DBlob** ppBytecodeBlob); +void Throwanerror(LPCSTR errormessage); + +// ------------------------------------------------------------ +// Our Model +// ------------------------------------------------------------ + +ModelLoader *ourModel; + +LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case WM_CLOSE: + DestroyWindow(hwnd); + break; + case WM_DESTROY: + PostQuitMessage(0); + break; + default: + return DefWindowProc(hwnd, msg, wParam, lParam); + } + return 0; +} + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpCmdLine, int nCmdShow) +{ + WNDCLASSEX wc; + MSG msg; + + wc.cbSize = sizeof(WNDCLASSEX); + wc.style = 0; + wc.lpfnWndProc = WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = g_szClassName; + wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); + + if (!RegisterClassEx(&wc)) + { + MessageBox(NULL, "Window Registration Failed!", "Error!", + MB_ICONEXCLAMATION | MB_OK); + return 0; + } + + RECT wr = { 0,0, SCREEN_WIDTH, SCREEN_HEIGHT }; + AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); + + hwnd = CreateWindowEx( + WS_EX_CLIENTEDGE, + g_szClassName, + " Simple Textured Directx11 Sample ", + WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, wr.right - wr.left, wr.bottom - wr.top, + NULL, NULL, hInstance, NULL + ); + + if (hwnd == NULL) + { + MessageBox(NULL, "Window Creation Failed!", "Error!", + MB_ICONEXCLAMATION | MB_OK); + return 0; + } + + ShowWindow(hwnd, nCmdShow); + UpdateWindow(hwnd); + + width = wr.right - wr.left; + height = wr.bottom - wr.top; + + InitD3D(hInstance, hwnd); + + while (true) + { + + if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + + if (msg.message == WM_QUIT) + break; + } + + RenderFrame(); + } + + CleanD3D(); + + return msg.wParam; +} + +void InitD3D(HINSTANCE hinstance, HWND hWnd) +{ + HRESULT hr; + + UINT createDeviceFlags = 0; +#ifdef _DEBUG + createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; +#endif + + D3D_DRIVER_TYPE driverTypes[] = + { + D3D_DRIVER_TYPE_HARDWARE, + D3D_DRIVER_TYPE_WARP, + D3D_DRIVER_TYPE_REFERENCE, + }; + UINT numDriverTypes = ARRAYSIZE(driverTypes); + + D3D_FEATURE_LEVEL featureLevels[] = + { + D3D_FEATURE_LEVEL_11_1, + D3D_FEATURE_LEVEL_11_0, + D3D_FEATURE_LEVEL_10_1, + D3D_FEATURE_LEVEL_10_0, + }; + UINT numFeatureLevels = ARRAYSIZE(featureLevels); + + for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++) + { + g_driverType = driverTypes[driverTypeIndex]; + hr = D3D11CreateDevice(nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels, + D3D11_SDK_VERSION, &dev, &g_featureLevel, &devcon); + + if (hr == E_INVALIDARG) + { + // DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it + hr = D3D11CreateDevice(nullptr, g_driverType, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1, + D3D11_SDK_VERSION, &dev, &g_featureLevel, &devcon); + } + + if (SUCCEEDED(hr)) + break; + } + if (FAILED(hr)) + Throwanerror("Directx Device Creation Failed!"); + + UINT m4xMsaaQuality; + dev->CheckMultisampleQualityLevels( + DXGI_FORMAT_R8G8B8A8_UNORM, 4, &m4xMsaaQuality); + + + // Obtain DXGI factory from device (since we used nullptr for pAdapter above) + IDXGIFactory1* dxgiFactory = nullptr; + { + IDXGIDevice* dxgiDevice = nullptr; + hr = dev->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast(&dxgiDevice)); + if (SUCCEEDED(hr)) + { + IDXGIAdapter* adapter = nullptr; + hr = dxgiDevice->GetAdapter(&adapter); + if (SUCCEEDED(hr)) + { + hr = adapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast(&dxgiFactory)); + adapter->Release(); + } + dxgiDevice->Release(); + } + } + if (FAILED(hr)) + Throwanerror("DXGI Factory couldn't be obtained!"); + + // Create swap chain + IDXGIFactory2* dxgiFactory2 = nullptr; + hr = dxgiFactory->QueryInterface(__uuidof(IDXGIFactory2), reinterpret_cast(&dxgiFactory2)); + if (dxgiFactory2) + { + // DirectX 11.1 or later + hr = dev->QueryInterface(__uuidof(ID3D11Device1), reinterpret_cast(&dev1)); + if (SUCCEEDED(hr)) + { + (void)devcon->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast(&devcon1)); + } + + DXGI_SWAP_CHAIN_DESC1 sd; + ZeroMemory(&sd, sizeof(sd)); + sd.Width = SCREEN_WIDTH; + sd.Height = SCREEN_HEIGHT; + sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd.SampleDesc.Count = 4; + sd.SampleDesc.Quality = m4xMsaaQuality - 1; + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd.BufferCount = 1; + + hr = dxgiFactory2->CreateSwapChainForHwnd(dev, hWnd, &sd, nullptr, nullptr, &swapchain1); + if (SUCCEEDED(hr)) + { + hr = swapchain1->QueryInterface(__uuidof(IDXGISwapChain), reinterpret_cast(&swapchain)); + } + + dxgiFactory2->Release(); + } + else + { + // DirectX 11.0 systems + DXGI_SWAP_CHAIN_DESC sd; + ZeroMemory(&sd, sizeof(sd)); + sd.BufferCount = 1; + sd.BufferDesc.Width = SCREEN_WIDTH; + sd.BufferDesc.Height = SCREEN_HEIGHT; + sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + sd.BufferDesc.RefreshRate.Numerator = 60; + sd.BufferDesc.RefreshRate.Denominator = 1; + sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; + sd.OutputWindow = hWnd; + sd.SampleDesc.Count = 1; + sd.SampleDesc.Quality = m4xMsaaQuality - 1; + sd.Windowed = TRUE; + + hr = dxgiFactory->CreateSwapChain(dev, &sd, &swapchain); + } + + // Note this tutorial doesn't handle full-screen swapchains so we block the ALT+ENTER shortcut + dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER); + + dxgiFactory->Release(); + + if (FAILED(hr)) + Throwanerror("Swapchain Creation Failed!"); + + ID3D11Texture2D *pBackBuffer; + swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer); + + dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer); + pBackBuffer->Release(); + + D3D11_TEXTURE2D_DESC descDepth; + ZeroMemory(&descDepth, sizeof(descDepth)); + descDepth.Width = SCREEN_WIDTH; + descDepth.Height = SCREEN_HEIGHT; + descDepth.MipLevels = 1; + descDepth.ArraySize = 1; + descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; + descDepth.SampleDesc.Count = 4; + descDepth.SampleDesc.Quality = m4xMsaaQuality - 1; + descDepth.Usage = D3D11_USAGE_DEFAULT; + descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL; + descDepth.CPUAccessFlags = 0; + descDepth.MiscFlags = 0; + hr = dev->CreateTexture2D(&descDepth, nullptr, &g_pDepthStencil); + if (FAILED(hr)) + Throwanerror("Depth Stencil Texture couldn't be created!"); + + // Create the depth stencil view + D3D11_DEPTH_STENCIL_VIEW_DESC descDSV; + ZeroMemory(&descDSV, sizeof(descDSV)); + descDSV.Format = descDepth.Format; + descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; + descDSV.Texture2D.MipSlice = 0; + hr = dev->CreateDepthStencilView(g_pDepthStencil, 0, &g_pDepthStencilView); + if (FAILED(hr)) + { + Throwanerror("Depth Stencil View couldn't be created!"); + } + + devcon->OMSetRenderTargets(1, &backbuffer, g_pDepthStencilView); + + D3D11_RASTERIZER_DESC rasterDesc; + ID3D11RasterizerState *rasterState; + rasterDesc.AntialiasedLineEnable = false; + rasterDesc.CullMode = D3D11_CULL_BACK; + rasterDesc.DepthBias = 0; + rasterDesc.DepthBiasClamp = 0.0f; + rasterDesc.DepthClipEnable = true; + rasterDesc.FillMode = D3D11_FILL_SOLID; + rasterDesc.FrontCounterClockwise = false; + rasterDesc.MultisampleEnable = false; + rasterDesc.ScissorEnable = false; + rasterDesc.SlopeScaledDepthBias = 0.0f; + + dev->CreateRasterizerState(&rasterDesc, &rasterState); + devcon->RSSetState(rasterState); + + D3D11_VIEWPORT viewport; + ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT)); + + viewport.TopLeftX = 0; + viewport.TopLeftY = 0; + viewport.MinDepth = 0.0f; + viewport.MaxDepth = 1.0f; + viewport.Width = SCREEN_WIDTH; + viewport.Height = SCREEN_HEIGHT; + + devcon->RSSetViewports(1, &viewport); + + InitPipeline(); + InitGraphics(); +} + +void CleanD3D(void) +{ + swapchain->SetFullscreenState(FALSE, NULL); + + ourModel->Close(); + g_pDepthStencil->Release(); + g_pDepthStencilView->Release(); + pLayout->Release(); + pVS->Release(); + pPS->Release(); + pConstantBuffer->Release(); + swapchain->Release(); + backbuffer->Release(); + dev->Release(); + devcon->Release(); +} + +void RenderFrame(void) +{ + static float t = 0.0f; + static ULONGLONG timeStart = 0; + ULONGLONG timeCur = GetTickCount64(); + if (timeStart == 0) + timeStart = timeCur; + t = (timeCur - timeStart) / 1000.0f; + + float clearColor[4] = { 0.0f, 0.2f, 0.4f, 1.0f }; + devcon->ClearRenderTargetView(backbuffer, clearColor); + devcon->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); + + devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + + m_World = XMMatrixRotationY(-t); + + ConstantBuffer cb; + cb.mWorld = XMMatrixTranspose(m_World); + cb.mView = XMMatrixTranspose(m_View); + cb.mProjection = XMMatrixTranspose(m_Projection); + devcon->UpdateSubresource(pConstantBuffer, 0, nullptr, &cb, 0, 0); + + devcon->VSSetShader(pVS, 0, 0); + devcon->VSSetConstantBuffers(0, 1, &pConstantBuffer); + devcon->PSSetShader(pPS, 0, 0); + devcon->PSSetSamplers(0, 1, &TexSamplerState); + ourModel->Draw(devcon); + + swapchain->Present(0, 0); +} + +void InitPipeline() +{ + ID3DBlob *VS, *PS; + CompileShaderFromFile(L"VertexShader.hlsl", 0, "main", "vs_4_0", &VS); + CompileShaderFromFile(L"PixelShader.hlsl", 0, "main", "ps_4_0", &PS); + + dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS); + dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS); + + D3D11_INPUT_ELEMENT_DESC ied[] = + { + { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, + { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 } + }; + + dev->CreateInputLayout(ied, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout); + devcon->IASetInputLayout(pLayout); +} + +void InitGraphics() +{ + HRESULT hr; + + m_Projection = XMMatrixPerspectiveFovLH(XM_PIDIV4, SCREEN_WIDTH / (float)SCREEN_HEIGHT, 0.01f, 1000.0f); + + D3D11_BUFFER_DESC bd; + ZeroMemory(&bd, sizeof(bd)); + + bd.Usage = D3D11_USAGE_DEFAULT; + bd.ByteWidth = sizeof(ConstantBuffer); + bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; + bd.CPUAccessFlags = 0; + + hr = dev->CreateBuffer(&bd, nullptr, &pConstantBuffer); + if (FAILED(hr)) + Throwanerror("Constant buffer couldn't be created"); + + D3D11_SAMPLER_DESC sampDesc; + ZeroMemory(&sampDesc, sizeof(sampDesc)); + sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; + sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; + sampDesc.MinLOD = 0; + sampDesc.MaxLOD = D3D11_FLOAT32_MAX; + + hr = dev->CreateSamplerState(&sampDesc, &TexSamplerState); + if (FAILED(hr)) + Throwanerror("Texture sampler state couldn't be created"); + + XMVECTOR Eye = XMVectorSet(0.0f, 5.0f, -300.0f, 0.0f); + XMVECTOR At = XMVectorSet(0.0f, 100.0f, 0.0f, 0.0f); + XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); + m_View = XMMatrixLookAtLH(Eye, At, Up); + + ourModel = new ModelLoader; + if (!ourModel->Load(hwnd, dev, devcon, "Models/myModel.fbx")) + Throwanerror("Model couldn't be loaded"); +} + +HRESULT CompileShaderFromFile(LPCWSTR pFileName, const D3D_SHADER_MACRO* pDefines, LPCSTR pEntryPoint, LPCSTR pShaderModel, ID3DBlob** ppBytecodeBlob) +{ + UINT compileFlags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR; + +#ifdef _DEBUG + compileFlags |= D3DCOMPILE_DEBUG; +#endif + + ID3DBlob* pErrorBlob = NULL; + + HRESULT result = D3DCompileFromFile(pFileName, pDefines, D3D_COMPILE_STANDARD_FILE_INCLUDE, pEntryPoint, pShaderModel, compileFlags, 0, ppBytecodeBlob, &pErrorBlob); + if (FAILED(result)) + { + if (pErrorBlob != NULL) + OutputDebugStringA((LPCSTR)pErrorBlob->GetBufferPointer()); + } + + if (pErrorBlob != NULL) + pErrorBlob->Release(); + + return result; +} + +void Throwanerror(LPCSTR errormessage) +{ + MessageBox(hwnd, errormessage, "Error!", MB_ICONERROR | MB_OK); +} \ No newline at end of file diff --git a/samples/SimpleTexturedOpenGL/CMakeLists.txt b/samples/SimpleTexturedOpenGL/CMakeLists.txt index 6c34acda5..1b206af50 100644 --- a/samples/SimpleTexturedOpenGL/CMakeLists.txt +++ b/samples/SimpleTexturedOpenGL/CMakeLists.txt @@ -11,6 +11,11 @@ IF ( NOT GLUT_FOUND ) ENDIF ( MSVC ) ENDIF ( NOT GLUT_FOUND ) +if ( MSVC ) + ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS ) + ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) +endif ( MSVC ) + INCLUDE_DIRECTORIES( ${Assimp_SOURCE_DIR}/include ${Assimp_SOURCE_DIR}/code diff --git a/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp b/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp index 083650f96..df05b56c4 100644 --- a/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp +++ b/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp @@ -13,6 +13,7 @@ // http://nehe.gamedev.net/ // ---------------------------------------------------------------------------- #include +#include #include #include #include @@ -666,7 +667,7 @@ BOOL CreateGLWindow(const char* title, int width, int height, int bits, bool ful PFD_SUPPORT_OPENGL | // Format Must Support OpenGL PFD_DOUBLEBUFFER, // Must Support Double Buffering PFD_TYPE_RGBA, // Request An RGBA Format - bits, // Select Our Color Depth + BYTE(bits), // Select Our Color Depth 0, 0, 0, 0, 0, 0, // Color Bits Ignored 0, // No Alpha Buffer 0, // Shift Bit Ignored diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 84c45451f..3520f9782 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,7 +1,8 @@ # Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # -# Copyright (c) 2006-2016, assimp team +# Copyright (c) 2006-2017, assimp team + # All rights reserved. # # Redistribution and use of this software in source and binary forms, @@ -37,7 +38,8 @@ #---------------------------------------------------------------------- cmake_minimum_required( VERSION 2.6 ) -#INCLUDE( AddGTest ) +include( CTest ) +enable_testing() INCLUDE_DIRECTORIES( ../contrib/gtest/include @@ -55,6 +57,7 @@ SOURCE_GROUP( unit FILES ) SET( TEST_SRCS + unit/UTLogStream.h unit/AbstractImportExportBase.cpp unit/TestIOSystem.h unit/TestModelFactory.h @@ -62,7 +65,7 @@ SET( TEST_SRCS unit/ut3DSImportExport.cpp unit/utACImportExport.cpp unit/utAMFImportExport.cpp - unit/utASEImportExport.cpp + unit/utASEImportExport.cpp unit/utAnim.cpp unit/AssimpAPITest.cpp unit/utB3DImportExport.cpp @@ -85,6 +88,7 @@ SET( TEST_SRCS unit/utFixInfacingNormals.cpp unit/utGenNormals.cpp unit/utglTFImportExport.cpp + unit/utglTF2ImportExport.cpp unit/utHMPImportExport.cpp unit/utIFCImportExport.cpp unit/utImporter.cpp @@ -103,12 +107,17 @@ SET( TEST_SRCS unit/SceneDiffer.cpp unit/utSIBImporter.cpp unit/utObjImportExport.cpp + unit/utObjTools.cpp + unit/utOpenGEXImportExport.cpp unit/utPretransformVertices.cpp unit/utPLYImportExport.cpp + unit/utPMXImporter.cpp unit/utRemoveComments.cpp unit/utRemoveComponent.cpp unit/utRemoveRedundantMaterials.cpp + unit/utRemoveVCProcess.cpp unit/utScenePreprocessor.cpp + unit/utSceneCombiner.cpp unit/utSharedPPData.cpp unit/utStringUtils.cpp unit/utSMDImportExport.cpp @@ -123,6 +132,8 @@ SET( TEST_SRCS unit/utVector3.cpp unit/utXImporterExporter.cpp unit/utD3MFImportExport.cpp + unit/utQ3DImportExport.cpp + unit/utProfiler.cpp ) SOURCE_GROUP( tests FILES ${TEST_SRCS} ) @@ -136,7 +147,7 @@ add_executable( unit ) add_definitions(-DASSIMP_TEST_MODELS_DIR="${CMAKE_CURRENT_LIST_DIR}/models") - + SET_PROPERTY( TARGET assimp PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX} ) IF( WIN32 ) @@ -152,15 +163,6 @@ ENDIF(MSVC) target_link_libraries( unit assimp ${platform_libs} ) add_subdirectory(headercheck) -#if (ASSIMP_COVERALLS) -# include(Coveralls) -# -# set(COVERAGE_SRCS ${assimp_src} ${TEST_SRCS} ) -# -# # Create the coveralls target. -# coveralls_setup( -# "${COVERAGE_SRCS}" # The source files. -# ON # If we should upload. -# "${PROJECT_SOURCE_DIR}/cmake-modules/") # (Optional) Alternate project cmake module path. -#endif() + +add_test( unittests unit ) diff --git a/test/models-nonbsd/MMD/Alicia_blade.pmx b/test/models-nonbsd/MMD/Alicia_blade.pmx new file mode 100644 index 000000000..cdd7709cc Binary files /dev/null and b/test/models-nonbsd/MMD/Alicia_blade.pmx differ diff --git a/test/models-nonbsd/MMD/readme.txt b/test/models-nonbsd/MMD/readme.txt new file mode 100644 index 000000000..d8c882420 --- /dev/null +++ b/test/models-nonbsd/MMD/readme.txt @@ -0,0 +1,49 @@ +———————————————————————— +ニコニ立体公å¼ã‚­ãƒ£ãƒ©ã‚¯ã‚¿ãƒ¼ã€Œãƒ‹ã‚³ãƒ‹ç«‹ä½“ã¡ã‚ƒã‚“〠+http://3d.nicovideo.jp/alicia/ +version 4 +©dwango, inc. All rights reserved. +———————————————————————— + + +ã“ã®åº¦ã¯ã€ãƒ‹ã‚³ãƒ‹ç«‹ä½“å…¬å¼ã‚­ãƒ£ãƒ©ã‚¯ã‚¿ãƒ¼ã€Œãƒ‹ã‚³ãƒ‹ç«‹ä½“ã¡ã‚ƒã‚“ã€ã‚’ダウンロードã„ãŸã ãã¾ã—ã¦ã‚ã‚ŠãŒã¨ã†ã”ã–ã„ã¾ã™ã€‚ + +â—¯ 内容物 +1. MikuMikuDance(MMD)用ファイル2種 (ニコニ立体ã¡ã‚ƒã‚“本体・ビーム彫刻刀) +2. MMD用モーションファイル16種 (ニコファーレã®ãƒ¢ãƒ¼ã‚·ãƒ§ãƒ³ã‚­ãƒ£ãƒ—ãƒãƒ£ãƒ¼ãƒ‡ãƒã‚¤ã‚¹ã‚’用ã„ã¦åŽéŒ²) +2. FBXファイル2種 (MMD用データã€Unity用データ) + MAXファイル(オリジナルデータ) +3. Unity Package1種 +4. ニコニ立体ã¡ã‚ƒã‚“å£ç´™1種 + + +◯よãã‚ã‚‹è³ªå• +* 「ニコニ立体ã¡ã‚ƒã‚“ã€ã¨ã€Œã‚¢ãƒªã‚·ã‚¢ãƒ»ã‚½ãƒªãƒƒãƒ‰ã€ã€æ­£å¼å称ã¯ã©ã¡ã‚‰ï¼Ÿ +キャラクターã®æœ¬åã¯ã‚¢ãƒªã‚·ã‚¢ãƒ»ã‚½ãƒªãƒƒãƒ‰ã§ã™ãŒã€ã‚¯ãƒ¬ã‚¸ãƒƒãƒˆç­‰ã§ã®è¡¨è¨˜ã¯ãƒ‹ã‚³ãƒ‹ç«‹ä½“ã¡ã‚ƒã‚“ãŒæ­£å¼å称ã¨ãªã‚Šã¾ã™ã€‚ +作å“発表ã®éš›ã«ã¯ã€Œãƒ‹ã‚³ãƒ‹ç«‹ä½“ã¡ã‚ƒã‚“ã€ã‚¿ã‚°ã‚’ã”活用ãã ã•ã„。 + +* ニコニ立体ã¡ã‚ƒã‚“を用ã„ãŸã€å¹´é½¢åˆ¶é™ã®ã‚る二次創作物ã®å…¬é–‹ã¯å¯èƒ½ãªã®ã‹ï¼Ÿ +利用è¦ç´„ã«ã‚ã‚‹ç¦æ­¢äº‹é …ã«æŠµè§¦ã—ãªã„é™ã‚Šã«ãŠã„ã¦å¯èƒ½ã§ã™ã€‚ + + +â—¯ 利用è¦ç´„抜粋 +å¿…ãšåˆ©ç”¨è¦ç´„( http://3d.nicovideo.jp/alicia/rule.html )ã‚’ã”確èªãã ã•ã„。 +利用è¦ç´„ã®æ”¹è¨‚ãªã©ã«ã‚ˆã£ã¦ä¸‹è¨˜æŠœç²‹ã¨åˆ©ç”¨è¦ç´„ã®å†…容ãŒç•°ãªã‚‹å ´åˆã¯åˆ©ç”¨è¦ç´„ãŒå„ªå…ˆã•ã‚Œã¾ã™ã€‚ + +* éžå–¶åˆ©ã€å–¶åˆ©ã«é–¢ã‚らãšå€‹äºº(åŒäººã‚µãƒ¼ã‚¯ãƒ«ãªã©ã€æ³•äººã‚’除ã団体をå«ã‚€)ã®åˆ©ç”¨ãŒå¯èƒ½ã§ã™ã€‚ +* 二次創作物ã«ã¤ã„ã¦æ ªå¼ä¼šç¤¾ãƒ‰ãƒ¯ãƒ³ã‚´(以下ã€å½“社)ã®ã‚¯ãƒ¬ã‚¸ãƒƒãƒˆã‚’表記ã™ã‚‹å¿…è¦ã¯ã‚ã‚Šã¾ã›ã‚“。 +* 改変物をé…布ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ +* niconico内ã§ã‚­ãƒ£ãƒ©ã‚¯ã‚¿ãƒ¼ã‚„モーションを利用ã—ãŸä½œå“を投稿ã™ã‚‹å ´åˆã¯ã€ã‚³ãƒ³ãƒ†ãƒ³ãƒ„ツリーã®è¦ªä½œå“ã«ã‚­ãƒ£ãƒ©ã‚¯ã‚¿ãƒ¼( http://3d.nicovideo.jp/works/td14712 )を登録ã™ã‚‹ã‚ˆã†åŠªã‚ã‚‹ã‚‚ã®ã¨ã—ã¾ã™ã€‚ + + +â—¯ç¦æ­¢äº‹é … +* 第三者ã®çŸ¥çš„財産権ãã®ä»–一切ã®æ¨©åˆ©åŠã³å誉を侵害ã—ãªã„ã“ã¨ã€‚ +* 当社(当社ãŒæä¾›ã™ã‚‹ã‚µãƒ¼ãƒ“ス等をå«ã‚€ï¼‰åŠã³å½“社キャラクターã®å誉・å“ä½å‚·ã¤ã‘る行為をã—ãªã„ã“ã¨ã€‚ +* å…¬åºè‰¯ä¿—ã«åã™ã‚‹è¡Œç‚ºã‚„目的ã€æš´åŠ›çš„ãªè¡¨ç¾ã€å社会的ãªè¡Œç‚ºã‚„目的ã€ç‰¹å®šã®ä¿¡æ¡ã‚„å®—æ•™ã€æ”¿æ²»çš„発言ã®ãŸã‚利用ã—ãªã„ã“ã¨ã€‚ +* 当社ã®å…¬å¼å•†å“ã§ã‚ã‚‹ã‹ã®ã‚ˆã†ãªèª¤è§£ã‚’æ‹›ã利用をã—ãªã„ã“ã¨ã€‚ +* ãã®ä»–ã€å½“社ãŒä¸é©åˆ‡ã¨åˆ¤æ–­ã™ã‚‹è¡Œç‚ºã«åˆ©ç”¨ã—ãªã„ã“ã¨ã€‚ + + +â—¯ クレジット +ä¼ç”»: æ ªå¼ä¼šç¤¾ãƒ‰ãƒ¯ãƒ³ã‚´ +キャラクターデザイン: 黒星紅白 +モデリング: 雨刻 \ No newline at end of file diff --git a/test/models/OBJ/spider.mtl b/test/models/OBJ/spider.mtl index 38207dcc6..d225a7c62 100644 --- a/test/models/OBJ/spider.mtl +++ b/test/models/OBJ/spider.mtl @@ -1,38 +1,38 @@ -# -# spider.mtl -# - -newmtl Skin -Ka 0.200000 0.200000 0.200000 -Kd 0.827451 0.792157 0.772549 -Ks 0.000000 0.000000 0.000000 -Ns 0.000000 -map_Kd .\wal67ar_small.jpg - -newmtl Brusttex -Ka 0.200000 0.200000 0.200000 -Kd 0.800000 0.800000 0.800000 -Ks 0.000000 0.000000 0.000000 -Ns 0.000000 -map_Kd .\wal69ar_small.jpg - -newmtl HLeibTex -Ka 0.200000 0.200000 0.200000 -Kd 0.690196 0.639216 0.615686 -Ks 0.000000 0.000000 0.000000 -Ns 0.000000 -map_Kd .\SpiderTex.jpg - -newmtl BeinTex -Ka 0.200000 0.200000 0.200000 -Kd 0.800000 0.800000 0.800000 -Ks 0.000000 0.000000 0.000000 -Ns 0.000000 -map_Kd .\drkwood2.jpg - -newmtl Augentex -Ka 0.200000 0.200000 0.200000 -Kd 0.800000 0.800000 0.800000 -Ks 0.000000 0.000000 0.000000 -Ns 0.000000 +# +# spider.mtl +# + +newmtl Skin +Ka 0.200000 0.200000 0.200000 +Kd 0.827451 0.792157 0.772549 +Ks 0.000000 0.000000 0.000000 +Ns 0.000000 +map_Kd .\wal67ar_small.jpg + +newmtl Brusttex +Ka 0.200000 0.200000 0.200000 +Kd 0.800000 0.800000 0.800000 +Ks 0.000000 0.000000 0.000000 +Ns 0.000000 +map_Kd .\wal69ar_small.jpg + +newmtl HLeibTex +Ka 0.200000 0.200000 0.200000 +Kd 0.690196 0.639216 0.615686 +Ks 0.000000 0.000000 0.000000 +Ns 0.000000 +map_Kd .\SpiderTex.jpg + +newmtl BeinTex +Ka 0.200000 0.200000 0.200000 +Kd 0.800000 0.800000 0.800000 +Ks 0.000000 0.000000 0.000000 +Ns 0.000000 +map_Kd .\drkwood2.jpg + +newmtl Augentex +Ka 0.200000 0.200000 0.200000 +Kd 0.800000 0.800000 0.800000 +Ks 0.000000 0.000000 0.000000 +Ns 0.000000 map_Kd .\engineflare1.jpg \ No newline at end of file diff --git a/test/models/OBJ/spider.obj b/test/models/OBJ/spider.obj index 6779e27df..3e8e70fbd 100644 --- a/test/models/OBJ/spider.obj +++ b/test/models/OBJ/spider.obj @@ -1,3226 +1,3436 @@ -# File produced by Open Asset Import Library (http://www.assimp.sf.net) -# (assimp v3.3.29758555) +# Wavefront OBJ exported by MilkShape 3D -mtllib spider.obj.mtl +mtllib spider.mtl -# 722 vertex positions -v 1.160378932952881 4.512683868408203 6.449167251586914 -v 22.65617179870605 10.21453857421875 16.86968994140625 -v 4.568314075469971 16.85711288452148 5.619616985321045 -v 14.40229797363281 32.89186859130859 3.414829015731812 -v 27.52080917358398 27.08032608032227 11.45156478881836 -v 39.18625640869141 16.23099708557129 12.6327018737793 -v -6.442715167999268 10.77740478515625 -0.5375289916992188 -v -8.120363235473633 15.6844596862793 -10.5 -v -0.8867700099945068 23.4237174987793 -4.342854022979736 -v -0.8867700099945068 23.4237174987793 -16.65714454650879 -v 14.40229797363281 32.89186859130859 -26.41482543945312 -v 12.95316505432129 36.87333679199219 -11.5 -v 30.52731704711914 37.50395202636719 -2.733282089233398 -v 30.52731704711914 37.50395202636719 -20.26671600341797 -v 44.30125045776367 33.96472930908203 -11.5 -v 45.09496688842773 27.71094512939453 2.684845924377441 -v 57.93621826171875 30.27653312683105 -11.5 -v 54.50359344482422 5.934020042419434 -11.5 -v 51.09176254272461 11.23489952087402 2.684845924377441 -v 45.09496688842773 27.71094512939453 -25.68484497070312 -v 39.18625640869141 16.23099708557129 -35.63270568847656 -v 51.09176254272461 11.23489952087402 -25.68484497070312 -v 27.52080917358398 27.08032608032227 -34.45156478881836 -v 4.568314075469971 16.85711288452148 -26.6196174621582 -v 1.160378932952881 4.512683868408203 -27.44916915893555 -v 22.65617179870605 10.21453857421875 -39.86968994140625 -v 7.838881015777588 -6.414187908172607 -26.6196174621582 -v 30.91004180908203 -12.4627857208252 -26.41482543945312 -v 37.22381591796875 0.4215309917926788 -34.45156478881836 -v 46.22711181640625 -5.630886077880859 -20.26671600341797 -v 32.35918426513672 -16.44425201416016 -11.5 -v 30.91004180908203 -12.4627857208252 3.414829015731812 -v 46.22711181640625 -5.630886077880859 -2.733282089233398 -v 4.405118942260742 -14.23004245758057 -16.65714454650879 -v -4.681486129760742 -8.784435272216797 -10.5 -v 4.405118942260742 -14.23004245758057 -4.342854022979736 -v -4.421391010284424 -3.605049133300781 -0.5375289916992188 -v 7.838881015777588 -6.414187908172607 5.619616985321045 -v 37.22381591796875 0.4215309917926788 11.45156478881836 -v -9.876476287841797 2.961555004119873 -10.5 -v -6.442715167999268 10.77740478515625 -20.46247100830078 -v -4.421391010284424 -3.605049133300781 -20.46247100830078 -v -41.85661315917969 -0.7548459768295288 9.430771827697754 -v -27.9502124786377 1.303017020225525 3.0814208984375 -v -32.62586212158203 10.86018753051758 8.47976016998291 -v -24.40152359008789 12.2247486114502 -3.122689962387085 -v -18.8264045715332 5.435883045196533 0.5830910205841064 -v -11.22126770019531 -4.132546901702881 1.127722024917603 -v -44.88201522827148 11.88719749450684 1.421121001243591 -v -44.84470367431641 15.22849273681641 -10 -v -35.57024002075195 16.59859085083008 -2.941359043121338 -v -35.57024002075195 16.59859085083008 -17.05864334106445 -v -24.40152359008789 12.2247486114502 -16.87730979919434 -v -23.77848243713379 14.14228057861328 -10 -v -8.432302474975586 6.445052146911621 -5.95761775970459 -v -8.432302474975586 6.445052146911621 -14.04238128662109 -v -1.337092995643616 1.108109951019287 -10 -v -3.30927300453186 -1.735224008560181 -0.5947030186653137 -v -0.4196679890155792 -7.642198085784912 -10 -v -6.305181980133057 -14.18209838867188 -10 -v -6.229438781738281 -10.72257518768311 -0.5947030186653137 -v -3.30927300453186 -1.735224008560181 -19.40529632568359 -v -11.22126770019531 -4.132546901702881 -21.12771987915039 -v -6.229438781738281 -10.72257518768311 -19.40529632568359 -v -18.8264045715332 5.435883045196533 -20.58309173583984 -v -32.62586212158203 10.86018753051758 -28.47975921630859 -v -41.85661315917969 -0.7548459768295288 -29.43077087402344 -v -27.9502124786377 1.303017020225525 -23.0814208984375 -v -39.19473266601562 -9.356718063354492 -28.47975921630859 -v -31.49889755249023 -9.618716239929199 -16.87730979919434 -v -22.99813652038574 -7.403382778167725 -20.58309173583984 -v -49.71383666992188 -2.983590126037598 1.421121001243591 -v -39.19473266601562 -9.356718063354492 8.47976016998291 -v -22.99813652038574 -7.403382778167725 0.5830910205841064 -v -31.49889755249023 -9.618716239929199 -3.122689962387085 -v -50.63702392578125 8.975393295288086 -10 -v -51.64759063720703 -5.708693981170654 -10 -v -44.88201522827148 11.88719749450684 -21.42111587524414 -v -49.71383666992188 -2.983590126037598 -21.42111587524414 -v -40.67147827148438 -3.47288703918457 -21.36916732788086 -v -41.96333312988281 -2.246160984039307 -18.48523330688477 -v -44.64511871337891 -3.443838119506836 -21.08979034423828 -v -87.6058349609375 -39.9835319519043 -104.3517227172852 -v -87.87104797363281 -40.01747512817383 -103.8583068847656 -v -87.9501953125 -39.45514678955078 -104.2601852416992 -v -47.09840393066406 7.389261245727539 -39.58503341674805 -v -47.14669799804688 8.704387664794922 -37.68162155151367 -v -55.4437255859375 28.01696014404297 -51.02064895629883 -v -55.80507659912109 29.50034332275391 -50.36057662963867 -v -56.41304779052734 27.51875305175781 -54.60213470458984 -v -57.93299102783203 29.20790100097656 -55.03944778442383 -v -67.98501586914062 13.43557167053223 -79.02035522460938 -v -69.89360046386719 14.10584259033203 -80.14413452148438 -v -81.67832183837891 -31.37918090820312 -101.2915573120117 -v -82.77850341796875 -29.84352111816406 -101.2665863037109 -v -45.27461242675781 -1.921316027641296 -17.56256103515625 -v -88.2349853515625 -39.3502311706543 -103.8660430908203 -v -48.86238861083984 8.964324951171875 -36.15071487426758 -v -56.92498016357422 29.82746124267578 -49.55580902099609 -v -60.01216888427734 29.56021118164062 -54.08668899536133 -v -72.06874084472656 14.20652008056641 -79.36090087890625 -v -83.47474670410156 -29.51860809326172 -100.4707794189453 -v -48.11187744140625 -2.742969989776611 -19.29600143432617 -v -88.2457275390625 -39.74774169921875 -103.4660797119141 -v -50.95351028442383 7.973351955413818 -36.14510726928711 -v -57.96013641357422 28.75201416015625 -49.21238708496094 -v -61.08487701416016 28.31040191650391 -52.46125793457031 -v -72.87251281738281 13.66179847717285 -77.26039123535156 -v -83.24275207519531 -30.64902877807617 -99.50344848632812 -v -48.33858871459961 -4.09240198135376 -22.38015365600586 -v -87.97438049316406 -40.34838485717773 -103.3615341186523 -v -51.84541320800781 6.477696895599365 -37.66901397705078 -v -58.13103866577148 27.08382415771484 -49.58887100219727 -v -60.34334564208984 26.39956665039062 -51.38712310791016 -v -71.69966125488281 12.8818302154541 -75.42439270019531 -v -82.25722503662109 -32.38360595703125 -99.09293365478516 -v -45.78402709960938 -4.953472137451172 -24.49265670776367 -v -87.62525177001953 -40.69983673095703 -103.6310958862305 -v -50.86646270751953 5.603586196899414 -39.57491683959961 -v -57.30899810791016 26.07907104492188 -50.40177917480469 -v -58.34596252441406 25.26664733886719 -51.67315673828125 -v -69.433349609375 12.45395088195801 -75.23539733886719 -v -81.26026153564453 -33.41617965698242 -99.54843139648438 -v -42.37185668945312 -4.677759170532227 -24.04270935058594 -v -87.46121978759766 -40.53748321533203 -104.0717544555664 -v -48.75384521484375 6.009276866912842 -40.42763137817383 -v -56.11302947998047 26.49437713623047 -51.03896713256836 -v -56.59683609008789 25.76473236083984 -53.10398483276367 -v -67.78019714355469 12.70041084289551 -76.83576965332031 -v -81.00263214111328 -32.96916198730469 -100.5268630981445 -v -45.856201171875 -3.096683979034424 0.9894610047340393 -v -42.83802795410156 -1.822747945785522 -1.17337703704834 -v -41.96012115478516 -3.15467095375061 1.817621946334839 -v -92.29042816162109 -39.21158981323242 57.38248825073242 -v -92.26210784912109 -39.83740234375 57.07994079589844 -v -91.95950317382812 -39.73274230957031 57.5407600402832 -v -49.36812591552734 8.476757049560547 19.08589744567871 -v -49.19630432128906 7.804555892944336 21.29348754882812 -v -54.25469207763672 27.27288055419922 30.44888496398926 -v -54.92575836181641 28.34239959716797 29.36605453491211 -v -57.45500946044922 28.70623016357422 33.83551406860352 -v -55.48647308349609 27.49809265136719 33.97690582275391 -v -67.46834564208984 9.109057426452637 43.49641799926758 -v -69.61196136474609 9.454971313476562 44.29645156860352 -v -87.01417541503906 -30.51413726806641 52.42203521728516 -v -85.97149658203125 -32.07468414306641 52.63847351074219 -v -45.98867797851562 -1.450130939483643 -2.535742998123169 -v -92.60006713867188 -39.16170501708984 56.99636840820312 -v -50.88497161865234 7.785149097442627 17.48099899291992 -v -55.98342132568359 28.08773803710938 28.45757293701172 -v -59.41564178466797 28.14698791503906 32.74097061157227 -v -71.61580657958984 8.682785987854004 43.43437957763672 -v -87.75607299804688 -30.29622077941895 51.63100051879883 -v -49.03958129882812 -2.317409992218018 -1.243530988693237 -v -92.65523529052734 -39.6205940246582 56.67316055297852 -v -52.60464477539062 6.250553131103516 17.68733215332031 -v -56.63124847412109 26.70069122314453 28.40756416320801 -v -59.89194488525391 26.24149322509766 31.51743125915527 -v -71.97093963623047 7.37397575378418 41.55935287475586 -v -87.63851928710938 -31.58496475219727 50.86106491088867 -v -49.69331359863281 -3.771508932113647 1.730138063430786 -v -92.41441345214844 -40.24274826049805 56.65629577636719 -v -53.23219299316406 5.028540134429932 19.54948425292969 -v -56.38141632080078 25.22571563720703 29.25366592407227 -v -58.52523040771484 24.42458915710449 31.08627510070801 -v -70.40996551513672 6.514069080352783 40.08333206176758 -v -86.75009155273438 -33.40998077392578 50.69198608398438 -v -47.45761871337891 -4.717469215393066 4.146055221557617 -v -92.05893707275391 -40.55963134765625 56.95841217041016 -v -52.29503631591797 5.039290904998779 21.6652717590332 -v -55.42203521728516 24.77352905273438 30.3587532043457 -v -56.34468841552734 24.06446647644043 31.77214431762695 -v -68.10823822021484 6.750600814819336 40.11775207519531 -v -85.75971984863281 -34.3969612121582 51.2510871887207 -v -44.01602935791016 -4.442947864532471 4.184988975524902 -v -91.85649871826172 -40.33267974853516 57.35205459594727 -v -50.4989013671875 6.274747848510742 22.44142532348633 -v -54.47554779052734 25.68461608886719 30.89064788818359 -v -54.99231719970703 25.43232727050781 33.05861282348633 -v -66.79914093017578 7.905498027801514 41.6367301940918 -v -85.4132080078125 -33.80271530151367 52.11734008789062 -v -32.53578186035156 -3.15467095375061 -19.16253662109375 -v -34.38373184204102 -1.822747945785522 -16.65216445922852 -v -36.48015213012695 -3.096683979034424 -19.71685028076172 -v -43.38578033447266 -41.58316040039062 -95.21874237060547 -v -43.91326141357422 -41.58873748779297 -95.02735137939453 -v -43.69423675537109 -41.06890106201172 -95.43450164794922 -v -35.0989875793457 7.804555892944336 -38.97930526733398 -v -36.35158920288086 8.476757049560547 -37.15337371826172 -v -37.55405807495117 27.27288055419922 -51.63281631469727 -v -38.67663192749023 28.34239959716797 -51.03059768676758 -v -36.8568000793457 27.49809265136719 -55.3040657043457 -v -38.63229751586914 28.70623016357422 -56.16587829589844 -v -39.32158660888672 4.109056949615479 -79.20964813232422 -v -40.77798843383789 4.454970836639404 -80.97431182861328 -v -40.8770866394043 -32.42660522460938 -89.88973236083984 -v -41.6864128112793 -30.95858383178711 -90.76108551025391 -v -37.81033325195312 -1.450130939483643 -16.44955062866211 -v -44.16765594482422 -40.94609069824219 -95.34366607666016 -v -38.46767044067383 7.785149097442627 -36.52191925048828 -v -40.04683303833008 28.08773803710938 -50.77265167236328 -v -40.87752914428711 28.14698791503906 -56.19830703735352 -v -42.94440460205078 3.682785987854004 -81.22965240478516 -v -42.73056793212891 -30.60493469238281 -90.66996002197266 -v -40.23527908325195 -2.317409992218018 -18.70730972290039 -v -44.44951629638672 -41.30718231201172 -95.01465606689453 -v -39.85378265380859 6.250553131103516 -37.56044387817383 -v -40.63287734985352 26.70069122314453 -51.05325317382812 -v -41.90177536010742 26.24149322509766 -55.37683486938477 -v -44.18946838378906 2.373975992202759 -79.78339385986328 -v -43.2232666015625 -31.63191223144531 -89.68506622314453 -v -39.8325309753418 -3.771508932113647 -21.72522735595703 -v -44.32761383056641 -41.88030242919922 -94.69525909423828 -v -39.4661750793457 5.028540134429932 -39.48690414428711 -v -39.99345779418945 25.22571563720703 -51.66109085083008 -v -40.93375778198242 24.42458915710449 -54.3200798034668 -v -43.57563781738281 1.514069080352783 -77.72464752197266 -v -42.79354858398438 -33.2662239074707 -88.54798126220703 -v -36.90536880493164 -4.717469215393066 -23.23079490661621 -v -43.89371490478516 -42.23382568359375 -94.62592315673828 -v -37.59667587280273 5.039290904998779 -40.85063934326172 -v -38.61006164550781 24.77352905273438 -52.13843154907227 -v -38.70241546630859 24.06446647644043 -53.82379531860352 -v -41.56508255004883 1.750601053237915 -76.60358428955078 -v -41.76493453979492 -34.27718353271484 -88.11498260498047 -v -33.65802383422852 -4.442947864532471 -22.09029006958008 -v -43.47456359863281 -42.10161590576172 -94.85892486572266 -v -35.65310668945312 6.274747848510742 -40.62473678588867 -v -37.52444076538086 25.68461608886719 -52.12581634521484 -v -36.88800048828125 25.43232727050781 -54.26172637939453 -v -39.6718864440918 2.905498027801514 -77.26450347900391 -v -40.91205215454102 -33.90352249145508 -88.71208953857422 -v -36.01900863647461 -3.216418027877808 -1.765162944793701 -v -34.50244522094727 -1.655421018600464 -5.032196044921875 -v -32.20283126831055 -2.602406978607178 -2.728740930557251 -v -28.69635772705078 -38.61240768432617 75.69805145263672 -v -28.86252021789551 -39.28370666503906 75.62229156494141 -v -28.3271656036377 -39.13187408447266 75.69469451904297 -v -36.10787582397461 8.519889831542969 15.56240081787109 -v -34.57637023925781 8.107364654541016 17.24739646911621 -v -39.05897903442383 27.08562469482422 30.08821868896484 -v -40.40615463256836 27.93409729003906 29.60663604736328 -v -39.89728164672852 28.39327239990234 34.70915603637695 -v -38.03726577758789 27.49446105957031 33.66647720336914 -v -34.5403938293457 17.31492233276367 46.75900650024414 -v -35.8452262878418 17.43609428405762 48.66624069213867 -v -28.96659469604492 -31.87043952941895 66.61157989501953 -v -28.00870513916016 -33.48403930664062 66.39229583740234 -v -37.94406127929688 -1.883904933929443 -4.875525951385498 -v -29.19070816040039 -38.59844589233398 75.64435577392578 -v -38.12530136108398 7.461886882781982 15.15559387207031 -v -41.7304801940918 27.44197845458984 29.49332809448242 -v -41.99584579467773 27.45536041259766 34.97609710693359 -v -37.80666732788086 16.30614280700684 49.14663314819336 -v -30.06003952026367 -31.71491622924805 66.54987335205078 -v -39.93606948852539 -3.115807056427002 -2.376658916473389 -v -29.43793296813965 -39.1004524230957 75.57405853271484 -v -39.1094856262207 5.730080127716064 16.33332061767578 -v -42.03471374511719 25.97990417480469 29.83365058898926 -v -42.752685546875 25.38702392578125 34.26618957519531 -v -38.94770431518555 14.77594661712646 47.83845138549805 -v -30.46564483642578 -33.13447570800781 66.25366973876953 -v -38.97844314575195 -4.423483848571777 0.5826259851455688 -v -29.25189590454102 -39.74045181274414 75.54013824462891 -v -38.3193473815918 4.6285400390625 18.20871162414551 -v -41.08975601196289 24.6487865447998 30.3713264465332 -v -41.59787368774414 23.74571800231934 33.11403656005859 -v -38.40911865234375 13.99774074554443 45.72681045532227 -v -29.87803268432617 -35.06025695800781 65.94594573974609 -v -35.79229736328125 -4.822233200073242 1.77397894859314 -v -28.77267646789551 -40.03646850585938 75.56807708740234 -v -36.34981918334961 4.986735820770264 19.36955642700195 -v -39.6071891784668 24.45104026794434 30.70144844055176 -v -39.40102005004883 23.76740074157715 32.38723373413086 -v -36.59642791748047 14.5575475692749 44.40173721313477 -v -28.7396183013916 -36.04206466674805 65.85849761962891 -v -32.77687454223633 -4.011776924133301 0.3002820014953613 -v -28.36112785339355 -39.7656364440918 75.63690948486328 -v -34.68405532836914 6.534968852996826 18.94173622131348 -v -38.70342254638672 25.53554534912109 30.5754222869873 -v -37.81640243530273 25.43576812744141 32.63310623168945 -v -34.87471389770508 16.03384399414062 44.86114120483398 -v -27.90771293640137 -35.34060668945312 66.05712127685547 -v -26.45577621459961 -3.443838119506836 -2.149142980575562 -v -26.46640014648438 -2.246160984039307 -5.887526988983154 -v -23.49448394775391 -3.47288703918457 -4.813465118408203 -v 5.039107799530029 -39.45514678955078 86.51023101806641 -v 4.668338775634766 -40.01747512817383 86.33621978759766 -v 5.211228847503662 -39.9835319519043 86.19824981689453 -v -16.25835037231445 8.704387664794922 11.1760082244873 -v -14.85560417175293 7.389261245727539 12.46347618103027 -v -12.42665863037109 28.01696014404297 26.41044998168945 -v -13.15249061584473 29.50034332275391 26.21185684204102 -v -11.26496505737305 29.20790100097656 30.99277114868164 -v -10.52369499206543 27.51875305175781 29.59563827514648 -v -0.9972569942474365 13.43557167053223 54.88214111328125 -v -1.514698028564453 14.10584259033203 57.03571319580078 -v 3.385565996170044 -29.84352111816406 80.76795196533203 -v 3.675970077514648 -31.37918090820312 79.70648956298828 -v -29.43033599853516 -1.921316027641296 -4.146553039550781 -v 4.587766170501709 -39.3502311706543 86.69120025634766 -v -18.55141067504883 8.964324951171875 11.34670639038086 -v -14.50934600830078 29.82746124267578 26.45841026306152 -v -13.3946418762207 29.56021118164062 31.82656478881836 -v -3.589093923568726 14.20652008056641 58.0562744140625 -v 2.445001125335693 -29.51860809326172 81.25101470947266 -v -30.15432739257812 -2.742969989776611 -0.9014430046081543 -v 4.197091102600098 -39.74774169921875 86.60486602783203 -v -20.00806045532227 7.973351955413818 12.8470344543457 -v -15.4754638671875 28.75201416015625 26.9644775390625 -v -15.30904579162598 28.31040191650391 31.46907806396484 -v -5.658416748046875 13.66179847717285 57.17532348632812 -v 1.562493085861206 -30.64902877807617 80.79186248779297 -v -28.0932731628418 -4.09240198135376 1.404078960418701 -v 4.161306858062744 -40.34838485717773 86.31630706787109 -v -19.53142166137695 6.477696895599365 14.54720878601074 -v -15.32335662841797 27.08382415771484 27.34894752502441 -v -15.56659698486328 26.39956665039062 30.18951416015625 -v -6.164387226104736 12.8818302154541 55.05625915527344 -v 1.402615070343018 -32.38360595703125 79.73628997802734 -v -24.79911041259766 -4.953472137451172 1.033954977989197 -v 4.507323265075684 -40.69983673095703 86.04276275634766 -v -17.48039627075195 5.603586196899414 15.16696166992188 -v -14.16756820678711 26.07907104492188 27.32230758666992 -v -13.97334671020508 25.26664733886719 28.95141792297363 -v -4.726027011871338 12.45395088195801 53.29472351074219 -v 2.08576488494873 -33.41617965698242 78.87914276123047 -v -22.75246810913086 -4.677759170532227 -1.733124017715454 -v 4.974565982818604 -40.53748321533203 85.99021148681641 -v -15.39944839477539 6.009276866912842 14.2396240234375 -v -12.87841987609863 26.49437713623047 26.90462684631348 -v -11.72904586791992 25.76473236083984 28.68713760375977 -v -2.426440954208374 12.70041084289551 53.21726226806641 -v 3.097472906112671 -32.96916198730469 78.86588287353516 -v -23.49448394775391 -3.47288703918457 -15.18653869628906 -v -26.46640014648438 -2.246160984039307 -14.11247634887695 -v -26.45577621459961 -3.443838119506836 -17.85086059570312 -v 5.211228847503662 -39.9835319519043 -106.1982498168945 -v 4.668338775634766 -40.01747512817383 -106.3362197875977 -v 5.039107799530029 -39.45514678955078 -106.5102310180664 -v -14.85560417175293 7.389261245727539 -32.46347808837891 -v -16.25835037231445 8.704387664794922 -31.17601013183594 -v -12.42665863037109 28.01696014404297 -46.41044616699219 -v -13.15249061584473 29.50034332275391 -46.21185302734375 -v -10.52369499206543 27.51875305175781 -49.59563446044922 -v -11.26496505737305 29.20790100097656 -50.99276733398438 -v -0.9972569942474365 13.43557167053223 -74.88213348388672 -v -1.514698028564453 14.10584259033203 -77.03571319580078 -v 3.675970077514648 -31.37918090820312 -99.70648956298828 -v 3.38556694984436 -29.84352111816406 -100.767951965332 -v -29.43033599853516 -1.921316027641296 -15.85345077514648 -v 4.587764739990234 -39.3502311706543 -106.6912002563477 -v -18.55141067504883 8.964324951171875 -31.34671020507812 -v -14.50934600830078 29.82746124267578 -46.45841217041016 -v -13.3946418762207 29.56021118164062 -51.82656097412109 -v -3.589093923568726 14.20652008056641 -78.05626678466797 -v 2.445001125335693 -29.51860809326172 -101.2510147094727 -v -30.15432739257812 -2.742969989776611 -19.09856033325195 -v 4.197090148925781 -39.74774169921875 -106.604866027832 -v -20.00806045532227 7.973351955413818 -32.8470344543457 -v -15.4754638671875 28.75201416015625 -46.9644775390625 -v -15.30904579162598 28.31040191650391 -51.46907806396484 -v -5.658416748046875 13.66179847717285 -77.17531585693359 -v 1.562493085861206 -30.64902877807617 -100.791862487793 -v -28.0932731628418 -4.09240198135376 -21.40408325195312 -v 4.161307811737061 -40.34838485717773 -106.3163070678711 -v -19.53142166137695 6.477696895599365 -34.54721069335938 -v -15.32335662841797 27.08382415771484 -47.34894561767578 -v -15.56659698486328 26.39956665039062 -50.18951416015625 -v -6.164387226104736 12.8818302154541 -75.05625152587891 -v 1.402615070343018 -32.38360595703125 -99.73628997802734 -v -24.79911041259766 -4.953472137451172 -21.03395843505859 -v 4.50732421875 -40.69983673095703 -106.0427627563477 -v -17.48039627075195 5.603586196899414 -35.16696166992188 -v -14.16756820678711 26.07907104492188 -47.32230377197266 -v -13.97334671020508 25.26664733886719 -48.951416015625 -v -4.726027011871338 12.45395088195801 -73.29471588134766 -v 2.08576488494873 -33.41617965698242 -98.87914276123047 -v -22.75246810913086 -4.677759170532227 -18.26688003540039 -v 4.974565982818604 -40.53748321533203 -105.9902114868164 -v -15.39944839477539 6.009276866912842 -34.2396240234375 -v -12.87841987609863 26.49437713623047 -46.90462493896484 -v -11.72904586791992 25.76473236083984 -48.6871337890625 -v -2.426440954208374 12.70041084289551 -73.21726226806641 -v 3.097472906112671 -32.96916198730469 -98.86588287353516 -v -14.25648880004883 -6.954940795898438 -3.301691055297852 -v -14.10265731811523 -6.075778961181641 -7.124460220336914 -v -11.2052116394043 -7.280231952667236 -5.841878890991211 -v 19.74986457824707 -37.60753631591797 68.32992553710938 -v 19.34836387634277 -38.14849472045898 68.15628051757812 -v 19.89711761474609 -38.15519714355469 68.03912353515625 -v -4.907510757446289 6.093640804290771 10.12681770324707 -v -2.877649068832397 5.517601013183594 11.07694053649902 -v 1.745674014091492 26.13694000244141 21.00781440734863 -v 0.4745520055294037 27.20939636230469 20.97971534729004 -v 3.233434915542603 28.02400207519531 25.24942970275879 -v 4.282450199127197 26.64773559570312 23.71314430236816 -v 14.8602180480957 5.642467975616455 47.61897277832031 -v 14.56025314331055 6.223588943481445 49.83868408203125 -v 18.9760627746582 -28.07810020446777 62.27335357666016 -v 19.20066070556641 -29.66015243530273 61.26537322998047 -v -17.11595153808594 -5.533359050750732 -5.528418064117432 -v 19.30024719238281 -37.46723175048828 68.48995971679688 -v -7.036674976348877 5.467060089111328 10.78174591064453 -v -0.8241369724273682 27.00916290283203 21.51090049743652 -v 1.346554040908813 27.59506225585938 26.51851081848145 -v 12.85833549499512 5.598269939422607 51.27650451660156 -v 18.04227828979492 -27.67663192749023 62.70982360839844 -v -17.97599411010742 -6.06142520904541 -2.255570888519287 -v 18.88686752319336 -37.83989715576172 68.39877319335938 -v -7.661820888519287 4.109711170196533 12.54856109619141 -v -1.172435998916626 25.68704986572266 22.20140266418457 -v 0.0426269993185997 25.68392181396484 26.56466102600098 -v 11.03606128692627 4.237391948699951 50.84969329833984 -v 17.10253143310547 -28.75799560546875 62.24617767333984 -v -16.03519439697266 -7.262344837188721 0.2294789999723434 -v 18.82099342346191 -38.44494247436523 68.12506103515625 -v -6.312249183654785 3.043694019317627 14.09679794311523 -v -0.3080709874629974 24.23861885070801 22.53124809265137 -v 0.3035619854927063 23.72967147827148 25.3531436920166 -v 10.46565055847168 3.165694952011108 48.87973022460938 -v 16.8643856048584 -30.50795555114746 61.23151397705078 -v -12.75498580932617 -8.23180103302002 0.05550599843263626 -v 19.15221405029297 -38.82671737670898 67.87483215332031 -v -4.004155158996582 3.07171893119812 14.26059532165527 -v 1.118067026138306 23.75459671020508 22.25203132629395 -v 1.932853937149048 23.20393180847168 23.79626274108887 -v 11.57662582397461 3.190187931060791 46.84990692138672 -v 17.50724792480469 -31.60873603820801 60.42989349365234 -v -10.6054573059082 -8.239757537841797 -2.646497964859009 -v 19.63114547729492 -38.69778442382812 67.83663940429688 -v -2.475620031356812 4.172726154327393 12.91663932800293 -v 2.032040119171143 24.59943771362305 21.57402229309082 -v 3.703634023666382 24.50261497497559 23.06640815734863 -v 13.53237915039062 4.292479038238525 46.28885650634766 -v 18.54694938659668 -31.23143768310547 60.44495391845703 -v -12.53854370117188 -7.280231952667236 -13.491455078125 -v -15.43598937988281 -6.075778961181641 -12.2088737487793 -v -15.58982086181641 -6.954940795898438 -16.03164291381836 -v 18.56378555297852 -38.15519714355469 -87.37246704101562 -v 18.0150318145752 -38.14849472045898 -87.4896240234375 -v 18.41653251647949 -37.60753631591797 -87.66326904296875 -v -4.210980892181396 5.517601013183594 -30.41027450561523 -v -6.240842819213867 6.093640804290771 -29.46015167236328 -v 0.4123420119285583 26.13694000244141 -40.34114837646484 -v -0.8587800264358521 27.20939636230469 -40.31304931640625 -v 2.949118137359619 26.64773559570312 -43.04647827148438 -v 1.900102972984314 28.02400207519531 -44.582763671875 -v 13.52688598632812 5.642467975616455 -66.95231628417969 -v 13.22692108154297 6.223588943481445 -69.17202758789062 -v 17.86732864379883 -29.66015243530273 -80.59872436523438 -v 17.64273071289062 -28.07810020446777 -81.60670471191406 -v -18.44928359985352 -5.533359050750732 -13.80491638183594 -v 17.96691513061523 -37.46723175048828 -87.82330322265625 -v -8.370006561279297 5.467060089111328 -30.11508178710938 -v -2.157469034194946 27.00916290283203 -40.84423828125 -v 0.01322199963033199 27.59506225585938 -45.85184478759766 -v 11.52500343322754 5.598269939422607 -70.60984802246094 -v 16.70894622802734 -27.67663192749023 -82.04316711425781 -v -19.309326171875 -6.06142520904541 -17.07776260375977 -v 17.55353546142578 -37.83989715576172 -87.73211669921875 -v -8.995153427124023 4.109711170196533 -31.88189697265625 -v -2.505768060684204 25.68704986572266 -41.53473663330078 -v -1.290704965591431 25.68392181396484 -45.89799499511719 -v 9.702729225158691 4.237391948699951 -70.18302917480469 -v 15.76919937133789 -28.75799560546875 -81.57952880859375 -v -17.36852645874023 -7.262344837188721 -19.56281280517578 -v 17.48766136169434 -38.44494247436523 -87.45840454101562 -v -7.645581245422363 3.043694019317627 -33.43013000488281 -v -1.641402959823608 24.23861885070801 -41.86458587646484 -v -1.029770016670227 23.72967147827148 -44.68647766113281 -v 9.132317543029785 3.165694952011108 -68.21307373046875 -v 15.53105354309082 -30.50795555114746 -80.56486511230469 -v -14.08831787109375 -8.23180103302002 -19.38883972167969 -v 17.81888198852539 -38.82671737670898 -87.20817565917969 -v -5.33748722076416 3.07171893119812 -33.59392929077148 -v -0.2152650058269501 23.75459671020508 -41.58536529541016 -v 0.5995219945907593 23.20393180847168 -43.12960052490234 -v 10.24329376220703 3.190187931060791 -66.18324279785156 -v 16.17391586303711 -31.60873603820801 -79.76324462890625 -v -11.93878936767578 -8.239757537841797 -16.68683624267578 -v 18.29781341552734 -38.69778442382812 -87.16998291015625 -v -3.808951854705811 4.172726154327393 -32.24997329711914 -v 0.6987079977989197 24.59943771362305 -40.90735626220703 -v 2.370301961898804 24.50261497497559 -42.39974212646484 -v 12.19904708862305 4.292479038238525 -65.6221923828125 -v 17.2136173248291 -31.23143768310547 -79.77830505371094 -v -66.77298736572266 -11.88561820983887 -0.2029989957809448 -v -61.49651336669922 6.340155124664307 -5.812275886535645 -v -62.98685073852539 9.870844841003418 -6.308485984802246 -v -61.44757843017578 8.190096855163574 -3.647036075592041 -v -63.97118377685547 3.661695003509521 -3.830467939376831 -v -64.84598541259766 4.368710994720459 -2.075659990310669 -v -62.55780410766602 11.30561256408691 -3.485913991928101 -v -67.13710784912109 4.622090816497803 -1.531195998191833 -v -63.99109649658203 13.34076976776123 -5.450253009796143 -v -69.11919403076172 4.231084823608398 -2.607095956802368 -v -64.66820526123047 12.76302528381348 -8.06086254119873 -v -69.29987335205078 3.490133047103882 -4.493171215057373 -v -64.07926177978516 10.00739574432373 -9.351896286010742 -v -67.54299163818359 2.957120895385742 -5.769162178039551 -v -62.66775894165039 7.148978233337402 -8.351184844970703 -v -65.17147064208984 3.033509969711304 -5.474239826202393 -v -66.72484588623047 1.179926037788391 10.02946090698242 -v -58.21265029907227 12.08680152893066 -3.032124042510986 -v -55.28428649902344 12.61780071258545 -0.7646610140800476 -v -55.50985717773438 10.27971935272217 -2.97612190246582 -v -59.68946075439453 8.144949913024902 1.861809968948364 -v -57.9158821105957 6.628377914428711 1.958868980407715 -v -52.63722610473633 10.23327159881592 -1.25485098361969 -v -56.29685974121094 6.188433170318604 3.356508016586304 -v -51.75783920288086 11.98240089416504 0.8355600237846375 -v -56.05172729492188 7.156466007232666 5.002277851104736 -v -53.53396987915039 14.21004676818848 1.72101902961731 -v -57.36484146118164 8.803488731384277 5.656900882720947 -v -56.62808227539062 15.23869514465332 0.7346760034561157 -v -59.24757766723633 9.889246940612793 4.827473163604736 -v -58.71025466918945 14.29374885559082 -1.380638957023621 -v -60.28214263916016 9.596194267272949 3.138458967208862 -v -53.9999885559082 26.33333778381348 -9.944446563720703 -v -44.00383377075195 24.25179481506348 -7.336516857147217 -v -43.19998550415039 24.25179481506348 -9.944446563720703 -v -46.64442825317383 24.25179481506348 -0.7607110142707825 -v -53.9999885559082 2.333333969116211 -9.944446563720703 -v -50.9999885559082 3.941030979156494 -4.748294830322266 -v -53.9999885559082 3.941030979156494 -3.944447040557861 -v -53.9999885559082 24.72564125061035 -3.944446086883545 -v -55.80000305175781 6.941027164459229 -4.748294830322266 -v -56.99998474121094 24.72564125061035 -4.748292922973633 -v -57.99615859985352 5.774363040924072 -6.944447040557861 -v -59.19614028930664 24.72564125061035 -6.944447040557861 -v -58.80000686645508 5.774363040924072 -9.944446563720703 -v -59.99999237060547 24.72564125061035 -9.944446563720703 -v -45.44443130493164 8.333334922790527 -0.08162699639797211 -v -48.80383682250977 8.333334922790527 -0.9444469809532166 -v -53.9999885559082 10.66667366027832 1.822437047958374 -v -59.19614028930664 8.333334922790527 -0.9444469809532166 -v -62.9999885559082 8.333334922790527 -4.748293876647949 -v -64.19229888916016 7.533350944519043 -9.944446563720703 -v -43.60768508911133 8.333334922790527 -9.944446563720703 -v -37.19998550415039 18.65442848205566 -9.944446563720703 -v -39.25212478637695 18.65442848205566 -0.06191999837756157 -v -43.64442825317383 18.65442848205566 3.756353855133057 -v -53.9999885559082 14.33333778381348 2.055552959442139 -v -61.41007232666016 13.47619915008545 -1.042665958404541 -v -64.60929870605469 13.47619915008545 -6.367094039916992 -v -66.39998626708984 12.33334636688232 -9.944446563720703 -v -38.80768203735352 21.88604164123535 -9.944446563720703 -v -40.64442825317383 21.88604164123535 -0.7607129812240601 -v -44.44827651977539 21.88604164123535 2.546009063720703 -v -53.9999885559082 20.33333778381348 0.4478580057621002 -v -60.29326629638672 19.47619819641113 -2.199142932891846 -v -63.06387329101562 19.47619819641113 -6.810235023498535 -v -64.39229583740234 20.33333778381348 -9.944446563720703 -v -63.32090759277344 15.14286994934082 -6.139256000518799 -v -62.36603164672852 15.39914894104004 -5.604844093322754 -v -62.33220672607422 15.06181526184082 -5.486823081970215 -v -62.95563125610352 14.64286994934082 -5.390261173248291 -v -62.37112808227539 14.47619819641113 -4.191868782043457 -v -62.07738494873047 15.07085609436035 -4.598177909851074 -v -61.73810577392578 15.73718452453613 -3.414914131164551 -v -61.64052581787109 15.30952644348145 -2.693876981735229 -v -61.55341339111328 16.74508094787598 -2.770823001861572 -v -61.42134857177734 16.64286994934082 -2.244477033615112 -v -61.58245086669922 17.63445472717285 -2.87214994430542 -v -61.56745147705078 17.80952644348145 -2.544080018997192 -v -61.72498321533203 18.15569496154785 -3.369262933731079 -v -61.85970306396484 18.47619819641113 -3.143272876739502 -v -62.29808807373047 18.64286994934082 -4.042075157165527 -v -61.89406585693359 18.04158973693848 -3.958856105804443 -v -62.73646926879883 18.14286994934082 -4.940859794616699 -v -62.07035064697266 17.69966316223145 -4.573657035827637 -v -62.11862945556641 16.98106575012207 -4.741918087005615 -v -62.95563125610352 16.97619819641113 -5.390261173248291 -v -62.20188140869141 16.16166877746582 -5.032281875610352 -v -63.24786376953125 16.30952644348145 -5.989458084106445 -v -15.18229866027832 -14.32931900024414 -14.04238128662109 -v -32.1219482421875 -11.5362491607666 -10 -v -15.18229866027832 -14.32931900024414 -5.95761775970459 -v -44.94972991943359 -12.26852130889893 -17.05864334106445 -v -44.94972991943359 -12.26852130889893 -2.941359043121338 -v -43.19998550415039 24.25179481506348 -9.988886833190918 -v -44.00383377075195 24.25179481506348 -12.59681606292725 -v -53.9999885559082 26.33333778381348 -9.988886833190918 -v -46.64442825317383 24.25179481506348 -19.17262077331543 -v -53.9999885559082 3.941030979156494 -15.9888858795166 -v -50.9999885559082 3.941030979156494 -15.18503856658936 -v -53.9999885559082 2.333333969116211 -9.988886833190918 -v -53.9999885559082 24.72564125061035 -15.9888858795166 -v -55.80000305175781 6.941027164459229 -15.18503856658936 -v -56.99998474121094 24.72564125061035 -15.18503952026367 -v -57.99615859985352 5.774363040924072 -12.98888683319092 -v -59.19614028930664 24.72564125061035 -12.98888683319092 -v -58.80000686645508 5.774363040924072 -9.988886833190918 -v -59.99999237060547 24.72564125061035 -9.988886833190918 -v -48.80383682250977 8.333334922790527 -18.9888858795166 -v -45.44443130493164 8.333334922790527 -19.85170555114746 -v -53.9999885559082 10.66667366027832 -21.75576972961426 -v -59.19614028930664 8.333334922790527 -18.9888858795166 -v -62.9999885559082 8.333334922790527 -15.18503856658936 -v -64.19229888916016 7.533350944519043 -9.988886833190918 -v -37.19998550415039 18.65442848205566 -9.988886833190918 -v -43.60768508911133 8.333334922790527 -9.988886833190918 -v -39.25212478637695 18.65442848205566 -19.87141227722168 -v -43.64442825317383 18.65442848205566 -23.68968772888184 -v -53.9999885559082 14.33333778381348 -21.9888858795166 -v -61.41007232666016 13.47619915008545 -18.89066886901855 -v -64.60929870605469 13.47619915008545 -13.56623935699463 -v -66.39998626708984 12.33334636688232 -9.988886833190918 -v -40.64442825317383 21.88604164123535 -19.17262077331543 -v -38.80768203735352 21.88604164123535 -9.988886833190918 -v -44.44827651977539 21.88604164123535 -22.47934150695801 -v -53.9999885559082 20.33333778381348 -20.38118934631348 -v -60.29326629638672 19.47619819641113 -17.73418998718262 -v -63.06387329101562 19.47619819641113 -13.12309837341309 -v -64.39229583740234 20.33333778381348 -9.988886833190918 -v -62.33220672607422 15.06181526184082 -14.44650936126709 -v -62.36603164672852 15.39914894104004 -14.32849025726318 -v -63.32090759277344 15.14286994934082 -13.79407787322998 -v -62.95563125610352 14.64286994934082 -14.54307270050049 -v -62.37112808227539 14.47619819641113 -15.74146461486816 -v -62.07738494873047 15.07085609436035 -15.33515357971191 -v -61.73810577392578 15.73718452453613 -16.51841926574707 -v -61.64052581787109 15.30952644348145 -17.23945426940918 -v -61.42134857177734 16.64286994934082 -17.68885612487793 -v -61.55341339111328 16.74508094787598 -17.16251182556152 -v -61.56745147705078 17.80952644348145 -17.38925361633301 -v -61.58245086669922 17.63445472717285 -17.06118202209473 -v -61.72498321533203 18.15569496154785 -16.5640697479248 -v -61.85970306396484 18.47619819641113 -16.79006004333496 -v -62.29808807373047 18.64286994934082 -15.89125633239746 -v -61.89406585693359 18.04158973693848 -15.97447776794434 -v -62.73646926879883 18.14286994934082 -14.99247264862061 -v -62.07035064697266 17.69966316223145 -15.35967445373535 -v -62.11862945556641 16.98106575012207 -15.19141483306885 -v -62.95563125610352 16.97619819641113 -14.54307270050049 -v -62.20188140869141 16.16166877746582 -14.90105247497559 -v -63.24786376953125 16.30952644348145 -13.94387531280518 -v -66.59115600585938 -11.97652816772461 -20.11215209960938 -v -61.26576614379883 8.099187850952148 -16.66811561584473 -v -62.80503845214844 9.779933929443359 -14.00666618347168 -v -61.31470108032227 6.249245166778564 -14.50287628173828 -v -64.66415405273438 4.277801990509033 -18.2394905090332 -v -63.78934860229492 3.570785999298096 -16.48468399047852 -v -62.37599182128906 11.21470260620117 -16.82923698425293 -v -66.95527648925781 4.531181812286377 -18.78395462036133 -v -63.80926132202148 13.24985885620117 -14.86489868164062 -v -68.93736267089844 4.140174865722656 -17.70805549621582 -v -64.48637390136719 12.67211532592773 -12.25428771972656 -v -69.1180419921875 3.399224042892456 -15.82198143005371 -v -63.89742660522461 9.916484832763672 -10.96325492858887 -v -67.36116027832031 2.8662109375 -14.54598999023438 -v -62.48594665527344 7.058069229125977 -11.96396636962891 -v -64.98963928222656 2.942600965499878 -14.84091186523438 -v -66.72484588623047 1.234470963478088 -28.69612312316895 -v -55.50985717773438 10.33426475524902 -15.69054412841797 -v -55.28428649902344 12.6723461151123 -17.90200424194336 -v -58.21265029907227 12.14134788513184 -15.63454246520996 -v -57.9158821105957 6.682922840118408 -20.62553215026855 -v -59.68946075439453 8.199495315551758 -20.52847480773926 -v -52.63722610473633 10.28781700134277 -17.41181564331055 -v -56.29685974121094 6.242978096008301 -22.02317237854004 -v -51.75783920288086 12.03694534301758 -19.50222587585449 -v -56.05172729492188 7.211010932922363 -23.66894340515137 -v -53.53396987915039 14.26459121704102 -20.38768196105957 -v -57.36484146118164 8.858034133911133 -24.32356452941895 -v -56.62808227539062 15.29323959350586 -19.40134239196777 -v -59.24757766723633 9.943792343139648 -23.49413871765137 -v -58.71025466918945 14.34829330444336 -17.28602600097656 -v -60.28214263916016 9.650739669799805 -21.80512428283691 -v -59.67054748535156 17.67085647583008 -1.853034973144531 -v -58.74361419677734 17.51846694946289 -2.271703958511353 -v -59.46704864501953 18.40674209594727 -2.53897500038147 -v -60.63759613037109 18.10347366333008 -2.337920904159546 -v -61.55588531494141 18.15423965454102 -3.37207293510437 -v -60.57522583007812 18.69086074829102 -3.431842088699341 -v -61.64485168457031 18.26233291625977 -4.609260082244873 -v -61.38417816162109 17.94110488891602 -5.717274188995361 -v -61.48154449462891 16.98392105102539 -6.448155879974365 -v -62.26735687255859 17.28479385375977 -5.621510982513428 -v -62.61495971679688 16.49116897583008 -5.094202995300293 -v -62.20498657226562 16.13167190551758 -6.081917762756348 -v -61.27806091308594 15.97928333282471 -6.500585079193115 -v -62.26735687255859 15.54427146911621 -4.988009929656982 -v -61.38417816162109 14.97993564605713 -4.639497756958008 -v -61.48154449462891 15.24338626861572 -5.814656257629395 -v -60.47430419921875 15.08453464508057 -3.54331111907959 -v -61.64485168457031 15.44609451293945 -3.584233999252319 -v -61.55588531494141 16.32414627075195 -2.705970048904419 -v -60.57522583007812 15.87463855743408 -2.406815052032471 -v -59.56442260742188 15.70901966094971 -2.636348009109497 -v -60.63759613037109 17.02777481079102 -1.946398019790649 -v -59.46704864501953 16.66621780395508 -1.905473947525024 -v -61.74577331542969 17.31189346313477 -2.839264869689941 -v -62.3682861328125 17.41006851196289 -4.243031024932861 -v -62.3682861328125 16.33436965942383 -3.851508140563965 -v -59.46704864501953 18.14007568359375 -17.19435882568359 -v -58.74361419677734 17.25180053710938 -17.46162986755371 -v -59.67054748535156 17.40419006347656 -17.88029861450195 -v -60.63759613037109 17.83680725097656 -17.39541244506836 -v -60.57522583007812 18.4241943359375 -16.30149078369141 -v -61.55588531494141 17.8875732421875 -16.36125946044922 -v -61.64485168457031 17.99566650390625 -15.12407302856445 -v -62.26735687255859 17.01812744140625 -14.1118221282959 -v -61.48154449462891 16.71725463867188 -13.28517723083496 -v -61.38417816162109 17.6744384765625 -14.01605987548828 -v -62.20498657226562 15.86500549316406 -13.65141487121582 -v -62.61495971679688 16.22450256347656 -14.63912963867188 -v -61.27806091308594 15.71261596679688 -13.23274803161621 -v -62.26735687255859 15.27760314941406 -14.74532318115234 -v -61.48154449462891 14.97671890258789 -13.91867828369141 -v -61.38417816162109 14.7132682800293 -15.09383583068848 -v -61.64485168457031 15.17942810058594 -16.14909934997559 -v -60.47430419921875 14.81786727905273 -16.19002342224121 -v -60.57522583007812 15.60797119140625 -17.32651901245117 -v -61.55588531494141 16.05747985839844 -17.02736282348633 -v -59.56442260742188 15.44235229492188 -17.09698486328125 -v -60.63759613037109 16.7611083984375 -17.78693389892578 -v -59.46704864501953 16.39955139160156 -17.82785987854004 -v -61.74577331542969 17.04522705078125 -16.89406776428223 -v -62.3682861328125 17.14340209960938 -15.49030303955078 -v -62.3682861328125 16.06770324707031 -15.8818244934082 +v 1.160379 4.512684 6.449167 +v 22.656172 10.214539 16.869690 +v 4.568314 16.857113 5.619617 +v 14.402298 32.891869 3.414829 +v 27.520809 27.080326 11.451565 +v 39.186256 16.230997 12.632702 +v -6.442715 10.777405 -0.537529 +v -8.120363 15.684460 -10.500000 +v -0.886770 23.423717 -4.342854 +v -0.886770 23.423717 -16.657145 +v 14.402298 32.891869 -26.414825 +v 12.953165 36.873337 -11.500000 +v 30.527317 37.503952 -2.733282 +v 30.527317 37.503952 -20.266716 +v 44.301250 33.964729 -11.500000 +v 45.094967 27.710945 2.684846 +v 57.936218 30.276533 -11.500000 +v 54.503593 5.934020 -11.500000 +v 51.091763 11.234900 2.684846 +v 45.094967 27.710945 -25.684845 +v 39.186256 16.230997 -35.632706 +v 51.091763 11.234900 -25.684845 +v 27.520809 27.080326 -34.451565 +v 4.568314 16.857113 -26.619617 +v 1.160379 4.512684 -27.449169 +v 22.656172 10.214539 -39.869690 +v 7.838881 -6.414188 -26.619617 +v 30.910042 -12.462786 -26.414825 +v 37.223816 0.421531 -34.451565 +v 46.227112 -5.630886 -20.266716 +v 32.359184 -16.444252 -11.500000 +v 30.910042 -12.462786 3.414829 +v 46.227112 -5.630886 -2.733282 +v 4.405119 -14.230042 -16.657145 +v -4.681486 -8.784435 -10.500000 +v 4.405119 -14.230042 -4.342854 +v -4.421391 -3.605049 -0.537529 +v 7.838881 -6.414188 5.619617 +v 37.223816 0.421531 11.451565 +v -9.876476 2.961555 -10.500000 +v -6.442715 10.777405 -20.462471 +v -4.421391 -3.605049 -20.462471 +v -41.856613 -0.754846 9.430772 +v -27.950212 1.303017 3.081421 +v -32.625862 10.860188 8.479760 +v -24.401524 12.224749 -3.122690 +v -18.826405 5.435883 0.583091 +v -11.221268 -4.132547 1.127722 +v -44.882015 11.887197 1.421121 +v -44.844704 15.228493 -10.000000 +v -35.570240 16.598591 -2.941359 +v -35.570240 16.598591 -17.058643 +v -24.401524 12.224749 -16.877310 +v -23.778482 14.142281 -10.000000 +v -8.432302 6.445052 -5.957618 +v -8.432302 6.445052 -14.042381 +v -1.337093 1.108110 -10.000000 +v -3.309273 -1.735224 -0.594703 +v -0.419668 -7.642198 -10.000000 +v -6.305182 -14.182098 -10.000000 +v -6.229439 -10.722575 -0.594703 +v -3.309273 -1.735224 -19.405296 +v -11.221268 -4.132547 -21.127720 +v -6.229439 -10.722575 -19.405296 +v -18.826405 5.435883 -20.583092 +v -32.625862 10.860188 -28.479759 +v -41.856613 -0.754846 -29.430771 +v -27.950212 1.303017 -23.081421 +v -39.194733 -9.356718 -28.479759 +v -31.498898 -9.618716 -16.877310 +v -22.998137 -7.403383 -20.583092 +v -31.498898 -9.618716 -3.122690 +v -51.647591 -5.708694 -10.000000 +v -49.713837 -2.983590 1.421121 +v -39.194733 -9.356718 8.479760 +v -22.998137 -7.403383 0.583091 +v -50.637024 8.975393 -10.000000 +v -44.882015 11.887197 -21.421116 +v -49.713837 -2.983590 -21.421116 +v -40.671478 -3.472887 -21.369167 +v -47.098404 7.389261 -39.585033 +v -55.443726 28.016960 -51.020649 +v -56.413048 27.518753 -54.602135 +v -67.985016 13.435572 -79.020355 +v -81.678322 -31.379181 -101.291557 +v -87.605835 -39.983532 -104.351723 +v -41.963333 -2.246161 -18.485233 +v -47.146698 8.704388 -37.681622 +v -55.805077 29.500343 -50.360577 +v -57.932991 29.207901 -55.039448 +v -69.893600 14.105843 -80.144135 +v -82.778503 -29.843521 -101.266586 +v -87.950195 -39.455147 -104.260185 +v -45.274612 -1.921316 -17.562561 +v -48.862389 8.964325 -36.150715 +v -56.924980 29.827461 -49.555809 +v -60.012169 29.560211 -54.086689 +v -72.068741 14.206520 -79.360901 +v -83.474747 -29.518608 -100.470779 +v -88.234985 -39.350231 -103.866043 +v -48.111877 -2.742970 -19.296001 +v -50.953510 7.973352 -36.145107 +v -57.960136 28.752014 -49.212387 +v -61.084877 28.310402 -52.461258 +v -72.872513 13.661798 -77.260391 +v -83.242752 -30.649029 -99.503448 +v -88.245728 -39.747742 -103.466080 +v -48.338589 -4.092402 -22.380154 +v -51.845413 6.477697 -37.669014 +v -58.131039 27.083824 -49.588871 +v -60.343346 26.399567 -51.387123 +v -71.699661 12.881830 -75.424393 +v -82.257225 -32.383606 -99.092934 +v -87.974380 -40.348385 -103.361534 +v -45.784027 -4.953472 -24.492657 +v -50.866463 5.603586 -39.574917 +v -57.308998 26.079071 -50.401779 +v -58.345963 25.266647 -51.673157 +v -69.433350 12.453951 -75.235397 +v -81.260262 -33.416180 -99.548431 +v -87.625252 -40.699837 -103.631096 +v -42.371857 -4.677759 -24.042709 +v -48.753845 6.009277 -40.427631 +v -56.113029 26.494377 -51.038967 +v -56.596836 25.764732 -53.103985 +v -67.780197 12.700411 -76.835770 +v -81.002632 -32.969162 -100.526863 +v -87.461220 -40.537483 -104.071754 +v -87.871048 -40.017475 -103.858307 +v -44.645119 -3.443838 -21.089790 +v -41.960121 -3.154671 1.817622 +v -49.196304 7.804556 21.293488 +v -54.254692 27.272881 30.448885 +v -55.486473 27.498093 33.976906 +v -67.468346 9.109057 43.496418 +v -85.971497 -32.074684 52.638474 +v -91.959503 -39.732742 57.540760 +v -42.838028 -1.822748 -1.173377 +v -49.368126 8.476757 19.085897 +v -54.925758 28.342400 29.366055 +v -57.455009 28.706230 33.835514 +v -69.611961 9.454971 44.296452 +v -87.014175 -30.514137 52.422035 +v -92.290428 -39.211590 57.382488 +v -45.988678 -1.450131 -2.535743 +v -50.884972 7.785149 17.480999 +v -55.983421 28.087738 28.457573 +v -59.415642 28.146988 32.740971 +v -71.615807 8.682786 43.434380 +v -87.756073 -30.296221 51.631001 +v -92.600067 -39.161705 56.996368 +v -49.039581 -2.317410 -1.243531 +v -52.604645 6.250553 17.687332 +v -56.631248 26.700691 28.407564 +v -59.891945 26.241493 31.517431 +v -71.970940 7.373976 41.559353 +v -87.638519 -31.584965 50.861065 +v -92.655235 -39.620594 56.673161 +v -49.693314 -3.771509 1.730138 +v -53.232193 5.028540 19.549484 +v -56.381416 25.225716 29.253666 +v -58.525230 24.424589 31.086275 +v -70.409966 6.514069 40.083332 +v -86.750092 -33.409981 50.691986 +v -92.414413 -40.242748 56.656296 +v -47.457619 -4.717469 4.146055 +v -52.295036 5.039291 21.665272 +v -55.422035 24.773529 30.358753 +v -56.344688 24.064466 31.772144 +v -68.108238 6.750601 40.117752 +v -85.759720 -34.396961 51.251087 +v -92.058937 -40.559631 56.958412 +v -44.016029 -4.442948 4.184989 +v -50.498901 6.274748 22.441425 +v -54.475548 25.684616 30.890648 +v -54.992317 25.432327 33.058613 +v -66.799141 7.905498 41.636730 +v -85.413208 -33.802715 52.117340 +v -91.856499 -40.332680 57.352055 +v -92.262108 -39.837402 57.079941 +v -45.856201 -3.096684 0.989461 +v -32.535782 -3.154671 -19.162537 +v -35.098988 7.804556 -38.979305 +v -37.554058 27.272881 -51.632816 +v -36.856800 27.498093 -55.304066 +v -39.321587 4.109057 -79.209648 +v -40.877087 -32.426605 -89.889732 +v -43.385780 -41.583160 -95.218742 +v -34.383732 -1.822748 -16.652164 +v -36.351589 8.476757 -37.153374 +v -38.676632 28.342400 -51.030598 +v -38.632298 28.706230 -56.165878 +v -40.777988 4.454971 -80.974312 +v -41.686413 -30.958584 -90.761086 +v -43.694237 -41.068901 -95.434502 +v -37.810333 -1.450131 -16.449551 +v -38.467670 7.785149 -36.521919 +v -40.046833 28.087738 -50.772652 +v -40.877529 28.146988 -56.198307 +v -42.944405 3.682786 -81.229652 +v -42.730568 -30.604935 -90.669960 +v -44.167656 -40.946091 -95.343666 +v -40.235279 -2.317410 -18.707310 +v -39.853783 6.250553 -37.560444 +v -40.632877 26.700691 -51.053253 +v -41.901775 26.241493 -55.376835 +v -44.189468 2.373976 -79.783394 +v -43.223267 -31.631912 -89.685066 +v -44.449516 -41.307182 -95.014656 +v -39.832531 -3.771509 -21.725227 +v -39.466175 5.028540 -39.486904 +v -39.993458 25.225716 -51.661091 +v -40.933758 24.424589 -54.320080 +v -43.575638 1.514069 -77.724648 +v -42.793549 -33.266224 -88.547981 +v -44.327614 -41.880302 -94.695259 +v -36.905369 -4.717469 -23.230795 +v -37.596676 5.039291 -40.850639 +v -38.610062 24.773529 -52.138432 +v -38.702415 24.064466 -53.823795 +v -41.565083 1.750601 -76.603584 +v -41.764935 -34.277184 -88.114983 +v -43.893715 -42.233826 -94.625923 +v -33.658024 -4.442948 -22.090290 +v -35.653107 6.274748 -40.624737 +v -37.524441 25.684616 -52.125816 +v -36.888000 25.432327 -54.261726 +v -39.671886 2.905498 -77.264503 +v -40.912052 -33.903522 -88.712090 +v -43.474564 -42.101616 -94.858925 +v -43.913261 -41.588737 -95.027351 +v -36.480152 -3.096684 -19.716850 +v -32.202831 -2.602407 -2.728741 +v -34.576370 8.107365 17.247396 +v -39.058979 27.085625 30.088219 +v -38.037266 27.494461 33.666477 +v -34.540394 17.314922 46.759007 +v -28.008705 -33.484039 66.392296 +v -28.327166 -39.131874 75.694695 +v -34.502445 -1.655421 -5.032196 +v -36.107876 8.519890 15.562401 +v -40.406155 27.934097 29.606636 +v -39.897282 28.393272 34.709156 +v -35.845226 17.436094 48.666241 +v -28.966595 -31.870440 66.611580 +v -28.696358 -38.612408 75.698051 +v -37.944061 -1.883905 -4.875526 +v -38.125301 7.461887 15.155594 +v -41.730480 27.441978 29.493328 +v -41.995846 27.455360 34.976097 +v -37.806667 16.306143 49.146633 +v -30.060040 -31.714916 66.549873 +v -29.190708 -38.598446 75.644356 +v -39.936069 -3.115807 -2.376659 +v -39.109486 5.730080 16.333321 +v -42.034714 25.979904 29.833651 +v -42.752686 25.387024 34.266190 +v -38.947704 14.775947 47.838451 +v -30.465645 -33.134476 66.253670 +v -29.437933 -39.100452 75.574059 +v -38.978443 -4.423484 0.582626 +v -38.319347 4.628540 18.208712 +v -41.089756 24.648787 30.371326 +v -41.597874 23.745718 33.114037 +v -38.409119 13.997741 45.726810 +v -29.878033 -35.060257 65.945946 +v -29.251896 -39.740452 75.540138 +v -35.792297 -4.822233 1.773979 +v -36.349819 4.986736 19.369556 +v -39.607189 24.451040 30.701448 +v -39.401020 23.767401 32.387234 +v -36.596428 14.557548 44.401737 +v -28.739618 -36.042065 65.858498 +v -28.772676 -40.036469 75.568077 +v -32.776875 -4.011777 0.300282 +v -34.684055 6.534969 18.941736 +v -38.703423 25.535545 30.575422 +v -37.816402 25.435768 32.633106 +v -34.874714 16.033844 44.861141 +v -27.907713 -35.340607 66.057121 +v -28.361128 -39.765636 75.636909 +v -28.862520 -39.283707 75.622292 +v -36.019009 -3.216418 -1.765163 +v -23.494484 -3.472887 -4.813465 +v -14.855604 7.389261 12.463476 +v -12.426659 28.016960 26.410450 +v -10.523695 27.518753 29.595638 +v -0.997257 13.435572 54.882141 +v 3.675970 -31.379181 79.706490 +v 5.211229 -39.983532 86.198250 +v -26.466400 -2.246161 -5.887527 +v -16.258350 8.704388 11.176008 +v -13.152491 29.500343 26.211857 +v -11.264965 29.207901 30.992771 +v -1.514698 14.105843 57.035713 +v 3.385566 -29.843521 80.767952 +v 5.039108 -39.455147 86.510231 +v -29.430336 -1.921316 -4.146553 +v -18.551411 8.964325 11.346706 +v -14.509346 29.827461 26.458410 +v -13.394642 29.560211 31.826565 +v -3.589094 14.206520 58.056274 +v 2.445001 -29.518608 81.251015 +v 4.587766 -39.350231 86.691200 +v -30.154327 -2.742970 -0.901443 +v -20.008060 7.973352 12.847034 +v -15.475464 28.752014 26.964478 +v -15.309046 28.310402 31.469078 +v -5.658417 13.661798 57.175323 +v 1.562493 -30.649029 80.791862 +v 4.197091 -39.747742 86.604866 +v -28.093273 -4.092402 1.404079 +v -19.531422 6.477697 14.547209 +v -15.323357 27.083824 27.348948 +v -15.566597 26.399567 30.189514 +v -6.164387 12.881830 55.056259 +v 1.402615 -32.383606 79.736290 +v 4.161307 -40.348385 86.316307 +v -24.799110 -4.953472 1.033955 +v -17.480396 5.603586 15.166962 +v -14.167568 26.079071 27.322308 +v -13.973347 25.266647 28.951418 +v -4.726027 12.453951 53.294724 +v 2.085765 -33.416180 78.879143 +v 4.507323 -40.699837 86.042763 +v -22.752468 -4.677759 -1.733124 +v -15.399448 6.009277 14.239624 +v -12.878420 26.494377 26.904627 +v -11.729046 25.764732 28.687138 +v -2.426441 12.700411 53.217262 +v 3.097473 -32.969162 78.865883 +v 4.974566 -40.537483 85.990211 +v 4.668339 -40.017475 86.336220 +v -26.455776 -3.443838 -2.149143 +v -23.494484 -3.472887 -15.186539 +v -14.855604 7.389261 -32.463478 +v -12.426659 28.016960 -46.410446 +v -10.523695 27.518753 -49.595634 +v -0.997257 13.435572 -74.882133 +v 3.675970 -31.379181 -99.706490 +v 5.211229 -39.983532 -106.198250 +v -26.466400 -2.246161 -14.112476 +v -16.258350 8.704388 -31.176010 +v -13.152491 29.500343 -46.211853 +v -11.264965 29.207901 -50.992767 +v -1.514698 14.105843 -77.035713 +v 3.385567 -29.843521 -100.767952 +v 5.039108 -39.455147 -106.510231 +v -29.430336 -1.921316 -15.853451 +v -18.551411 8.964325 -31.346710 +v -14.509346 29.827461 -46.458412 +v -13.394642 29.560211 -51.826561 +v -3.589094 14.206520 -78.056267 +v 2.445001 -29.518608 -101.251015 +v 4.587765 -39.350231 -106.691200 +v -30.154327 -2.742970 -19.098560 +v -20.008060 7.973352 -32.847034 +v -15.475464 28.752014 -46.964478 +v -15.309046 28.310402 -51.469078 +v -5.658417 13.661798 -77.175316 +v 1.562493 -30.649029 -100.791862 +v 4.197090 -39.747742 -106.604866 +v -28.093273 -4.092402 -21.404083 +v -19.531422 6.477697 -34.547211 +v -15.323357 27.083824 -47.348946 +v -15.566597 26.399567 -50.189514 +v -6.164387 12.881830 -75.056252 +v 1.402615 -32.383606 -99.736290 +v 4.161308 -40.348385 -106.316307 +v -24.799110 -4.953472 -21.033958 +v -17.480396 5.603586 -35.166962 +v -14.167568 26.079071 -47.322304 +v -13.973347 25.266647 -48.951416 +v -4.726027 12.453951 -73.294716 +v 2.085765 -33.416180 -98.879143 +v 4.507324 -40.699837 -106.042763 +v -22.752468 -4.677759 -18.266880 +v -15.399448 6.009277 -34.239624 +v -12.878420 26.494377 -46.904625 +v -11.729046 25.764732 -48.687134 +v -2.426441 12.700411 -73.217262 +v 3.097473 -32.969162 -98.865883 +v 4.974566 -40.537483 -105.990211 +v 4.668339 -40.017475 -106.336220 +v -26.455776 -3.443838 -17.850861 +v -11.205212 -7.280232 -5.841879 +v -2.877649 5.517601 11.076941 +v 1.745674 26.136940 21.007814 +v 4.282450 26.647736 23.713144 +v 14.860218 5.642468 47.618973 +v 19.200661 -29.660152 61.265373 +v 19.897118 -38.155197 68.039124 +v -14.102657 -6.075779 -7.124460 +v -4.907511 6.093641 10.126818 +v 0.474552 27.209396 20.979715 +v 3.233435 28.024002 25.249430 +v 14.560253 6.223589 49.838684 +v 18.976063 -28.078100 62.273354 +v 19.749865 -37.607536 68.329926 +v -17.115952 -5.533359 -5.528418 +v -7.036675 5.467060 10.781746 +v -0.824137 27.009163 21.510900 +v 1.346554 27.595062 26.518511 +v 12.858335 5.598270 51.276505 +v 18.042278 -27.676632 62.709824 +v 19.300247 -37.467232 68.489960 +v -17.975994 -6.061425 -2.255571 +v -7.661821 4.109711 12.548561 +v -1.172436 25.687050 22.201403 +v 0.042627 25.683922 26.564661 +v 11.036061 4.237392 50.849693 +v 17.102531 -28.757996 62.246178 +v 18.886868 -37.839897 68.398773 +v -16.035194 -7.262345 0.229479 +v -6.312249 3.043694 14.096798 +v -0.308071 24.238619 22.531248 +v 0.303562 23.729671 25.353144 +v 10.465651 3.165695 48.879730 +v 16.864386 -30.507956 61.231514 +v 18.820993 -38.444942 68.125061 +v -12.754986 -8.231801 0.055506 +v -4.004155 3.071719 14.260595 +v 1.118067 23.754597 22.252031 +v 1.932854 23.203932 23.796263 +v 11.576626 3.190188 46.849907 +v 17.507248 -31.608736 60.429893 +v 19.152214 -38.826717 67.874832 +v -10.605457 -8.239758 -2.646498 +v -2.475620 4.172726 12.916639 +v 2.032040 24.599438 21.574022 +v 3.703634 24.502615 23.066408 +v 13.532379 4.292479 46.288857 +v 18.546949 -31.231438 60.444954 +v 19.631145 -38.697784 67.836639 +v 19.348364 -38.148495 68.156281 +v -14.256489 -6.954941 -3.301691 +v -12.538544 -7.280232 -13.491455 +v -4.210981 5.517601 -30.410275 +v 0.412342 26.136940 -40.341148 +v 2.949118 26.647736 -43.046478 +v 13.526886 5.642468 -66.952316 +v 17.867329 -29.660152 -80.598724 +v 18.563786 -38.155197 -87.372467 +v -15.435989 -6.075779 -12.208874 +v -6.240843 6.093641 -29.460152 +v -0.858780 27.209396 -40.313049 +v 1.900103 28.024002 -44.582764 +v 13.226921 6.223589 -69.172028 +v 17.642731 -28.078100 -81.606705 +v 18.416533 -37.607536 -87.663269 +v -18.449284 -5.533359 -13.804916 +v -8.370007 5.467060 -30.115082 +v -2.157469 27.009163 -40.844238 +v 0.013222 27.595062 -45.851845 +v 11.525003 5.598270 -70.609848 +v 16.708946 -27.676632 -82.043167 +v 17.966915 -37.467232 -87.823303 +v -19.309326 -6.061425 -17.077763 +v -8.995153 4.109711 -31.881897 +v -2.505768 25.687050 -41.534737 +v -1.290705 25.683922 -45.897995 +v 9.702729 4.237392 -70.183029 +v 15.769199 -28.757996 -81.579529 +v 17.553535 -37.839897 -87.732117 +v -17.368526 -7.262345 -19.562813 +v -7.645581 3.043694 -33.430130 +v -1.641403 24.238619 -41.864586 +v -1.029770 23.729671 -44.686478 +v 9.132318 3.165695 -68.213074 +v 15.531054 -30.507956 -80.564865 +v 17.487661 -38.444942 -87.458405 +v -14.088318 -8.231801 -19.388840 +v -5.337487 3.071719 -33.593929 +v -0.215265 23.754597 -41.585365 +v 0.599522 23.203932 -43.129601 +v 10.243294 3.190188 -66.183243 +v 16.173916 -31.608736 -79.763245 +v 17.818882 -38.826717 -87.208176 +v -11.938789 -8.239758 -16.686836 +v -3.808952 4.172726 -32.249973 +v 0.698708 24.599438 -40.907356 +v 2.370302 24.502615 -42.399742 +v 12.199047 4.292479 -65.622192 +v 17.213617 -31.231438 -79.778305 +v 18.297813 -38.697784 -87.169983 +v 18.015032 -38.148495 -87.489624 +v -15.589821 -6.954941 -16.031643 +v -66.772987 -11.885618 -0.202999 +v -63.971184 3.661695 -3.830468 +v -61.496513 6.340155 -5.812276 +v -66.772987 -11.885618 -0.202999 +v -64.845985 4.368711 -2.075660 +v -61.447578 8.190097 -3.647036 +v -66.772987 -11.885618 -0.202999 +v -67.137108 4.622091 -1.531196 +v -62.557804 11.305613 -3.485914 +v -66.772987 -11.885618 -0.202999 +v -69.119194 4.231085 -2.607096 +v -63.991096 13.340770 -5.450253 +v -66.772987 -11.885618 -0.202999 +v -69.299873 3.490133 -4.493171 +v -64.668205 12.763025 -8.060863 +v -66.772987 -11.885618 -0.202999 +v -67.542992 2.957121 -5.769162 +v -64.079262 10.007396 -9.351896 +v -66.772987 -11.885618 -0.202999 +v -65.171471 3.033510 -5.474240 +v -62.667759 7.148978 -8.351185 +v -62.986851 9.870845 -6.308486 +v -66.772987 -11.885618 -0.202999 +v -66.724846 1.179926 10.029461 +v -59.689461 8.144950 1.861810 +v -58.212650 12.086802 -3.032124 +v -66.724846 1.179926 10.029461 +v -57.915882 6.628378 1.958869 +v -55.509857 10.279719 -2.976122 +v -66.724846 1.179926 10.029461 +v -56.296860 6.188433 3.356508 +v -52.637226 10.233272 -1.254851 +v -66.724846 1.179926 10.029461 +v -56.051727 7.156466 5.002278 +v -51.757839 11.982401 0.835560 +v -66.724846 1.179926 10.029461 +v -57.364841 8.803489 5.656901 +v -53.533970 14.210047 1.721019 +v -66.724846 1.179926 10.029461 +v -59.247578 9.889247 4.827473 +v -56.628082 15.238695 0.734676 +v -66.724846 1.179926 10.029461 +v -60.282143 9.596194 3.138459 +v -58.710255 14.293749 -1.380639 +v -55.284286 12.617801 -0.764661 +v -66.724846 1.179926 10.029461 +v -53.999989 26.333338 -9.944447 +v -53.999989 2.333334 -9.944447 +v -50.999989 3.941031 -4.748295 +v -53.999989 3.941031 -3.944447 +v -55.800003 6.941027 -4.748295 +v -57.996159 5.774363 -6.944447 +v -58.800007 5.774363 -9.944447 +v -43.607685 8.333335 -9.944447 +v -45.444431 8.333335 -0.081627 +v -48.803837 8.333335 -0.944447 +v -53.999989 10.666674 1.822437 +v -59.196140 8.333335 -0.944447 +v -62.999989 8.333335 -4.748294 +v -64.192299 7.533351 -9.944447 +v -37.199986 18.654428 -9.944447 +v -39.252125 18.654428 -0.061920 +v -43.644428 18.654428 3.756354 +v -53.999989 14.333338 2.055553 +v -61.410072 13.476199 -1.042666 +v -64.609299 13.476199 -6.367094 +v -66.399986 12.333346 -9.944447 +v -38.807682 21.886042 -9.944447 +v -40.644428 21.886042 -0.760713 +v -44.448277 21.886042 2.546009 +v -53.999989 20.333338 0.447858 +v -60.293266 19.476198 -2.199143 +v -63.063873 19.476198 -6.810235 +v -64.392296 20.333338 -9.944447 +v -43.199986 24.251795 -9.944447 +v -44.003834 24.251795 -7.336517 +v -46.644428 24.251795 -0.760711 +v -53.999989 24.725641 -3.944446 +v -56.999985 24.725641 -4.748293 +v -59.196140 24.725641 -6.944447 +v -59.999992 24.725641 -9.944447 +v -61.567451 17.809526 -2.544080 +v -61.859703 18.476198 -3.143273 +v -62.298088 18.642870 -4.042075 +v -62.736469 18.142870 -4.940860 +v -62.955631 16.976198 -5.390261 +v -63.247864 16.309526 -5.989458 +v -63.320908 15.142870 -6.139256 +v -62.955631 14.642870 -5.390261 +v -62.371128 14.476198 -4.191869 +v -61.640526 15.309526 -2.693877 +v -61.421349 16.642870 -2.244477 +v -61.724983 18.155695 -3.369263 +v -61.894066 18.041590 -3.958856 +v -62.070351 17.699663 -4.573657 +v -62.118629 16.981066 -4.741918 +v -62.201881 16.161669 -5.032282 +v -62.366032 15.399149 -5.604844 +v -62.332207 15.061815 -5.486823 +v -62.077385 15.070856 -4.598178 +v -61.738106 15.737185 -3.414914 +v -61.553413 16.745081 -2.770823 +v -61.582451 17.634455 -2.872150 +v -6.305182 -14.182098 -10.000000 +v -6.229439 -10.722575 -0.594703 +v -6.229439 -10.722575 -19.405296 +v -39.194733 -9.356718 -28.479759 +v -31.498898 -9.618716 -16.877310 +v -22.998137 -7.403383 -20.583092 +v -15.182299 -14.329319 -14.042381 +v -32.121948 -11.536249 -10.000000 +v -31.498898 -9.618716 -3.122690 +v -15.182299 -14.329319 -5.957618 +v -44.949730 -12.268521 -17.058643 +v -51.647591 -5.708694 -10.000000 +v -44.949730 -12.268521 -2.941359 +v -49.713837 -2.983590 1.421121 +v -39.194733 -9.356718 8.479760 +v -22.998137 -7.403383 0.583091 +v -49.713837 -2.983590 -21.421116 +v -53.999989 26.333338 -9.988887 +v -53.999989 2.333334 -9.988887 +v -50.999989 3.941031 -15.185039 +v -53.999989 3.941031 -15.988886 +v -55.800003 6.941027 -15.185039 +v -57.996159 5.774363 -12.988887 +v -58.800007 5.774363 -9.988887 +v -43.607685 8.333335 -9.988887 +v -45.444431 8.333335 -19.851706 +v -48.803837 8.333335 -18.988886 +v -53.999989 10.666674 -21.755770 +v -59.196140 8.333335 -18.988886 +v -62.999989 8.333335 -15.185039 +v -64.192299 7.533351 -9.988887 +v -37.199986 18.654428 -9.988887 +v -39.252125 18.654428 -19.871412 +v -43.644428 18.654428 -23.689688 +v -53.999989 14.333338 -21.988886 +v -61.410072 13.476199 -18.890669 +v -64.609299 13.476199 -13.566239 +v -66.399986 12.333346 -9.988887 +v -38.807682 21.886042 -9.988887 +v -40.644428 21.886042 -19.172621 +v -44.448277 21.886042 -22.479342 +v -53.999989 20.333338 -20.381189 +v -60.293266 19.476198 -17.734190 +v -63.063873 19.476198 -13.123098 +v -64.392296 20.333338 -9.988887 +v -43.199986 24.251795 -9.988887 +v -44.003834 24.251795 -12.596816 +v -46.644428 24.251795 -19.172621 +v -53.999989 24.725641 -15.988886 +v -56.999985 24.725641 -15.185040 +v -59.196140 24.725641 -12.988887 +v -59.999992 24.725641 -9.988887 +v -61.567451 17.809526 -17.389254 +v -61.859703 18.476198 -16.790060 +v -62.298088 18.642870 -15.891256 +v -62.736469 18.142870 -14.992473 +v -62.955631 16.976198 -14.543073 +v -63.247864 16.309526 -13.943875 +v -63.320908 15.142870 -13.794078 +v -62.955631 14.642870 -14.543073 +v -62.371128 14.476198 -15.741465 +v -61.640526 15.309526 -17.239454 +v -61.421349 16.642870 -17.688856 +v -61.724983 18.155695 -16.564070 +v -61.894066 18.041590 -15.974478 +v -62.070351 17.699663 -15.359674 +v -62.118629 16.981066 -15.191415 +v -62.201881 16.161669 -14.901052 +v -62.366032 15.399149 -14.328490 +v -62.332207 15.061815 -14.446509 +v -62.077385 15.070856 -15.335154 +v -61.738106 15.737185 -16.518419 +v -61.553413 16.745081 -17.162512 +v -61.582451 17.634455 -17.061182 +v -66.591156 -11.976528 -20.112152 +v -63.789349 3.570786 -16.484684 +v -61.314701 6.249245 -14.502876 +v -66.591156 -11.976528 -20.112152 +v -64.664154 4.277802 -18.239491 +v -61.265766 8.099188 -16.668116 +v -66.591156 -11.976528 -20.112152 +v -66.955276 4.531182 -18.783955 +v -62.375992 11.214703 -16.829237 +v -66.591156 -11.976528 -20.112152 +v -68.937363 4.140175 -17.708055 +v -63.809261 13.249859 -14.864899 +v -66.591156 -11.976528 -20.112152 +v -69.118042 3.399224 -15.821981 +v -64.486374 12.672115 -12.254288 +v -66.591156 -11.976528 -20.112152 +v -67.361160 2.866211 -14.545990 +v -63.897427 9.916485 -10.963255 +v -66.591156 -11.976528 -20.112152 +v -64.989639 2.942601 -14.840912 +v -62.485947 7.058069 -11.963966 +v -62.805038 9.779934 -14.006666 +v -66.591156 -11.976528 -20.112152 +v -66.724846 1.234471 -28.696123 +v -59.689461 8.199495 -20.528475 +v -58.212650 12.141348 -15.634542 +v -66.724846 1.234471 -28.696123 +v -57.915882 6.682923 -20.625532 +v -55.509857 10.334265 -15.690544 +v -66.724846 1.234471 -28.696123 +v -56.296860 6.242978 -22.023172 +v -52.637226 10.287817 -17.411816 +v -66.724846 1.234471 -28.696123 +v -56.051727 7.211011 -23.668943 +v -51.757839 12.036945 -19.502226 +v -66.724846 1.234471 -28.696123 +v -57.364841 8.858034 -24.323565 +v -53.533970 14.264591 -20.387682 +v -66.724846 1.234471 -28.696123 +v -59.247578 9.943792 -23.494139 +v -56.628082 15.293240 -19.401342 +v -66.724846 1.234471 -28.696123 +v -60.282143 9.650740 -21.805124 +v -58.710255 14.348293 -17.286026 +v -55.284286 12.672346 -17.902004 +v -66.724846 1.234471 -28.696123 +v -59.670547 17.670856 -1.853035 +v -58.743614 17.518467 -2.271704 +v -59.467049 18.406742 -2.538975 +v -60.637596 18.103474 -2.337921 +v -61.555885 18.154240 -3.372073 +v -60.575226 18.690861 -3.431842 +v -61.644852 18.262333 -4.609260 +v -61.384178 17.941105 -5.717274 +v -61.278061 15.979283 -6.500585 +v -61.481544 16.983921 -6.448156 +v -62.267357 17.284794 -5.621511 +v -62.614960 16.491169 -5.094203 +v -62.204987 16.131672 -6.081918 +v -62.267357 15.544271 -4.988010 +v -61.384178 14.979936 -4.639498 +v -61.481544 15.243386 -5.814656 +v -60.474304 15.084535 -3.543311 +v -59.564423 15.709020 -2.636348 +v -61.644852 15.446095 -3.584234 +v -61.555885 16.324146 -2.705970 +v -60.575226 15.874639 -2.406815 +v -60.637596 17.027775 -1.946398 +v -59.467049 16.666218 -1.905474 +v -61.745773 17.311893 -2.839265 +v -62.368286 17.410069 -4.243031 +v -62.368286 16.334370 -3.851508 +v -59.670547 17.404190 -17.880299 +v -58.743614 17.251801 -17.461630 +v -59.467049 18.140076 -17.194359 +v -60.637596 17.836807 -17.395412 +v -61.555885 17.887573 -16.361259 +v -60.575226 18.424194 -16.301491 +v -61.644852 17.995667 -15.124073 +v -61.384178 17.674438 -14.016060 +v -61.278061 15.712616 -13.232748 +v -61.481544 16.717255 -13.285177 +v -62.267357 17.018127 -14.111822 +v -62.614960 16.224503 -14.639130 +v -62.204987 15.865005 -13.651415 +v -62.267357 15.277603 -14.745323 +v -61.384178 14.713268 -15.093836 +v -61.481544 14.976719 -13.918678 +v -60.474304 14.817867 -16.190023 +v -59.564423 15.442352 -17.096985 +v -61.644852 15.179428 -16.149099 +v -61.555885 16.057480 -17.027363 +v -60.575226 15.607971 -17.326519 +v -60.637596 16.761108 -17.786934 +v -59.467049 16.399551 -17.827860 +v -61.745773 17.045227 -16.894068 +v -62.368286 17.143402 -15.490303 +v -62.368286 16.067703 -15.881825 +# 762 vertices -# 302 UV coordinates -vt 0.1861920058727264 0.2227180004119873 0 -vt 0.5031800270080566 0.03906299918889999 0 -vt 0.2364480048418045 0.2373390048742294 0 -vt 0.3814640045166016 0.2761969864368439 0 -vt 0.5749170184135437 0.134553998708725 0 -vt 0.7469409704208374 0.1137370020151138 0 -vt 0.07407300174236298 0.3458549976348877 0 -vt 0.04933400079607964 0.5214380025863647 0 -vt 0.1560039967298508 0.4129219949245453 0 -vt 0.1560039967298508 0.6299539804458618 0 -vt 0.3814640045166016 0.8019279837608337 0 -vt 0.3600949943065643 0.5390629768371582 0 -vt 0.6192520260810852 0.384553998708725 0 -vt 0.6192520260810852 0.6935709714889526 0 -vt 0.8223689794540405 0.5390629768371582 0 -vt 0.8340740203857422 0.2890630066394806 0 -vt 1.023437976837158 0.5390629768371582 0 -vt 0.9728180170059204 0.5390629768371582 0 -vt 0.9225059747695923 0.2890630066394806 0 -vt 0.8340740203857422 0.7890629768371582 0 -vt 0.7469409704208374 0.9643880128860474 0 -vt 0.9225059747695923 0.7890629768371582 0 -vt 0.5749170184135437 0.9435709714889526 0 -vt 0.2364480048418045 0.8055369853973389 0 -vt 0.1861920058727264 0.8201580047607422 0 -vt 0.5031800270080566 1.039062976837158 0 -vt 0.2846769988536835 0.8055369853973389 0 -vt 0.6248959898948669 0.8019279837608337 0 -vt 0.7180020213127136 0.9435709714889526 0 -vt 0.8507689833641052 0.6935709714889526 0 -vt 0.646265983581543 0.5390629768371582 0 -vt 0.6248959898948669 0.2761969864368439 0 -vt 0.8507689833641052 0.384553998708725 0 -vt 0.2340410053730011 0.6299539804458618 0 -vt 0.1000450029969215 0.5214380025863647 0 -vt 0.2340410053730011 0.4129219949245453 0 -vt 0.1038810014724731 0.3458549976348877 0 -vt 0.2846769988536835 0.2373390048742294 0 -vt 0.7180020213127136 0.134553998708725 0 -vt 0.02343799918889999 0.5214380025863647 0 -vt 0.07407300174236298 0.6970210075378418 0 -vt 0.1038810014724731 0.6970210075378418 0 -vt -0.06587100028991699 -0.4100160002708435 0 -vt 0.4030880033969879 -0.109436996281147 0 -vt 0.1274410039186478 -0.364995002746582 0 -vt 0.4030880033969879 0.1842669993638992 0 -vt 0.6787350177764893 0.008834999985992908 0 -vt 1.058290958404541 -0.01694799959659576 0 -vt -0.3185659945011139 -0.03083699941635132 0 -vt -0.3557040095329285 0.5098400115966797 0 -vt -0.04291899874806404 0.175683006644249 0 -vt -0.04291899874806404 0.8439980149269104 0 -vt 0.4030880033969879 0.8354139924049377 0 -vt 0.4030880033969879 0.5098400115966797 0 -vt 1.035338997840881 0.3184730112552643 0 -vt 1.035338997840881 0.7012069821357727 0 -vt 1.348124027252197 0.5098400115966797 0 -vt 1.310984969139099 0.06459199637174606 0 -vt 1.481344938278198 0.5098400115966797 0 -vt 1.310984969139099 0.9550889730453491 0 -vt 1.058290958404541 1.03662896156311 0 -vt 0.6787350177764893 1.010846018791199 0 -vt 0.1274410039186478 1.384675025939941 0 -vt -0.06587100028991699 1.429695963859558 0 -vt 0.4030880033969879 1.129117012023926 0 -vt -0.4889250099658966 0.5098400115966797 0 -vt -0.3185659945011139 1.050518035888672 0 -vt 0 1 0 -vt 0 0 0 -vt 0 0.1666669994592667 0 -vt 0.1428570002317429 0.1666669994592667 0 -vt 0.1428570002317429 0 0 -vt 0 0.3333329856395721 0 -vt 0.1428570002317429 0.3333329856395721 0 -vt 0 0.5 0 -vt 0.1428570002317429 0.5 0 -vt 0 0.6666669845581055 0 -vt 0.1428570002317429 0.6666669845581055 0 -vt 0 0.8333330154418945 0 -vt 0.1428570002317429 0.8333330154418945 0 -vt 0.1428570002317429 1 0 -vt 0.2857140004634857 0 0 -vt 0.2857140004634857 0.1666669994592667 0 -vt 0.2857140004634857 0.3333329856395721 0 -vt 0.2857140004634857 0.5 0 -vt 0.2857140004634857 0.6666669845581055 0 -vt 0.2857140004634857 0.8333330154418945 0 -vt 0.2857140004634857 1 0 -vt 0.4285709857940674 0.1666669994592667 0 -vt 0.4285709857940674 0 0 -vt 0.4285709857940674 0.3333329856395721 0 -vt 0.4285709857940674 0.5 0 -vt 0.4285709857940674 0.6666669845581055 0 -vt 0.4285709857940674 0.8333330154418945 0 -vt 0.4285709857940674 1 0 -vt 0.5714290142059326 0 0 -vt 0.5714290142059326 0.1666669994592667 0 -vt 0.5714290142059326 0.3333329856395721 0 -vt 0.5714290142059326 0.5 0 -vt 0.5714290142059326 0.6666669845581055 0 -vt 0.5714290142059326 0.8333330154418945 0 -vt 0.5714290142059326 1 0 -vt 0.7142860293388367 0.1666669994592667 0 -vt 0.7142860293388367 0 0 -vt 0.7142860293388367 0.3333329856395721 0 -vt 0.7142860293388367 0.5 0 -vt 0.7142860293388367 0.6666669845581055 0 -vt 0.7142860293388367 0.8333330154418945 0 -vt 0.7142860293388367 1 0 -vt 0.8571429848670959 0 0 -vt 0.8571429848670959 0.1666669994592667 0 -vt 0.8571429848670959 0.3333329856395721 0 -vt 0.8571429848670959 0.5 0 -vt 0.8571429848670959 0.6666669845581055 0 -vt 0.8571429848670959 0.8333330154418945 0 -vt 0.8571429848670959 1 0 -vt 1 0.1666669994592667 0 -vt 1 0 0 -vt 1 0.3333329856395721 0 -vt 1 0.5 0 -vt 1 0.6666669845581055 0 -vt 1 0.8333330154418945 0 -vt 1 1 0 -vt 0.3329190015792847 0.2726939916610718 0 -vt 0.4468950033187866 0.3977729976177216 0 -vt 0.4569770097732544 0.4220040142536163 0 -vt 0.4028989970684052 0.4104689955711365 0 -vt 0.4066259860992432 0.379391998052597 0 -vt 0.3709700107574463 0.3842439949512482 0 -vt 0.3996250033378601 0.4318499863147736 0 -vt 0.3599070012569427 0.3859829902648926 0 -vt 0.439538985490799 0.4458169937133789 0 -vt 0.3817679882049561 0.3832989931106567 0 -vt 0.4925839900970459 0.4418520033359528 0 -vt 0.420091986656189 0.3782140016555786 0 -vt 0.5188159942626953 0.4229409992694855 0 -vt 0.4460189938545227 0.3745560050010681 0 -vt 0.4984830021858215 0.4033240079879761 0 -vt 0.4400259852409363 0.3750799894332886 0 -vt 0.3448100090026855 0.3380840122699738 0 -vt 0.4880180060863495 0.4240910112857819 0 -vt 0.4631580114364624 0.428277999162674 0 -vt 0.487405002117157 0.409841001033783 0 -vt 0.4343610107898712 0.3930070102214813 0 -vt 0.4332970082759857 0.3810479938983917 0 -vt 0.468531996011734 0.4094749987125397 0 -vt 0.4179730117321014 0.377579003572464 0 -vt 0.4456129968166351 0.4232679903507233 0 -vt 0.3999280035495758 0.3852129876613617 0 -vt 0.4359039962291718 0.4408339858055115 0 -vt 0.392751008272171 0.3982000052928925 0 -vt 0.4467189908027649 0.4489449858665466 0 -vt 0.4018450081348419 0.4067620038986206 0 -vt 0.4699110090732574 0.4414939880371094 0 -vt 0.4203630089759827 0.4044510126113892 0 -vt 0.1903489977121353 0.9132689833641052 0 -vt 0 0.9132689833641052 0 -vt 0.6703060269355774 0.9132689833641052 0 -vt 0.3792589902877808 0.06698700040578842 0 -vt 0.4379310011863708 0.06698700040578842 0 -vt 0.4379310011863708 0.9330130219459534 0 -vt 0.3792589902877808 0.1919869929552078 0 -vt 0.3792589902877808 0.9330130219459534 0 -vt 0.2189649939537048 0.1433759927749634 0 -vt 0.2189649939537048 0.9330130219459534 0 -vt 0 0.1433759927749634 0 -vt 0 0.9330130219459534 0 -vt 0.719871997833252 0.25 0 -vt 0.6568959951400757 0.25 0 -vt 0.8588460087776184 0.3472220003604889 0 -vt 0.3792589902877808 0.25 0 -vt 0 0.2166669964790344 0 -vt 0 0.25 0 -vt 0 0.6800450086593628 0 -vt 0.721310019493103 0.6800450086593628 0 -vt 1 0.6800450086593628 0 -vt 0.8758609890937805 0.5 0 -vt 0.6497269868850708 0.4642859995365143 0 -vt 0.2611050009727478 0.4642859995365143 0 -vt 0 0.4166670143604279 0 -vt 0 0.8146960139274597 0 -vt 0.6703060269355774 0.8146960139274597 0 -vt 0.9116590023040771 0.8146960139274597 0 -vt 0.7585179805755615 0.75 0 -vt 0.5653179883956909 0.7142860293388367 0 -vt 0.2287610024213791 0.7142860293388367 0 -vt 0 0.75 0 -vt 0.2777349948883057 0.5337309837341309 0 -vt 0.3167409896850586 0.5444089770317078 0 -vt 0.3253549933433533 0.5303530097007751 0 -vt 0.3324030041694641 0.5128970146179199 0 -vt 0.419871985912323 0.5059530138969421 0 -vt 0.3902159929275513 0.5307300090789795 0 -vt 0.4765799939632416 0.558493971824646 0 -vt 0.5292080044746399 0.5406749844551086 0 -vt 0.5235919952392578 0.6004890203475952 0 -vt 0.5620089769363403 0.5962309837341309 0 -vt 0.5161960124969482 0.6375470161437988 0 -vt 0.5401409864425659 0.6448410153388977 0 -vt 0.4799120128154755 0.6592649817466736 0 -vt 0.4964070022106171 0.6726189851760864 0 -vt 0.4308049976825714 0.6795639991760254 0 -vt 0.4368790090084076 0.6545109748840332 0 -vt 0.3652040064334869 0.6587309837341309 0 -vt 0.3920060098171234 0.6402639746665955 0 -vt 0.379723995923996 0.6103219985961914 0 -vt 0.3324030041694641 0.6101189851760864 0 -vt 0.3585309982299805 0.5761809945106506 0 -vt 0.2886680066585541 0.5823410153388977 0 -vt 0.445345014333725 0.6860769987106323 0 -vt 0.607125997543335 0.786342978477478 0 -vt 0.8164219856262207 0.6093729734420776 0 -vt 0.9782029986381531 0.754476010799408 0 -vt 0.445345014333725 0.5 0 -vt 0.445345014333725 0.3139230012893677 0 -vt 0.8164219856262207 0.3906269967556 0 -vt 0.1835779994726181 0.69098299741745 0 -vt 0.1835779994726181 0.30901700258255 0 -vt 0.02179699949920177 0.19098299741745 0 -vt 0.2835640013217926 0 0 -vt 0.607125997543335 0.2136570066213608 0 -vt 0.9782029986381531 0.2455240041017532 0 -vt 0.2835640013217926 1 0 -vt 0.02179699949920177 0.80901700258255 0 -vt 1 0.9132689833641052 0 -vt 0.8096510171890259 0.9132689833641052 0 -vt 0.329694002866745 0.9132689833641052 0 -vt 0.5620689988136292 0.06698700040578842 0 -vt 0.6207410097122192 0.06698700040578842 0 -vt 0.5620689988136292 0.9330130219459534 0 -vt 0.6207410097122192 0.1919869929552078 0 -vt 0.6207410097122192 0.9330130219459534 0 -vt 0.7810350060462952 0.1433759927749634 0 -vt 0.7810350060462952 0.9330130219459534 0 -vt 1 0.1433759927749634 0 -vt 1 0.9330130219459534 0 -vt 0.3431040048599243 0.25 0 -vt 0.280128002166748 0.25 0 -vt 0.1411540061235428 0.3472220003604889 0 -vt 0.6207410097122192 0.25 0 -vt 1 0.2166669964790344 0 -vt 1 0.25 0 -vt 0.2786900103092194 0.6800450086593628 0 -vt 0.1241390034556389 0.5 0 -vt 0.3502730131149292 0.4642859995365143 0 -vt 0.7388949990272522 0.4642859995365143 0 -vt 1 0.4166670143604279 0 -vt 0.329694002866745 0.8146960139274597 0 -vt 1 0.8146960139274597 0 -vt 0.08834099769592285 0.8146960139274597 0 -vt 0.2414820045232773 0.75 0 -vt 0.4346820116043091 0.7142860293388367 0 -vt 0.7712389826774597 0.7142860293388367 0 -vt 1 0.75 0 -vt 0.6746450066566467 0.5303530097007751 0 -vt 0.6832590103149414 0.5444089770317078 0 -vt 0.7222650051116943 0.5337309837341309 0 -vt 0.6675969958305359 0.5128970146179199 0 -vt 0.580128014087677 0.5059530138969421 0 -vt 0.6097840070724487 0.5307300090789795 0 -vt 0.523419976234436 0.558493971824646 0 -vt 0.4707919955253601 0.5406749844551086 0 -vt 0.4379909932613373 0.5962309837341309 0 -vt 0.4764080047607422 0.6004890203475952 0 -vt 0.4598590135574341 0.6448410153388977 0 -vt 0.4838039875030518 0.6375470161437988 0 -vt 0.5200880169868469 0.6592649817466736 0 -vt 0.5035930275917053 0.6726189851760864 0 -vt 0.5691949725151062 0.6795639991760254 0 -vt 0.5631210207939148 0.6545109748840332 0 -vt 0.6347960233688354 0.6587309837341309 0 -vt 0.6079949736595154 0.6402639746665955 0 -vt 0.6202759742736816 0.6103219985961914 0 -vt 0.6675969958305359 0.6101189851760864 0 -vt 0.6414690017700195 0.5761809945106506 0 -vt 0.7113320231437683 0.5823410153388977 0 -vt 1.046875 0.7720100283622742 0 -vt 0.9567909836769104 0.7309449911117554 0 -vt 0.8992829918861389 0.9703119993209839 0 -vt 0.9425439834594727 0.8885890245437622 0 -vt 0.7200279831886292 0.9022690057754517 0 -vt 0.7071679830551147 1.046875 0 -vt 0.4538260102272034 0.9313979744911194 0 -vt 0.2154179960489273 0.8448349833488464 0 -vt 0.05815599858760834 0.5868980288505554 0 -vt 0.2360229939222336 0.6679760217666626 0 -vt 0.349481999874115 0.4541139900684357 0 -vt 0.1369580030441284 0.3572390079498291 0 -vt 0.046875 0.3161740005016327 0 -vt 0.3723309934139252 0.1989489942789078 0 -vt 0.4473200142383575 0.046875 0 -vt 0.1944639980792999 0.11786799877882 0 -vt 0.6831830143928528 0.07506199926137924 0 -vt 0.674377977848053 0.1724929958581924 0 -vt 0.8633509874343872 0.4091059863567352 0 -vt 0.9277200102806091 0.287975013256073 0 -vt 0.8783320188522339 0.2433450073003769 0 -vt 1.026785969734192 0.5987160205841064 0 -vt 1.035591959953308 0.5012850165367126 0 -vt 0.8346710205078125 0.6752780079841614 0 -vt 0.5326259732246399 0.7017340064048767 0 -vt 0.6168689727783203 0.4118610024452209 0 +vt 0.186192 0.222718 +vt 0.503180 0.039063 +vt 0.236448 0.237339 +vt 0.381464 0.276197 +vt 0.574917 0.134554 +vt 0.746941 0.113737 +vt 0.074073 0.345855 +vt 0.049334 0.521438 +vt 0.156004 0.412922 +vt 0.156004 0.629954 +vt 0.381464 0.801928 +vt 0.360095 0.539063 +vt 0.619252 0.384554 +vt 0.619252 0.693571 +vt 0.822369 0.539063 +vt 0.834074 0.289063 +vt 1.023438 0.539063 +vt 0.972818 0.539063 +vt 0.922506 0.289063 +vt 0.834074 0.789063 +vt 0.746941 0.964388 +vt 0.922506 0.789063 +vt 0.574917 0.943571 +vt 0.236448 0.805537 +vt 0.186192 0.820158 +vt 0.503180 1.039063 +vt 0.284677 0.805537 +vt 0.624896 0.801928 +vt 0.718002 0.943571 +vt 0.850769 0.693571 +vt 0.646266 0.539063 +vt 0.624896 0.276197 +vt 0.850769 0.384554 +vt 0.234041 0.629954 +vt 0.100045 0.521438 +vt 0.234041 0.412922 +vt 0.103881 0.345855 +vt 0.284677 0.237339 +vt 0.718002 0.134554 +vt 0.023438 0.521438 +vt 0.074073 0.697021 +vt 0.103881 0.697021 +vt -0.065871 -0.410016 +vt 0.403088 -0.109437 +vt 0.127441 -0.364995 +vt 0.403088 0.184267 +vt 0.678735 0.008835 +vt 1.058291 -0.016948 +vt -0.318566 -0.030837 +vt -0.355704 0.509840 +vt -0.042919 0.175683 +vt -0.042919 0.843998 +vt 0.403088 0.835414 +vt 0.403088 0.509840 +vt 1.035339 0.318473 +vt 1.035339 0.701207 +vt 1.348124 0.509840 +vt 1.310985 0.064592 +vt 1.481345 0.509840 +vt 1.310985 0.955089 +vt 1.058291 1.036629 +vt 0.678735 1.010846 +vt 0.127441 1.384675 +vt -0.065871 1.429696 +vt 0.403088 1.129117 +vt -0.488925 0.509840 +vt -0.318566 1.050518 +vt 0.000000 1.000000 +vt 0.000000 0.000000 +vt 0.000000 0.166667 +vt 0.142857 0.166667 +vt 0.142857 0.000000 +vt 0.000000 0.333333 +vt 0.142857 0.333333 +vt 0.000000 0.500000 +vt 0.142857 0.500000 +vt 0.000000 0.666667 +vt 0.142857 0.666667 +vt 0.000000 0.833333 +vt 0.142857 0.833333 +vt 0.142857 1.000000 +vt 0.285714 0.000000 +vt 0.285714 0.166667 +vt 0.285714 0.333333 +vt 0.285714 0.500000 +vt 0.285714 0.666667 +vt 0.285714 0.833333 +vt 0.285714 1.000000 +vt 0.428571 0.166667 +vt 0.428571 0.000000 +vt 0.428571 0.333333 +vt 0.428571 0.500000 +vt 0.428571 0.666667 +vt 0.428571 0.833333 +vt 0.428571 1.000000 +vt 0.571429 0.000000 +vt 0.571429 0.166667 +vt 0.571429 0.333333 +vt 0.571429 0.500000 +vt 0.571429 0.666667 +vt 0.571429 0.833333 +vt 0.571429 1.000000 +vt 0.714286 0.166667 +vt 0.714286 0.000000 +vt 0.714286 0.333333 +vt 0.714286 0.500000 +vt 0.714286 0.666667 +vt 0.714286 0.833333 +vt 0.714286 1.000000 +vt 0.857143 0.000000 +vt 0.857143 0.166667 +vt 0.857143 0.333333 +vt 0.857143 0.500000 +vt 0.857143 0.666667 +vt 0.857143 0.833333 +vt 0.857143 1.000000 +vt 1.000000 0.166667 +vt 1.000000 0.000000 +vt 1.000000 0.333333 +vt 1.000000 0.500000 +vt 1.000000 0.666667 +vt 1.000000 0.833333 +vt 1.000000 1.000000 +vt 0.332919 0.272694 +vt 0.446895 0.397773 +vt 0.456977 0.422004 +vt 0.402899 0.410469 +vt 0.406626 0.379392 +vt 0.370970 0.384244 +vt 0.399625 0.431850 +vt 0.359907 0.385983 +vt 0.439539 0.445817 +vt 0.381768 0.383299 +vt 0.492584 0.441852 +vt 0.420092 0.378214 +vt 0.518816 0.422941 +vt 0.446019 0.374556 +vt 0.498483 0.403324 +vt 0.440026 0.375080 +vt 0.344810 0.338084 +vt 0.488018 0.424091 +vt 0.463158 0.428278 +vt 0.487405 0.409841 +vt 0.434361 0.393007 +vt 0.433297 0.381048 +vt 0.468532 0.409475 +vt 0.417973 0.377579 +vt 0.445613 0.423268 +vt 0.399928 0.385213 +vt 0.435904 0.440834 +vt 0.392751 0.398200 +vt 0.446719 0.448945 +vt 0.401845 0.406762 +vt 0.469911 0.441494 +vt 0.420363 0.404451 +vt 0.190349 0.913269 +vt 0.000000 0.913269 +vt 0.670306 0.913269 +vt 0.379259 0.066987 +vt 0.437931 0.066987 +vt 0.437931 0.933013 +vt 0.379259 0.191987 +vt 0.379259 0.933013 +vt 0.218965 0.143376 +vt 0.218965 0.933013 +vt 0.000000 0.143376 +vt 0.000000 0.933013 +vt 0.719872 0.250000 +vt 0.656896 0.250000 +vt 0.858846 0.347222 +vt 0.379259 0.250000 +vt 0.000000 0.216667 +vt 0.000000 0.250000 +vt 0.000000 0.680045 +vt 0.721310 0.680045 +vt 1.000000 0.680045 +vt 0.875861 0.500000 +vt 0.649727 0.464286 +vt 0.261105 0.464286 +vt 0.000000 0.416667 +vt 0.000000 0.814696 +vt 0.670306 0.814696 +vt 0.911659 0.814696 +vt 0.758518 0.750000 +vt 0.565318 0.714286 +vt 0.228761 0.714286 +vt 0.000000 0.750000 +vt 0.277735 0.533731 +vt 0.316741 0.544409 +vt 0.325355 0.530353 +vt 0.332403 0.512897 +vt 0.419872 0.505953 +vt 0.390216 0.530730 +vt 0.476580 0.558494 +vt 0.529208 0.540675 +vt 0.523592 0.600489 +vt 0.562009 0.596231 +vt 0.516196 0.637547 +vt 0.540141 0.644841 +vt 0.479912 0.659265 +vt 0.496407 0.672619 +vt 0.430805 0.679564 +vt 0.436879 0.654511 +vt 0.365204 0.658731 +vt 0.392006 0.640264 +vt 0.379724 0.610322 +vt 0.332403 0.610119 +vt 0.358531 0.576181 +vt 0.288668 0.582341 +vt 0.445345 0.686077 +vt 0.607126 0.786343 +vt 0.816422 0.609373 +vt 0.978203 0.754476 +vt 0.445345 0.500000 +vt 0.445345 0.313923 +vt 0.816422 0.390627 +vt 0.183578 0.690983 +vt 0.183578 0.309017 +vt 0.021797 0.190983 +vt 0.283564 0.000000 +vt 0.607126 0.213657 +vt 0.978203 0.245524 +vt 0.283564 1.000000 +vt 0.021797 0.809017 +vt 1.000000 0.913269 +vt 0.809651 0.913269 +vt 0.329694 0.913269 +vt 0.562069 0.066987 +vt 0.620741 0.066987 +vt 0.562069 0.933013 +vt 0.620741 0.191987 +vt 0.620741 0.933013 +vt 0.781035 0.143376 +vt 0.781035 0.933013 +vt 1.000000 0.143376 +vt 1.000000 0.933013 +vt 0.343104 0.250000 +vt 0.280128 0.250000 +vt 0.141154 0.347222 +vt 0.620741 0.250000 +vt 1.000000 0.216667 +vt 1.000000 0.250000 +vt 0.278690 0.680045 +vt 0.124139 0.500000 +vt 0.350273 0.464286 +vt 0.738895 0.464286 +vt 1.000000 0.416667 +vt 0.329694 0.814696 +vt 1.000000 0.814696 +vt 0.088341 0.814696 +vt 0.241482 0.750000 +vt 0.434682 0.714286 +vt 0.771239 0.714286 +vt 1.000000 0.750000 +vt 0.674645 0.530353 +vt 0.683259 0.544409 +vt 0.722265 0.533731 +vt 0.667597 0.512897 +vt 0.580128 0.505953 +vt 0.609784 0.530730 +vt 0.523420 0.558494 +vt 0.470792 0.540675 +vt 0.437991 0.596231 +vt 0.476408 0.600489 +vt 0.459859 0.644841 +vt 0.483804 0.637547 +vt 0.520088 0.659265 +vt 0.503593 0.672619 +vt 0.569195 0.679564 +vt 0.563121 0.654511 +vt 0.634796 0.658731 +vt 0.607995 0.640264 +vt 0.620276 0.610322 +vt 0.667597 0.610119 +vt 0.641469 0.576181 +vt 0.711332 0.582341 +vt 1.046875 0.772010 +vt 0.956791 0.730945 +vt 0.899283 0.970312 +vt 0.942544 0.888589 +vt 0.720028 0.902269 +vt 0.707168 1.046875 +vt 0.453826 0.931398 +vt 0.215418 0.844835 +vt 0.058156 0.586898 +vt 0.236023 0.667976 +vt 0.349482 0.454114 +vt 0.136958 0.357239 +vt 0.046875 0.316174 +vt 0.372331 0.198949 +vt 0.447320 0.046875 +vt 0.194464 0.117868 +vt 0.683183 0.075062 +vt 0.674378 0.172493 +vt 0.863351 0.409106 +vt 0.927720 0.287975 +vt 0.878332 0.243345 +vt 1.026786 0.598716 +vt 1.035592 0.501285 +vt 0.834671 0.675278 +vt 0.532626 0.701734 +vt 0.616869 0.411861 +# 302 texture coordinates -# 747 vertex normals -vn -0.5375880002975464 -0.07179799675941467 0.840146005153656 -vn -0.1515550017356873 -0.01711099967360497 0.9883009791374207 -vn -0.510263979434967 0.3471930027008057 0.7868220210075378 -vn -0.383882999420166 0.7247530221939087 0.572160005569458 -vn 0.006790999788790941 0.5470830202102661 0.8370509743690491 -vn 0.4419640004634857 0.160861998796463 0.8824920058250427 -vn -0.8104130029678345 0.1847179979085922 0.5559759736061096 -vn -0.9155340194702148 0.4022400081157684 0 -vn -0.710112988948822 0.6201850175857544 0.3333309888839722 -vn -0.7216730117797852 0.6078910231590271 -0.3311449885368347 -vn -0.4136289954185486 0.7018579840660095 -0.5799199938774109 -vn -0.4094110131263733 0.9123499989509583 0.0004339999868534505 -vn 0.1323229968547821 0.9380099773406982 0.3203549981117249 -vn 0.1323229968547821 0.9380099773406982 -0.3203549981117249 -vn 0.3397679924964905 0.940509021282196 0 -vn 0.4818519949913025 0.6178590059280396 0.6213449835777283 -vn 0.8813369870185852 0.4724879860877991 0 -vn 0.9429519772529602 -0.3329299986362457 0 -vn 0.7952039837837219 -0.09252200275659561 0.5992419719696045 -vn 0.4818519949913025 0.6178590059280396 -0.6213449835777283 -vn 0.4419640004634857 0.160861998796463 -0.8824920058250427 -vn 0.7952039837837219 -0.09252200275659561 -0.5992419719696045 -vn -0.01252099964767694 0.539700984954834 -0.841763973236084 -vn -0.5448579788208008 0.3272939920425415 -0.7720159888267517 -vn -0.5613030195236206 -0.07517900317907333 -0.8241890072822571 -vn -0.1957750022411346 -0.0270760003477335 -0.9802749752998352 -vn -0.2998470067977905 -0.5292649865150452 -0.793707013130188 -vn 0.1448850035667419 -0.802478015422821 -0.578823983669281 -vn 0.343163013458252 -0.4203700125217438 -0.8399569988250732 -vn 0.7043060064315796 -0.6335020065307617 -0.3203549981117249 -vn 0.2609860002994537 -0.9653429985046387 0.0003220000071451068 -vn 0.173225998878479 -0.8032519817352295 0.569894015789032 -vn 0.7043060064315796 -0.6335020065307617 0.3203549981117249 -vn -0.3462300002574921 -0.8729979991912842 -0.3435100018978119 -vn -0.769195020198822 -0.6390140056610107 0 -vn -0.334289014339447 -0.8776149749755859 0.3435750007629395 -vn -0.7281039953231812 -0.4009419977664948 0.5559759736061096 -vn -0.2649039924144745 -0.5273450016975403 0.8072999715805054 -vn 0.3593209981918335 -0.4139899909496307 0.8363620042800903 -vn -0.9902679920196533 -0.1391730010509491 -0 -vn -0.8104130029678345 0.1847179979085922 -0.5559759736061096 -vn -0.7281039953231812 -0.4009419977664948 -0.5559759736061096 -vn -0.2362789958715439 0.02918500080704689 0.9712470173835754 -vn 0.3209069967269897 -0.1081760004162788 0.9409130215644836 -vn 0.2328509986400604 0.4920690059661865 0.8388379812240601 -vn 0.4011589884757996 0.816008985042572 0.4161730110645294 -vn 0.3620760142803192 0.3835749924182892 0.8495709896087646 -vn 0.1260980069637299 -0.04097200185060501 0.9911710023880005 -vn -0.604686975479126 0.6148959994316101 0.5062180161476135 -vn -0.4789099991321564 0.8778640031814575 0 -vn 0.03857599943876266 0.9693480134010315 0.2426449954509735 -vn 0.03857599943876266 0.9693480134010315 -0.2426449954509735 -vn 0.4011589884757996 0.816008985042572 -0.4161730110645294 -vn 0.3609150052070618 0.9325990080833435 0 -vn 0.4944109916687012 0.798675000667572 0.3430379927158356 -vn 0.4944109916687012 0.798675000667572 -0.3430379927158356 -vn 0.8612650036811829 0.5081560015678406 0 -vn 0.6479099988937378 0.2460869997739792 0.7208700180053711 -vn 0.9510570168495178 -0.30901700258255 0 -vn 0.7433170080184937 -0.668940007686615 0 -vn 0.5354629755020142 -0.3628270030021667 0.7626510262489319 -vn 0.6479099988937378 0.2460860013961792 -0.7208700180053711 -vn 0.1260980069637299 -0.04097200185060501 -0.9911710023880005 -vn 0.5354629755020142 -0.3628270030021667 -0.7626510262489319 -vn 0.3620760142803192 0.3835749924182892 -0.8495709896087646 -vn 0.2328509986400604 0.4920690059661865 -0.8388379812240601 -vn -0.2362789958715439 0.02918500080704689 -0.9712470173835754 -vn 0.3209069967269897 -0.1081760004162788 -0.9409130215644836 -vn 0.1329340040683746 -0.4152190089225769 -0.8999559879302979 -vn 0.1888570040464401 -0.9709110260009766 -0.1471920013427734 -vn 0.1993210017681122 -0.4351809918880463 -0.8780030012130737 -vn -0.8620179891586304 0.08302299678325653 0.5000320076942444 -vn 0.1329340040683746 -0.4152190089225769 0.8999559879302979 -vn 0.1993210017681122 -0.4351809918880463 0.8780019879341125 -vn 0.1888570040464401 -0.9709110260009766 0.1471920013427734 -vn -0.9302049875259399 0.3670400083065033 0 -vn -0.9976400136947632 0.0686580017209053 0 -vn -0.604686975479126 0.6148959994316101 -0.5062180161476135 -vn -0.8620179891586304 0.08302299678325653 -0.5000320076942444 -vn 0.02138300053775311 -0.9165120124816895 0.3994359970092773 -vn -0.7818620204925537 -0.4315609931945801 -0.4499419927597046 -vn 0.9563360214233398 0.2284609973430634 -0.1822829991579056 -vn 0.8339009881019592 -0.1045610010623932 -0.5419189929962158 -vn 0.767799973487854 0.6018419861793518 0.2197020053863525 -vn 0.5461239814758301 0.7825490236282349 0.2989400029182434 -vn 0.9109249711036682 0.174918994307518 -0.3736560046672821 -vn 0.7487580180168152 0.6616759896278381 -0.03931299969553947 -vn 0.949258029460907 -0.04748500138521194 -0.3108929991722107 -vn 0.4068360030651093 0.8022599816322327 -0.4368790090084076 -vn 0.7691559791564941 0.182668998837471 -0.6123980283737183 -vn 0.1995120048522949 0.6090829968452454 -0.7676020264625549 -vn 0.6676030158996582 0.001959000015631318 -0.7445150017738342 -vn -0.0993880033493042 0.4149369895458221 -0.9044049978256226 -vn 0.3527739942073822 0.07949899882078171 -0.932325005531311 -vn -0.2833180129528046 0.4208430051803589 -0.8617550134658813 -vn -0.05747900158166885 0.8575270175933838 0.5112180113792419 -vn 0.1317239999771118 0.7430220246315002 0.6561769843101501 -vn -0.005809000227600336 0.8595520257949829 0.5110160112380981 -vn -0.3505710065364838 0.931430995464325 -0.09765499830245972 -vn -0.6476929783821106 0.6648160219192505 -0.372173011302948 -vn -0.8983089923858643 0.4048080146312714 -0.1707939952611923 -vn -0.8662490248680115 0.4800429940223694 -0.1384589970111847 -vn -0.7151209712028503 0.3602499961853027 0.5990179777145386 -vn -0.8666250109672546 0.3417699933052063 0.3635300099849701 -vn -0.6623769998550415 0.2970130145549774 0.6877800226211548 -vn -0.8117250204086304 0.3888390064239502 0.4357819855213165 -vn -0.9508990049362183 0.2433879971504211 0.1911900043487549 -vn -0.8467730283737183 0.07804299890995026 0.5261989831924438 -vn -0.7594159841537476 0.1409499943256378 0.6351540088653564 -vn -0.9400110244750977 -0.3405149877071381 -0.02069300040602684 -vn -0.9724000096321106 -0.2049909979104996 0.1114299967885017 -vn -0.8170300126075745 -0.3317660093307495 0.4715850055217743 -vn -0.6166999936103821 -0.3858979940414429 0.6861220002174377 -vn -0.5654150247573853 -0.4132109880447388 0.7138370275497437 -vn -0.3424369990825653 -0.3165769875049591 0.884598970413208 -vn -0.2633169889450073 -0.3102239966392517 0.9134690165519714 -vn -0.4920729994773865 -0.6772800087928772 -0.5469520092010498 -vn -0.2165350019931793 -0.8325880169868469 -0.5098140239715576 -vn -0.336313009262085 -0.9366880059242249 -0.09751000255346298 -vn 0.08508399873971939 -0.8829479813575745 0.4616970121860504 -vn 0.1960570067167282 -0.7339509725570679 0.6502910256385803 -vn 0.454815000295639 -0.6157029867172241 0.6434699892997742 -vn 0.4893380105495453 -0.7108240127563477 0.5052499771118164 -vn 0.4581849873065948 -0.6546030044555664 -0.6013000011444092 -vn 0.2736169993877411 -0.5752760171890259 -0.7708380222320557 -vn 0.5572580099105835 -0.6418589949607849 -0.526764988899231 -vn 0.7707909941673279 -0.6368250250816345 0.01830600015819073 -vn 0.8732380270957947 -0.4872829914093018 0.003169999923557043 -vn 0.8787599802017212 -0.285726010799408 -0.3822849988937378 -vn 0.7752519845962524 -0.4531359970569611 -0.4400599896907806 -vn 0.07676800340414047 -0.9022539854049683 -0.4243170022964478 -vn -0.7608579993247986 -0.310029000043869 0.5700669884681702 -vn 0.6989830136299133 0.6327279806137085 -0.333285003900528 -vn 0.9189450144767761 -0.0186110008507967 0.3939450085163116 -vn 0.9469230175018311 0.2427060008049011 0.2107869982719421 -vn 0.5977060198783875 0.7759019732475281 -0.2018010020256042 -vn 0.8984569907188416 0.3959749937057495 0.1896820068359375 -vn 0.5849769711494446 0.7775779962539673 -0.2305970042943954 -vn 0.06112100183963776 0.8655030131340027 0.4971610009670258 -vn 0.81489098072052 0.173455998301506 0.5530520081520081 -vn 0.488323986530304 0.05219599977135658 0.8711000084877014 -vn -0.07333800196647644 0.3724580109119415 0.9251469969749451 -vn -0.1685570031404495 0.420635998249054 0.8914330005645752 -vn 0.5626059770584106 0.01164999976754189 0.8266429901123047 -vn 0.424549013376236 0.2200690060853958 0.8782529830932617 -vn -0.2022739946842194 0.5748890042304993 0.792834997177124 -vn -0.2014950066804886 0.8707110285758972 -0.4486219882965088 -vn -0.1475190073251724 0.7000659704208374 -0.6986740231513977 -vn -0.247406005859375 0.6800289750099182 -0.6901819705963135 -vn -0.6592289805412292 0.7426900267601013 -0.1175960004329681 -vn -0.8238279819488525 0.5144019722938538 0.2381149977445602 -vn -0.8807550072669983 0.462224006652832 0.1030530035495758 -vn -0.8354460000991821 0.5381479859352112 0.1114759966731071 -vn -0.8354330062866211 0.2911489903926849 -0.4661380052566528 -vn -0.7990170121192932 0.4768629968166351 -0.3662959933280945 -vn -0.7965649962425232 -0.008375000208616257 -0.6044949889183044 -vn -0.7460759878158569 0.1244580000638962 -0.654125988483429 -vn -0.8470270037651062 0.2575120031833649 -0.4650079905986786 -vn -0.7743350267410278 0.09411299973726273 -0.6257380247116089 -vn -0.7994340062141418 0.06731099635362625 -0.5969709753990173 -vn -0.914825975894928 -0.4032889902591705 0.0212399996817112 -vn -0.9607080221176147 -0.2765470147132874 0.02371999993920326 -vn -0.7760940194129944 -0.562736988067627 -0.2846130132675171 -vn -0.2481050044298172 -0.5148569941520691 -0.820589005947113 -vn -0.2315990030765533 -0.2342070043087006 -0.9441980123519897 -vn -0.2359499931335449 -0.3241190016269684 -0.9161189794540405 -vn -0.3423370122909546 -0.4482719898223877 -0.825747013092041 -vn -0.3890469968318939 -0.6779909729957581 0.6236749887466431 -vn -0.2865490019321442 -0.8684669733047485 0.4045419991016388 -vn -0.05829200148582458 -0.911346971988678 0.407490998506546 -vn 0.4559510052204132 -0.7950720191001892 -0.3999620079994202 -vn 0.4897150099277496 -0.5246649980545044 -0.6963520050048828 -vn 0.5158429741859436 -0.6365799903869629 -0.5733000040054321 -vn 0.423911988735199 -0.8095009922981262 -0.4062100052833557 -vn 0.5356029868125916 -0.6355810165405273 0.5560269951820374 -vn 0.4908620119094849 -0.4675160050392151 0.7351760268211365 -vn 0.7313770055770874 -0.3685759902000427 0.5737929940223694 -vn 0.8901190161705017 -0.3876970112323761 0.2395379990339279 -vn 0.8836299777030945 -0.404119998216629 0.2363989949226379 -vn 0.8226990103721619 -0.324539989233017 0.4667330086231232 -vn 0.7892469763755798 -0.4085890054702759 0.4584139883518219 -vn -0.07298800349235535 -0.9022539854049683 0.4249840080738068 -vn -0.2881479859352112 -0.512224018573761 -0.8090720176696777 -vn 0.9188060164451599 0.3839870095252991 0.09137199819087982 -vn 0.993162989616394 0.114096000790596 -0.02468799985945225 -vn 0.4343830049037933 0.7090979814529419 0.5554199814796448 -vn 0.4718630015850067 0.8051769733428955 0.3592160046100616 -vn 0.8680509924888611 0.4418930113315582 0.2263129949569702 -vn 0.3869659900665283 0.8111780285835266 0.4384610056877136 -vn 0.9717289805412292 0.2360440045595169 0.005162999965250492 -vn 0.2779389917850494 0.90385901927948 -0.3252519965171814 -vn 0.9075610041618347 0.1839890033006668 -0.377467006444931 -vn 0.3897979855537415 0.4576799869537354 -0.7991160154342651 -vn 0.9741809964179993 -0.04597700014710426 -0.2210370004177094 -vn 0.4417490065097809 0.2665829956531525 -0.8566160202026367 -vn 0.8866739869117737 0.01747499965131283 -0.4620650112628937 -vn 0.3720920085906982 0.3275539875030518 -0.8684790134429932 -vn -0.3850800096988678 0.8340460062026978 0.3950709998607635 -vn -0.4761059880256653 0.6599609851837158 0.581184983253479 -vn -0.5561609864234924 0.6855729818344116 0.4697610139846802 -vn -0.6268590092658997 0.7454360127449036 -0.2266560047864914 -vn -0.5542709827423096 0.4361459910869598 -0.7089149951934814 -vn -0.5615590214729309 0.3103019893169403 -0.7670490145683289 -vn -0.5438100099563599 0.4169149994850159 -0.7283220291137695 -vn -0.9747139811515808 0.1763579994440079 0.1372230052947998 -vn -0.9172520041465759 0.3692820072174072 0.1492629945278168 -vn -0.9827640056610107 -0.03630400076508522 0.1812669932842255 -vn -0.9872050285339355 0.07037699967622757 0.1430840045213699 -vn -0.9887080192565918 0.09066099673509598 -0.119318999350071 -vn -0.9954649806022644 0.06980500370264053 -0.0646279975771904 -vn -0.9868990182876587 0.1531080007553101 -0.0508820004761219 -vn -0.7857019901275635 -0.5462189912796021 -0.2903740108013153 -vn -0.8021669983863831 -0.4474230110645294 -0.3953999876976013 -vn -0.7882999777793884 -0.6091880202293396 -0.08644299954175949 -vn -0.6353080272674561 -0.5868319869041443 0.5020080208778381 -vn -0.7489200234413147 -0.3426479995250702 0.5671960115432739 -vn -0.8290749788284302 -0.1998199969530106 0.5222129821777344 -vn -0.8114089965820312 -0.2435930073261261 0.5312989950180054 -vn -0.02972600050270557 -0.7129759788513184 -0.7005580067634583 -vn -0.1212550029158592 -0.8703849911689758 -0.4772070050239563 -vn 0.1511760056018829 -0.9298509955406189 -0.3354449868202209 -vn 0.2028409987688065 -0.8257309794425964 0.5263310074806213 -vn 0.08091399818658829 -0.5281829833984375 0.8452659845352173 -vn 0.01067500002682209 -0.4742409884929657 0.8803300261497498 -vn 0.0144889997318387 -0.6355460286140442 0.7719269990921021 -vn 0.7427240014076233 -0.5451459884643555 -0.3888140022754669 -vn 0.7865099906921387 -0.3833020031452179 -0.4842329919338226 -vn 0.9205939769744873 -0.3581419885158539 -0.1556950062513351 -vn 0.8897669911384583 -0.3594259917736053 0.2812969982624054 -vn 0.8730049729347229 -0.2942259907722473 0.3889650106430054 -vn 0.9076560139656067 -0.2917299866676331 0.3017520010471344 -vn 0.8630970120429993 -0.4457089900970459 0.2375019937753677 -vn 0.04144300147891045 -0.9088649749755859 -0.415026992559433 -vn -0.1099570021033287 -0.08454799652099609 0.9903339743614197 -vn 0.2451310008764267 0.7632600069046021 -0.5977830290794373 -vn 0.9554449915885925 0.2843270003795624 -0.07926099747419357 -vn 0.8238049745559692 0.5351709723472595 -0.1869129985570908 -vn 0.2853530049324036 0.8679130077362061 -0.4065710008144379 -vn 0.7501500248908997 0.5809810161590576 -0.3158090114593506 -vn 0.193001002073288 0.8577240109443665 -0.4765090048313141 -vn 0.1220619976520538 0.9612579941749573 0.2471510022878647 -vn 0.8907639980316162 0.4299469888210297 -0.147257000207901 -vn 0.8693600296974182 0.404801994562149 0.2834579944610596 -vn 0.3425579965114594 0.6023179888725281 0.7210180163383484 -vn 0.4495930075645447 0.5570510029792786 0.6982550024986267 -vn 0.9799709916114807 0.1605979949235916 0.1177510023117065 -vn 0.9129520058631897 0.3300270140171051 0.2400040030479431 -vn 0.3969599902629852 0.7427070140838623 0.5392670035362244 -vn -0.5626519918441772 0.7477009892463684 -0.3526549935340881 -vn -0.640733003616333 0.5571630001068115 -0.5282340049743652 -vn -0.7121180295944214 0.5705819725990295 -0.4090529978275299 -vn -0.7194139957427979 0.6329879760742188 0.2859529852867126 -vn -0.5416349768638611 0.3929080069065094 0.7431390285491943 -vn -0.5068719983100891 0.4453279972076416 0.7380809783935547 -vn -0.5300359725952148 0.6580139994621277 0.5348640084266663 -vn -0.9993979930877686 0.002857000101357698 -0.03458600118756294 -vn -0.9778590202331543 0.2025559991598129 -0.05256599932909012 -vn -0.9748870134353638 -0.2087630033493042 -0.07754799723625183 -vn -0.9908090233802795 -0.1349709928035736 -0.00891099963337183 -vn -0.9714679718017578 -0.08408299833536148 0.2217649966478348 -vn -0.9839869737625122 -0.0358319990336895 0.1746020019054413 -vn -0.9879299998283386 0.05565499886870384 0.1445589959621429 -vn -0.6447849869728088 -0.6683390140533447 0.3709119856357574 -vn -0.6672559976577759 -0.5719799995422363 0.4770840108394623 -vn -0.6573889851570129 -0.7345010042190552 0.1683689951896667 -vn -0.5605350136756897 -0.7363070249557495 -0.3790149986743927 -vn -0.692903995513916 -0.5403270125389099 -0.4774209856987 -vn -0.805446982383728 -0.4507080018520355 -0.3848600089550018 -vn -0.8070970177650452 -0.5522969961166382 -0.2087150067090988 -vn 0.1668089926242828 -0.6945620179176331 0.699828028678894 -vn 0.08150500059127808 -0.8694409728050232 0.4872680008411407 -vn 0.3440600037574768 -0.8835279941558838 0.3178069889545441 -vn 0.3032650053501129 -0.806547999382019 -0.5074549913406372 -vn 0.1325059980154037 -0.5874869823455811 -0.7983120083808899 -vn 0.02260999940335751 -0.6936299800872803 -0.719976007938385 -vn 0.04509999975562096 -0.9239140152931213 -0.3799329996109009 -vn 0.8621219992637634 -0.401540994644165 0.3090479969978333 -vn 0.8867239952087402 -0.2328619956970215 0.3993679881095886 -vn 0.9798589944839478 -0.1908919960260391 0.05861499905586243 -vn 0.9012619853019714 -0.1982769966125488 -0.3852449953556061 -vn 0.8543739914894104 -0.1819390058517456 -0.4867680072784424 -vn 0.9012380242347717 -0.2525070011615753 -0.3521510064601898 -vn 0.8982779979705811 -0.4129990041255951 -0.1500930041074753 -vn -0.272473007440567 -0.9165120124816895 -0.2928540110588074 -vn 0.2474620044231415 -0.4315969944000244 0.8674600124359131 -vn 0.3753190040588379 0.6018419861793518 -0.7049270272254944 -vn 0.9690999984741211 -0.1045589968562126 -0.2234120070934296 -vn 0.7954490184783936 0.2284629940986633 -0.5613070130348206 -vn 0.1643320024013519 0.7825480103492737 -0.6005110144615173 -vn 0.9015669822692871 0.174918994307518 -0.395700991153717 -vn 0.5484110116958618 0.6616759896278381 -0.5113030076026917 -vn 0.596875011920929 0.8022609949111938 0.01082899980247021 -vn 0.8830479979515076 -0.04748399928212166 -0.4668749868869781 -vn 0.9758470058441162 0.1404889971017838 -0.1672890037298203 -vn 0.6950060129165649 0.6005629897117615 0.3953349888324738 -vn 0.8043910264968872 0.3754850029945374 0.4603970050811768 -vn 0.9504550099372864 -0.06233000010251999 -0.3045510053634644 -vn 0.9899749755859375 0.07949800044298172 -0.1167469993233681 -vn 0.7676119804382324 0.4208459854125977 0.4833849966526031 -vn -0.4076670110225677 0.8575270175933838 -0.3137750029563904 -vn -0.3805089890956879 0.7430220246315002 -0.550574004650116 -vn -0.371628999710083 0.8595520257949829 -0.3508029878139496 -vn -0.1732809990644455 0.931430995464325 0.320017009973526 -vn -0.08834400027990341 0.681833028793335 0.7261540293693542 -vn -0.09786199778318405 0.460783988237381 0.882099986076355 -vn -0.07521700114011765 0.4800420105457306 0.8740149736404419 -vn -0.9276620149612427 0.3602499961853027 0.09830199927091599 -vn -0.8635100126266479 0.3417719900608063 0.3708679974079132 -vn -0.9548730254173279 0.2970120012760162 -0.001296999980695546 -vn -0.877348005771637 0.388837993144989 0.2811869978904724 -vn -0.7982050180435181 0.2586430013179779 0.5440329909324646 -vn -0.8309450149536133 0.1299329996109009 0.5409700274467468 -vn -0.80000901222229 0.1409460008144379 0.5831969976425171 -vn -0.6381030082702637 -0.3405129909515381 0.6905620098114014 -vn -0.7556419968605042 -0.2049909979104996 0.6220800280570984 -vn -0.9067860245704651 -0.3317669928073883 0.2601329982280731 -vn -0.9219499826431274 -0.3858990073204041 -0.03300400078296661 -vn -0.9323030114173889 -0.3608480095863342 -0.02450799942016602 -vn -0.9716429710388184 -0.2363799959421158 0.005919000133872032 -vn -0.9500359892845154 -0.3102270066738129 0.03450300171971321 -vn 0.05162100121378899 -0.6772800087928772 0.7339119911193848 -vn 0.2163099944591522 -0.8325870037078857 0.509909987449646 -vn -0.1634809970855713 -0.9366880059242249 0.3096620142459869 -vn -0.2730129957199097 -0.8829479813575745 -0.3819249868392944 -vn -0.3344889879226685 -0.7286760210990906 -0.5976189970970154 -vn -0.4082350134849548 -0.6025800108909607 -0.6857410073280334 -vn -0.3718569874763489 -0.7108250260353088 -0.5970349907875061 -vn 0.7508220076560974 -0.6546019911766052 0.08810699731111526 -vn 0.7445650100708008 -0.5752760171890259 0.3386459946632385 -vn 0.7660269737243652 -0.6418589949607849 -0.03493599966168404 -vn 0.5222679972648621 -0.6368250250816345 -0.5671759843826294 -vn 0.5276669859886169 -0.5274670124053955 -0.6658419966697693 -vn 0.6410369873046875 -0.3752210140228271 -0.6695380210876465 -vn 0.6145420074462891 -0.4531340003013611 -0.6457610130310059 -vn -0.2724759876728058 -0.9165120124816895 0.2928540110588074 -vn 0.2474450021982193 -0.4315490126609802 -0.8674880266189575 -vn 0.7954490184783936 0.2284629940986633 0.5613070130348206 -vn 0.9690999984741211 -0.1045589968562126 0.2234120070934296 -vn 0.3753179907798767 0.6018419861793518 0.7049270272254944 -vn 0.1643320024013519 0.7825480103492737 0.6005110144615173 -vn 0.9015669822692871 0.174918994307518 0.395700991153717 -vn 0.5484099984169006 0.6616759896278381 0.5113030076026917 -vn 0.8830469846725464 -0.04748500138521194 0.4668749868869781 -vn 0.596875011920929 0.8022609949111938 -0.01082899980247021 -vn 0.9758470058441162 0.1404889971017838 0.1672890037298203 -vn 0.6950060129165649 0.6005640029907227 -0.3953360021114349 -vn 0.9504539966583252 -0.06233000010251999 0.3045510053634644 -vn 0.8043910264968872 0.3754850029945374 -0.4603970050811768 -vn 0.9899749755859375 0.07949800044298172 0.1167469993233681 -vn 0.767611026763916 0.4208459854125977 -0.4833849966526031 -vn -0.4076670110225677 0.8575270175933838 0.3137750029563904 -vn -0.3805089890956879 0.7430220246315002 0.550574004650116 -vn -0.371628999710083 0.8595520257949829 0.3508029878139496 -vn -0.1732809990644455 0.931430995464325 -0.320017009973526 -vn -0.0883449986577034 0.681833028793335 -0.7261540293693542 -vn -0.09786199778318405 0.460783988237381 -0.882099986076355 -vn -0.07521700114011765 0.4800420105457306 -0.8740149736404419 -vn -0.9276620149612427 0.3602499961853027 -0.09830199927091599 -vn -0.8635100126266479 0.3417719900608063 -0.3708679974079132 -vn -0.9548730254173279 0.2970120012760162 0.001296999980695546 -vn -0.877348005771637 0.388837993144989 -0.2811869978904724 -vn -0.7982050180435181 0.2586430013179779 -0.5440329909324646 -vn -0.8309450149536133 0.1299329996109009 -0.5409700274467468 -vn -0.8000100255012512 0.1409450024366379 -0.5831959843635559 -vn -0.6381030082702637 -0.3405129909515381 -0.6905620098114014 -vn -0.7556419968605042 -0.2049909979104996 -0.6220809817314148 -vn -0.9067860245704651 -0.3317669928073883 -0.2601329982280731 -vn -0.9219499826431274 -0.3858990073204041 0.03300400078296661 -vn -0.9323030114173889 -0.3608480095863342 0.02450799942016602 -vn -0.9716429710388184 -0.2363799959421158 -0.005919000133872032 -vn -0.9500359892845154 -0.3102270066738129 -0.03450300171971321 -vn 0.05162100121378899 -0.6772800087928772 -0.7339119911193848 -vn 0.2163099944591522 -0.8325870037078857 -0.509909987449646 -vn -0.1634809970855713 -0.9366869926452637 -0.3096620142459869 -vn -0.2730129957199097 -0.8829479813575745 0.3819249868392944 -vn -0.3344880044460297 -0.7286760210990906 0.5976200103759766 -vn -0.4082350134849548 -0.6025800108909607 0.6857410073280334 -vn -0.3718569874763489 -0.7108250260353088 0.5970349907875061 -vn 0.7508220076560974 -0.6546019911766052 -0.08810699731111526 -vn 0.7445650100708008 -0.5752760171890259 -0.3386459946632385 -vn 0.7660269737243652 -0.6418589949607849 0.03493599966168404 -vn 0.5222679972648621 -0.6368250250816345 0.5671769976615906 -vn 0.5276669859886169 -0.5274670124053955 0.6658419966697693 -vn 0.6410369873046875 -0.3752210140228271 0.6695380210876465 -vn 0.6145420074462891 -0.4531340003013611 0.6457610130310059 -vn -0.287102997303009 -0.9309409856796265 -0.2256560027599335 -vn 0.1843679994344711 -0.4218010008335114 0.8877459764480591 -vn 0.07405100017786026 0.6319169998168945 -0.7714899778366089 -vn 0.8553329706192017 0.06064699962735176 -0.5145170092582703 -vn 0.7307729721069336 0.3228900134563446 -0.6014260053634644 -vn 0.2098069936037064 0.7427859902381897 -0.6358069777488708 -vn 0.6162220239639282 0.3713270127773285 -0.6945400238037109 -vn 0.09581899642944336 0.7464309930801392 -0.6585279703140259 -vn 0.4080640077590942 0.9123439788818359 0.03336000069975853 -vn 0.8213359713554382 0.1804669946432114 -0.5411459803581238 -vn 0.969681978225708 0.1661700010299683 -0.17917600274086 -vn 0.7540370225906372 0.5044180154800415 0.4207040071487427 -vn 0.828561007976532 0.3165900111198425 0.4617980122566223 -vn 0.9432830214500427 -0.08009400218725204 -0.3221819996833801 -vn 0.9967989921569824 0.009220999665558338 -0.07941699773073196 -vn 0.775767982006073 0.3821409940719604 0.5021479725837708 -vn -0.5359219908714294 0.8157860040664673 -0.2174420058727264 -vn -0.7117419838905334 0.631197988986969 -0.3082410097122192 -vn -0.7205860018730164 0.6709820032119751 -0.1747539937496185 -vn -0.4114960134029388 0.7961680293083191 0.4436070024967194 -vn -0.0943790003657341 0.527301013469696 0.8444210290908813 -vn -0.06975200027227402 0.4077039957046509 0.9104459881782532 -vn -0.07522699981927872 0.5093169808387756 0.8572840094566345 -vn -0.899321973323822 0.2172179967164993 0.3795219957828522 -vn -0.8569710254669189 0.4048359990119934 0.318917989730835 -vn -0.9294880032539368 0.002263000002130866 0.3688459992408752 -vn -0.9130200147628784 0.1119910031557083 0.3922390043735504 -vn -0.7752439975738525 0.1555069983005524 0.6122210025787354 -vn -0.809952974319458 0.130293995141983 0.5718389749526978 -vn -0.8099700212478638 0.21145099401474 0.5470259785652161 -vn -0.5124379992485046 -0.4739649891853333 0.7160750031471252 -vn -0.4707460105419159 -0.3654879927635193 0.8030049800872803 -vn -0.6227080225944519 -0.5545240044593811 0.5520300269126892 -vn -0.8047950267791748 -0.5929269790649414 -0.02723599970340729 -vn -0.9356880187988281 -0.3495660126209259 -0.04786499962210655 -vn -0.9798259735107422 -0.1990929991006851 0.01738799922168255 -vn -0.9696599841117859 -0.2444050014019012 0.004995000082999468 -vn 0.3460299968719482 -0.6453220248222351 0.6810449957847595 -vn 0.1500509977340698 -0.8165979981422424 0.5573610067367554 -vn 0.305963009595871 -0.9033949971199036 0.3004390001296997 -vn -0.1068940013647079 -0.8791000247001648 -0.4644969999790192 -vn -0.3793039917945862 -0.6047009825706482 -0.70033198595047 -vn -0.4574509859085083 -0.5502709746360779 -0.6985269784927368 -vn -0.3967710137367249 -0.701295018196106 -0.5922489762306213 -vn 0.8359060287475586 -0.5488340258598328 -0.006517999805510044 -vn 0.9236019849777222 -0.3818440139293671 0.03396600112318993 -vn 0.8632140159606934 -0.3933719992637634 -0.3164179921150208 -vn 0.6054999828338623 -0.4316779971122742 -0.6685979962348938 -vn 0.5342289805412292 -0.3754520118236542 -0.7573869824409485 -vn 0.6098309755325317 -0.3671579957008362 -0.7023540139198303 -vn 0.6060940027236938 -0.5121269822120667 -0.6085860133171082 -vn -0.2871040105819702 -0.9309409856796265 0.2256550043821335 -vn 0.1843840032815933 -0.4217509925365448 -0.8877660036087036 -vn 0.7307729721069336 0.3228900134563446 0.6014260053634644 -vn 0.8553329706192017 0.06064699962735176 0.5145170092582703 -vn 0.07405100017786026 0.6319169998168945 0.7714899778366089 -vn 0.2098069936037064 0.7427859902381897 0.6358069777488708 -vn 0.6162220239639282 0.3713270127773285 0.6945400238037109 -vn 0.09581799805164337 0.7464309930801392 0.6585279703140259 -vn 0.8213359713554382 0.1804669946432114 0.5411450266838074 -vn 0.4080640077590942 0.9123439788818359 -0.03336000069975853 -vn 0.969681978225708 0.1661700010299683 0.17917500436306 -vn 0.7540370225906372 0.5044180154800415 -0.4207040071487427 -vn 0.9432830214500427 -0.08009400218725204 0.3221819996833801 -vn 0.8285599946975708 0.3165900111198425 -0.4617989957332611 -vn 0.9967989921569824 0.009220999665558338 0.07941699773073196 -vn 0.775767982006073 0.3821409940719604 -0.5021479725837708 -vn -0.5359219908714294 0.8157860040664673 0.2174420058727264 -vn -0.7117419838905334 0.631197988986969 0.3082410097122192 -vn -0.7205860018730164 0.6709820032119751 0.1747539937496185 -vn -0.4114960134029388 0.7961680293083191 -0.4436070024967194 -vn -0.09437999874353409 0.527301013469696 -0.8444210290908813 -vn -0.06975200027227402 0.4077039957046509 -0.9104459881782532 -vn -0.07522699981927872 0.5093169808387756 -0.8572850227355957 -vn -0.899321973323822 0.2172179967164993 -0.3795219957828522 -vn -0.8569710254669189 0.4048359990119934 -0.318917989730835 -vn -0.9294880032539368 0.002263000002130866 -0.3688449859619141 -vn -0.9130200147628784 0.1119910031557083 -0.3922390043735504 -vn -0.7752439975738525 0.1555059999227524 -0.6122210025787354 -vn -0.8099520206451416 0.130293995141983 -0.5718389749526978 -vn -0.8099690079689026 0.21144999563694 -0.5470269918441772 -vn -0.5124379992485046 -0.4739649891853333 -0.7160750031471252 -vn -0.4707460105419159 -0.3654879927635193 -0.8030049800872803 -vn -0.6227080225944519 -0.5545240044593811 -0.5520300269126892 -vn -0.8047950267791748 -0.5929279923439026 0.02723599970340729 -vn -0.9356880187988281 -0.3495660126209259 0.04786499962210655 -vn -0.9798259735107422 -0.1990929991006851 -0.01738799922168255 -vn -0.9696599841117859 -0.2444050014019012 -0.004995000082999468 -vn 0.3460299968719482 -0.6453220248222351 -0.6810449957847595 -vn 0.1500509977340698 -0.8165979981422424 -0.5573610067367554 -vn 0.3059639930725098 -0.9033949971199036 -0.3004390001296997 -vn -0.1068949997425079 -0.8791000247001648 0.464495986700058 -vn -0.3793050050735474 -0.6047009825706482 0.70033198595047 -vn -0.4574509859085083 -0.5502709746360779 0.6985269784927368 -vn -0.3967710137367249 -0.7012940049171448 0.5922489762306213 -vn 0.8359060287475586 -0.5488340258598328 0.006517999805510044 -vn 0.9236019849777222 -0.3818440139293671 -0.03396600112318993 -vn 0.8632140159606934 -0.3933730125427246 0.3164179921150208 -vn 0.6054999828338623 -0.4316790103912354 0.6685979962348938 -vn 0.5342299938201904 -0.3754520118236542 0.7573869824409485 -vn 0.6098309755325317 -0.3671579957008362 0.7023540139198303 -vn 0.6060940027236938 -0.5121260285377502 0.6085860133171082 -vn 0 0 0 -vn 0.8919450044631958 0.3336060047149658 -0.3051899969577789 -vn 0.8852859735488892 -0.05170800164341927 0.4621630012989044 -vn 0.8717010021209717 -0.4864040017127991 -0.05957400053739548 -vn 0.6025350093841553 -0.1140230000019073 0.7899060249328613 -vn 0.7673320174217224 -0.6138780117034912 0.1853529959917068 -vn 0.6157039999961853 -0.2387659996747971 0.750931978225708 -vn -0.1322280019521713 0.07659800350666046 0.9882550239562988 -vn -0.1344829946756363 0.2189230024814606 0.9664300084114075 -vn -0.08265399932861328 0.3330360054969788 0.9392849802970886 -vn -0.7942630052566528 0.3628509938716888 0.4873250126838684 -vn -0.686972975730896 0.5388749837875366 0.4875270128250122 -vn -0.9116560220718384 -0.2424139976501465 -0.3318400084972382 -vn -0.903469979763031 -0.005853999871760607 -0.4286110103130341 -vn -0.8802070021629333 0.2844929993152618 -0.3798680007457733 -vn -0.3590719997882843 -0.2934069931507111 -0.8859909772872925 -vn -0.5312150120735168 -0.1616500020027161 -0.8316730260848999 -vn 0.5217099785804749 -0.3334519863128662 -0.7852569818496704 -vn 0.4982230067253113 -0.5182129740715027 -0.6951469779014587 -vn 0.3192520141601562 -0.6669300198554993 -0.6732630133628845 -vn 0.4172089993953705 0.6029300093650818 -0.6800090074539185 -vn -0.3909519910812378 -0.5063930153846741 -0.7685850262641907 -vn -0.785847008228302 -0.2199160009622574 -0.5779989957809448 -vn -0.1128029972314835 -0.7670649886131287 -0.6315749883651733 -vn -0.6768519878387451 -0.4520730078220367 -0.5809479951858521 -vn -0.07061299681663513 -0.7851089835166931 -0.6153200268745422 -vn 0.4044640064239502 -0.913004994392395 -0.05320600047707558 -vn 0.5100409984588623 -0.8511109948158264 -0.1243719980120659 -vn 0.600862979888916 -0.7767530083656311 -0.188727006316185 -vn 0.7341600060462952 -0.2982490062713623 0.6099640130996704 -vn 0.8028550148010254 -0.2451270073652267 0.5434489846229553 -vn 0.2039200067520142 0.286547988653183 0.9361129999160767 -vn 0.2590579986572266 0.3469229936599731 0.90140700340271 -vn 0.3050769865512848 0.4136070013046265 0.857820987701416 -vn -0.3951399922370911 0.6723129749298096 0.6259869933128357 -vn -0.3882040083408356 0.6723269820213318 0.6302970051765442 -vn -0.8444070219993591 0.5085629820823669 -0.1683440059423447 -vn -0.9073770046234131 0.4102010130882263 -0.09166599810123444 -vn -0.9431279897689819 0.3317759931087494 0.02084000036120415 -vn -0.03268500044941902 0.9875209927558899 0.1540600061416626 -vn 0.2856169939041138 0.9530180096626282 0.1008900031447411 -vn 0.3564079999923706 0.9297230243682861 0.092678003013134 -vn 0.05804499983787537 0.9152950048446655 0.3985790014266968 -vn -0.4380980134010315 -0.8398249745368958 0.3205699920654297 -vn 0.0398080013692379 -0.7493849992752075 0.6609370112419128 -vn -0.4364219903945923 -0.7586889863014221 0.4836600124835968 -vn -0.1446219980716705 0.8584669828414917 0.4920569956302643 -vn -0.3905079960823059 -0.8025469779968262 0.4510230123996735 -vn -0.3789550065994263 0.7686259746551514 0.5153710246086121 -vn -0.3518399894237518 -0.8554270267486572 0.3800710141658783 -vn -0.5039129853248596 0.8112840056419373 0.2964630126953125 -vn -0.4345029890537262 -0.8862379789352417 0.1605930030345917 -vn -0.5895540118217468 0.7668499946594238 0.2537069916725159 -vn 0.4611240029335022 -0.5667420029640198 0.682765007019043 -vn -0.03327900171279907 -0.5302489995956421 0.8471890091896057 -vn -0.1550759971141815 -0.4793860018253326 0.8637940287590027 -vn -0.3325540125370026 -0.6754969954490662 0.6581119894981384 -vn -0.6243529915809631 -0.6490340232849121 0.434671014547348 -vn -0.6404299736022949 -0.7232750058174133 0.258307009935379 -vn 0.8391460180282593 -0.5209720134735107 0.1562740057706833 -vn 0.9793859720230103 -0.04739199951291084 0.1963589936494827 -vn 0.8591970205307007 -0.01306600030511618 0.5114780068397522 -vn 0.1697809994220734 0.01797799952328205 0.9853180050849915 -vn -0.2981239855289459 0.09316399693489075 0.949970006942749 -vn -0.6025810241699219 0.1407950073480606 0.785539984703064 -vn -0.7606229782104492 0.3568800091743469 0.5422999858856201 -vn -0.9164419770240784 -0.01278399955481291 0.3999640047550201 -vn 0.7099589705467224 0.6897799968719482 0.1419920027256012 -vn 0.6163280010223389 0.7111549973487854 0.3382270038127899 -vn 0.1215279996395111 0.6381019949913025 0.7602999806404114 -vn -0.3081580102443695 0.474483996629715 0.8245630264282227 -vn -0.5849490165710449 0.4978660047054291 0.64028400182724 -vn -0.8313949704170227 0.3698750138282776 0.414698988199234 -vn -0.7773889899253845 0.439754992723465 0.4497570097446442 -vn -0.7120980024337769 0.07437500357627869 0.6981300115585327 -vn -0.5221620202064514 -0.5821250081062317 0.6232789754867554 -vn -0.5362930297851562 0.8426250219345093 0.04870999976992607 -vn -0.6278550028800964 0.7403159737586975 0.2402739971876144 -vn -0.817995011806488 0.4767960011959076 0.3217920064926147 -vn -0.7291709780693054 0.6557949781417847 0.1955550014972687 -vn -0.9585440158843994 0.2151080071926117 0.1868750005960464 -vn -0.9505919814109802 0.1639280021190643 0.2636339962482452 -vn -0.9833920001983643 -0.02283000014722347 0.1800519973039627 -vn -0.8917449712753296 0.1107539981603622 0.4387759864330292 -vn -0.9918580055236816 -0.08782999962568283 0.09221799671649933 -vn -0.8591039776802063 0.04482100158929825 0.5098350048065186 -vn -0.8949519991874695 -0.4028989970684052 0.1916580051183701 -vn -0.9036110043525696 0.009092999622225761 0.4282569885253906 -vn -0.8893200159072876 0.01745700091123581 0.4569520056247711 -vn -0.7315409779548645 -0.4924210011959076 0.4715610146522522 -vn -0.7941030263900757 -0.1783780008554459 0.581017017364502 -vn -0.6259329915046692 -0.3735530078411102 0.6845920085906982 -vn -0.5845080018043518 -0.1848309934139252 0.7900559902191162 -vn -0.8015180230140686 -0.1042689979076385 0.5888090133666992 -vn -0.6420310139656067 -0.2967270016670227 0.7069290280342102 -vn -0.8202810287475586 -0.1234560012817383 0.5584779977798462 -vn 0.01690500043332577 -0.9364719986915588 -0.3503330051898956 -vn -0.09879499673843384 -0.7398999929428101 -0.6654229760169983 -vn -0.06946200132369995 -0.9367489814758301 -0.3430390059947968 -vn 0.123930998146534 -0.9922909736633301 0 -vn 0.03589100018143654 -0.8559809923171997 -0.5157600045204163 -vn -0.0289510004222393 -0.999580979347229 0 -vn 0.01690500043332577 -0.9364719986915588 0.3503330051898956 -vn -0.06946200132369995 -0.9367489814758301 0.3430390059947968 -vn -0.3344019949436188 -0.9161610007286072 -0.2209639996290207 -vn -0.7904769778251648 -0.6124920248985291 -0 -vn -0.3344019949436188 -0.9161610007286072 0.2209639996290207 -vn -0.7410100102424622 -0.556659996509552 0.375544011592865 -vn -0.2743130028247833 -0.8896610140800476 0.3650420010089874 -vn -0.09879499673843384 -0.7398999929428101 0.6654229760169983 -vn 0.03589100018143654 -0.8559809923171997 0.5157600045204163 -vn -0.2743130028247833 -0.8896610140800476 -0.3650420010089874 -vn -0.7410100102424622 -0.556659996509552 -0.375544011592865 -vn 0.3564079999923706 0.9297230243682861 -0.092678003013134 -vn 0.2856169939041138 0.9530180096626282 -0.1008900031447411 -vn -0.03268500044941902 0.9875209927558899 -0.1540600061416626 -vn 0.05804499983787537 0.9152950048446655 -0.3985790014266968 -vn -0.4364219903945923 -0.7586889863014221 -0.4836600124835968 -vn 0.0398080013692379 -0.7493849992752075 -0.6609370112419128 -vn -0.4380980134010315 -0.8398249745368958 -0.3205699920654297 -vn -0.1446219980716705 0.8584669828414917 -0.4920569956302643 -vn -0.3905079960823059 -0.8025469779968262 -0.4510230123996735 -vn -0.3789550065994263 0.7686259746551514 -0.5153710246086121 -vn -0.3518399894237518 -0.8554270267486572 -0.3800710141658783 -vn -0.5039129853248596 0.8112840056419373 -0.2964630126953125 -vn -0.4345029890537262 -0.8862379789352417 -0.1605930030345917 -vn -0.5895540118217468 0.7668499946594238 -0.2537069916725159 -vn -0.03327900171279907 -0.5302489995956421 -0.8471890091896057 -vn 0.4611240029335022 -0.5667420029640198 -0.682765007019043 -vn -0.1550759971141815 -0.4793860018253326 -0.8637940287590027 -vn -0.3325540125370026 -0.6754969954490662 -0.6581119894981384 -vn -0.624351978302002 -0.6490340232849121 -0.434671014547348 -vn -0.6404299736022949 -0.7232750058174133 -0.258307009935379 -vn 0.9793859720230103 -0.04739199951291084 -0.1963589936494827 -vn 0.8391469717025757 -0.5209720134735107 -0.1562740057706833 -vn 0.8591970205307007 -0.01306699961423874 -0.5114780068397522 -vn 0.1697809994220734 0.01797799952328205 -0.9853180050849915 -vn -0.2981239855289459 0.09316399693489075 -0.949970006942749 -vn -0.6025800108909607 0.1407950073480606 -0.785539984703064 -vn -0.7606229782104492 0.3568800091743469 -0.5422999858856201 -vn -0.9164419770240784 -0.01278399955481291 -0.3999640047550201 -vn 0.6163280010223389 0.7111549973487854 -0.3382270038127899 -vn 0.7099589705467224 0.6897799968719482 -0.1419920027256012 -vn 0.1215270012617111 0.6381019949913025 -0.7602999806404114 -vn -0.3081580102443695 0.474483996629715 -0.8245630264282227 -vn -0.5849490165710449 0.4978669881820679 -0.64028400182724 -vn -0.8313949704170227 0.3698750138282776 -0.414698988199234 -vn -0.7773889899253845 0.439754992723465 -0.4497570097446442 -vn -0.5362920165061951 0.8426259756088257 -0.04870999976992607 -vn -0.522163987159729 -0.5821229815483093 -0.6232799887657166 -vn -0.7120980024337769 0.07437700033187866 -0.6981289982795715 -vn -0.6278539896011353 0.7403159737586975 -0.2402739971876144 -vn -0.817995011806488 0.4767970144748688 -0.3217920064926147 -vn -0.7291709780693054 0.6557959914207458 -0.1955550014972687 -vn -0.9585440158843994 0.2151080071926117 -0.1868750005960464 -vn -0.9505919814109802 0.1639280021190643 -0.2636339962482452 -vn -0.8917449712753296 0.1107529997825623 -0.4387759864330292 -vn -0.9833920001983643 -0.02283000014722347 -0.1800529956817627 -vn -0.8591039776802063 0.04482100158929825 -0.5098339915275574 -vn -0.9918580055236816 -0.08783099800348282 -0.09221699833869934 -vn -0.8949530124664307 -0.4028989970684052 -0.1916570067405701 -vn -0.9036110043525696 0.009092999622225761 -0.4282569885253906 -vn -0.8893200159072876 0.0174579992890358 -0.4569520056247711 -vn -0.7315409779548645 -0.4924199879169464 -0.4715610146522522 -vn -0.7941030263900757 -0.1783780008554459 -0.5810179710388184 -vn -0.625931978225708 -0.3735530078411102 -0.6845930218696594 -vn -0.5845069885253906 -0.1848299950361252 -0.7900559902191162 -vn -0.8015180230140686 -0.1042689979076385 -0.5888090133666992 -vn -0.6420310139656067 -0.2967270016670227 -0.7069299817085266 -vn -0.8202810287475586 -0.1234560012817383 -0.5584779977798462 -vn 0.8919439911842346 0.3336179852485657 0.3051789999008179 -vn 0.6025350093841553 -0.1140210032463074 -0.7899050116539001 -vn 0.8717020153999329 -0.4864020049571991 0.05957499891519547 -vn 0.8852850198745728 -0.05170699954032898 -0.4621649980545044 -vn 0.7673349976539612 -0.6138749718666077 -0.1853519976139069 -vn 0.6157060265541077 -0.2387650012969971 -0.7509310245513916 -vn -0.1322280019521713 0.07659800350666046 -0.9882550239562988 -vn -0.1344819962978363 0.2189230024814606 -0.9664300084114075 -vn -0.08265399932861328 0.3330360054969788 -0.9392840266227722 -vn -0.7942630052566528 0.3628509938716888 -0.4873250126838684 -vn -0.686972975730896 0.5388749837875366 -0.487525999546051 -vn -0.9116560220718384 -0.2424139976501465 0.3318400084972382 -vn -0.903469979763031 -0.005853999871760607 0.4286110103130341 -vn -0.8802070021629333 0.2844929993152618 0.3798680007457733 -vn -0.3590719997882843 -0.2934069931507111 0.8859909772872925 -vn -0.5312150120735168 -0.1616500020027161 0.8316730260848999 -vn 0.5217090249061584 -0.3334519863128662 0.7852579951286316 -vn 0.4982230067253113 -0.5182120203971863 0.6951479911804199 -vn 0.319252997636795 -0.6669290065765381 0.6732640266418457 -vn 0.4172079861164093 0.602931022644043 0.6800090074539185 -vn -0.1128029972314835 -0.7670649886131287 0.6315749883651733 -vn -0.785847008228302 -0.2199160009622574 0.5779979825019836 -vn -0.3909519910812378 -0.5063920021057129 0.7685850262641907 -vn -0.6768519878387451 -0.4520730078220367 0.5809479951858521 -vn -0.07061299681663513 -0.7851079702377319 0.6153200268745422 -vn 0.4044640064239502 -0.913004994392395 0.05320600047707558 -vn 0.5100420117378235 -0.8511109948158264 0.1243719980120659 -vn 0.600862979888916 -0.7767530083656311 0.188727006316185 -vn 0.7341600060462952 -0.2982490062713623 -0.6099640130996704 -vn 0.8028540015220642 -0.2451270073652267 -0.5434499979019165 -vn 0.2039200067520142 0.286547988653183 -0.9361129999160767 -vn 0.2590579986572266 0.3469229936599731 -0.90140700340271 -vn 0.3050769865512848 0.4136070013046265 -0.857820987701416 -vn -0.3951399922370911 0.6723120212554932 -0.6259880065917969 -vn -0.3882040083408356 0.6723269820213318 -0.6302970051765442 -vn -0.8444070219993591 0.5085629820823669 0.1683440059423447 -vn -0.9073770046234131 0.4102010130882263 0.09166599810123444 -vn -0.9431279897689819 0.3317759931087494 -0.02084000036120415 -vn 0.09283199906349182 0.3405439853668213 0.9356340169906616 -vn 0.4332149922847748 0.3082599937915802 0.8469359874725342 -vn 0.07513599842786789 0.7418090105056763 0.666388988494873 -vn -0.3755930066108704 0.6224439740180969 0.6866539716720581 -vn -0.6413879990577698 0.6895880103111267 0.3362880051136017 -vn -0.3539179861545563 0.8731229901313782 0.3352580070495605 -vn -0.6627640128135681 0.7462409734725952 -0.06218799948692322 -vn -0.5455629825592041 0.6585090160369873 -0.5183889865875244 -vn -0.5422859787940979 0.2685939967632294 -0.7961050271987915 -vn -0.7763820290565491 0.4680269956588745 -0.4221160113811493 -vn -0.9955589771270752 -0.03219699859619141 -0.08845899999141693 -vn -0.7381539940834045 -0.2307370007038116 -0.633948028087616 -vn -0.433216005563736 -0.3082579970359802 -0.8469359874725342 -vn -0.7763850092887878 -0.6298570036888123 -0.02251699939370155 -vn -0.4675639867782593 -0.8743969798088074 0.1296679973602295 -vn -0.5422919988632202 -0.7174760103225708 -0.4372040033340454 -vn -0.1898339986801147 -0.8541020154953003 0.4842230081558228 -vn -0.5458049774169922 -0.7113950252532959 0.4427349865436554 -vn -0.6413909792900085 -0.3120909929275513 0.7008680105209351 -vn -0.2153560072183609 -0.6237800121307373 0.7513459920883179 -vn 0.03750099986791611 -0.724698007106781 0.6880459785461426 -vn -0.3755939900875092 -0.03544300049543381 0.9261069893836975 -vn 0.07813700288534164 -0.2686049938201904 0.9600759744644165 -vn -0.7573850154876709 0.2233279943466187 0.6135900020599365 -vn -0.902417004108429 0.4006629884243011 0.1584679931402206 -vn -0.902417004108429 -0.2050659954547882 0.3789339959621429 -vn 0.07513599842786789 0.7418090105056763 -0.666388988494873 -vn 0.4332149922847748 0.3082599937915802 -0.8469359874725342 -vn 0.09283199906349182 0.3405439853668213 -0.935634970664978 -vn -0.3755930066108704 0.6224439740180969 -0.6866539716720581 -vn -0.3539179861545563 0.8731229901313782 -0.3352569937705994 -vn -0.6413879990577698 0.6895880103111267 -0.3362880051136017 -vn -0.6627640128135681 0.7462409734725952 0.06218799948692322 -vn -0.7763820290565491 0.4680269956588745 0.4221160113811493 -vn -0.5422859787940979 0.2685939967632294 0.7961050271987915 -vn -0.5455620288848877 0.6585100293159485 0.5183889865875244 -vn -0.7381539940834045 -0.2307370007038116 0.633948028087616 -vn -0.9955589771270752 -0.03219600021839142 0.08845899999141693 -vn -0.433216005563736 -0.3082579970359802 0.8469359874725342 -vn -0.7763850092887878 -0.6298559904098511 0.02251699939370155 -vn -0.5422919988632202 -0.717477023601532 0.4372040033340454 -vn -0.4675650000572205 -0.8743969798088074 -0.1296679973602295 -vn -0.5458049774169922 -0.7113940119743347 -0.4427359998226166 -vn -0.1898339986801147 -0.8541020154953003 -0.4842230081558228 -vn -0.2153560072183609 -0.6237789988517761 -0.7513459920883179 -vn -0.6413909792900085 -0.3120909929275513 -0.7008690237998962 -vn 0.03750099986791611 -0.724698007106781 -0.6880459785461426 -vn -0.3755939900875092 -0.03544300049543381 -0.9261059761047363 -vn 0.07813599705696106 -0.2686049938201904 -0.9600759744644165 -vn -0.7573840022087097 0.2233279943466187 -0.6135900020599365 -vn -0.902417004108429 0.4006629884243011 -0.1584679931402206 -vn -0.902417004108429 -0.2050659954547882 -0.3789339959621429 +vn -0.537588 -0.071798 0.840146 +vn -0.151555 -0.017111 0.988301 +vn -0.510264 0.347193 0.786822 +vn -0.383883 0.724753 0.572160 +vn 0.006791 0.547083 0.837051 +vn 0.441964 0.160862 0.882492 +vn -0.810413 0.184718 0.555976 +vn -0.915534 0.402240 -0.000000 +vn -0.710113 0.620185 0.333331 +vn -0.721673 0.607891 -0.331145 +vn -0.413629 0.701858 -0.579920 +vn -0.409411 0.912350 0.000434 +vn 0.132323 0.938010 0.320355 +vn 0.132323 0.938010 -0.320355 +vn 0.339768 0.940509 -0.000000 +vn 0.481852 0.617859 0.621345 +vn 0.881337 0.472488 -0.000000 +vn 0.942952 -0.332930 -0.000000 +vn 0.795204 -0.092522 0.599242 +vn 0.481852 0.617859 -0.621345 +vn 0.441964 0.160862 -0.882492 +vn 0.795204 -0.092522 -0.599242 +vn -0.012521 0.539701 -0.841764 +vn -0.544858 0.327294 -0.772016 +vn -0.561303 -0.075179 -0.824189 +vn -0.195775 -0.027076 -0.980275 +vn -0.299847 -0.529265 -0.793707 +vn 0.144885 -0.802478 -0.578824 +vn 0.343163 -0.420370 -0.839957 +vn 0.704306 -0.633502 -0.320355 +vn 0.260986 -0.965343 0.000322 +vn 0.173226 -0.803252 0.569894 +vn 0.704306 -0.633502 0.320355 +vn -0.346230 -0.872998 -0.343510 +vn -0.769195 -0.639014 0.000000 +vn -0.334289 -0.877615 0.343575 +vn -0.728104 -0.400942 0.555976 +vn -0.264904 -0.527345 0.807300 +vn 0.359321 -0.413990 0.836362 +vn -0.990268 -0.139173 -0.000000 +vn -0.810413 0.184718 -0.555976 +vn -0.728104 -0.400942 -0.555976 +vn -0.236279 0.029185 0.971247 +vn 0.320907 -0.108176 0.940913 +vn 0.232851 0.492069 0.838838 +vn 0.401159 0.816009 0.416173 +vn 0.362076 0.383575 0.849571 +vn 0.126098 -0.040972 0.991171 +vn -0.604687 0.614896 0.506218 +vn -0.478910 0.877864 -0.000000 +vn 0.038576 0.969348 0.242645 +vn 0.038576 0.969348 -0.242645 +vn 0.401159 0.816009 -0.416173 +vn 0.360915 0.932599 0.000000 +vn 0.494411 0.798675 0.343038 +vn 0.494411 0.798675 -0.343038 +vn 0.861265 0.508156 -0.000000 +vn 0.647910 0.246087 0.720870 +vn 0.951057 -0.309017 -0.000000 +vn 0.743317 -0.668940 -0.000000 +vn 0.535463 -0.362827 0.762651 +vn 0.647910 0.246086 -0.720870 +vn 0.126098 -0.040972 -0.991171 +vn 0.535463 -0.362827 -0.762651 +vn 0.362076 0.383575 -0.849571 +vn 0.232851 0.492069 -0.838838 +vn -0.236279 0.029185 -0.971247 +vn 0.320907 -0.108176 -0.940913 +vn 0.132934 -0.415219 -0.899956 +vn 0.188857 -0.970911 -0.147192 +vn 0.199321 -0.435181 -0.878003 +vn -0.862018 0.083023 0.500032 +vn 0.132934 -0.415219 0.899956 +vn 0.199321 -0.435181 0.878002 +vn 0.188857 -0.970911 0.147192 +vn -0.930205 0.367040 -0.000000 +vn -0.997640 0.068658 -0.000000 +vn -0.604687 0.614896 -0.506218 +vn -0.862018 0.083023 -0.500032 +vn 0.021383 -0.916512 0.399436 +vn -0.781862 -0.431561 -0.449942 +vn 0.956336 0.228461 -0.182283 +vn 0.833901 -0.104561 -0.541919 +vn 0.767800 0.601842 0.219702 +vn 0.546124 0.782549 0.298940 +vn 0.910925 0.174919 -0.373656 +vn 0.748758 0.661676 -0.039313 +vn 0.949258 -0.047485 -0.310893 +vn 0.406836 0.802260 -0.436879 +vn 0.769156 0.182669 -0.612398 +vn 0.199512 0.609083 -0.767602 +vn 0.667603 0.001959 -0.744515 +vn -0.099388 0.414937 -0.904405 +vn 0.352774 0.079499 -0.932325 +vn -0.283318 0.420843 -0.861755 +vn -0.057479 0.857527 0.511218 +vn 0.131724 0.743022 0.656177 +vn -0.005809 0.859552 0.511016 +vn -0.350571 0.931431 -0.097655 +vn -0.647693 0.664816 -0.372173 +vn -0.898309 0.404808 -0.170794 +vn -0.866249 0.480043 -0.138459 +vn -0.715121 0.360250 0.599018 +vn -0.866625 0.341770 0.363530 +vn -0.662377 0.297013 0.687780 +vn -0.811725 0.388839 0.435782 +vn -0.950899 0.243388 0.191190 +vn -0.846773 0.078043 0.526199 +vn -0.759416 0.140950 0.635154 +vn -0.940011 -0.340515 -0.020693 +vn -0.972400 -0.204991 0.111430 +vn -0.817030 -0.331766 0.471585 +vn -0.616700 -0.385898 0.686122 +vn -0.565415 -0.413211 0.713837 +vn -0.342437 -0.316577 0.884599 +vn -0.263317 -0.310224 0.913469 +vn -0.492073 -0.677280 -0.546952 +vn -0.216535 -0.832588 -0.509814 +vn -0.336313 -0.936688 -0.097510 +vn 0.085084 -0.882948 0.461697 +vn 0.196057 -0.733951 0.650291 +vn 0.454815 -0.615703 0.643470 +vn 0.489338 -0.710824 0.505250 +vn 0.458185 -0.654603 -0.601300 +vn 0.273617 -0.575276 -0.770838 +vn 0.557258 -0.641859 -0.526765 +vn 0.770791 -0.636825 0.018306 +vn 0.873238 -0.487283 0.003170 +vn 0.878760 -0.285726 -0.382285 +vn 0.775252 -0.453136 -0.440060 +vn 0.076768 -0.902254 -0.424317 +vn -0.760858 -0.310029 0.570067 +vn 0.698983 0.632728 -0.333285 +vn 0.918945 -0.018611 0.393945 +vn 0.946923 0.242706 0.210787 +vn 0.597706 0.775902 -0.201801 +vn 0.898457 0.395975 0.189682 +vn 0.584977 0.777578 -0.230597 +vn 0.061121 0.865503 0.497161 +vn 0.814891 0.173456 0.553052 +vn 0.488324 0.052196 0.871100 +vn -0.073338 0.372458 0.925147 +vn -0.168557 0.420636 0.891433 +vn 0.562606 0.011650 0.826643 +vn 0.424549 0.220069 0.878253 +vn -0.202274 0.574889 0.792835 +vn -0.201495 0.870711 -0.448622 +vn -0.147519 0.700066 -0.698674 +vn -0.247406 0.680029 -0.690182 +vn -0.659229 0.742690 -0.117596 +vn -0.823828 0.514402 0.238115 +vn -0.880755 0.462224 0.103053 +vn -0.835446 0.538148 0.111476 +vn -0.835433 0.291149 -0.466138 +vn -0.799017 0.476863 -0.366296 +vn -0.796565 -0.008375 -0.604495 +vn -0.746076 0.124458 -0.654126 +vn -0.847027 0.257512 -0.465008 +vn -0.774335 0.094113 -0.625738 +vn -0.799434 0.067311 -0.596971 +vn -0.914826 -0.403289 0.021240 +vn -0.960708 -0.276547 0.023720 +vn -0.776094 -0.562737 -0.284613 +vn -0.248105 -0.514857 -0.820589 +vn -0.231599 -0.234207 -0.944198 +vn -0.235950 -0.324119 -0.916119 +vn -0.342337 -0.448272 -0.825747 +vn -0.389047 -0.677991 0.623675 +vn -0.286549 -0.868467 0.404542 +vn -0.058292 -0.911347 0.407491 +vn 0.455951 -0.795072 -0.399962 +vn 0.489715 -0.524665 -0.696352 +vn 0.515843 -0.636580 -0.573300 +vn 0.423912 -0.809501 -0.406210 +vn 0.535603 -0.635581 0.556027 +vn 0.490862 -0.467516 0.735176 +vn 0.731377 -0.368576 0.573793 +vn 0.890119 -0.387697 0.239538 +vn 0.883630 -0.404120 0.236399 +vn 0.822699 -0.324540 0.466733 +vn 0.789247 -0.408589 0.458414 +vn -0.072988 -0.902254 0.424984 +vn -0.288148 -0.512224 -0.809072 +vn 0.918806 0.383987 0.091372 +vn 0.993163 0.114096 -0.024688 +vn 0.434383 0.709098 0.555420 +vn 0.471863 0.805177 0.359216 +vn 0.868051 0.441893 0.226313 +vn 0.386966 0.811178 0.438461 +vn 0.971729 0.236044 0.005163 +vn 0.277939 0.903859 -0.325252 +vn 0.907561 0.183989 -0.377467 +vn 0.389798 0.457680 -0.799116 +vn 0.974181 -0.045977 -0.221037 +vn 0.441749 0.266583 -0.856616 +vn 0.886674 0.017475 -0.462065 +vn 0.372092 0.327554 -0.868479 +vn -0.385080 0.834046 0.395071 +vn -0.476106 0.659961 0.581185 +vn -0.556161 0.685573 0.469761 +vn -0.626859 0.745436 -0.226656 +vn -0.554271 0.436146 -0.708915 +vn -0.561559 0.310302 -0.767049 +vn -0.543810 0.416915 -0.728322 +vn -0.974714 0.176358 0.137223 +vn -0.917252 0.369282 0.149263 +vn -0.982764 -0.036304 0.181267 +vn -0.987205 0.070377 0.143084 +vn -0.988708 0.090661 -0.119319 +vn -0.995465 0.069805 -0.064628 +vn -0.986899 0.153108 -0.050882 +vn -0.785702 -0.546219 -0.290374 +vn -0.802167 -0.447423 -0.395400 +vn -0.788300 -0.609188 -0.086443 +vn -0.635308 -0.586832 0.502008 +vn -0.748920 -0.342648 0.567196 +vn -0.829075 -0.199820 0.522213 +vn -0.811409 -0.243593 0.531299 +vn -0.029726 -0.712976 -0.700558 +vn -0.121255 -0.870385 -0.477207 +vn 0.151176 -0.929851 -0.335445 +vn 0.202841 -0.825731 0.526331 +vn 0.080914 -0.528183 0.845266 +vn 0.010675 -0.474241 0.880330 +vn 0.014489 -0.635546 0.771927 +vn 0.742724 -0.545146 -0.388814 +vn 0.786510 -0.383302 -0.484233 +vn 0.920594 -0.358142 -0.155695 +vn 0.889767 -0.359426 0.281297 +vn 0.873005 -0.294226 0.388965 +vn 0.907656 -0.291730 0.301752 +vn 0.863097 -0.445709 0.237502 +vn 0.041443 -0.908865 -0.415027 +vn -0.109957 -0.084548 0.990334 +vn 0.245131 0.763260 -0.597783 +vn 0.955445 0.284327 -0.079261 +vn 0.823805 0.535171 -0.186913 +vn 0.285353 0.867913 -0.406571 +vn 0.750150 0.580981 -0.315809 +vn 0.193001 0.857724 -0.476509 +vn 0.122062 0.961258 0.247151 +vn 0.890764 0.429947 -0.147257 +vn 0.869360 0.404802 0.283458 +vn 0.342558 0.602318 0.721018 +vn 0.449593 0.557051 0.698255 +vn 0.979971 0.160598 0.117751 +vn 0.912952 0.330027 0.240004 +vn 0.396960 0.742707 0.539267 +vn -0.562652 0.747701 -0.352655 +vn -0.640733 0.557163 -0.528234 +vn -0.712118 0.570582 -0.409053 +vn -0.719414 0.632988 0.285953 +vn -0.541635 0.392908 0.743139 +vn -0.506872 0.445328 0.738081 +vn -0.530036 0.658014 0.534864 +vn -0.999398 0.002857 -0.034586 +vn -0.977859 0.202556 -0.052566 +vn -0.974887 -0.208763 -0.077548 +vn -0.990809 -0.134971 -0.008911 +vn -0.971468 -0.084083 0.221765 +vn -0.983987 -0.035832 0.174602 +vn -0.987930 0.055655 0.144559 +vn -0.644785 -0.668339 0.370912 +vn -0.667256 -0.571980 0.477084 +vn -0.657389 -0.734501 0.168369 +vn -0.560535 -0.736307 -0.379015 +vn -0.692904 -0.540327 -0.477421 +vn -0.805447 -0.450708 -0.384860 +vn -0.807097 -0.552297 -0.208715 +vn 0.166809 -0.694562 0.699828 +vn 0.081505 -0.869441 0.487268 +vn 0.344060 -0.883528 0.317807 +vn 0.303265 -0.806548 -0.507455 +vn 0.132506 -0.587487 -0.798312 +vn 0.022610 -0.693630 -0.719976 +vn 0.045100 -0.923914 -0.379933 +vn 0.862122 -0.401541 0.309048 +vn 0.886724 -0.232862 0.399368 +vn 0.979859 -0.190892 0.058615 +vn 0.901262 -0.198277 -0.385245 +vn 0.854374 -0.181939 -0.486768 +vn 0.901238 -0.252507 -0.352151 +vn 0.898278 -0.412999 -0.150093 +vn -0.272473 -0.916512 -0.292854 +vn 0.247462 -0.431597 0.867460 +vn 0.375319 0.601842 -0.704927 +vn 0.969100 -0.104559 -0.223412 +vn 0.795449 0.228463 -0.561307 +vn 0.164332 0.782548 -0.600511 +vn 0.901567 0.174919 -0.395701 +vn 0.548411 0.661676 -0.511303 +vn 0.596875 0.802261 0.010829 +vn 0.883048 -0.047484 -0.466875 +vn 0.975847 0.140489 -0.167289 +vn 0.695006 0.600563 0.395335 +vn 0.804391 0.375485 0.460397 +vn 0.950455 -0.062330 -0.304551 +vn 0.989975 0.079498 -0.116747 +vn 0.767612 0.420846 0.483385 +vn -0.407667 0.857527 -0.313775 +vn -0.380509 0.743022 -0.550574 +vn -0.371629 0.859552 -0.350803 +vn -0.173281 0.931431 0.320017 +vn -0.088344 0.681833 0.726154 +vn -0.097862 0.460784 0.882100 +vn -0.075217 0.480042 0.874015 +vn -0.927662 0.360250 0.098302 +vn -0.863510 0.341772 0.370868 +vn -0.954873 0.297012 -0.001297 +vn -0.877348 0.388838 0.281187 +vn -0.798205 0.258643 0.544033 +vn -0.830945 0.129933 0.540970 +vn -0.800009 0.140946 0.583197 +vn -0.638103 -0.340513 0.690562 +vn -0.755642 -0.204991 0.622080 +vn -0.906786 -0.331767 0.260133 +vn -0.921950 -0.385899 -0.033004 +vn -0.932303 -0.360848 -0.024508 +vn -0.971643 -0.236380 0.005919 +vn -0.950036 -0.310227 0.034503 +vn 0.051621 -0.677280 0.733912 +vn 0.216310 -0.832587 0.509910 +vn -0.163481 -0.936688 0.309662 +vn -0.273013 -0.882948 -0.381925 +vn -0.334489 -0.728676 -0.597619 +vn -0.408235 -0.602580 -0.685741 +vn -0.371857 -0.710825 -0.597035 +vn 0.750822 -0.654602 0.088107 +vn 0.744565 -0.575276 0.338646 +vn 0.766027 -0.641859 -0.034936 +vn 0.522268 -0.636825 -0.567176 +vn 0.527667 -0.527467 -0.665842 +vn 0.641037 -0.375221 -0.669538 +vn 0.614542 -0.453134 -0.645761 +vn -0.272476 -0.916512 0.292854 +vn 0.247445 -0.431549 -0.867488 +vn 0.795449 0.228463 0.561307 +vn 0.969100 -0.104559 0.223412 +vn 0.375318 0.601842 0.704927 +vn 0.164332 0.782548 0.600511 +vn 0.901567 0.174919 0.395701 +vn 0.548410 0.661676 0.511303 +vn 0.883047 -0.047485 0.466875 +vn 0.596875 0.802261 -0.010829 +vn 0.975847 0.140489 0.167289 +vn 0.695006 0.600564 -0.395336 +vn 0.950454 -0.062330 0.304551 +vn 0.804391 0.375485 -0.460397 +vn 0.989975 0.079498 0.116747 +vn 0.767611 0.420846 -0.483385 +vn -0.407667 0.857527 0.313775 +vn -0.380509 0.743022 0.550574 +vn -0.371629 0.859552 0.350803 +vn -0.173281 0.931431 -0.320017 +vn -0.088345 0.681833 -0.726154 +vn -0.097862 0.460784 -0.882100 +vn -0.075217 0.480042 -0.874015 +vn -0.927662 0.360250 -0.098302 +vn -0.863510 0.341772 -0.370868 +vn -0.954873 0.297012 0.001297 +vn -0.877348 0.388838 -0.281187 +vn -0.798205 0.258643 -0.544033 +vn -0.830945 0.129933 -0.540970 +vn -0.800010 0.140945 -0.583196 +vn -0.638103 -0.340513 -0.690562 +vn -0.755642 -0.204991 -0.622081 +vn -0.906786 -0.331767 -0.260133 +vn -0.921950 -0.385899 0.033004 +vn -0.932303 -0.360848 0.024508 +vn -0.971643 -0.236380 -0.005919 +vn -0.950036 -0.310227 -0.034503 +vn 0.051621 -0.677280 -0.733912 +vn 0.216310 -0.832587 -0.509910 +vn -0.163481 -0.936687 -0.309662 +vn -0.273013 -0.882948 0.381925 +vn -0.334488 -0.728676 0.597620 +vn -0.408235 -0.602580 0.685741 +vn -0.371857 -0.710825 0.597035 +vn 0.750822 -0.654602 -0.088107 +vn 0.744565 -0.575276 -0.338646 +vn 0.766027 -0.641859 0.034936 +vn 0.522268 -0.636825 0.567177 +vn 0.527667 -0.527467 0.665842 +vn 0.641037 -0.375221 0.669538 +vn 0.614542 -0.453134 0.645761 +vn -0.287103 -0.930941 -0.225656 +vn 0.184368 -0.421801 0.887746 +vn 0.074051 0.631917 -0.771490 +vn 0.855333 0.060647 -0.514517 +vn 0.730773 0.322890 -0.601426 +vn 0.209807 0.742786 -0.635807 +vn 0.616222 0.371327 -0.694540 +vn 0.095819 0.746431 -0.658528 +vn 0.408064 0.912344 0.033360 +vn 0.821336 0.180467 -0.541146 +vn 0.969682 0.166170 -0.179176 +vn 0.754037 0.504418 0.420704 +vn 0.828561 0.316590 0.461798 +vn 0.943283 -0.080094 -0.322182 +vn 0.996799 0.009221 -0.079417 +vn 0.775768 0.382141 0.502148 +vn -0.535922 0.815786 -0.217442 +vn -0.711742 0.631198 -0.308241 +vn -0.720586 0.670982 -0.174754 +vn -0.411496 0.796168 0.443607 +vn -0.094379 0.527301 0.844421 +vn -0.069752 0.407704 0.910446 +vn -0.075227 0.509317 0.857284 +vn -0.899322 0.217218 0.379522 +vn -0.856971 0.404836 0.318918 +vn -0.929488 0.002263 0.368846 +vn -0.913020 0.111991 0.392239 +vn -0.775244 0.155507 0.612221 +vn -0.809953 0.130294 0.571839 +vn -0.809970 0.211451 0.547026 +vn -0.512438 -0.473965 0.716075 +vn -0.470746 -0.365488 0.803005 +vn -0.622708 -0.554524 0.552030 +vn -0.804795 -0.592927 -0.027236 +vn -0.935688 -0.349566 -0.047865 +vn -0.979826 -0.199093 0.017388 +vn -0.969660 -0.244405 0.004995 +vn 0.346030 -0.645322 0.681045 +vn 0.150051 -0.816598 0.557361 +vn 0.305963 -0.903395 0.300439 +vn -0.106894 -0.879100 -0.464497 +vn -0.379304 -0.604701 -0.700332 +vn -0.457451 -0.550271 -0.698527 +vn -0.396771 -0.701295 -0.592249 +vn 0.835906 -0.548834 -0.006518 +vn 0.923602 -0.381844 0.033966 +vn 0.863214 -0.393372 -0.316418 +vn 0.605500 -0.431678 -0.668598 +vn 0.534229 -0.375452 -0.757387 +vn 0.609831 -0.367158 -0.702354 +vn 0.606094 -0.512127 -0.608586 +vn -0.287104 -0.930941 0.225655 +vn 0.184384 -0.421751 -0.887766 +vn 0.730773 0.322890 0.601426 +vn 0.855333 0.060647 0.514517 +vn 0.074051 0.631917 0.771490 +vn 0.209807 0.742786 0.635807 +vn 0.616222 0.371327 0.694540 +vn 0.095818 0.746431 0.658528 +vn 0.821336 0.180467 0.541145 +vn 0.408064 0.912344 -0.033360 +vn 0.969682 0.166170 0.179175 +vn 0.754037 0.504418 -0.420704 +vn 0.943283 -0.080094 0.322182 +vn 0.828560 0.316590 -0.461799 +vn 0.996799 0.009221 0.079417 +vn 0.775768 0.382141 -0.502148 +vn -0.535922 0.815786 0.217442 +vn -0.711742 0.631198 0.308241 +vn -0.720586 0.670982 0.174754 +vn -0.411496 0.796168 -0.443607 +vn -0.094380 0.527301 -0.844421 +vn -0.069752 0.407704 -0.910446 +vn -0.075227 0.509317 -0.857285 +vn -0.899322 0.217218 -0.379522 +vn -0.856971 0.404836 -0.318918 +vn -0.929488 0.002263 -0.368845 +vn -0.913020 0.111991 -0.392239 +vn -0.775244 0.155506 -0.612221 +vn -0.809952 0.130294 -0.571839 +vn -0.809969 0.211450 -0.547027 +vn -0.512438 -0.473965 -0.716075 +vn -0.470746 -0.365488 -0.803005 +vn -0.622708 -0.554524 -0.552030 +vn -0.804795 -0.592928 0.027236 +vn -0.935688 -0.349566 0.047865 +vn -0.979826 -0.199093 -0.017388 +vn -0.969660 -0.244405 -0.004995 +vn 0.346030 -0.645322 -0.681045 +vn 0.150051 -0.816598 -0.557361 +vn 0.305964 -0.903395 -0.300439 +vn -0.106895 -0.879100 0.464496 +vn -0.379305 -0.604701 0.700332 +vn -0.457451 -0.550271 0.698527 +vn -0.396771 -0.701294 0.592249 +vn 0.835906 -0.548834 0.006518 +vn 0.923602 -0.381844 -0.033966 +vn 0.863214 -0.393373 0.316418 +vn 0.605500 -0.431679 0.668598 +vn 0.534230 -0.375452 0.757387 +vn 0.609831 -0.367158 0.702354 +vn 0.606094 -0.512126 0.608586 +vn 0.000000 0.000000 0.000000 +vn 0.891945 0.333606 -0.305190 +vn 0.885286 -0.051708 0.462163 +vn 0.871701 -0.486404 -0.059574 +vn 0.602535 -0.114023 0.789906 +vn 0.767332 -0.613878 0.185353 +vn 0.615704 -0.238766 0.750932 +vn -0.132228 0.076598 0.988255 +vn -0.134483 0.218923 0.966430 +vn -0.082654 0.333036 0.939285 +vn -0.794263 0.362851 0.487325 +vn -0.686973 0.538875 0.487527 +vn -0.911656 -0.242414 -0.331840 +vn -0.903470 -0.005854 -0.428611 +vn -0.880207 0.284493 -0.379868 +vn -0.359072 -0.293407 -0.885991 +vn -0.531215 -0.161650 -0.831673 +vn 0.521710 -0.333452 -0.785257 +vn 0.498223 -0.518213 -0.695147 +vn 0.319252 -0.666930 -0.673263 +vn 0.417209 0.602930 -0.680009 +vn -0.390952 -0.506393 -0.768585 +vn -0.785847 -0.219916 -0.577999 +vn -0.112803 -0.767065 -0.631575 +vn -0.676852 -0.452073 -0.580948 +vn -0.070613 -0.785109 -0.615320 +vn 0.404464 -0.913005 -0.053206 +vn 0.510041 -0.851111 -0.124372 +vn 0.600863 -0.776753 -0.188727 +vn 0.734160 -0.298249 0.609964 +vn 0.802855 -0.245127 0.543449 +vn 0.203920 0.286548 0.936113 +vn 0.259058 0.346923 0.901407 +vn 0.305077 0.413607 0.857821 +vn -0.395140 0.672313 0.625987 +vn -0.388204 0.672327 0.630297 +vn -0.844407 0.508563 -0.168344 +vn -0.907377 0.410201 -0.091666 +vn -0.943128 0.331776 0.020840 +vn -0.032685 0.987521 0.154060 +vn 0.285617 0.953018 0.100890 +vn 0.356408 0.929723 0.092678 +vn 0.058045 0.915295 0.398579 +vn -0.438098 -0.839825 0.320570 +vn 0.039808 -0.749385 0.660937 +vn -0.436422 -0.758689 0.483660 +vn -0.144622 0.858467 0.492057 +vn -0.390508 -0.802547 0.451023 +vn -0.378955 0.768626 0.515371 +vn -0.351840 -0.855427 0.380071 +vn -0.503913 0.811284 0.296463 +vn -0.434503 -0.886238 0.160593 +vn -0.589554 0.766850 0.253707 +vn 0.461124 -0.566742 0.682765 +vn -0.033279 -0.530249 0.847189 +vn -0.155076 -0.479386 0.863794 +vn -0.332554 -0.675497 0.658112 +vn -0.624353 -0.649034 0.434671 +vn -0.640430 -0.723275 0.258307 +vn 0.839146 -0.520972 0.156274 +vn 0.979386 -0.047392 0.196359 +vn 0.859197 -0.013066 0.511478 +vn 0.169781 0.017978 0.985318 +vn -0.298124 0.093164 0.949970 +vn -0.602581 0.140795 0.785540 +vn -0.760623 0.356880 0.542300 +vn -0.916442 -0.012784 0.399964 +vn 0.709959 0.689780 0.141992 +vn 0.616328 0.711155 0.338227 +vn 0.121528 0.638102 0.760300 +vn -0.308158 0.474484 0.824563 +vn -0.584949 0.497866 0.640284 +vn -0.831395 0.369875 0.414699 +vn -0.777389 0.439755 0.449757 +vn -0.712098 0.074375 0.698130 +vn -0.522162 -0.582125 0.623279 +vn -0.536293 0.842625 0.048710 +vn -0.627855 0.740316 0.240274 +vn -0.817995 0.476796 0.321792 +vn -0.729171 0.655795 0.195555 +vn -0.958544 0.215108 0.186875 +vn -0.950592 0.163928 0.263634 +vn -0.983392 -0.022830 0.180052 +vn -0.891745 0.110754 0.438776 +vn -0.991858 -0.087830 0.092218 +vn -0.859104 0.044821 0.509835 +vn -0.894952 -0.402899 0.191658 +vn -0.903611 0.009093 0.428257 +vn -0.889320 0.017457 0.456952 +vn -0.731541 -0.492421 0.471561 +vn -0.794103 -0.178378 0.581017 +vn -0.625933 -0.373553 0.684592 +vn -0.584508 -0.184831 0.790056 +vn -0.801518 -0.104269 0.588809 +vn -0.642031 -0.296727 0.706929 +vn -0.820281 -0.123456 0.558478 +vn 0.016905 -0.936472 -0.350333 +vn -0.098795 -0.739900 -0.665423 +vn -0.069462 -0.936749 -0.343039 +vn 0.123931 -0.992291 -0.000000 +vn 0.035891 -0.855981 -0.515760 +vn -0.028951 -0.999581 0.000000 +vn 0.016905 -0.936472 0.350333 +vn -0.069462 -0.936749 0.343039 +vn -0.334402 -0.916161 -0.220964 +vn -0.790477 -0.612492 -0.000000 +vn -0.334402 -0.916161 0.220964 +vn -0.741010 -0.556660 0.375544 +vn -0.274313 -0.889661 0.365042 +vn -0.098795 -0.739900 0.665423 +vn 0.035891 -0.855981 0.515760 +vn -0.274313 -0.889661 -0.365042 +vn -0.741010 -0.556660 -0.375544 +vn 0.356408 0.929723 -0.092678 +vn 0.285617 0.953018 -0.100890 +vn -0.032685 0.987521 -0.154060 +vn 0.058045 0.915295 -0.398579 +vn -0.436422 -0.758689 -0.483660 +vn 0.039808 -0.749385 -0.660937 +vn -0.438098 -0.839825 -0.320570 +vn -0.144622 0.858467 -0.492057 +vn -0.390508 -0.802547 -0.451023 +vn -0.378955 0.768626 -0.515371 +vn -0.351840 -0.855427 -0.380071 +vn -0.503913 0.811284 -0.296463 +vn -0.434503 -0.886238 -0.160593 +vn -0.589554 0.766850 -0.253707 +vn -0.033279 -0.530249 -0.847189 +vn 0.461124 -0.566742 -0.682765 +vn -0.155076 -0.479386 -0.863794 +vn -0.332554 -0.675497 -0.658112 +vn -0.624352 -0.649034 -0.434671 +vn -0.640430 -0.723275 -0.258307 +vn 0.979386 -0.047392 -0.196359 +vn 0.839147 -0.520972 -0.156274 +vn 0.859197 -0.013067 -0.511478 +vn 0.169781 0.017978 -0.985318 +vn -0.298124 0.093164 -0.949970 +vn -0.602580 0.140795 -0.785540 +vn -0.760623 0.356880 -0.542300 +vn -0.916442 -0.012784 -0.399964 +vn 0.616328 0.711155 -0.338227 +vn 0.709959 0.689780 -0.141992 +vn 0.121527 0.638102 -0.760300 +vn -0.308158 0.474484 -0.824563 +vn -0.584949 0.497867 -0.640284 +vn -0.831395 0.369875 -0.414699 +vn -0.777389 0.439755 -0.449757 +vn -0.536292 0.842626 -0.048710 +vn -0.522164 -0.582123 -0.623280 +vn -0.712098 0.074377 -0.698129 +vn -0.627854 0.740316 -0.240274 +vn -0.817995 0.476797 -0.321792 +vn -0.729171 0.655796 -0.195555 +vn -0.958544 0.215108 -0.186875 +vn -0.950592 0.163928 -0.263634 +vn -0.891745 0.110753 -0.438776 +vn -0.983392 -0.022830 -0.180053 +vn -0.859104 0.044821 -0.509834 +vn -0.991858 -0.087831 -0.092217 +vn -0.894953 -0.402899 -0.191657 +vn -0.903611 0.009093 -0.428257 +vn -0.889320 0.017458 -0.456952 +vn -0.731541 -0.492420 -0.471561 +vn -0.794103 -0.178378 -0.581018 +vn -0.625932 -0.373553 -0.684593 +vn -0.584507 -0.184830 -0.790056 +vn -0.801518 -0.104269 -0.588809 +vn -0.642031 -0.296727 -0.706930 +vn -0.820281 -0.123456 -0.558478 +vn 0.891944 0.333618 0.305179 +vn 0.602535 -0.114021 -0.789905 +vn 0.871702 -0.486402 0.059575 +vn 0.885285 -0.051707 -0.462165 +vn 0.767335 -0.613875 -0.185352 +vn 0.615706 -0.238765 -0.750931 +vn -0.132228 0.076598 -0.988255 +vn -0.134482 0.218923 -0.966430 +vn -0.082654 0.333036 -0.939284 +vn -0.794263 0.362851 -0.487325 +vn -0.686973 0.538875 -0.487526 +vn -0.911656 -0.242414 0.331840 +vn -0.903470 -0.005854 0.428611 +vn -0.880207 0.284493 0.379868 +vn -0.359072 -0.293407 0.885991 +vn -0.531215 -0.161650 0.831673 +vn 0.521709 -0.333452 0.785258 +vn 0.498223 -0.518212 0.695148 +vn 0.319253 -0.666929 0.673264 +vn 0.417208 0.602931 0.680009 +vn -0.112803 -0.767065 0.631575 +vn -0.785847 -0.219916 0.577998 +vn -0.390952 -0.506392 0.768585 +vn -0.676852 -0.452073 0.580948 +vn -0.070613 -0.785108 0.615320 +vn 0.404464 -0.913005 0.053206 +vn 0.510042 -0.851111 0.124372 +vn 0.600863 -0.776753 0.188727 +vn 0.734160 -0.298249 -0.609964 +vn 0.802854 -0.245127 -0.543450 +vn 0.203920 0.286548 -0.936113 +vn 0.259058 0.346923 -0.901407 +vn 0.305077 0.413607 -0.857821 +vn -0.395140 0.672312 -0.625988 +vn -0.388204 0.672327 -0.630297 +vn -0.844407 0.508563 0.168344 +vn -0.907377 0.410201 0.091666 +vn -0.943128 0.331776 -0.020840 +vn 0.092832 0.340544 0.935634 +vn 0.433215 0.308260 0.846936 +vn 0.075136 0.741809 0.666389 +vn -0.375593 0.622444 0.686654 +vn -0.641388 0.689588 0.336288 +vn -0.353918 0.873123 0.335258 +vn -0.662764 0.746241 -0.062188 +vn -0.545563 0.658509 -0.518389 +vn -0.542286 0.268594 -0.796105 +vn -0.776382 0.468027 -0.422116 +vn -0.995559 -0.032197 -0.088459 +vn -0.738154 -0.230737 -0.633948 +vn -0.433216 -0.308258 -0.846936 +vn -0.776385 -0.629857 -0.022517 +vn -0.467564 -0.874397 0.129668 +vn -0.542292 -0.717476 -0.437204 +vn -0.189834 -0.854102 0.484223 +vn -0.545805 -0.711395 0.442735 +vn -0.641391 -0.312091 0.700868 +vn -0.215356 -0.623780 0.751346 +vn 0.037501 -0.724698 0.688046 +vn -0.375594 -0.035443 0.926107 +vn 0.078137 -0.268605 0.960076 +vn -0.757385 0.223328 0.613590 +vn -0.902417 0.400663 0.158468 +vn -0.902417 -0.205066 0.378934 +vn 0.075136 0.741809 -0.666389 +vn 0.433215 0.308260 -0.846936 +vn 0.092832 0.340544 -0.935635 +vn -0.375593 0.622444 -0.686654 +vn -0.353918 0.873123 -0.335257 +vn -0.641388 0.689588 -0.336288 +vn -0.662764 0.746241 0.062188 +vn -0.776382 0.468027 0.422116 +vn -0.542286 0.268594 0.796105 +vn -0.545562 0.658510 0.518389 +vn -0.738154 -0.230737 0.633948 +vn -0.995559 -0.032196 0.088459 +vn -0.433216 -0.308258 0.846936 +vn -0.776385 -0.629856 0.022517 +vn -0.542292 -0.717477 0.437204 +vn -0.467565 -0.874397 -0.129668 +vn -0.545805 -0.711394 -0.442736 +vn -0.189834 -0.854102 -0.484223 +vn -0.215356 -0.623779 -0.751346 +vn -0.641391 -0.312091 -0.700869 +vn 0.037501 -0.724698 -0.688046 +vn -0.375594 -0.035443 -0.926106 +vn 0.078136 -0.268605 -0.960076 +vn -0.757384 0.223328 -0.613590 +vn -0.902417 0.400663 -0.158468 +vn -0.902417 -0.205066 -0.378934 +# 747 normals -# Mesh 'HLeib01_HLeib01_HLeib01_HLeib01' with 80 faces -g HLeib01_HLeib01_HLeib01_HLeib01 +g HLeib01 usemtl HLeibTex -f 1/1/1 2/2/2 3/3/3 -f 4/4/4 3/3/3 5/5/5 -f 6/6/6 5/5/5 2/2/2 -f 3/3/3 2/2/2 5/5/5 -f 1/1/1 3/3/3 7/7/7 -f 8/8/8 7/7/7 9/9/9 -f 4/4/4 9/9/9 3/3/3 -f 7/7/7 3/3/3 9/9/9 -f 8/8/8 9/9/9 10/10/10 -f 11/11/11 10/10/10 12/12/12 -f 4/4/4 12/12/12 9/9/9 -f 10/10/10 9/9/9 12/12/12 -f 4/4/4 13/13/13 12/12/12 -f 11/11/11 12/12/12 14/14/14 -f 15/15/15 14/14/14 13/13/13 -f 12/12/12 13/13/13 14/14/14 -f 4/4/4 5/5/5 13/13/13 -f 15/15/15 13/13/13 16/16/16 -f 6/6/6 16/16/16 5/5/5 -f 13/13/13 5/5/5 16/16/16 -f 15/15/15 16/16/16 17/17/17 -f 18/18/18 17/17/17 19/19/19 -f 6/6/6 19/19/19 16/16/16 -f 17/17/17 16/16/16 19/19/19 -f 15/15/15 17/17/17 20/20/20 -f 21/21/21 20/20/20 22/22/22 -f 18/18/18 22/22/22 17/17/17 -f 20/20/20 17/17/17 22/22/22 -f 11/11/11 14/14/14 23/23/23 -f 21/21/21 23/23/23 20/20/20 -f 15/15/15 20/20/20 14/14/14 -f 23/23/23 14/14/14 20/20/20 -f 11/11/11 23/23/23 24/24/24 -f 25/25/25 24/24/24 26/26/26 -f 21/21/21 26/26/26 23/23/23 -f 24/24/24 23/23/23 26/26/26 -f 25/25/25 26/26/26 27/27/27 -f 28/28/28 27/27/27 29/29/29 -f 21/21/21 29/29/29 26/26/26 -f 27/27/27 26/26/26 29/29/29 -f 28/28/28 29/29/29 30/30/30 -f 18/18/18 30/30/30 22/22/22 -f 21/21/21 22/22/22 29/29/29 -f 30/30/30 29/29/29 22/22/22 -f 28/28/28 30/30/30 31/31/31 -f 32/32/32 31/31/31 33/33/33 -f 18/18/18 33/33/33 30/30/30 -f 31/31/31 30/30/30 33/33/33 -f 28/28/28 31/31/31 34/34/34 -f 35/35/35 34/34/34 36/36/36 -f 32/32/32 36/36/36 31/31/31 -f 34/34/34 31/31/31 36/36/36 -f 35/35/35 36/36/36 37/37/37 -f 1/1/1 37/37/37 38/38/38 -f 32/32/32 38/38/38 36/36/36 -f 37/37/37 36/36/36 38/38/38 -f 1/1/1 38/38/38 2/2/2 -f 6/6/6 2/2/2 39/39/39 -f 32/32/32 39/39/39 38/38/38 -f 2/2/2 38/38/38 39/39/39 -f 32/32/32 33/33/33 39/39/39 -f 6/6/6 39/39/39 19/19/19 -f 18/18/18 19/19/19 33/33/33 -f 39/39/39 33/33/33 19/19/19 -f 8/8/8 40/40/40 7/7/7 -f 1/1/1 7/7/7 37/37/37 -f 35/35/35 37/37/37 40/40/40 -f 7/7/7 40/40/40 37/37/37 -f 8/8/8 41/41/41 40/40/40 -f 35/35/35 40/40/40 42/42/42 -f 25/25/25 42/42/42 41/41/41 -f 40/40/40 41/41/41 42/42/42 -f 8/8/8 10/10/10 41/41/41 -f 25/25/25 41/41/41 24/24/24 -f 11/11/11 24/24/24 10/10/10 -f 41/41/41 10/10/10 24/24/24 -f 28/28/28 34/34/34 27/27/27 -f 25/25/25 27/27/27 42/42/42 -f 35/35/35 42/42/42 34/34/34 -f 27/27/27 34/34/34 42/42/42 +s 1 +f 1/1/1 2/2/2 3/3/3 +f 4/4/4 3/3/3 5/5/5 +f 6/6/6 5/5/5 2/2/2 +f 3/3/3 2/2/2 5/5/5 +f 1/1/1 3/3/3 7/7/7 +f 8/8/8 7/7/7 9/9/9 +f 4/4/4 9/9/9 3/3/3 +f 7/7/7 3/3/3 9/9/9 +f 8/8/8 9/9/9 10/10/10 +f 11/11/11 10/10/10 12/12/12 +f 4/4/4 12/12/12 9/9/9 +f 10/10/10 9/9/9 12/12/12 +f 4/4/4 13/13/13 12/12/12 +f 11/11/11 12/12/12 14/14/14 +f 15/15/15 14/14/14 13/13/13 +f 12/12/12 13/13/13 14/14/14 +f 4/4/4 5/5/5 13/13/13 +f 15/15/15 13/13/13 16/16/16 +f 6/6/6 16/16/16 5/5/5 +f 13/13/13 5/5/5 16/16/16 +f 15/15/15 16/16/16 17/17/17 +f 18/18/18 17/17/17 19/19/19 +f 6/6/6 19/19/19 16/16/16 +f 17/17/17 16/16/16 19/19/19 +f 15/15/15 17/17/17 20/20/20 +f 21/21/21 20/20/20 22/22/22 +f 18/18/18 22/22/22 17/17/17 +f 20/20/20 17/17/17 22/22/22 +f 11/11/11 14/14/14 23/23/23 +f 21/21/21 23/23/23 20/20/20 +f 15/15/15 20/20/20 14/14/14 +f 23/23/23 14/14/14 20/20/20 +f 11/11/11 23/23/23 24/24/24 +f 25/25/25 24/24/24 26/26/26 +f 21/21/21 26/26/26 23/23/23 +f 24/24/24 23/23/23 26/26/26 +f 25/25/25 26/26/26 27/27/27 +f 28/28/28 27/27/27 29/29/29 +f 21/21/21 29/29/29 26/26/26 +f 27/27/27 26/26/26 29/29/29 +f 28/28/28 29/29/29 30/30/30 +f 18/18/18 30/30/30 22/22/22 +f 21/21/21 22/22/22 29/29/29 +f 30/30/30 29/29/29 22/22/22 +f 28/28/28 30/30/30 31/31/31 +f 32/32/32 31/31/31 33/33/33 +f 18/18/18 33/33/33 30/30/30 +f 31/31/31 30/30/30 33/33/33 +f 28/28/28 31/31/31 34/34/34 +f 35/35/35 34/34/34 36/36/36 +f 32/32/32 36/36/36 31/31/31 +f 34/34/34 31/31/31 36/36/36 +f 35/35/35 36/36/36 37/37/37 +f 1/1/1 37/37/37 38/38/38 +f 32/32/32 38/38/38 36/36/36 +f 37/37/37 36/36/36 38/38/38 +f 1/1/1 38/38/38 2/2/2 +f 6/6/6 2/2/2 39/39/39 +f 32/32/32 39/39/39 38/38/38 +f 2/2/2 38/38/38 39/39/39 +f 32/32/32 33/33/33 39/39/39 +f 6/6/6 39/39/39 19/19/19 +f 18/18/18 19/19/19 33/33/33 +f 39/39/39 33/33/33 19/19/19 +f 8/8/8 40/40/40 7/7/7 +f 1/1/1 7/7/7 37/37/37 +f 35/35/35 37/37/37 40/40/40 +f 7/7/7 40/40/40 37/37/37 +f 8/8/8 41/41/41 40/40/40 +f 35/35/35 40/40/40 42/42/42 +f 25/25/25 42/42/42 41/41/41 +f 40/40/40 41/41/41 42/42/42 +f 8/8/8 10/10/10 41/41/41 +f 25/25/25 41/41/41 24/24/24 +f 11/11/11 24/24/24 10/10/10 +f 41/41/41 10/10/10 24/24/24 +f 28/28/28 34/34/34 27/27/27 +f 25/25/25 27/27/27 42/42/42 +f 35/35/35 42/42/42 34/34/34 +f 27/27/27 34/34/34 42/42/42 +# 80 triangles in group -# Mesh 'OK_OK_OK_OK' with 60 faces -g OK_OK_OK_OK +g OK usemtl Skin -f 43/43/43 44/44/44 45/45/45 -f 46/46/46 45/45/45 47/47/47 -f 48/48/48 47/47/47 44/44/44 -f 45/45/45 44/44/44 47/47/47 -f 43/43/43 45/45/45 49/49/49 -f 50/50/50 49/49/49 51/51/51 -f 46/46/46 51/51/51 45/45/45 -f 49/49/49 45/45/45 51/51/51 -f 50/50/50 51/51/51 52/52/52 -f 53/53/53 52/52/52 54/54/54 -f 46/46/46 54/54/54 51/51/51 -f 52/52/52 51/51/51 54/54/54 -f 46/46/46 55/55/55 54/54/54 -f 53/53/53 54/54/54 56/56/56 -f 57/57/57 56/56/56 55/55/55 -f 54/54/54 55/55/55 56/56/56 -f 46/46/46 47/47/47 55/55/55 -f 57/57/57 55/55/55 58/58/58 -f 48/48/48 58/58/58 47/47/47 -f 55/55/55 47/47/47 58/58/58 -f 57/57/57 58/58/58 59/59/59 -f 60/57/60 59/59/59 61/58/61 -f 48/48/48 61/58/61 58/58/58 -f 59/59/59 58/58/58 61/58/61 -f 57/57/57 59/59/59 62/60/62 -f 63/61/63 62/60/62 64/60/64 -f 60/57/60 64/60/64 59/59/59 -f 62/60/62 59/59/59 64/60/64 -f 53/53/53 56/56/56 65/62/65 -f 63/61/63 65/62/65 62/60/62 -f 57/57/57 62/60/62 56/56/56 -f 65/62/65 56/56/56 62/60/62 -f 53/53/53 65/62/65 66/63/66 -f 67/64/67 66/63/66 68/65/68 -f 63/61/63 68/65/68 65/62/65 -f 66/63/66 65/62/65 68/65/68 -f 67/64/67 68/65/68 69/63/69 -f 70/53/70 69/63/69 71/62/71 -f 63/61/63 71/62/71 68/65/68 -f 69/63/69 68/65/68 71/62/71 -f 63/61/63 64/60/64 71/62/71 -f 43/43/43 72/49/72 73/45/73 -f 43/43/43 73/45/73 44/44/44 -f 48/48/48 44/44/44 74/47/74 -f 75/46/75 74/47/74 73/45/73 -f 44/44/44 73/45/73 74/47/74 -f 48/48/48 74/47/74 61/58/61 -f 50/50/50 76/66/76 49/49/49 -f 43/43/43 49/49/49 72/49/72 -f 77/50/77 72/49/72 76/66/76 -f 49/49/49 76/66/76 72/49/72 -f 50/50/50 78/67/78 76/66/76 -f 77/50/77 76/66/76 79/67/79 -f 67/64/67 79/67/79 78/67/78 -f 76/66/76 78/67/78 79/67/79 -f 50/50/50 52/52/52 78/67/78 -f 67/64/67 78/67/78 66/63/66 -f 53/53/53 66/63/66 52/52/52 -f 78/67/78 52/52/52 66/63/66 -f 67/64/67 69/63/69 79/67/79 +f 43/43/43 44/44/44 45/45/45 +f 46/46/46 45/45/45 47/47/47 +f 48/48/48 47/47/47 44/44/44 +f 45/45/45 44/44/44 47/47/47 +f 43/43/43 45/45/45 49/49/49 +f 50/50/50 49/49/49 51/51/51 +f 46/46/46 51/51/51 45/45/45 +f 49/49/49 45/45/45 51/51/51 +f 50/50/50 51/51/51 52/52/52 +f 53/53/53 52/52/52 54/54/54 +f 46/46/46 54/54/54 51/51/51 +f 52/52/52 51/51/51 54/54/54 +f 46/46/46 55/55/55 54/54/54 +f 53/53/53 54/54/54 56/56/56 +f 57/57/57 56/56/56 55/55/55 +f 54/54/54 55/55/55 56/56/56 +f 46/46/46 47/47/47 55/55/55 +f 57/57/57 55/55/55 58/58/58 +f 48/48/48 58/58/58 47/47/47 +f 55/55/55 47/47/47 58/58/58 +f 57/57/57 58/58/58 59/59/59 +f 60/57/60 59/59/59 61/58/61 +f 48/48/48 61/58/61 58/58/58 +f 59/59/59 58/58/58 61/58/61 +f 57/57/57 59/59/59 62/60/62 +f 63/61/63 62/60/62 64/60/64 +f 60/57/60 64/60/64 59/59/59 +f 62/60/62 59/59/59 64/60/64 +f 53/53/53 56/56/56 65/62/65 +f 63/61/63 65/62/65 62/60/62 +f 57/57/57 62/60/62 56/56/56 +f 65/62/65 56/56/56 62/60/62 +f 53/53/53 65/62/65 66/63/66 +f 67/64/67 66/63/66 68/65/68 +f 63/61/63 68/65/68 65/62/65 +f 66/63/66 65/62/65 68/65/68 +f 67/64/67 68/65/68 69/63/69 +f 70/53/70 69/63/69 71/62/71 +f 63/61/63 71/62/71 68/65/68 +f 69/63/69 68/65/68 71/62/71 +f 63/61/63 64/60/64 71/62/71 +f 43/43/43 74/49/72 75/45/73 +f 43/43/43 75/45/73 44/44/44 +f 48/48/48 44/44/44 76/47/74 +f 72/46/75 76/47/74 75/45/73 +f 44/44/44 75/45/73 76/47/74 +f 48/48/48 76/47/74 61/58/61 +f 50/50/50 77/66/76 49/49/49 +f 43/43/43 49/49/49 74/49/72 +f 73/50/77 74/49/72 77/66/76 +f 49/49/49 77/66/76 74/49/72 +f 50/50/50 78/67/78 77/66/76 +f 73/50/77 77/66/76 79/67/79 +f 67/64/67 79/67/79 78/67/78 +f 77/66/76 78/67/78 79/67/79 +f 50/50/50 52/52/52 78/67/78 +f 67/64/67 78/67/78 66/63/66 +f 53/53/53 66/63/66 52/52/52 +f 78/67/78 52/52/52 66/63/66 +f 67/64/67 69/63/69 79/67/79 +# 60 triangles in group -# Mesh 'Bein1Li_Bein1Li_Bein1Li_Bein1Li' with 98 faces -g Bein1Li_Bein1Li_Bein1Li_Bein1Li +g Bein1Li usemtl BeinTex -f 80/68/80 81/68/80 82/68/80 -f 83/68/81 84/68/81 85/68/81 -f 80/69/82 86/70/83 87/71/84 -f 80/69/82 87/71/84 81/72/85 -f 86/70/83 88/73/86 87/71/84 -f 88/73/86 89/74/87 87/71/84 -f 88/73/86 90/75/88 91/76/89 -f 88/73/86 91/76/89 89/74/87 -f 90/75/88 92/77/90 91/76/89 -f 92/77/90 93/78/91 91/76/89 -f 92/77/90 94/79/92 95/80/93 -f 92/77/90 95/80/93 93/78/91 -f 94/79/92 83/68/94 95/80/93 -f 83/68/94 85/81/95 95/80/93 -f 81/68/80 96/68/80 82/68/80 -f 85/68/81 84/68/81 97/68/81 -f 81/72/85 87/71/84 96/82/96 -f 87/71/84 98/83/97 96/82/96 -f 87/71/84 89/74/87 99/84/98 -f 87/71/84 99/84/98 98/83/97 -f 89/74/87 91/76/89 99/84/98 -f 91/76/89 100/85/99 99/84/98 -f 91/76/89 93/78/91 101/86/100 -f 91/76/89 101/86/100 100/85/99 -f 93/78/91 95/80/93 101/86/100 -f 95/80/93 102/87/101 101/86/100 -f 95/80/93 85/81/95 97/88/102 -f 95/80/93 97/88/102 102/87/101 -f 96/68/80 103/68/80 82/68/80 -f 97/68/81 84/68/81 104/68/81 -f 96/82/96 98/83/97 105/89/103 -f 96/82/96 105/89/103 103/90/104 -f 98/83/97 99/84/98 105/89/103 -f 99/84/98 106/91/105 105/89/103 -f 99/84/98 100/85/99 107/92/106 -f 99/84/98 107/92/106 106/91/105 -f 100/85/99 101/86/100 107/92/106 -f 101/86/100 108/93/107 107/92/106 -f 101/86/100 102/87/101 109/94/108 -f 101/86/100 109/94/108 108/93/107 -f 102/87/101 97/88/102 109/94/108 -f 97/88/102 104/95/109 109/94/108 -f 103/68/80 110/68/80 82/68/80 -f 104/68/81 84/68/81 111/68/81 -f 103/90/104 105/89/103 110/96/110 -f 105/89/103 112/97/111 110/96/110 -f 105/89/103 106/91/105 113/98/112 -f 105/89/103 113/98/112 112/97/111 -f 106/91/105 107/92/106 113/98/112 -f 107/92/106 114/99/113 113/98/112 -f 107/92/106 108/93/107 115/100/114 -f 107/92/106 115/100/114 114/99/113 -f 108/93/107 109/94/108 115/100/114 -f 109/94/108 116/101/115 115/100/114 -f 109/94/108 104/95/109 111/102/116 -f 109/94/108 111/102/116 116/101/115 -f 110/68/80 117/68/80 82/68/80 -f 111/68/81 84/68/81 118/68/81 -f 110/96/110 112/97/111 119/103/117 -f 110/96/110 119/103/117 117/104/118 -f 112/97/111 113/98/112 119/103/117 -f 113/98/112 120/105/119 119/103/117 -f 113/98/112 114/99/113 121/106/120 -f 113/98/112 121/106/120 120/105/119 -f 114/99/113 115/100/114 121/106/120 -f 115/100/114 122/107/121 121/106/120 -f 115/100/114 116/101/115 123/108/122 -f 115/100/114 123/108/122 122/107/121 -f 116/101/115 111/102/116 123/108/122 -f 111/102/116 118/109/123 123/108/122 -f 117/68/80 124/68/80 82/68/80 -f 118/68/81 84/68/81 125/68/81 -f 117/104/118 119/103/117 124/110/124 -f 119/103/117 126/111/125 124/110/124 -f 119/103/117 120/105/119 127/112/126 -f 119/103/117 127/112/126 126/111/125 -f 120/105/119 121/106/120 127/112/126 -f 121/106/120 128/113/127 127/112/126 -f 121/106/120 122/107/121 129/114/128 -f 121/106/120 129/114/128 128/113/127 -f 122/107/121 123/108/122 129/114/128 -f 123/108/122 130/115/129 129/114/128 -f 123/108/122 118/109/123 125/116/130 -f 123/108/122 125/116/130 130/115/129 -f 124/68/80 80/68/80 82/68/80 -f 125/68/81 84/68/81 83/68/81 -f 124/110/124 126/111/125 86/117/83 -f 124/110/124 86/117/83 80/118/82 -f 126/111/125 127/112/126 86/117/83 -f 127/112/126 88/119/86 86/117/83 -f 127/112/126 128/113/127 90/120/88 -f 127/112/126 90/120/88 88/119/86 -f 128/113/127 129/114/128 90/120/88 -f 129/114/128 92/121/90 90/120/88 -f 129/114/128 130/115/129 94/122/92 -f 129/114/128 94/122/92 92/121/90 -f 130/115/129 125/116/130 94/122/92 -f 125/116/130 83/123/94 94/122/92 +s 2 +f 80/68/80 87/68/80 130/68/80 +f 86/68/81 129/68/81 93/68/81 +s 1 +f 80/69/82 81/70/83 88/71/84 +f 80/69/82 88/71/84 87/72/85 +f 81/70/83 82/73/86 88/71/84 +f 82/73/86 89/74/87 88/71/84 +f 82/73/86 83/75/88 90/76/89 +f 82/73/86 90/76/89 89/74/87 +f 83/75/88 84/77/90 90/76/89 +f 84/77/90 91/78/91 90/76/89 +f 84/77/90 85/79/92 92/80/93 +f 84/77/90 92/80/93 91/78/91 +f 85/79/92 86/68/94 92/80/93 +f 86/68/94 93/81/95 92/80/93 +s 2 +f 87/68/80 94/68/80 130/68/80 +f 93/68/81 129/68/81 100/68/81 +s 1 +f 87/72/85 88/71/84 94/82/96 +f 88/71/84 95/83/97 94/82/96 +f 88/71/84 89/74/87 96/84/98 +f 88/71/84 96/84/98 95/83/97 +f 89/74/87 90/76/89 96/84/98 +f 90/76/89 97/85/99 96/84/98 +f 90/76/89 91/78/91 98/86/100 +f 90/76/89 98/86/100 97/85/99 +f 91/78/91 92/80/93 98/86/100 +f 92/80/93 99/87/101 98/86/100 +f 92/80/93 93/81/95 100/88/102 +f 92/80/93 100/88/102 99/87/101 +s 2 +f 94/68/80 101/68/80 130/68/80 +f 100/68/81 129/68/81 107/68/81 +s 1 +f 94/82/96 95/83/97 102/89/103 +f 94/82/96 102/89/103 101/90/104 +f 95/83/97 96/84/98 102/89/103 +f 96/84/98 103/91/105 102/89/103 +f 96/84/98 97/85/99 104/92/106 +f 96/84/98 104/92/106 103/91/105 +f 97/85/99 98/86/100 104/92/106 +f 98/86/100 105/93/107 104/92/106 +f 98/86/100 99/87/101 106/94/108 +f 98/86/100 106/94/108 105/93/107 +f 99/87/101 100/88/102 106/94/108 +f 100/88/102 107/95/109 106/94/108 +s 2 +f 101/68/80 108/68/80 130/68/80 +f 107/68/81 129/68/81 114/68/81 +s 1 +f 101/90/104 102/89/103 108/96/110 +f 102/89/103 109/97/111 108/96/110 +f 102/89/103 103/91/105 110/98/112 +f 102/89/103 110/98/112 109/97/111 +f 103/91/105 104/92/106 110/98/112 +f 104/92/106 111/99/113 110/98/112 +f 104/92/106 105/93/107 112/100/114 +f 104/92/106 112/100/114 111/99/113 +f 105/93/107 106/94/108 112/100/114 +f 106/94/108 113/101/115 112/100/114 +f 106/94/108 107/95/109 114/102/116 +f 106/94/108 114/102/116 113/101/115 +s 2 +f 108/68/80 115/68/80 130/68/80 +f 114/68/81 129/68/81 121/68/81 +s 1 +f 108/96/110 109/97/111 116/103/117 +f 108/96/110 116/103/117 115/104/118 +f 109/97/111 110/98/112 116/103/117 +f 110/98/112 117/105/119 116/103/117 +f 110/98/112 111/99/113 118/106/120 +f 110/98/112 118/106/120 117/105/119 +f 111/99/113 112/100/114 118/106/120 +f 112/100/114 119/107/121 118/106/120 +f 112/100/114 113/101/115 120/108/122 +f 112/100/114 120/108/122 119/107/121 +f 113/101/115 114/102/116 120/108/122 +f 114/102/116 121/109/123 120/108/122 +s 2 +f 115/68/80 122/68/80 130/68/80 +f 121/68/81 129/68/81 128/68/81 +s 1 +f 115/104/118 116/103/117 122/110/124 +f 116/103/117 123/111/125 122/110/124 +f 116/103/117 117/105/119 124/112/126 +f 116/103/117 124/112/126 123/111/125 +f 117/105/119 118/106/120 124/112/126 +f 118/106/120 125/113/127 124/112/126 +f 118/106/120 119/107/121 126/114/128 +f 118/106/120 126/114/128 125/113/127 +f 119/107/121 120/108/122 126/114/128 +f 120/108/122 127/115/129 126/114/128 +f 120/108/122 121/109/123 128/116/130 +f 120/108/122 128/116/130 127/115/129 +s 2 +f 122/68/80 80/68/80 130/68/80 +f 128/68/81 129/68/81 86/68/81 +s 1 +f 122/110/124 123/111/125 81/117/83 +f 122/110/124 81/117/83 80/118/82 +f 123/111/125 124/112/126 81/117/83 +f 124/112/126 82/119/86 81/117/83 +f 124/112/126 125/113/127 83/120/88 +f 124/112/126 83/120/88 82/119/86 +f 125/113/127 126/114/128 83/120/88 +f 126/114/128 84/121/90 83/120/88 +f 126/114/128 127/115/129 85/122/92 +f 126/114/128 85/122/92 84/121/90 +f 127/115/129 128/116/130 85/122/92 +f 128/116/130 86/123/94 85/122/92 +# 98 triangles in group -# Mesh 'Bein1Re_Bein1Re_Bein1Re_Bein1Re' with 98 faces -g Bein1Re_Bein1Re_Bein1Re_Bein1Re +g Bein1Re usemtl BeinTex -f 131/68/131 132/68/131 133/68/131 -f 134/68/132 135/68/132 136/68/132 -f 137/71/133 138/70/134 133/69/135 -f 132/72/136 137/71/133 133/69/135 -f 137/71/133 139/73/137 138/70/134 -f 137/71/133 140/74/138 139/73/137 -f 141/76/139 142/75/140 139/73/137 -f 140/74/138 141/76/139 139/73/137 -f 141/76/139 143/77/141 142/75/140 -f 141/76/139 144/78/142 143/77/141 -f 145/80/143 146/79/144 143/77/141 -f 144/78/142 145/80/143 143/77/141 -f 145/80/143 136/68/145 146/79/144 -f 145/80/143 134/81/146 136/68/145 -f 131/68/131 147/68/131 132/68/131 -f 148/68/132 135/68/132 134/68/132 -f 147/82/147 137/71/133 132/72/136 -f 147/82/147 149/83/148 137/71/133 -f 150/84/149 140/74/138 137/71/133 -f 149/83/148 150/84/149 137/71/133 -f 150/84/149 141/76/139 140/74/138 -f 150/84/149 151/85/150 141/76/139 -f 152/86/151 144/78/142 141/76/139 -f 151/85/150 152/86/151 141/76/139 -f 152/86/151 145/80/143 144/78/142 -f 152/86/151 153/87/152 145/80/143 -f 148/88/153 134/81/146 145/80/143 -f 153/87/152 148/88/153 145/80/143 -f 131/68/131 154/68/131 147/68/131 -f 155/68/132 135/68/132 148/68/132 -f 156/89/154 149/83/148 147/82/147 -f 154/90/155 156/89/154 147/82/147 -f 156/89/154 150/84/149 149/83/148 -f 156/89/154 157/91/156 150/84/149 -f 158/92/157 151/85/150 150/84/149 -f 157/91/156 158/92/157 150/84/149 -f 158/92/157 152/86/151 151/85/150 -f 158/92/157 159/93/158 152/86/151 -f 160/94/159 153/87/152 152/86/151 -f 159/93/158 160/94/159 152/86/151 -f 160/94/159 148/88/153 153/87/152 -f 160/94/159 155/95/160 148/88/153 -f 131/68/131 161/68/131 154/68/131 -f 162/68/132 135/68/132 155/68/132 -f 161/96/161 156/89/154 154/90/155 -f 161/96/161 163/97/162 156/89/154 -f 164/98/163 157/91/156 156/89/154 -f 163/97/162 164/98/163 156/89/154 -f 164/98/163 158/92/157 157/91/156 -f 164/98/163 165/99/164 158/92/157 -f 166/100/165 159/93/158 158/92/157 -f 165/99/164 166/100/165 158/92/157 -f 166/100/165 160/94/159 159/93/158 -f 166/100/165 167/101/166 160/94/159 -f 162/102/167 155/95/160 160/94/159 -f 167/101/166 162/102/167 160/94/159 -f 131/68/131 168/68/131 161/68/131 -f 169/68/132 135/68/132 162/68/132 -f 170/103/168 163/97/162 161/96/161 -f 168/104/169 170/103/168 161/96/161 -f 170/103/168 164/98/163 163/97/162 -f 170/103/168 171/105/170 164/98/163 -f 172/106/171 165/99/164 164/98/163 -f 171/105/170 172/106/171 164/98/163 -f 172/106/171 166/100/165 165/99/164 -f 172/106/171 173/107/172 166/100/165 -f 174/108/173 167/101/166 166/100/165 -f 173/107/172 174/108/173 166/100/165 -f 174/108/173 162/102/167 167/101/166 -f 174/108/173 169/109/174 162/102/167 -f 131/68/131 175/68/131 168/68/131 -f 176/68/132 135/68/132 169/68/132 -f 175/110/175 170/103/168 168/104/169 -f 175/110/175 177/111/176 170/103/168 -f 178/112/177 171/105/170 170/103/168 -f 177/111/176 178/112/177 170/103/168 -f 178/112/177 172/106/171 171/105/170 -f 178/112/177 179/113/178 172/106/171 -f 180/114/179 173/107/172 172/106/171 -f 179/113/178 180/114/179 172/106/171 -f 180/114/179 174/108/173 173/107/172 -f 180/114/179 181/115/180 174/108/173 -f 176/116/181 169/109/174 174/108/173 -f 181/115/180 176/116/181 174/108/173 -f 131/68/131 133/68/131 175/68/131 -f 136/68/132 135/68/132 176/68/132 -f 138/117/134 177/111/176 175/110/175 -f 133/118/135 138/117/134 175/110/175 -f 138/117/134 178/112/177 177/111/176 -f 138/117/134 139/119/137 178/112/177 -f 142/120/140 179/113/178 178/112/177 -f 139/119/137 142/120/140 178/112/177 -f 142/120/140 180/114/179 179/113/178 -f 142/120/140 143/121/141 180/114/179 -f 146/122/144 181/115/180 180/114/179 -f 143/121/141 146/122/144 180/114/179 -f 146/122/144 176/116/181 181/115/180 -f 146/122/144 136/123/145 176/116/181 +s 2 +f 181/68/131 138/68/131 131/68/131 +f 144/68/132 180/68/132 137/68/132 +s 1 +f 139/71/133 132/70/134 131/69/135 +f 138/72/136 139/71/133 131/69/135 +f 139/71/133 133/73/137 132/70/134 +f 139/71/133 140/74/138 133/73/137 +f 141/76/139 134/75/140 133/73/137 +f 140/74/138 141/76/139 133/73/137 +f 141/76/139 135/77/141 134/75/140 +f 141/76/139 142/78/142 135/77/141 +f 143/80/143 136/79/144 135/77/141 +f 142/78/142 143/80/143 135/77/141 +f 143/80/143 137/68/145 136/79/144 +f 143/80/143 144/81/146 137/68/145 +s 2 +f 181/68/131 145/68/131 138/68/131 +f 151/68/132 180/68/132 144/68/132 +s 1 +f 145/82/147 139/71/133 138/72/136 +f 145/82/147 146/83/148 139/71/133 +f 147/84/149 140/74/138 139/71/133 +f 146/83/148 147/84/149 139/71/133 +f 147/84/149 141/76/139 140/74/138 +f 147/84/149 148/85/150 141/76/139 +f 149/86/151 142/78/142 141/76/139 +f 148/85/150 149/86/151 141/76/139 +f 149/86/151 143/80/143 142/78/142 +f 149/86/151 150/87/152 143/80/143 +f 151/88/153 144/81/146 143/80/143 +f 150/87/152 151/88/153 143/80/143 +s 2 +f 181/68/131 152/68/131 145/68/131 +f 158/68/132 180/68/132 151/68/132 +s 1 +f 153/89/154 146/83/148 145/82/147 +f 152/90/155 153/89/154 145/82/147 +f 153/89/154 147/84/149 146/83/148 +f 153/89/154 154/91/156 147/84/149 +f 155/92/157 148/85/150 147/84/149 +f 154/91/156 155/92/157 147/84/149 +f 155/92/157 149/86/151 148/85/150 +f 155/92/157 156/93/158 149/86/151 +f 157/94/159 150/87/152 149/86/151 +f 156/93/158 157/94/159 149/86/151 +f 157/94/159 151/88/153 150/87/152 +f 157/94/159 158/95/160 151/88/153 +s 2 +f 181/68/131 159/68/131 152/68/131 +f 165/68/132 180/68/132 158/68/132 +s 1 +f 159/96/161 153/89/154 152/90/155 +f 159/96/161 160/97/162 153/89/154 +f 161/98/163 154/91/156 153/89/154 +f 160/97/162 161/98/163 153/89/154 +f 161/98/163 155/92/157 154/91/156 +f 161/98/163 162/99/164 155/92/157 +f 163/100/165 156/93/158 155/92/157 +f 162/99/164 163/100/165 155/92/157 +f 163/100/165 157/94/159 156/93/158 +f 163/100/165 164/101/166 157/94/159 +f 165/102/167 158/95/160 157/94/159 +f 164/101/166 165/102/167 157/94/159 +s 2 +f 181/68/131 166/68/131 159/68/131 +f 172/68/132 180/68/132 165/68/132 +s 1 +f 167/103/168 160/97/162 159/96/161 +f 166/104/169 167/103/168 159/96/161 +f 167/103/168 161/98/163 160/97/162 +f 167/103/168 168/105/170 161/98/163 +f 169/106/171 162/99/164 161/98/163 +f 168/105/170 169/106/171 161/98/163 +f 169/106/171 163/100/165 162/99/164 +f 169/106/171 170/107/172 163/100/165 +f 171/108/173 164/101/166 163/100/165 +f 170/107/172 171/108/173 163/100/165 +f 171/108/173 165/102/167 164/101/166 +f 171/108/173 172/109/174 165/102/167 +s 2 +f 181/68/131 173/68/131 166/68/131 +f 179/68/132 180/68/132 172/68/132 +s 1 +f 173/110/175 167/103/168 166/104/169 +f 173/110/175 174/111/176 167/103/168 +f 175/112/177 168/105/170 167/103/168 +f 174/111/176 175/112/177 167/103/168 +f 175/112/177 169/106/171 168/105/170 +f 175/112/177 176/113/178 169/106/171 +f 177/114/179 170/107/172 169/106/171 +f 176/113/178 177/114/179 169/106/171 +f 177/114/179 171/108/173 170/107/172 +f 177/114/179 178/115/180 171/108/173 +f 179/116/181 172/109/174 171/108/173 +f 178/115/180 179/116/181 171/108/173 +s 2 +f 181/68/131 131/68/131 173/68/131 +f 137/68/132 180/68/132 179/68/132 +s 1 +f 132/117/134 174/111/176 173/110/175 +f 131/118/135 132/117/134 173/110/175 +f 132/117/134 175/112/177 174/111/176 +f 132/117/134 133/119/137 175/112/177 +f 134/120/140 176/113/178 175/112/177 +f 133/119/137 134/120/140 175/112/177 +f 134/120/140 177/114/179 176/113/178 +f 134/120/140 135/121/141 177/114/179 +f 136/122/144 178/115/180 177/114/179 +f 135/121/141 136/122/144 177/114/179 +f 136/122/144 179/116/181 178/115/180 +f 136/122/144 137/123/145 179/116/181 +# 98 triangles in group -# Mesh 'Bein2Li_Bein2Li_Bein2Li_Bein2Li' with 98 faces -g Bein2Li_Bein2Li_Bein2Li_Bein2Li +g Bein2Li usemtl BeinTex -f 182/68/182 183/68/182 184/68/182 -f 185/68/183 186/68/183 187/68/183 -f 182/69/184 188/70/185 189/71/186 -f 182/69/184 189/71/186 183/72/187 -f 188/70/185 190/73/188 189/71/186 -f 190/73/188 191/74/189 189/71/186 -f 190/73/188 192/75/190 193/76/191 -f 190/73/188 193/76/191 191/74/189 -f 192/75/190 194/77/192 193/76/191 -f 194/77/192 195/78/193 193/76/191 -f 194/77/192 196/79/194 197/80/195 -f 194/77/192 197/80/195 195/78/193 -f 196/79/194 185/68/196 197/80/195 -f 185/68/196 187/81/197 197/80/195 -f 183/68/182 198/68/182 184/68/182 -f 187/68/183 186/68/183 199/68/183 -f 183/72/187 189/71/186 198/82/198 -f 189/71/186 200/83/199 198/82/198 -f 189/71/186 191/74/189 201/84/200 -f 189/71/186 201/84/200 200/83/199 -f 191/74/189 193/76/191 201/84/200 -f 193/76/191 202/85/201 201/84/200 -f 193/76/191 195/78/193 203/86/202 -f 193/76/191 203/86/202 202/85/201 -f 195/78/193 197/80/195 203/86/202 -f 197/80/195 204/87/203 203/86/202 -f 197/80/195 187/81/197 199/88/204 -f 197/80/195 199/88/204 204/87/203 -f 198/68/182 205/68/182 184/68/182 -f 199/68/183 186/68/183 206/68/183 -f 198/82/198 200/83/199 207/89/205 -f 198/82/198 207/89/205 205/90/206 -f 200/83/199 201/84/200 207/89/205 -f 201/84/200 208/91/207 207/89/205 -f 201/84/200 202/85/201 209/92/208 -f 201/84/200 209/92/208 208/91/207 -f 202/85/201 203/86/202 209/92/208 -f 203/86/202 210/93/209 209/92/208 -f 203/86/202 204/87/203 211/94/210 -f 203/86/202 211/94/210 210/93/209 -f 204/87/203 199/88/204 211/94/210 -f 199/88/204 206/95/211 211/94/210 -f 205/68/182 212/68/182 184/68/182 -f 206/68/183 186/68/183 213/68/183 -f 205/90/206 207/89/205 212/96/212 -f 207/89/205 214/97/213 212/96/212 -f 207/89/205 208/91/207 215/98/214 -f 207/89/205 215/98/214 214/97/213 -f 208/91/207 209/92/208 215/98/214 -f 209/92/208 216/99/215 215/98/214 -f 209/92/208 210/93/209 217/100/216 -f 209/92/208 217/100/216 216/99/215 -f 210/93/209 211/94/210 217/100/216 -f 211/94/210 218/101/217 217/100/216 -f 211/94/210 206/95/211 213/102/218 -f 211/94/210 213/102/218 218/101/217 -f 212/68/182 219/68/182 184/68/182 -f 213/68/183 186/68/183 220/68/183 -f 212/96/212 214/97/213 221/103/219 -f 212/96/212 221/103/219 219/104/220 -f 214/97/213 215/98/214 221/103/219 -f 215/98/214 222/105/221 221/103/219 -f 215/98/214 216/99/215 223/106/222 -f 215/98/214 223/106/222 222/105/221 -f 216/99/215 217/100/216 223/106/222 -f 217/100/216 224/107/223 223/106/222 -f 217/100/216 218/101/217 225/108/224 -f 217/100/216 225/108/224 224/107/223 -f 218/101/217 213/102/218 225/108/224 -f 213/102/218 220/109/225 225/108/224 -f 219/68/182 226/68/182 184/68/182 -f 220/68/183 186/68/183 227/68/183 -f 219/104/220 221/103/219 226/110/226 -f 221/103/219 228/111/227 226/110/226 -f 221/103/219 222/105/221 229/112/228 -f 221/103/219 229/112/228 228/111/227 -f 222/105/221 223/106/222 229/112/228 -f 223/106/222 230/113/229 229/112/228 -f 223/106/222 224/107/223 231/114/230 -f 223/106/222 231/114/230 230/113/229 -f 224/107/223 225/108/224 231/114/230 -f 225/108/224 232/115/231 231/114/230 -f 225/108/224 220/109/225 227/116/232 -f 225/108/224 227/116/232 232/115/231 -f 226/68/182 182/68/182 184/68/182 -f 227/68/183 186/68/183 185/68/183 -f 226/110/226 228/111/227 188/117/185 -f 226/110/226 188/117/185 182/118/184 -f 228/111/227 229/112/228 188/117/185 -f 229/112/228 190/119/188 188/117/185 -f 229/112/228 230/113/229 192/120/190 -f 229/112/228 192/120/190 190/119/188 -f 230/113/229 231/114/230 192/120/190 -f 231/114/230 194/121/192 192/120/190 -f 231/114/230 232/115/231 196/122/194 -f 231/114/230 196/122/194 194/121/192 -f 232/115/231 227/116/232 196/122/194 -f 227/116/232 185/123/196 196/122/194 +s 2 +f 182/68/182 189/68/182 232/68/182 +f 188/68/183 231/68/183 195/68/183 +s 1 +f 182/69/184 183/70/185 190/71/186 +f 182/69/184 190/71/186 189/72/187 +f 183/70/185 184/73/188 190/71/186 +f 184/73/188 191/74/189 190/71/186 +f 184/73/188 185/75/190 192/76/191 +f 184/73/188 192/76/191 191/74/189 +f 185/75/190 186/77/192 192/76/191 +f 186/77/192 193/78/193 192/76/191 +f 186/77/192 187/79/194 194/80/195 +f 186/77/192 194/80/195 193/78/193 +f 187/79/194 188/68/196 194/80/195 +f 188/68/196 195/81/197 194/80/195 +s 2 +f 189/68/182 196/68/182 232/68/182 +f 195/68/183 231/68/183 202/68/183 +s 1 +f 189/72/187 190/71/186 196/82/198 +f 190/71/186 197/83/199 196/82/198 +f 190/71/186 191/74/189 198/84/200 +f 190/71/186 198/84/200 197/83/199 +f 191/74/189 192/76/191 198/84/200 +f 192/76/191 199/85/201 198/84/200 +f 192/76/191 193/78/193 200/86/202 +f 192/76/191 200/86/202 199/85/201 +f 193/78/193 194/80/195 200/86/202 +f 194/80/195 201/87/203 200/86/202 +f 194/80/195 195/81/197 202/88/204 +f 194/80/195 202/88/204 201/87/203 +s 2 +f 196/68/182 203/68/182 232/68/182 +f 202/68/183 231/68/183 209/68/183 +s 1 +f 196/82/198 197/83/199 204/89/205 +f 196/82/198 204/89/205 203/90/206 +f 197/83/199 198/84/200 204/89/205 +f 198/84/200 205/91/207 204/89/205 +f 198/84/200 199/85/201 206/92/208 +f 198/84/200 206/92/208 205/91/207 +f 199/85/201 200/86/202 206/92/208 +f 200/86/202 207/93/209 206/92/208 +f 200/86/202 201/87/203 208/94/210 +f 200/86/202 208/94/210 207/93/209 +f 201/87/203 202/88/204 208/94/210 +f 202/88/204 209/95/211 208/94/210 +s 2 +f 203/68/182 210/68/182 232/68/182 +f 209/68/183 231/68/183 216/68/183 +s 1 +f 203/90/206 204/89/205 210/96/212 +f 204/89/205 211/97/213 210/96/212 +f 204/89/205 205/91/207 212/98/214 +f 204/89/205 212/98/214 211/97/213 +f 205/91/207 206/92/208 212/98/214 +f 206/92/208 213/99/215 212/98/214 +f 206/92/208 207/93/209 214/100/216 +f 206/92/208 214/100/216 213/99/215 +f 207/93/209 208/94/210 214/100/216 +f 208/94/210 215/101/217 214/100/216 +f 208/94/210 209/95/211 216/102/218 +f 208/94/210 216/102/218 215/101/217 +s 2 +f 210/68/182 217/68/182 232/68/182 +f 216/68/183 231/68/183 223/68/183 +s 1 +f 210/96/212 211/97/213 218/103/219 +f 210/96/212 218/103/219 217/104/220 +f 211/97/213 212/98/214 218/103/219 +f 212/98/214 219/105/221 218/103/219 +f 212/98/214 213/99/215 220/106/222 +f 212/98/214 220/106/222 219/105/221 +f 213/99/215 214/100/216 220/106/222 +f 214/100/216 221/107/223 220/106/222 +f 214/100/216 215/101/217 222/108/224 +f 214/100/216 222/108/224 221/107/223 +f 215/101/217 216/102/218 222/108/224 +f 216/102/218 223/109/225 222/108/224 +s 2 +f 217/68/182 224/68/182 232/68/182 +f 223/68/183 231/68/183 230/68/183 +s 1 +f 217/104/220 218/103/219 224/110/226 +f 218/103/219 225/111/227 224/110/226 +f 218/103/219 219/105/221 226/112/228 +f 218/103/219 226/112/228 225/111/227 +f 219/105/221 220/106/222 226/112/228 +f 220/106/222 227/113/229 226/112/228 +f 220/106/222 221/107/223 228/114/230 +f 220/106/222 228/114/230 227/113/229 +f 221/107/223 222/108/224 228/114/230 +f 222/108/224 229/115/231 228/114/230 +f 222/108/224 223/109/225 230/116/232 +f 222/108/224 230/116/232 229/115/231 +s 2 +f 224/68/182 182/68/182 232/68/182 +f 230/68/183 231/68/183 188/68/183 +s 1 +f 224/110/226 225/111/227 183/117/185 +f 224/110/226 183/117/185 182/118/184 +f 225/111/227 226/112/228 183/117/185 +f 226/112/228 184/119/188 183/117/185 +f 226/112/228 227/113/229 185/120/190 +f 226/112/228 185/120/190 184/119/188 +f 227/113/229 228/114/230 185/120/190 +f 228/114/230 186/121/192 185/120/190 +f 228/114/230 229/115/231 187/122/194 +f 228/114/230 187/122/194 186/121/192 +f 229/115/231 230/116/232 187/122/194 +f 230/116/232 188/123/196 187/122/194 +# 98 triangles in group -# Mesh 'Bein2Re_Bein2Re_Bein2Re_Bein2Re' with 98 faces -g Bein2Re_Bein2Re_Bein2Re_Bein2Re +g Bein2Re usemtl BeinTex -f 233/68/233 234/68/233 235/68/233 -f 236/68/234 237/68/234 238/68/234 -f 239/71/235 240/70/236 235/69/237 -f 234/72/238 239/71/235 235/69/237 -f 239/71/235 241/73/239 240/70/236 -f 239/71/235 242/74/240 241/73/239 -f 243/76/241 244/75/242 241/73/239 -f 242/74/240 243/76/241 241/73/239 -f 243/76/241 245/77/243 244/75/242 -f 243/76/241 246/78/244 245/77/243 -f 247/80/245 248/79/246 245/77/243 -f 246/78/244 247/80/245 245/77/243 -f 247/80/245 238/68/247 248/79/246 -f 247/80/245 236/81/248 238/68/247 -f 233/68/233 249/68/233 234/68/233 -f 250/68/234 237/68/234 236/68/234 -f 249/82/249 239/71/235 234/72/238 -f 249/82/249 251/83/250 239/71/235 -f 252/84/251 242/74/240 239/71/235 -f 251/83/250 252/84/251 239/71/235 -f 252/84/251 243/76/241 242/74/240 -f 252/84/251 253/85/252 243/76/241 -f 254/86/253 246/78/244 243/76/241 -f 253/85/252 254/86/253 243/76/241 -f 254/86/253 247/80/245 246/78/244 -f 254/86/253 255/87/254 247/80/245 -f 250/88/255 236/81/248 247/80/245 -f 255/87/254 250/88/255 247/80/245 -f 233/68/233 256/68/233 249/68/233 -f 257/68/234 237/68/234 250/68/234 -f 258/89/256 251/83/250 249/82/249 -f 256/90/257 258/89/256 249/82/249 -f 258/89/256 252/84/251 251/83/250 -f 258/89/256 259/91/258 252/84/251 -f 260/92/259 253/85/252 252/84/251 -f 259/91/258 260/92/259 252/84/251 -f 260/92/259 254/86/253 253/85/252 -f 260/92/259 261/93/260 254/86/253 -f 262/94/261 255/87/254 254/86/253 -f 261/93/260 262/94/261 254/86/253 -f 262/94/261 250/88/255 255/87/254 -f 262/94/261 257/95/262 250/88/255 -f 233/68/233 263/68/233 256/68/233 -f 264/68/234 237/68/234 257/68/234 -f 263/96/263 258/89/256 256/90/257 -f 263/96/263 265/97/264 258/89/256 -f 266/98/265 259/91/258 258/89/256 -f 265/97/264 266/98/265 258/89/256 -f 266/98/265 260/92/259 259/91/258 -f 266/98/265 267/99/266 260/92/259 -f 268/100/267 261/93/260 260/92/259 -f 267/99/266 268/100/267 260/92/259 -f 268/100/267 262/94/261 261/93/260 -f 268/100/267 269/101/268 262/94/261 -f 264/102/269 257/95/262 262/94/261 -f 269/101/268 264/102/269 262/94/261 -f 233/68/233 270/68/233 263/68/233 -f 271/68/234 237/68/234 264/68/234 -f 272/103/270 265/97/264 263/96/263 -f 270/104/271 272/103/270 263/96/263 -f 272/103/270 266/98/265 265/97/264 -f 272/103/270 273/105/272 266/98/265 -f 274/106/273 267/99/266 266/98/265 -f 273/105/272 274/106/273 266/98/265 -f 274/106/273 268/100/267 267/99/266 -f 274/106/273 275/107/274 268/100/267 -f 276/108/275 269/101/268 268/100/267 -f 275/107/274 276/108/275 268/100/267 -f 276/108/275 264/102/269 269/101/268 -f 276/108/275 271/109/276 264/102/269 -f 233/68/233 277/68/233 270/68/233 -f 278/68/234 237/68/234 271/68/234 -f 277/110/277 272/103/270 270/104/271 -f 277/110/277 279/111/278 272/103/270 -f 280/112/279 273/105/272 272/103/270 -f 279/111/278 280/112/279 272/103/270 -f 280/112/279 274/106/273 273/105/272 -f 280/112/279 281/113/280 274/106/273 -f 282/114/281 275/107/274 274/106/273 -f 281/113/280 282/114/281 274/106/273 -f 282/114/281 276/108/275 275/107/274 -f 282/114/281 283/115/282 276/108/275 -f 278/116/283 271/109/276 276/108/275 -f 283/115/282 278/116/283 276/108/275 -f 233/68/233 235/68/233 277/68/233 -f 238/68/234 237/68/234 278/68/234 -f 240/117/236 279/111/278 277/110/277 -f 235/118/237 240/117/236 277/110/277 -f 240/117/236 280/112/279 279/111/278 -f 240/117/236 241/119/239 280/112/279 -f 244/120/242 281/113/280 280/112/279 -f 241/119/239 244/120/242 280/112/279 -f 244/120/242 282/114/281 281/113/280 -f 244/120/242 245/121/243 282/114/281 -f 248/122/246 283/115/282 282/114/281 -f 245/121/243 248/122/246 282/114/281 -f 248/122/246 278/116/283 283/115/282 -f 248/122/246 238/123/247 278/116/283 +s 2 +f 283/68/233 240/68/233 233/68/233 +f 246/68/234 282/68/234 239/68/234 +s 1 +f 241/71/235 234/70/236 233/69/237 +f 240/72/238 241/71/235 233/69/237 +f 241/71/235 235/73/239 234/70/236 +f 241/71/235 242/74/240 235/73/239 +f 243/76/241 236/75/242 235/73/239 +f 242/74/240 243/76/241 235/73/239 +f 243/76/241 237/77/243 236/75/242 +f 243/76/241 244/78/244 237/77/243 +f 245/80/245 238/79/246 237/77/243 +f 244/78/244 245/80/245 237/77/243 +f 245/80/245 239/68/247 238/79/246 +f 245/80/245 246/81/248 239/68/247 +s 2 +f 283/68/233 247/68/233 240/68/233 +f 253/68/234 282/68/234 246/68/234 +s 1 +f 247/82/249 241/71/235 240/72/238 +f 247/82/249 248/83/250 241/71/235 +f 249/84/251 242/74/240 241/71/235 +f 248/83/250 249/84/251 241/71/235 +f 249/84/251 243/76/241 242/74/240 +f 249/84/251 250/85/252 243/76/241 +f 251/86/253 244/78/244 243/76/241 +f 250/85/252 251/86/253 243/76/241 +f 251/86/253 245/80/245 244/78/244 +f 251/86/253 252/87/254 245/80/245 +f 253/88/255 246/81/248 245/80/245 +f 252/87/254 253/88/255 245/80/245 +s 2 +f 283/68/233 254/68/233 247/68/233 +f 260/68/234 282/68/234 253/68/234 +s 1 +f 255/89/256 248/83/250 247/82/249 +f 254/90/257 255/89/256 247/82/249 +f 255/89/256 249/84/251 248/83/250 +f 255/89/256 256/91/258 249/84/251 +f 257/92/259 250/85/252 249/84/251 +f 256/91/258 257/92/259 249/84/251 +f 257/92/259 251/86/253 250/85/252 +f 257/92/259 258/93/260 251/86/253 +f 259/94/261 252/87/254 251/86/253 +f 258/93/260 259/94/261 251/86/253 +f 259/94/261 253/88/255 252/87/254 +f 259/94/261 260/95/262 253/88/255 +s 2 +f 283/68/233 261/68/233 254/68/233 +f 267/68/234 282/68/234 260/68/234 +s 1 +f 261/96/263 255/89/256 254/90/257 +f 261/96/263 262/97/264 255/89/256 +f 263/98/265 256/91/258 255/89/256 +f 262/97/264 263/98/265 255/89/256 +f 263/98/265 257/92/259 256/91/258 +f 263/98/265 264/99/266 257/92/259 +f 265/100/267 258/93/260 257/92/259 +f 264/99/266 265/100/267 257/92/259 +f 265/100/267 259/94/261 258/93/260 +f 265/100/267 266/101/268 259/94/261 +f 267/102/269 260/95/262 259/94/261 +f 266/101/268 267/102/269 259/94/261 +s 2 +f 283/68/233 268/68/233 261/68/233 +f 274/68/234 282/68/234 267/68/234 +s 1 +f 269/103/270 262/97/264 261/96/263 +f 268/104/271 269/103/270 261/96/263 +f 269/103/270 263/98/265 262/97/264 +f 269/103/270 270/105/272 263/98/265 +f 271/106/273 264/99/266 263/98/265 +f 270/105/272 271/106/273 263/98/265 +f 271/106/273 265/100/267 264/99/266 +f 271/106/273 272/107/274 265/100/267 +f 273/108/275 266/101/268 265/100/267 +f 272/107/274 273/108/275 265/100/267 +f 273/108/275 267/102/269 266/101/268 +f 273/108/275 274/109/276 267/102/269 +s 2 +f 283/68/233 275/68/233 268/68/233 +f 281/68/234 282/68/234 274/68/234 +s 1 +f 275/110/277 269/103/270 268/104/271 +f 275/110/277 276/111/278 269/103/270 +f 277/112/279 270/105/272 269/103/270 +f 276/111/278 277/112/279 269/103/270 +f 277/112/279 271/106/273 270/105/272 +f 277/112/279 278/113/280 271/106/273 +f 279/114/281 272/107/274 271/106/273 +f 278/113/280 279/114/281 271/106/273 +f 279/114/281 273/108/275 272/107/274 +f 279/114/281 280/115/282 273/108/275 +f 281/116/283 274/109/276 273/108/275 +f 280/115/282 281/116/283 273/108/275 +s 2 +f 283/68/233 233/68/233 275/68/233 +f 239/68/234 282/68/234 281/68/234 +s 1 +f 234/117/236 276/111/278 275/110/277 +f 233/118/237 234/117/236 275/110/277 +f 234/117/236 277/112/279 276/111/278 +f 234/117/236 235/119/239 277/112/279 +f 236/120/242 278/113/280 277/112/279 +f 235/119/239 236/120/242 277/112/279 +f 236/120/242 279/114/281 278/113/280 +f 236/120/242 237/121/243 279/114/281 +f 238/122/246 280/115/282 279/114/281 +f 237/121/243 238/122/246 279/114/281 +f 238/122/246 281/116/283 280/115/282 +f 238/122/246 239/123/247 281/116/283 +# 98 triangles in group -# Mesh 'Bein3Re_Bein3Re_Bein3Re_Bein3Re' with 98 faces -g Bein3Re_Bein3Re_Bein3Re_Bein3Re +g Bein3Re usemtl BeinTex -f 284/68/284 285/68/284 286/68/284 -f 287/68/285 288/68/285 289/68/285 -f 290/71/286 291/70/287 286/69/288 -f 285/72/289 290/71/286 286/69/288 -f 290/71/286 292/73/290 291/70/287 -f 290/71/286 293/74/291 292/73/290 -f 294/76/292 295/75/293 292/73/290 -f 293/74/291 294/76/292 292/73/290 -f 294/76/292 296/77/294 295/75/293 -f 294/76/292 297/78/295 296/77/294 -f 298/80/296 299/79/297 296/77/294 -f 297/78/295 298/80/296 296/77/294 -f 298/80/296 289/68/298 299/79/297 -f 298/80/296 287/81/299 289/68/298 -f 284/68/284 300/68/284 285/68/284 -f 301/68/285 288/68/285 287/68/285 -f 300/82/300 290/71/286 285/72/289 -f 300/82/300 302/83/301 290/71/286 -f 303/84/302 293/74/291 290/71/286 -f 302/83/301 303/84/302 290/71/286 -f 303/84/302 294/76/292 293/74/291 -f 303/84/302 304/85/303 294/76/292 -f 305/86/304 297/78/295 294/76/292 -f 304/85/303 305/86/304 294/76/292 -f 305/86/304 298/80/296 297/78/295 -f 305/86/304 306/87/305 298/80/296 -f 301/88/306 287/81/299 298/80/296 -f 306/87/305 301/88/306 298/80/296 -f 284/68/284 307/68/284 300/68/284 -f 308/68/285 288/68/285 301/68/285 -f 309/89/307 302/83/301 300/82/300 -f 307/90/308 309/89/307 300/82/300 -f 309/89/307 303/84/302 302/83/301 -f 309/89/307 310/91/309 303/84/302 -f 311/92/310 304/85/303 303/84/302 -f 310/91/309 311/92/310 303/84/302 -f 311/92/310 305/86/304 304/85/303 -f 311/92/310 312/93/311 305/86/304 -f 313/94/312 306/87/305 305/86/304 -f 312/93/311 313/94/312 305/86/304 -f 313/94/312 301/88/306 306/87/305 -f 313/94/312 308/95/313 301/88/306 -f 284/68/284 314/68/284 307/68/284 -f 315/68/285 288/68/285 308/68/285 -f 314/96/314 309/89/307 307/90/308 -f 314/96/314 316/97/315 309/89/307 -f 317/98/316 310/91/309 309/89/307 -f 316/97/315 317/98/316 309/89/307 -f 317/98/316 311/92/310 310/91/309 -f 317/98/316 318/99/317 311/92/310 -f 319/100/318 312/93/311 311/92/310 -f 318/99/317 319/100/318 311/92/310 -f 319/100/318 313/94/312 312/93/311 -f 319/100/318 320/101/319 313/94/312 -f 315/102/320 308/95/313 313/94/312 -f 320/101/319 315/102/320 313/94/312 -f 284/68/284 321/68/284 314/68/284 -f 322/68/285 288/68/285 315/68/285 -f 323/103/321 316/97/315 314/96/314 -f 321/104/322 323/103/321 314/96/314 -f 323/103/321 317/98/316 316/97/315 -f 323/103/321 324/105/323 317/98/316 -f 325/106/324 318/99/317 317/98/316 -f 324/105/323 325/106/324 317/98/316 -f 325/106/324 319/100/318 318/99/317 -f 325/106/324 326/107/325 319/100/318 -f 327/108/326 320/101/319 319/100/318 -f 326/107/325 327/108/326 319/100/318 -f 327/108/326 315/102/320 320/101/319 -f 327/108/326 322/109/327 315/102/320 -f 284/68/284 328/68/284 321/68/284 -f 329/68/285 288/68/285 322/68/285 -f 328/110/328 323/103/321 321/104/322 -f 328/110/328 330/111/329 323/103/321 -f 331/112/330 324/105/323 323/103/321 -f 330/111/329 331/112/330 323/103/321 -f 331/112/330 325/106/324 324/105/323 -f 331/112/330 332/113/331 325/106/324 -f 333/114/332 326/107/325 325/106/324 -f 332/113/331 333/114/332 325/106/324 -f 333/114/332 327/108/326 326/107/325 -f 333/114/332 334/115/333 327/108/326 -f 329/116/334 322/109/327 327/108/326 -f 334/115/333 329/116/334 327/108/326 -f 284/68/284 286/68/284 328/68/284 -f 289/68/285 288/68/285 329/68/285 -f 291/117/287 330/111/329 328/110/328 -f 286/118/288 291/117/287 328/110/328 -f 291/117/287 331/112/330 330/111/329 -f 291/117/287 292/119/290 331/112/330 -f 295/120/293 332/113/331 331/112/330 -f 292/119/290 295/120/293 331/112/330 -f 295/120/293 333/114/332 332/113/331 -f 295/120/293 296/121/294 333/114/332 -f 299/122/297 334/115/333 333/114/332 -f 296/121/294 299/122/297 333/114/332 -f 299/122/297 329/116/334 334/115/333 -f 299/122/297 289/123/298 329/116/334 +s 2 +f 334/68/284 291/68/284 284/68/284 +f 297/68/285 333/68/285 290/68/285 +s 1 +f 292/71/286 285/70/287 284/69/288 +f 291/72/289 292/71/286 284/69/288 +f 292/71/286 286/73/290 285/70/287 +f 292/71/286 293/74/291 286/73/290 +f 294/76/292 287/75/293 286/73/290 +f 293/74/291 294/76/292 286/73/290 +f 294/76/292 288/77/294 287/75/293 +f 294/76/292 295/78/295 288/77/294 +f 296/80/296 289/79/297 288/77/294 +f 295/78/295 296/80/296 288/77/294 +f 296/80/296 290/68/298 289/79/297 +f 296/80/296 297/81/299 290/68/298 +s 2 +f 334/68/284 298/68/284 291/68/284 +f 304/68/285 333/68/285 297/68/285 +s 1 +f 298/82/300 292/71/286 291/72/289 +f 298/82/300 299/83/301 292/71/286 +f 300/84/302 293/74/291 292/71/286 +f 299/83/301 300/84/302 292/71/286 +f 300/84/302 294/76/292 293/74/291 +f 300/84/302 301/85/303 294/76/292 +f 302/86/304 295/78/295 294/76/292 +f 301/85/303 302/86/304 294/76/292 +f 302/86/304 296/80/296 295/78/295 +f 302/86/304 303/87/305 296/80/296 +f 304/88/306 297/81/299 296/80/296 +f 303/87/305 304/88/306 296/80/296 +s 2 +f 334/68/284 305/68/284 298/68/284 +f 311/68/285 333/68/285 304/68/285 +s 1 +f 306/89/307 299/83/301 298/82/300 +f 305/90/308 306/89/307 298/82/300 +f 306/89/307 300/84/302 299/83/301 +f 306/89/307 307/91/309 300/84/302 +f 308/92/310 301/85/303 300/84/302 +f 307/91/309 308/92/310 300/84/302 +f 308/92/310 302/86/304 301/85/303 +f 308/92/310 309/93/311 302/86/304 +f 310/94/312 303/87/305 302/86/304 +f 309/93/311 310/94/312 302/86/304 +f 310/94/312 304/88/306 303/87/305 +f 310/94/312 311/95/313 304/88/306 +s 2 +f 334/68/284 312/68/284 305/68/284 +f 318/68/285 333/68/285 311/68/285 +s 1 +f 312/96/314 306/89/307 305/90/308 +f 312/96/314 313/97/315 306/89/307 +f 314/98/316 307/91/309 306/89/307 +f 313/97/315 314/98/316 306/89/307 +f 314/98/316 308/92/310 307/91/309 +f 314/98/316 315/99/317 308/92/310 +f 316/100/318 309/93/311 308/92/310 +f 315/99/317 316/100/318 308/92/310 +f 316/100/318 310/94/312 309/93/311 +f 316/100/318 317/101/319 310/94/312 +f 318/102/320 311/95/313 310/94/312 +f 317/101/319 318/102/320 310/94/312 +s 2 +f 334/68/284 319/68/284 312/68/284 +f 325/68/285 333/68/285 318/68/285 +s 1 +f 320/103/321 313/97/315 312/96/314 +f 319/104/322 320/103/321 312/96/314 +f 320/103/321 314/98/316 313/97/315 +f 320/103/321 321/105/323 314/98/316 +f 322/106/324 315/99/317 314/98/316 +f 321/105/323 322/106/324 314/98/316 +f 322/106/324 316/100/318 315/99/317 +f 322/106/324 323/107/325 316/100/318 +f 324/108/326 317/101/319 316/100/318 +f 323/107/325 324/108/326 316/100/318 +f 324/108/326 318/102/320 317/101/319 +f 324/108/326 325/109/327 318/102/320 +s 2 +f 334/68/284 326/68/284 319/68/284 +f 332/68/285 333/68/285 325/68/285 +s 1 +f 326/110/328 320/103/321 319/104/322 +f 326/110/328 327/111/329 320/103/321 +f 328/112/330 321/105/323 320/103/321 +f 327/111/329 328/112/330 320/103/321 +f 328/112/330 322/106/324 321/105/323 +f 328/112/330 329/113/331 322/106/324 +f 330/114/332 323/107/325 322/106/324 +f 329/113/331 330/114/332 322/106/324 +f 330/114/332 324/108/326 323/107/325 +f 330/114/332 331/115/333 324/108/326 +f 332/116/334 325/109/327 324/108/326 +f 331/115/333 332/116/334 324/108/326 +s 2 +f 334/68/284 284/68/284 326/68/284 +f 290/68/285 333/68/285 332/68/285 +s 1 +f 285/117/287 327/111/329 326/110/328 +f 284/118/288 285/117/287 326/110/328 +f 285/117/287 328/112/330 327/111/329 +f 285/117/287 286/119/290 328/112/330 +f 287/120/293 329/113/331 328/112/330 +f 286/119/290 287/120/293 328/112/330 +f 287/120/293 330/114/332 329/113/331 +f 287/120/293 288/121/294 330/114/332 +f 289/122/297 331/115/333 330/114/332 +f 288/121/294 289/122/297 330/114/332 +f 289/122/297 332/116/334 331/115/333 +f 289/122/297 290/123/298 332/116/334 +# 98 triangles in group -# Mesh 'Bein3Li_Bein3Li_Bein3Li_Bein3Li' with 98 faces -g Bein3Li_Bein3Li_Bein3Li_Bein3Li +g Bein3Li usemtl BeinTex -f 335/68/335 336/68/335 337/68/335 -f 338/68/336 339/68/336 340/68/336 -f 335/69/337 341/70/338 342/71/339 -f 335/69/337 342/71/339 336/72/340 -f 341/70/338 343/73/341 342/71/339 -f 343/73/341 344/74/342 342/71/339 -f 343/73/341 345/75/343 346/76/344 -f 343/73/341 346/76/344 344/74/342 -f 345/75/343 347/77/345 346/76/344 -f 347/77/345 348/78/346 346/76/344 -f 347/77/345 349/79/347 350/80/348 -f 347/77/345 350/80/348 348/78/346 -f 349/79/347 338/68/349 350/80/348 -f 338/68/349 340/81/350 350/80/348 -f 336/68/335 351/68/335 337/68/335 -f 340/68/336 339/68/336 352/68/336 -f 336/72/340 342/71/339 351/82/351 -f 342/71/339 353/83/352 351/82/351 -f 342/71/339 344/74/342 354/84/353 -f 342/71/339 354/84/353 353/83/352 -f 344/74/342 346/76/344 354/84/353 -f 346/76/344 355/85/354 354/84/353 -f 346/76/344 348/78/346 356/86/355 -f 346/76/344 356/86/355 355/85/354 -f 348/78/346 350/80/348 356/86/355 -f 350/80/348 357/87/356 356/86/355 -f 350/80/348 340/81/350 352/88/357 -f 350/80/348 352/88/357 357/87/356 -f 351/68/335 358/68/335 337/68/335 -f 352/68/336 339/68/336 359/68/336 -f 351/82/351 353/83/352 360/89/358 -f 351/82/351 360/89/358 358/90/359 -f 353/83/352 354/84/353 360/89/358 -f 354/84/353 361/91/360 360/89/358 -f 354/84/353 355/85/354 362/92/361 -f 354/84/353 362/92/361 361/91/360 -f 355/85/354 356/86/355 362/92/361 -f 356/86/355 363/93/362 362/92/361 -f 356/86/355 357/87/356 364/94/363 -f 356/86/355 364/94/363 363/93/362 -f 357/87/356 352/88/357 364/94/363 -f 352/88/357 359/95/364 364/94/363 -f 358/68/335 365/68/335 337/68/335 -f 359/68/336 339/68/336 366/68/336 -f 358/90/359 360/89/358 365/96/365 -f 360/89/358 367/97/366 365/96/365 -f 360/89/358 361/91/360 368/98/367 -f 360/89/358 368/98/367 367/97/366 -f 361/91/360 362/92/361 368/98/367 -f 362/92/361 369/99/368 368/98/367 -f 362/92/361 363/93/362 370/100/369 -f 362/92/361 370/100/369 369/99/368 -f 363/93/362 364/94/363 370/100/369 -f 364/94/363 371/101/370 370/100/369 -f 364/94/363 359/95/364 366/102/371 -f 364/94/363 366/102/371 371/101/370 -f 365/68/335 372/68/335 337/68/335 -f 366/68/336 339/68/336 373/68/336 -f 365/96/365 367/97/366 374/103/372 -f 365/96/365 374/103/372 372/104/373 -f 367/97/366 368/98/367 374/103/372 -f 368/98/367 375/105/374 374/103/372 -f 368/98/367 369/99/368 376/106/375 -f 368/98/367 376/106/375 375/105/374 -f 369/99/368 370/100/369 376/106/375 -f 370/100/369 377/107/376 376/106/375 -f 370/100/369 371/101/370 378/108/377 -f 370/100/369 378/108/377 377/107/376 -f 371/101/370 366/102/371 378/108/377 -f 366/102/371 373/109/378 378/108/377 -f 372/68/335 379/68/335 337/68/335 -f 373/68/336 339/68/336 380/68/336 -f 372/104/373 374/103/372 379/110/379 -f 374/103/372 381/111/380 379/110/379 -f 374/103/372 375/105/374 382/112/381 -f 374/103/372 382/112/381 381/111/380 -f 375/105/374 376/106/375 382/112/381 -f 376/106/375 383/113/382 382/112/381 -f 376/106/375 377/107/376 384/114/383 -f 376/106/375 384/114/383 383/113/382 -f 377/107/376 378/108/377 384/114/383 -f 378/108/377 385/115/384 384/114/383 -f 378/108/377 373/109/378 380/116/385 -f 378/108/377 380/116/385 385/115/384 -f 379/68/335 335/68/335 337/68/335 -f 380/68/336 339/68/336 338/68/336 -f 379/110/379 381/111/380 341/117/338 -f 379/110/379 341/117/338 335/118/337 -f 381/111/380 382/112/381 341/117/338 -f 382/112/381 343/119/341 341/117/338 -f 382/112/381 383/113/382 345/120/343 -f 382/112/381 345/120/343 343/119/341 -f 383/113/382 384/114/383 345/120/343 -f 384/114/383 347/121/345 345/120/343 -f 384/114/383 385/115/384 349/122/347 -f 384/114/383 349/122/347 347/121/345 -f 385/115/384 380/116/385 349/122/347 -f 380/116/385 338/123/349 349/122/347 +s 2 +f 335/68/335 342/68/335 385/68/335 +f 341/68/336 384/68/336 348/68/336 +s 1 +f 335/69/337 336/70/338 343/71/339 +f 335/69/337 343/71/339 342/72/340 +f 336/70/338 337/73/341 343/71/339 +f 337/73/341 344/74/342 343/71/339 +f 337/73/341 338/75/343 345/76/344 +f 337/73/341 345/76/344 344/74/342 +f 338/75/343 339/77/345 345/76/344 +f 339/77/345 346/78/346 345/76/344 +f 339/77/345 340/79/347 347/80/348 +f 339/77/345 347/80/348 346/78/346 +f 340/79/347 341/68/349 347/80/348 +f 341/68/349 348/81/350 347/80/348 +s 2 +f 342/68/335 349/68/335 385/68/335 +f 348/68/336 384/68/336 355/68/336 +s 1 +f 342/72/340 343/71/339 349/82/351 +f 343/71/339 350/83/352 349/82/351 +f 343/71/339 344/74/342 351/84/353 +f 343/71/339 351/84/353 350/83/352 +f 344/74/342 345/76/344 351/84/353 +f 345/76/344 352/85/354 351/84/353 +f 345/76/344 346/78/346 353/86/355 +f 345/76/344 353/86/355 352/85/354 +f 346/78/346 347/80/348 353/86/355 +f 347/80/348 354/87/356 353/86/355 +f 347/80/348 348/81/350 355/88/357 +f 347/80/348 355/88/357 354/87/356 +s 2 +f 349/68/335 356/68/335 385/68/335 +f 355/68/336 384/68/336 362/68/336 +s 1 +f 349/82/351 350/83/352 357/89/358 +f 349/82/351 357/89/358 356/90/359 +f 350/83/352 351/84/353 357/89/358 +f 351/84/353 358/91/360 357/89/358 +f 351/84/353 352/85/354 359/92/361 +f 351/84/353 359/92/361 358/91/360 +f 352/85/354 353/86/355 359/92/361 +f 353/86/355 360/93/362 359/92/361 +f 353/86/355 354/87/356 361/94/363 +f 353/86/355 361/94/363 360/93/362 +f 354/87/356 355/88/357 361/94/363 +f 355/88/357 362/95/364 361/94/363 +s 2 +f 356/68/335 363/68/335 385/68/335 +f 362/68/336 384/68/336 369/68/336 +s 1 +f 356/90/359 357/89/358 363/96/365 +f 357/89/358 364/97/366 363/96/365 +f 357/89/358 358/91/360 365/98/367 +f 357/89/358 365/98/367 364/97/366 +f 358/91/360 359/92/361 365/98/367 +f 359/92/361 366/99/368 365/98/367 +f 359/92/361 360/93/362 367/100/369 +f 359/92/361 367/100/369 366/99/368 +f 360/93/362 361/94/363 367/100/369 +f 361/94/363 368/101/370 367/100/369 +f 361/94/363 362/95/364 369/102/371 +f 361/94/363 369/102/371 368/101/370 +s 2 +f 363/68/335 370/68/335 385/68/335 +f 369/68/336 384/68/336 376/68/336 +s 1 +f 363/96/365 364/97/366 371/103/372 +f 363/96/365 371/103/372 370/104/373 +f 364/97/366 365/98/367 371/103/372 +f 365/98/367 372/105/374 371/103/372 +f 365/98/367 366/99/368 373/106/375 +f 365/98/367 373/106/375 372/105/374 +f 366/99/368 367/100/369 373/106/375 +f 367/100/369 374/107/376 373/106/375 +f 367/100/369 368/101/370 375/108/377 +f 367/100/369 375/108/377 374/107/376 +f 368/101/370 369/102/371 375/108/377 +f 369/102/371 376/109/378 375/108/377 +s 2 +f 370/68/335 377/68/335 385/68/335 +f 376/68/336 384/68/336 383/68/336 +s 1 +f 370/104/373 371/103/372 377/110/379 +f 371/103/372 378/111/380 377/110/379 +f 371/103/372 372/105/374 379/112/381 +f 371/103/372 379/112/381 378/111/380 +f 372/105/374 373/106/375 379/112/381 +f 373/106/375 380/113/382 379/112/381 +f 373/106/375 374/107/376 381/114/383 +f 373/106/375 381/114/383 380/113/382 +f 374/107/376 375/108/377 381/114/383 +f 375/108/377 382/115/384 381/114/383 +f 375/108/377 376/109/378 383/116/385 +f 375/108/377 383/116/385 382/115/384 +s 2 +f 377/68/335 335/68/335 385/68/335 +f 383/68/336 384/68/336 341/68/336 +s 1 +f 377/110/379 378/111/380 336/117/338 +f 377/110/379 336/117/338 335/118/337 +f 378/111/380 379/112/381 336/117/338 +f 379/112/381 337/119/341 336/117/338 +f 379/112/381 380/113/382 338/120/343 +f 379/112/381 338/120/343 337/119/341 +f 380/113/382 381/114/383 338/120/343 +f 381/114/383 339/121/345 338/120/343 +f 381/114/383 382/115/384 340/122/347 +f 381/114/383 340/122/347 339/121/345 +f 382/115/384 383/116/385 340/122/347 +f 383/116/385 341/123/349 340/122/347 +# 98 triangles in group -# Mesh 'Bein4Re_Bein4Re_Bein4Re_Bein4Re' with 98 faces -g Bein4Re_Bein4Re_Bein4Re_Bein4Re +g Bein4Re usemtl BeinTex -f 386/68/386 387/68/386 388/68/386 -f 389/68/387 390/68/387 391/68/387 -f 392/71/388 393/70/389 388/69/390 -f 387/72/391 392/71/388 388/69/390 -f 392/71/388 394/73/392 393/70/389 -f 392/71/388 395/74/393 394/73/392 -f 396/76/394 397/75/395 394/73/392 -f 395/74/393 396/76/394 394/73/392 -f 396/76/394 398/77/396 397/75/395 -f 396/76/394 399/78/397 398/77/396 -f 400/80/398 401/79/399 398/77/396 -f 399/78/397 400/80/398 398/77/396 -f 400/80/398 391/68/400 401/79/399 -f 400/80/398 389/81/401 391/68/400 -f 386/68/386 402/68/386 387/68/386 -f 403/68/387 390/68/387 389/68/387 -f 402/82/402 392/71/388 387/72/391 -f 402/82/402 404/83/403 392/71/388 -f 405/84/404 395/74/393 392/71/388 -f 404/83/403 405/84/404 392/71/388 -f 405/84/404 396/76/394 395/74/393 -f 405/84/404 406/85/405 396/76/394 -f 407/86/406 399/78/397 396/76/394 -f 406/85/405 407/86/406 396/76/394 -f 407/86/406 400/80/398 399/78/397 -f 407/86/406 408/87/407 400/80/398 -f 403/88/408 389/81/401 400/80/398 -f 408/87/407 403/88/408 400/80/398 -f 386/68/386 409/68/386 402/68/386 -f 410/68/387 390/68/387 403/68/387 -f 411/89/409 404/83/403 402/82/402 -f 409/90/410 411/89/409 402/82/402 -f 411/89/409 405/84/404 404/83/403 -f 411/89/409 412/91/411 405/84/404 -f 413/92/412 406/85/405 405/84/404 -f 412/91/411 413/92/412 405/84/404 -f 413/92/412 407/86/406 406/85/405 -f 413/92/412 414/93/413 407/86/406 -f 415/94/414 408/87/407 407/86/406 -f 414/93/413 415/94/414 407/86/406 -f 415/94/414 403/88/408 408/87/407 -f 415/94/414 410/95/415 403/88/408 -f 386/68/386 416/68/386 409/68/386 -f 417/68/387 390/68/387 410/68/387 -f 416/96/416 411/89/409 409/90/410 -f 416/96/416 418/97/417 411/89/409 -f 419/98/418 412/91/411 411/89/409 -f 418/97/417 419/98/418 411/89/409 -f 419/98/418 413/92/412 412/91/411 -f 419/98/418 420/99/419 413/92/412 -f 421/100/420 414/93/413 413/92/412 -f 420/99/419 421/100/420 413/92/412 -f 421/100/420 415/94/414 414/93/413 -f 421/100/420 422/101/421 415/94/414 -f 417/102/422 410/95/415 415/94/414 -f 422/101/421 417/102/422 415/94/414 -f 386/68/386 423/68/386 416/68/386 -f 424/68/387 390/68/387 417/68/387 -f 425/103/423 418/97/417 416/96/416 -f 423/104/424 425/103/423 416/96/416 -f 425/103/423 419/98/418 418/97/417 -f 425/103/423 426/105/425 419/98/418 -f 427/106/426 420/99/419 419/98/418 -f 426/105/425 427/106/426 419/98/418 -f 427/106/426 421/100/420 420/99/419 -f 427/106/426 428/107/427 421/100/420 -f 429/108/428 422/101/421 421/100/420 -f 428/107/427 429/108/428 421/100/420 -f 429/108/428 417/102/422 422/101/421 -f 429/108/428 424/109/429 417/102/422 -f 386/68/386 430/68/386 423/68/386 -f 431/68/387 390/68/387 424/68/387 -f 430/110/430 425/103/423 423/104/424 -f 430/110/430 432/111/431 425/103/423 -f 433/112/432 426/105/425 425/103/423 -f 432/111/431 433/112/432 425/103/423 -f 433/112/432 427/106/426 426/105/425 -f 433/112/432 434/113/433 427/106/426 -f 435/114/434 428/107/427 427/106/426 -f 434/113/433 435/114/434 427/106/426 -f 435/114/434 429/108/428 428/107/427 -f 435/114/434 436/115/435 429/108/428 -f 431/116/436 424/109/429 429/108/428 -f 436/115/435 431/116/436 429/108/428 -f 386/68/386 388/68/386 430/68/386 -f 391/68/387 390/68/387 431/68/387 -f 393/117/389 432/111/431 430/110/430 -f 388/118/390 393/117/389 430/110/430 -f 393/117/389 433/112/432 432/111/431 -f 393/117/389 394/119/392 433/112/432 -f 397/120/395 434/113/433 433/112/432 -f 394/119/392 397/120/395 433/112/432 -f 397/120/395 435/114/434 434/113/433 -f 397/120/395 398/121/396 435/114/434 -f 401/122/399 436/115/435 435/114/434 -f 398/121/396 401/122/399 435/114/434 -f 401/122/399 431/116/436 436/115/435 -f 401/122/399 391/123/400 431/116/436 +s 2 +f 436/68/386 393/68/386 386/68/386 +f 399/68/387 435/68/387 392/68/387 +s 1 +f 394/71/388 387/70/389 386/69/390 +f 393/72/391 394/71/388 386/69/390 +f 394/71/388 388/73/392 387/70/389 +f 394/71/388 395/74/393 388/73/392 +f 396/76/394 389/75/395 388/73/392 +f 395/74/393 396/76/394 388/73/392 +f 396/76/394 390/77/396 389/75/395 +f 396/76/394 397/78/397 390/77/396 +f 398/80/398 391/79/399 390/77/396 +f 397/78/397 398/80/398 390/77/396 +f 398/80/398 392/68/400 391/79/399 +f 398/80/398 399/81/401 392/68/400 +s 2 +f 436/68/386 400/68/386 393/68/386 +f 406/68/387 435/68/387 399/68/387 +s 1 +f 400/82/402 394/71/388 393/72/391 +f 400/82/402 401/83/403 394/71/388 +f 402/84/404 395/74/393 394/71/388 +f 401/83/403 402/84/404 394/71/388 +f 402/84/404 396/76/394 395/74/393 +f 402/84/404 403/85/405 396/76/394 +f 404/86/406 397/78/397 396/76/394 +f 403/85/405 404/86/406 396/76/394 +f 404/86/406 398/80/398 397/78/397 +f 404/86/406 405/87/407 398/80/398 +f 406/88/408 399/81/401 398/80/398 +f 405/87/407 406/88/408 398/80/398 +s 2 +f 436/68/386 407/68/386 400/68/386 +f 413/68/387 435/68/387 406/68/387 +s 1 +f 408/89/409 401/83/403 400/82/402 +f 407/90/410 408/89/409 400/82/402 +f 408/89/409 402/84/404 401/83/403 +f 408/89/409 409/91/411 402/84/404 +f 410/92/412 403/85/405 402/84/404 +f 409/91/411 410/92/412 402/84/404 +f 410/92/412 404/86/406 403/85/405 +f 410/92/412 411/93/413 404/86/406 +f 412/94/414 405/87/407 404/86/406 +f 411/93/413 412/94/414 404/86/406 +f 412/94/414 406/88/408 405/87/407 +f 412/94/414 413/95/415 406/88/408 +s 2 +f 436/68/386 414/68/386 407/68/386 +f 420/68/387 435/68/387 413/68/387 +s 1 +f 414/96/416 408/89/409 407/90/410 +f 414/96/416 415/97/417 408/89/409 +f 416/98/418 409/91/411 408/89/409 +f 415/97/417 416/98/418 408/89/409 +f 416/98/418 410/92/412 409/91/411 +f 416/98/418 417/99/419 410/92/412 +f 418/100/420 411/93/413 410/92/412 +f 417/99/419 418/100/420 410/92/412 +f 418/100/420 412/94/414 411/93/413 +f 418/100/420 419/101/421 412/94/414 +f 420/102/422 413/95/415 412/94/414 +f 419/101/421 420/102/422 412/94/414 +s 2 +f 436/68/386 421/68/386 414/68/386 +f 427/68/387 435/68/387 420/68/387 +s 1 +f 422/103/423 415/97/417 414/96/416 +f 421/104/424 422/103/423 414/96/416 +f 422/103/423 416/98/418 415/97/417 +f 422/103/423 423/105/425 416/98/418 +f 424/106/426 417/99/419 416/98/418 +f 423/105/425 424/106/426 416/98/418 +f 424/106/426 418/100/420 417/99/419 +f 424/106/426 425/107/427 418/100/420 +f 426/108/428 419/101/421 418/100/420 +f 425/107/427 426/108/428 418/100/420 +f 426/108/428 420/102/422 419/101/421 +f 426/108/428 427/109/429 420/102/422 +s 2 +f 436/68/386 428/68/386 421/68/386 +f 434/68/387 435/68/387 427/68/387 +s 1 +f 428/110/430 422/103/423 421/104/424 +f 428/110/430 429/111/431 422/103/423 +f 430/112/432 423/105/425 422/103/423 +f 429/111/431 430/112/432 422/103/423 +f 430/112/432 424/106/426 423/105/425 +f 430/112/432 431/113/433 424/106/426 +f 432/114/434 425/107/427 424/106/426 +f 431/113/433 432/114/434 424/106/426 +f 432/114/434 426/108/428 425/107/427 +f 432/114/434 433/115/435 426/108/428 +f 434/116/436 427/109/429 426/108/428 +f 433/115/435 434/116/436 426/108/428 +s 2 +f 436/68/386 386/68/386 428/68/386 +f 392/68/387 435/68/387 434/68/387 +s 1 +f 387/117/389 429/111/431 428/110/430 +f 386/118/390 387/117/389 428/110/430 +f 387/117/389 430/112/432 429/111/431 +f 387/117/389 388/119/392 430/112/432 +f 389/120/395 431/113/433 430/112/432 +f 388/119/392 389/120/395 430/112/432 +f 389/120/395 432/114/434 431/113/433 +f 389/120/395 390/121/396 432/114/434 +f 391/122/399 433/115/435 432/114/434 +f 390/121/396 391/122/399 432/114/434 +f 391/122/399 434/116/436 433/115/435 +f 391/122/399 392/123/400 434/116/436 +# 98 triangles in group -# Mesh 'Bein4Li_Bein4Li_Bein4Li_Bein4Li' with 98 faces -g Bein4Li_Bein4Li_Bein4Li_Bein4Li +g Bein4Li usemtl BeinTex -f 437/68/437 438/68/437 439/68/437 -f 440/68/438 441/68/438 442/68/438 -f 437/69/439 443/70/440 444/71/441 -f 437/69/439 444/71/441 438/72/442 -f 443/70/440 445/73/443 444/71/441 -f 445/73/443 446/74/444 444/71/441 -f 445/73/443 447/75/445 448/76/446 -f 445/73/443 448/76/446 446/74/444 -f 447/75/445 449/77/447 448/76/446 -f 449/77/447 450/78/448 448/76/446 -f 449/77/447 451/79/449 452/80/450 -f 449/77/447 452/80/450 450/78/448 -f 451/79/449 440/68/451 452/80/450 -f 440/68/451 442/81/452 452/80/450 -f 438/68/437 453/68/437 439/68/437 -f 442/68/438 441/68/438 454/68/438 -f 438/72/442 444/71/441 453/82/453 -f 444/71/441 455/83/454 453/82/453 -f 444/71/441 446/74/444 456/84/455 -f 444/71/441 456/84/455 455/83/454 -f 446/74/444 448/76/446 456/84/455 -f 448/76/446 457/85/456 456/84/455 -f 448/76/446 450/78/448 458/86/457 -f 448/76/446 458/86/457 457/85/456 -f 450/78/448 452/80/450 458/86/457 -f 452/80/450 459/87/458 458/86/457 -f 452/80/450 442/81/452 454/88/459 -f 452/80/450 454/88/459 459/87/458 -f 453/68/437 460/68/437 439/68/437 -f 454/68/438 441/68/438 461/68/438 -f 453/82/453 455/83/454 462/89/460 -f 453/82/453 462/89/460 460/90/461 -f 455/83/454 456/84/455 462/89/460 -f 456/84/455 463/91/462 462/89/460 -f 456/84/455 457/85/456 464/92/463 -f 456/84/455 464/92/463 463/91/462 -f 457/85/456 458/86/457 464/92/463 -f 458/86/457 465/93/464 464/92/463 -f 458/86/457 459/87/458 466/94/465 -f 458/86/457 466/94/465 465/93/464 -f 459/87/458 454/88/459 466/94/465 -f 454/88/459 461/95/466 466/94/465 -f 460/68/437 467/68/437 439/68/437 -f 461/68/438 441/68/438 468/68/438 -f 460/90/461 462/89/460 467/96/467 -f 462/89/460 469/97/468 467/96/467 -f 462/89/460 463/91/462 470/98/469 -f 462/89/460 470/98/469 469/97/468 -f 463/91/462 464/92/463 470/98/469 -f 464/92/463 471/99/470 470/98/469 -f 464/92/463 465/93/464 472/100/471 -f 464/92/463 472/100/471 471/99/470 -f 465/93/464 466/94/465 472/100/471 -f 466/94/465 473/101/472 472/100/471 -f 466/94/465 461/95/466 468/102/473 -f 466/94/465 468/102/473 473/101/472 -f 467/68/437 474/68/437 439/68/437 -f 468/68/438 441/68/438 475/68/438 -f 467/96/467 469/97/468 476/103/474 -f 467/96/467 476/103/474 474/104/475 -f 469/97/468 470/98/469 476/103/474 -f 470/98/469 477/105/476 476/103/474 -f 470/98/469 471/99/470 478/106/477 -f 470/98/469 478/106/477 477/105/476 -f 471/99/470 472/100/471 478/106/477 -f 472/100/471 479/107/478 478/106/477 -f 472/100/471 473/101/472 480/108/479 -f 472/100/471 480/108/479 479/107/478 -f 473/101/472 468/102/473 480/108/479 -f 468/102/473 475/109/480 480/108/479 -f 474/68/437 481/68/437 439/68/437 -f 475/68/438 441/68/438 482/68/438 -f 474/104/475 476/103/474 481/110/481 -f 476/103/474 483/111/482 481/110/481 -f 476/103/474 477/105/476 484/112/483 -f 476/103/474 484/112/483 483/111/482 -f 477/105/476 478/106/477 484/112/483 -f 478/106/477 485/113/484 484/112/483 -f 478/106/477 479/107/478 486/114/485 -f 478/106/477 486/114/485 485/113/484 -f 479/107/478 480/108/479 486/114/485 -f 480/108/479 487/115/486 486/114/485 -f 480/108/479 475/109/480 482/116/487 -f 480/108/479 482/116/487 487/115/486 -f 481/68/437 437/68/437 439/68/437 -f 482/68/438 441/68/438 440/68/438 -f 481/110/481 483/111/482 443/117/440 -f 481/110/481 443/117/440 437/118/439 -f 483/111/482 484/112/483 443/117/440 -f 484/112/483 445/119/443 443/117/440 -f 484/112/483 485/113/484 447/120/445 -f 484/112/483 447/120/445 445/119/443 -f 485/113/484 486/114/485 447/120/445 -f 486/114/485 449/121/447 447/120/445 -f 486/114/485 487/115/486 451/122/449 -f 486/114/485 451/122/449 449/121/447 -f 487/115/486 482/116/487 451/122/449 -f 482/116/487 440/123/451 451/122/449 +s 2 +f 437/68/437 444/68/437 487/68/437 +f 443/68/438 486/68/438 450/68/438 +s 1 +f 437/69/439 438/70/440 445/71/441 +f 437/69/439 445/71/441 444/72/442 +f 438/70/440 439/73/443 445/71/441 +f 439/73/443 446/74/444 445/71/441 +f 439/73/443 440/75/445 447/76/446 +f 439/73/443 447/76/446 446/74/444 +f 440/75/445 441/77/447 447/76/446 +f 441/77/447 448/78/448 447/76/446 +f 441/77/447 442/79/449 449/80/450 +f 441/77/447 449/80/450 448/78/448 +f 442/79/449 443/68/451 449/80/450 +f 443/68/451 450/81/452 449/80/450 +s 2 +f 444/68/437 451/68/437 487/68/437 +f 450/68/438 486/68/438 457/68/438 +s 1 +f 444/72/442 445/71/441 451/82/453 +f 445/71/441 452/83/454 451/82/453 +f 445/71/441 446/74/444 453/84/455 +f 445/71/441 453/84/455 452/83/454 +f 446/74/444 447/76/446 453/84/455 +f 447/76/446 454/85/456 453/84/455 +f 447/76/446 448/78/448 455/86/457 +f 447/76/446 455/86/457 454/85/456 +f 448/78/448 449/80/450 455/86/457 +f 449/80/450 456/87/458 455/86/457 +f 449/80/450 450/81/452 457/88/459 +f 449/80/450 457/88/459 456/87/458 +s 2 +f 451/68/437 458/68/437 487/68/437 +f 457/68/438 486/68/438 464/68/438 +s 1 +f 451/82/453 452/83/454 459/89/460 +f 451/82/453 459/89/460 458/90/461 +f 452/83/454 453/84/455 459/89/460 +f 453/84/455 460/91/462 459/89/460 +f 453/84/455 454/85/456 461/92/463 +f 453/84/455 461/92/463 460/91/462 +f 454/85/456 455/86/457 461/92/463 +f 455/86/457 462/93/464 461/92/463 +f 455/86/457 456/87/458 463/94/465 +f 455/86/457 463/94/465 462/93/464 +f 456/87/458 457/88/459 463/94/465 +f 457/88/459 464/95/466 463/94/465 +s 2 +f 458/68/437 465/68/437 487/68/437 +f 464/68/438 486/68/438 471/68/438 +s 1 +f 458/90/461 459/89/460 465/96/467 +f 459/89/460 466/97/468 465/96/467 +f 459/89/460 460/91/462 467/98/469 +f 459/89/460 467/98/469 466/97/468 +f 460/91/462 461/92/463 467/98/469 +f 461/92/463 468/99/470 467/98/469 +f 461/92/463 462/93/464 469/100/471 +f 461/92/463 469/100/471 468/99/470 +f 462/93/464 463/94/465 469/100/471 +f 463/94/465 470/101/472 469/100/471 +f 463/94/465 464/95/466 471/102/473 +f 463/94/465 471/102/473 470/101/472 +s 2 +f 465/68/437 472/68/437 487/68/437 +f 471/68/438 486/68/438 478/68/438 +s 1 +f 465/96/467 466/97/468 473/103/474 +f 465/96/467 473/103/474 472/104/475 +f 466/97/468 467/98/469 473/103/474 +f 467/98/469 474/105/476 473/103/474 +f 467/98/469 468/99/470 475/106/477 +f 467/98/469 475/106/477 474/105/476 +f 468/99/470 469/100/471 475/106/477 +f 469/100/471 476/107/478 475/106/477 +f 469/100/471 470/101/472 477/108/479 +f 469/100/471 477/108/479 476/107/478 +f 470/101/472 471/102/473 477/108/479 +f 471/102/473 478/109/480 477/108/479 +s 2 +f 472/68/437 479/68/437 487/68/437 +f 478/68/438 486/68/438 485/68/438 +s 1 +f 472/104/475 473/103/474 479/110/481 +f 473/103/474 480/111/482 479/110/481 +f 473/103/474 474/105/476 481/112/483 +f 473/103/474 481/112/483 480/111/482 +f 474/105/476 475/106/477 481/112/483 +f 475/106/477 482/113/484 481/112/483 +f 475/106/477 476/107/478 483/114/485 +f 475/106/477 483/114/485 482/113/484 +f 476/107/478 477/108/479 483/114/485 +f 477/108/479 484/115/486 483/114/485 +f 477/108/479 478/109/480 485/116/487 +f 477/108/479 485/116/487 484/115/486 +s 2 +f 479/68/437 437/68/437 487/68/437 +f 485/68/438 486/68/438 443/68/438 +s 1 +f 479/110/481 480/111/482 438/117/440 +f 479/110/481 438/117/440 437/118/439 +f 480/111/482 481/112/483 438/117/440 +f 481/112/483 439/119/443 438/117/440 +f 481/112/483 482/113/484 440/120/445 +f 481/112/483 440/120/445 439/119/443 +f 482/113/484 483/114/485 440/120/445 +f 483/114/485 441/121/447 440/120/445 +f 483/114/485 484/115/486 442/122/449 +f 483/114/485 442/122/449 441/121/447 +f 484/115/486 485/116/487 442/122/449 +f 485/116/487 443/123/451 442/122/449 +# 98 triangles in group -# Mesh 'Zahn_Zahn_Zahn_Zahn' with 42 faces -g Zahn_Zahn_Zahn_Zahn +g Zahn usemtl BeinTex -f 488/124/488 488/124/488 488/124/488 -f 489/125/489 490/126/489 491/127/489 -f 488/124/490 492/128/491 493/129/492 -f 488/124/490 493/129/492 488/124/488 -f 492/128/491 489/125/493 493/129/492 -f 489/125/493 491/127/494 493/129/492 -f 488/124/488 488/124/488 488/124/488 -f 491/127/489 490/126/489 494/130/489 -f 488/124/488 493/129/492 488/124/495 -f 493/129/492 495/131/496 488/124/495 -f 493/129/492 491/127/494 494/130/497 -f 493/129/492 494/130/497 495/131/496 -f 488/124/488 488/124/488 488/124/488 -f 494/130/489 490/126/489 496/132/489 -f 488/124/495 495/131/496 497/133/498 -f 488/124/495 497/133/498 488/124/488 -f 495/131/496 494/130/497 497/133/498 -f 494/130/497 496/132/499 497/133/498 -f 488/124/488 488/124/488 488/124/488 -f 496/132/489 490/126/489 498/134/489 -f 488/124/488 497/133/498 488/124/500 -f 497/133/498 499/135/501 488/124/500 -f 497/133/498 496/132/499 498/134/502 -f 497/133/498 498/134/502 499/135/501 -f 488/124/488 488/124/488 488/124/488 -f 498/134/489 490/126/489 500/136/489 -f 488/124/500 499/135/501 501/137/503 -f 488/124/500 501/137/503 488/124/488 -f 499/135/501 498/134/502 501/137/503 -f 498/134/502 500/136/504 501/137/503 -f 488/124/488 488/124/488 488/124/488 -f 500/136/489 490/126/489 502/138/489 -f 488/124/488 501/137/503 488/124/505 -f 501/137/503 503/139/506 488/124/505 -f 501/137/503 500/136/504 502/138/507 -f 501/137/503 502/138/507 503/139/506 -f 488/124/488 488/124/488 488/124/488 -f 502/138/489 490/126/489 489/125/489 -f 488/124/505 503/139/506 492/128/491 -f 488/124/505 492/128/491 488/124/490 -f 503/139/506 502/138/507 492/128/491 -f 502/138/507 489/125/493 492/128/491 +s 2 +f 488/124/488 491/124/488 510/124/488 +f 490/125/489 509/126/489 493/127/489 +s 1 +f 488/124/490 489/128/491 492/129/492 +f 488/124/490 492/129/492 491/124/488 +f 489/128/491 490/125/493 492/129/492 +f 490/125/493 493/127/494 492/129/492 +s 2 +f 491/124/488 494/124/488 510/124/488 +f 493/127/489 509/126/489 496/130/489 +s 1 +f 491/124/488 492/129/492 494/124/495 +f 492/129/492 495/131/496 494/124/495 +f 492/129/492 493/127/494 496/130/497 +f 492/129/492 496/130/497 495/131/496 +s 2 +f 494/124/488 497/124/488 510/124/488 +f 496/130/489 509/126/489 499/132/489 +s 1 +f 494/124/495 495/131/496 498/133/498 +f 494/124/495 498/133/498 497/124/488 +f 495/131/496 496/130/497 498/133/498 +f 496/130/497 499/132/499 498/133/498 +s 2 +f 497/124/488 500/124/488 510/124/488 +f 499/132/489 509/126/489 502/134/489 +s 1 +f 497/124/488 498/133/498 500/124/500 +f 498/133/498 501/135/501 500/124/500 +f 498/133/498 499/132/499 502/134/502 +f 498/133/498 502/134/502 501/135/501 +s 2 +f 500/124/488 503/124/488 510/124/488 +f 502/134/489 509/126/489 505/136/489 +s 1 +f 500/124/500 501/135/501 504/137/503 +f 500/124/500 504/137/503 503/124/488 +f 501/135/501 502/134/502 504/137/503 +f 502/134/502 505/136/504 504/137/503 +s 2 +f 503/124/488 506/124/488 510/124/488 +f 505/136/489 509/126/489 508/138/489 +s 1 +f 503/124/488 504/137/503 506/124/505 +f 504/137/503 507/139/506 506/124/505 +f 504/137/503 505/136/504 508/138/507 +f 504/137/503 508/138/507 507/139/506 +s 2 +f 506/124/488 488/124/488 510/124/488 +f 508/138/489 509/126/489 490/125/489 +s 1 +f 506/124/505 507/139/506 489/128/491 +f 506/124/505 489/128/491 488/124/490 +f 507/139/506 508/138/507 489/128/491 +f 508/138/507 490/125/493 489/128/491 +# 42 triangles in group -# Mesh 'klZahn_klZahn_klZahn_klZahn' with 42 faces -g klZahn_klZahn_klZahn_klZahn +g klZahn usemtl BeinTex -f 504/140/488 504/140/488 504/140/488 -f 505/141/508 506/142/508 507/143/508 -f 504/140/509 508/144/510 509/145/511 -f 504/140/509 509/145/511 504/140/488 -f 508/144/510 505/141/512 509/145/511 -f 505/141/512 507/143/513 509/145/511 -f 504/140/488 504/140/488 504/140/488 -f 507/143/508 506/142/508 510/146/508 -f 504/140/488 509/145/511 504/140/514 -f 509/145/511 511/147/515 504/140/514 -f 509/145/511 507/143/513 510/146/516 -f 509/145/511 510/146/516 511/147/515 -f 504/140/488 504/140/488 504/140/488 -f 510/146/508 506/142/508 512/148/508 -f 504/140/514 511/147/515 513/149/517 -f 504/140/514 513/149/517 504/140/488 -f 511/147/515 510/146/516 513/149/517 -f 510/146/516 512/148/518 513/149/517 -f 504/140/488 504/140/488 504/140/488 -f 512/148/508 506/142/508 514/150/508 -f 504/140/488 513/149/517 504/140/519 -f 513/149/517 515/151/520 504/140/519 -f 513/149/517 512/148/518 514/150/521 -f 513/149/517 514/150/521 515/151/520 -f 504/140/488 504/140/488 504/140/488 -f 514/150/508 506/142/508 516/152/508 -f 504/140/519 515/151/520 517/153/522 -f 504/140/519 517/153/522 504/140/488 -f 515/151/520 514/150/521 517/153/522 -f 514/150/521 516/152/523 517/153/522 -f 504/140/488 504/140/488 504/140/488 -f 516/152/508 506/142/508 518/154/508 -f 504/140/488 517/153/522 504/140/524 -f 517/153/522 519/155/525 504/140/524 -f 517/153/522 516/152/523 518/154/526 -f 517/153/522 518/154/526 519/155/525 -f 504/140/488 504/140/488 504/140/488 -f 518/154/508 506/142/508 505/141/508 -f 504/140/524 519/155/525 508/144/510 -f 504/140/524 508/144/510 504/140/509 -f 519/155/525 518/154/526 508/144/510 -f 518/154/526 505/141/512 508/144/510 +s 2 +f 511/140/488 514/140/488 533/140/488 +f 513/141/508 532/142/508 516/143/508 +s 1 +f 511/140/509 512/144/510 515/145/511 +f 511/140/509 515/145/511 514/140/488 +f 512/144/510 513/141/512 515/145/511 +f 513/141/512 516/143/513 515/145/511 +s 2 +f 514/140/488 517/140/488 533/140/488 +f 516/143/508 532/142/508 519/146/508 +s 1 +f 514/140/488 515/145/511 517/140/514 +f 515/145/511 518/147/515 517/140/514 +f 515/145/511 516/143/513 519/146/516 +f 515/145/511 519/146/516 518/147/515 +s 2 +f 517/140/488 520/140/488 533/140/488 +f 519/146/508 532/142/508 522/148/508 +s 1 +f 517/140/514 518/147/515 521/149/517 +f 517/140/514 521/149/517 520/140/488 +f 518/147/515 519/146/516 521/149/517 +f 519/146/516 522/148/518 521/149/517 +s 2 +f 520/140/488 523/140/488 533/140/488 +f 522/148/508 532/142/508 525/150/508 +s 1 +f 520/140/488 521/149/517 523/140/519 +f 521/149/517 524/151/520 523/140/519 +f 521/149/517 522/148/518 525/150/521 +f 521/149/517 525/150/521 524/151/520 +s 2 +f 523/140/488 526/140/488 533/140/488 +f 525/150/508 532/142/508 528/152/508 +s 1 +f 523/140/519 524/151/520 527/153/522 +f 523/140/519 527/153/522 526/140/488 +f 524/151/520 525/150/521 527/153/522 +f 525/150/521 528/152/523 527/153/522 +s 2 +f 526/140/488 529/140/488 533/140/488 +f 528/152/508 532/142/508 531/154/508 +s 1 +f 526/140/488 527/153/522 529/140/524 +f 527/153/522 530/155/525 529/140/524 +f 527/153/522 528/152/523 531/154/526 +f 527/153/522 531/154/526 530/155/525 +s 2 +f 529/140/488 511/140/488 533/140/488 +f 531/154/508 532/142/508 513/141/508 +s 1 +f 529/140/524 530/155/525 512/144/510 +f 529/140/524 512/144/510 511/140/509 +f 530/155/525 531/154/526 512/144/510 +f 531/154/526 513/141/512 512/144/510 +# 42 triangles in group -# Mesh 'Kopf_Kopf_Kopf_Kopf' with 90 faces -g Kopf_Kopf_Kopf_Kopf +g Kopf usemtl Skin -f 520/68/527 521/156/528 522/157/529 -f 520/68/527 523/158/530 521/156/528 -f 524/69/531 525/159/532 526/160/533 -f 520/68/527 527/161/534 523/158/530 -f 524/69/531 526/160/533 528/162/535 -f 520/68/527 529/163/536 527/161/534 -f 524/69/531 528/162/535 530/164/537 -f 520/68/527 531/165/538 529/163/536 -f 524/69/531 530/164/537 532/166/539 -f 520/68/527 533/167/540 531/165/538 -f 534/168/541 535/169/542 525/159/532 -f 525/159/532 535/169/542 536/170/543 -f 525/159/532 536/170/543 526/160/533 -f 526/160/533 536/170/543 528/162/535 -f 536/170/543 537/169/544 528/162/535 -f 528/162/535 537/169/544 538/171/545 -f 528/162/535 538/171/545 530/164/537 -f 530/164/537 538/171/545 532/166/539 -f 538/171/545 539/172/546 532/166/539 -f 540/173/547 541/174/548 534/168/541 -f 541/174/548 542/175/549 534/168/541 -f 534/168/541 542/175/549 543/176/550 -f 534/168/541 543/176/550 535/169/542 -f 535/169/542 543/176/550 536/170/543 -f 543/176/550 544/177/551 536/170/543 -f 536/170/543 544/177/551 545/178/552 -f 536/170/543 545/178/552 537/169/544 -f 537/169/544 545/178/552 538/171/545 -f 545/178/552 546/179/553 538/171/545 -f 538/171/545 546/179/553 547/180/554 -f 538/171/545 547/180/554 539/172/546 -f 541/174/548 548/181/555 549/182/556 -f 541/174/548 549/182/556 542/175/549 -f 542/175/549 549/182/556 543/176/550 -f 549/182/556 550/183/557 543/176/550 -f 543/176/550 550/183/557 551/184/558 -f 543/176/550 551/184/558 544/177/551 -f 544/177/551 551/184/558 545/178/552 -f 551/184/558 552/185/559 545/178/552 -f 546/179/553 553/186/560 547/180/554 -f 553/186/560 554/187/561 547/180/554 -f 548/181/555 522/157/529 549/182/556 -f 522/157/529 521/156/528 549/182/556 -f 549/182/556 521/156/528 523/158/530 -f 549/182/556 523/158/530 550/183/557 -f 550/183/557 523/158/530 551/184/558 -f 523/158/530 527/161/534 551/184/558 -f 551/184/558 527/161/534 529/163/536 -f 551/184/558 529/163/536 552/185/559 -f 552/185/559 529/163/536 553/186/560 -f 529/163/536 531/165/538 553/186/560 -f 553/186/560 531/165/538 533/167/540 -f 553/186/560 533/167/540 554/187/561 -f 555/188/562 556/189/563 557/190/564 -f 546/179/553 558/191/565 557/190/564 -f 557/190/564 555/188/562 546/179/553 -f 559/192/566 558/191/565 546/179/553 -f 558/191/565 559/192/566 560/193/567 -f 560/193/567 557/190/564 558/191/565 -f 561/194/568 560/193/567 559/192/566 -f 559/192/566 562/195/569 561/194/568 -f 563/196/570 561/194/568 564/197/571 -f 562/195/569 564/197/571 561/194/568 -f 565/198/572 563/196/570 566/199/573 -f 563/196/570 564/197/571 566/199/573 -f 566/199/573 567/200/574 565/198/572 -f 566/199/573 568/201/575 567/200/574 -f 568/201/575 569/202/576 567/200/574 -f 570/203/577 567/200/574 569/202/576 -f 569/202/576 571/204/578 570/203/577 -f 572/205/579 570/203/577 571/204/578 -f 573/206/580 572/205/579 571/204/578 -f 571/204/578 574/207/581 573/206/580 -f 575/208/582 573/206/580 574/207/581 -f 574/207/581 576/209/583 575/208/582 -f 556/189/563 575/208/582 576/209/583 -f 576/209/583 555/188/562 556/189/563 -f 555/188/562 553/186/560 546/179/553 -f 555/188/562 576/209/583 553/186/560 -f 576/209/583 574/207/581 553/186/560 -f 574/207/581 571/204/578 553/186/560 -f 571/204/578 569/202/576 553/186/560 -f 552/185/559 553/186/560 569/202/576 -f 569/202/576 568/201/575 552/185/559 -f 568/201/575 566/199/573 552/185/559 -f 559/192/566 546/179/553 545/178/552 -f 562/195/569 559/192/566 545/178/552 -f 564/197/571 562/195/569 545/178/552 -f 545/178/552 552/185/559 566/199/573 -f 564/197/571 566/199/573 545/178/552 +f 534/68/527 563/156/528 562/157/529 +f 534/68/527 564/158/530 563/156/528 +f 535/69/531 536/159/532 537/160/533 +f 534/68/527 565/161/534 564/158/530 +f 535/69/531 537/160/533 538/162/535 +f 534/68/527 566/163/536 565/161/534 +f 535/69/531 538/162/535 539/164/537 +f 534/68/527 567/165/538 566/163/536 +f 535/69/531 539/164/537 540/166/539 +f 534/68/527 568/167/540 567/165/538 +f 542/168/541 543/169/542 536/159/532 +f 536/159/532 543/169/542 544/170/543 +f 536/159/532 544/170/543 537/160/533 +f 537/160/533 544/170/543 538/162/535 +f 544/170/543 545/169/544 538/162/535 +f 538/162/535 545/169/544 546/171/545 +f 538/162/535 546/171/545 539/164/537 +f 539/164/537 546/171/545 540/166/539 +f 546/171/545 547/172/546 540/166/539 +f 541/173/547 548/174/548 542/168/541 +f 548/174/548 549/175/549 542/168/541 +f 542/168/541 549/175/549 550/176/550 +f 542/168/541 550/176/550 543/169/542 +f 543/169/542 550/176/550 544/170/543 +f 550/176/550 551/177/551 544/170/543 +f 544/170/543 551/177/551 552/178/552 +f 544/170/543 552/178/552 545/169/544 +f 545/169/544 552/178/552 546/171/545 +f 552/178/552 553/179/553 546/171/545 +f 546/171/545 553/179/553 554/180/554 +f 546/171/545 554/180/554 547/172/546 +f 548/174/548 555/181/555 556/182/556 +f 548/174/548 556/182/556 549/175/549 +f 549/175/549 556/182/556 550/176/550 +f 556/182/556 557/183/557 550/176/550 +f 550/176/550 557/183/557 558/184/558 +f 550/176/550 558/184/558 551/177/551 +f 551/177/551 558/184/558 552/178/552 +f 558/184/558 559/185/559 552/178/552 +f 553/179/553 560/186/560 554/180/554 +f 560/186/560 561/187/561 554/180/554 +f 555/181/555 562/157/529 556/182/556 +f 562/157/529 563/156/528 556/182/556 +f 556/182/556 563/156/528 564/158/530 +f 556/182/556 564/158/530 557/183/557 +f 557/183/557 564/158/530 558/184/558 +f 564/158/530 565/161/534 558/184/558 +f 558/184/558 565/161/534 566/163/536 +f 558/184/558 566/163/536 559/185/559 +f 559/185/559 566/163/536 560/186/560 +f 566/163/536 567/165/538 560/186/560 +f 560/186/560 567/165/538 568/167/540 +f 560/186/560 568/167/540 561/187/561 +f 575/188/562 585/189/563 586/190/564 +f 553/179/553 576/191/565 586/190/564 +f 586/190/564 575/188/562 553/179/553 +f 577/192/566 576/191/565 553/179/553 +f 576/191/565 577/192/566 587/193/567 +f 587/193/567 586/190/564 576/191/565 +f 588/194/568 587/193/567 577/192/566 +f 577/192/566 578/195/569 588/194/568 +f 589/196/570 588/194/568 579/197/571 +f 578/195/569 579/197/571 588/194/568 +f 590/198/572 589/196/570 569/199/573 +f 589/196/570 579/197/571 569/199/573 +f 569/199/573 580/200/574 590/198/572 +f 569/199/573 570/201/575 580/200/574 +f 570/201/575 571/202/576 580/200/574 +f 581/203/577 580/200/574 571/202/576 +f 571/202/576 572/204/578 581/203/577 +f 582/205/579 581/203/577 572/204/578 +f 583/206/580 582/205/579 572/204/578 +f 572/204/578 573/207/581 583/206/580 +f 584/208/582 583/206/580 573/207/581 +f 573/207/581 574/209/583 584/208/582 +f 585/189/563 584/208/582 574/209/583 +f 574/209/583 575/188/562 585/189/563 +f 575/188/562 560/186/560 553/179/553 +f 575/188/562 574/209/583 560/186/560 +f 574/209/583 573/207/581 560/186/560 +f 573/207/581 572/204/578 560/186/560 +f 572/204/578 571/202/576 560/186/560 +f 559/185/559 560/186/560 571/202/576 +f 571/202/576 570/201/575 559/185/559 +f 570/201/575 569/199/573 559/185/559 +f 577/192/566 553/179/553 552/178/552 +f 578/195/569 577/192/566 552/178/552 +f 579/197/571 578/195/569 552/178/552 +f 552/178/552 559/185/559 569/199/573 +f 579/197/571 569/199/573 552/178/552 +# 90 triangles in group -# Mesh 'Brust_Brust_Brust_Brust' with 20 faces -g Brust_Brust_Brust_Brust +g Brust usemtl Skin -f 70/210/584 71/211/585 577/212/586 -f 60/120/587 577/212/586 64/213/588 -f 577/212/586 71/211/585 64/213/588 -f 70/210/584 577/212/586 578/214/589 -f 75/215/590 578/214/589 579/216/591 -f 60/120/587 579/216/591 577/212/586 -f 578/214/589 577/212/586 579/216/591 -f 70/210/584 578/214/589 580/217/592 -f 77/75/593 580/217/592 581/218/594 -f 75/215/590 581/218/594 578/214/589 -f 580/217/592 578/214/589 581/218/594 -f 77/75/593 581/218/594 72/219/595 -f 75/215/590 73/220/596 581/218/594 -f 72/219/595 581/218/594 73/220/596 -f 75/215/590 579/216/591 74/221/597 -f 60/120/587 61/222/598 579/216/591 -f 74/221/597 579/216/591 61/222/598 -f 70/210/584 580/217/592 69/223/599 -f 77/75/593 79/224/600 580/217/592 -f 69/223/599 580/217/592 79/224/600 +f 595/210/584 596/211/585 597/212/586 +f 591/120/587 597/212/586 593/213/588 +f 597/212/586 596/211/585 593/213/588 +f 595/210/584 597/212/586 598/214/589 +f 599/215/590 598/214/589 600/216/591 +f 591/120/587 600/216/591 597/212/586 +f 598/214/589 597/212/586 600/216/591 +f 595/210/584 598/214/589 601/217/592 +f 602/75/593 601/217/592 603/218/594 +f 599/215/590 603/218/594 598/214/589 +f 601/217/592 598/214/589 603/218/594 +f 602/75/593 603/218/594 604/219/595 +f 599/215/590 605/220/596 603/218/594 +f 604/219/595 603/218/594 605/220/596 +f 599/215/590 600/216/591 606/221/597 +f 591/120/587 592/222/598 600/216/591 +f 606/221/597 600/216/591 592/222/598 +f 595/210/584 601/217/592 594/223/599 +f 602/75/593 607/224/600 601/217/592 +f 594/223/599 601/217/592 607/224/600 +# 20 triangles in group -# Mesh 'Kopf2_Kopf2_Kopf2_Kopf2' with 90 faces -g Kopf2_Kopf2_Kopf2_Kopf2 +g Kopf2 usemtl Skin -f 582/225/601 583/226/602 584/123/603 -f 583/226/602 585/227/604 584/123/603 -f 586/228/605 587/229/606 588/118/607 -f 585/227/604 589/230/608 584/123/603 -f 590/231/609 586/228/605 588/118/607 -f 589/230/608 591/232/610 584/123/603 -f 592/233/611 590/231/609 588/118/607 -f 591/232/610 593/234/612 584/123/603 -f 594/235/613 592/233/611 588/118/607 -f 593/234/612 595/236/614 584/123/603 -f 587/229/606 596/237/615 597/238/616 -f 598/239/617 596/237/615 587/229/606 -f 586/228/605 598/239/617 587/229/606 -f 590/231/609 598/239/617 586/228/605 -f 590/231/609 599/237/618 598/239/617 -f 600/240/619 599/237/618 590/231/609 -f 592/233/611 600/240/619 590/231/609 -f 594/235/613 600/240/619 592/233/611 -f 594/235/613 601/241/620 600/240/619 -f 597/238/616 602/176/621 603/242/622 -f 597/238/616 604/243/623 602/176/621 -f 605/174/624 604/243/623 597/238/616 -f 596/237/615 605/174/624 597/238/616 -f 598/239/617 605/174/624 596/237/615 -f 598/239/617 606/244/625 605/174/624 -f 607/245/626 606/244/625 598/239/617 -f 599/237/618 607/245/626 598/239/617 -f 600/240/619 607/245/626 599/237/618 -f 600/240/619 608/246/627 607/245/626 -f 609/247/628 608/246/627 600/240/619 -f 601/241/620 609/247/628 600/240/619 -f 610/248/629 611/249/630 602/176/621 -f 604/243/623 610/248/629 602/176/621 -f 605/174/624 610/248/629 604/243/623 -f 605/174/624 612/250/631 610/248/629 -f 613/251/632 612/250/631 605/174/624 -f 606/244/625 613/251/632 605/174/624 -f 607/245/626 613/251/632 606/244/625 -f 607/245/626 614/252/633 613/251/632 -f 609/247/628 615/253/634 608/246/627 -f 609/247/628 616/254/635 615/253/634 -f 610/248/629 582/225/601 611/249/630 -f 610/248/629 583/226/602 582/225/601 -f 585/227/604 583/226/602 610/248/629 -f 612/250/631 585/227/604 610/248/629 -f 613/251/632 585/227/604 612/250/631 -f 613/251/632 589/230/608 585/227/604 -f 591/232/610 589/230/608 613/251/632 -f 614/252/633 591/232/610 613/251/632 -f 615/253/634 591/232/610 614/252/633 -f 615/253/634 593/234/612 591/232/610 -f 595/236/614 593/234/612 615/253/634 -f 616/254/635 595/236/614 615/253/634 -f 617/255/636 618/256/637 619/257/638 -f 617/255/636 620/258/639 608/246/627 -f 608/246/627 619/257/638 617/255/636 -f 608/246/627 620/258/639 621/259/640 -f 622/260/641 621/259/640 620/258/639 -f 620/258/639 617/255/636 622/260/641 -f 621/259/640 622/260/641 623/261/642 -f 623/261/642 624/262/643 621/259/640 -f 625/263/644 623/261/642 626/264/645 -f 623/261/642 625/263/644 624/262/643 -f 627/265/646 626/264/645 628/266/647 -f 627/265/646 625/263/644 626/264/645 -f 628/266/647 629/267/648 627/265/646 -f 629/267/648 630/268/649 627/265/646 -f 629/267/648 631/269/650 630/268/649 -f 631/269/650 629/267/648 632/270/651 -f 632/270/651 633/271/652 631/269/650 -f 633/271/652 632/270/651 634/272/653 -f 633/271/652 634/272/653 635/273/654 -f 635/273/654 636/274/655 633/271/652 -f 636/274/655 635/273/654 637/275/656 -f 637/275/656 638/276/657 636/274/655 -f 638/276/657 637/275/656 618/256/637 -f 618/256/637 619/257/638 638/276/657 -f 608/246/627 615/253/634 619/257/638 -f 615/253/634 638/276/657 619/257/638 -f 615/253/634 636/274/655 638/276/657 -f 615/253/634 633/271/652 636/274/655 -f 615/253/634 631/269/650 633/271/652 -f 631/269/650 615/253/634 614/252/633 -f 614/252/633 630/268/649 631/269/650 -f 614/252/633 627/265/646 630/268/649 -f 607/245/626 608/246/627 621/259/640 -f 607/245/626 621/259/640 624/262/643 -f 607/245/626 624/262/643 625/263/644 -f 627/265/646 614/252/633 607/245/626 -f 607/245/626 627/265/646 625/263/644 +f 636/225/601 637/226/602 608/123/603 +f 637/226/602 638/227/604 608/123/603 +f 611/228/605 610/229/606 609/118/607 +f 638/227/604 639/230/608 608/123/603 +f 612/231/609 611/228/605 609/118/607 +f 639/230/608 640/232/610 608/123/603 +f 613/233/611 612/231/609 609/118/607 +f 640/232/610 641/234/612 608/123/603 +f 614/235/613 613/233/611 609/118/607 +f 641/234/612 642/236/614 608/123/603 +f 610/229/606 617/237/615 616/238/616 +f 618/239/617 617/237/615 610/229/606 +f 611/228/605 618/239/617 610/229/606 +f 612/231/609 618/239/617 611/228/605 +f 612/231/609 619/237/618 618/239/617 +f 620/240/619 619/237/618 612/231/609 +f 613/233/611 620/240/619 612/231/609 +f 614/235/613 620/240/619 613/233/611 +f 614/235/613 621/241/620 620/240/619 +f 616/238/616 622/176/621 615/242/622 +f 616/238/616 623/243/623 622/176/621 +f 624/174/624 623/243/623 616/238/616 +f 617/237/615 624/174/624 616/238/616 +f 618/239/617 624/174/624 617/237/615 +f 618/239/617 625/244/625 624/174/624 +f 626/245/626 625/244/625 618/239/617 +f 619/237/618 626/245/626 618/239/617 +f 620/240/619 626/245/626 619/237/618 +f 620/240/619 627/246/627 626/245/626 +f 628/247/628 627/246/627 620/240/619 +f 621/241/620 628/247/628 620/240/619 +f 630/248/629 629/249/630 622/176/621 +f 623/243/623 630/248/629 622/176/621 +f 624/174/624 630/248/629 623/243/623 +f 624/174/624 631/250/631 630/248/629 +f 632/251/632 631/250/631 624/174/624 +f 625/244/625 632/251/632 624/174/624 +f 626/245/626 632/251/632 625/244/625 +f 626/245/626 633/252/633 632/251/632 +f 628/247/628 634/253/634 627/246/627 +f 628/247/628 635/254/635 634/253/634 +f 630/248/629 636/225/601 629/249/630 +f 630/248/629 637/226/602 636/225/601 +f 638/227/604 637/226/602 630/248/629 +f 631/250/631 638/227/604 630/248/629 +f 632/251/632 638/227/604 631/250/631 +f 632/251/632 639/230/608 638/227/604 +f 640/232/610 639/230/608 632/251/632 +f 633/252/633 640/232/610 632/251/632 +f 634/253/634 640/232/610 633/252/633 +f 634/253/634 641/234/612 640/232/610 +f 642/236/614 641/234/612 634/253/634 +f 635/254/635 642/236/614 634/253/634 +f 660/255/636 659/256/637 649/257/638 +f 660/255/636 650/258/639 627/246/627 +f 627/246/627 649/257/638 660/255/636 +f 627/246/627 650/258/639 651/259/640 +f 661/260/641 651/259/640 650/258/639 +f 650/258/639 660/255/636 661/260/641 +f 651/259/640 661/260/641 662/261/642 +f 662/261/642 652/262/643 651/259/640 +f 653/263/644 662/261/642 663/264/645 +f 662/261/642 653/263/644 652/262/643 +f 643/265/646 663/264/645 664/266/647 +f 643/265/646 653/263/644 663/264/645 +f 664/266/647 654/267/648 643/265/646 +f 654/267/648 644/268/649 643/265/646 +f 654/267/648 645/269/650 644/268/649 +f 645/269/650 654/267/648 655/270/651 +f 655/270/651 646/271/652 645/269/650 +f 646/271/652 655/270/651 656/272/653 +f 646/271/652 656/272/653 657/273/654 +f 657/273/654 647/274/655 646/271/652 +f 647/274/655 657/273/654 658/275/656 +f 658/275/656 648/276/657 647/274/655 +f 648/276/657 658/275/656 659/256/637 +f 659/256/637 649/257/638 648/276/657 +f 627/246/627 634/253/634 649/257/638 +f 634/253/634 648/276/657 649/257/638 +f 634/253/634 647/274/655 648/276/657 +f 634/253/634 646/271/652 647/274/655 +f 634/253/634 645/269/650 646/271/652 +f 645/269/650 634/253/634 633/252/633 +f 633/252/633 644/268/649 645/269/650 +f 633/252/633 643/265/646 644/268/649 +f 626/245/626 627/246/627 651/259/640 +f 626/245/626 651/259/640 652/262/643 +f 626/245/626 652/262/643 653/263/644 +f 643/265/646 633/252/633 626/245/626 +f 626/245/626 643/265/646 653/263/644 +# 90 triangles in group -# Mesh 'Zahn2_Zahn2_Zahn2_Zahn2' with 42 faces -g Zahn2_Zahn2_Zahn2_Zahn2 +g Zahn2 usemtl BeinTex -f 639/124/488 639/124/488 639/124/488 -f 640/127/658 641/126/658 642/125/658 -f 643/129/659 644/128/660 639/124/661 -f 639/124/488 643/129/659 639/124/661 -f 643/129/659 642/125/662 644/128/660 -f 643/129/659 640/127/663 642/125/662 -f 639/124/488 639/124/488 639/124/488 -f 645/130/658 641/126/658 640/127/658 -f 639/124/664 643/129/659 639/124/488 -f 639/124/664 646/131/665 643/129/659 -f 645/130/666 640/127/663 643/129/659 -f 646/131/665 645/130/666 643/129/659 -f 639/124/488 639/124/488 639/124/488 -f 647/132/658 641/126/658 645/130/658 -f 648/133/667 646/131/665 639/124/664 -f 639/124/488 648/133/667 639/124/664 -f 648/133/667 645/130/666 646/131/665 -f 648/133/667 647/132/668 645/130/666 -f 639/124/488 639/124/488 639/124/488 -f 649/134/658 641/126/658 647/132/658 -f 639/124/669 648/133/667 639/124/488 -f 639/124/669 650/135/670 648/133/667 -f 649/134/671 647/132/668 648/133/667 -f 650/135/670 649/134/671 648/133/667 -f 639/124/488 639/124/488 639/124/488 -f 651/136/658 641/126/658 649/134/658 -f 652/137/672 650/135/670 639/124/669 -f 639/124/488 652/137/672 639/124/669 -f 652/137/672 649/134/671 650/135/670 -f 652/137/672 651/136/673 649/134/671 -f 639/124/488 639/124/488 639/124/488 -f 653/138/658 641/126/658 651/136/658 -f 639/124/674 652/137/672 639/124/488 -f 639/124/674 654/139/675 652/137/672 -f 653/138/676 651/136/673 652/137/672 -f 654/139/675 653/138/676 652/137/672 -f 639/124/488 639/124/488 639/124/488 -f 642/125/658 641/126/658 653/138/658 -f 644/128/660 654/139/675 639/124/674 -f 639/124/661 644/128/660 639/124/674 -f 644/128/660 653/138/676 654/139/675 -f 644/128/660 642/125/662 653/138/676 +s 2 +f 687/124/488 668/124/488 665/124/488 +f 670/127/658 686/126/658 667/125/658 +s 1 +f 669/129/659 666/128/660 665/124/661 +f 668/124/488 669/129/659 665/124/661 +f 669/129/659 667/125/662 666/128/660 +f 669/129/659 670/127/663 667/125/662 +s 2 +f 687/124/488 671/124/488 668/124/488 +f 673/130/658 686/126/658 670/127/658 +s 1 +f 671/124/664 669/129/659 668/124/488 +f 671/124/664 672/131/665 669/129/659 +f 673/130/666 670/127/663 669/129/659 +f 672/131/665 673/130/666 669/129/659 +s 2 +f 687/124/488 674/124/488 671/124/488 +f 676/132/658 686/126/658 673/130/658 +s 1 +f 675/133/667 672/131/665 671/124/664 +f 674/124/488 675/133/667 671/124/664 +f 675/133/667 673/130/666 672/131/665 +f 675/133/667 676/132/668 673/130/666 +s 2 +f 687/124/488 677/124/488 674/124/488 +f 679/134/658 686/126/658 676/132/658 +s 1 +f 677/124/669 675/133/667 674/124/488 +f 677/124/669 678/135/670 675/133/667 +f 679/134/671 676/132/668 675/133/667 +f 678/135/670 679/134/671 675/133/667 +s 2 +f 687/124/488 680/124/488 677/124/488 +f 682/136/658 686/126/658 679/134/658 +s 1 +f 681/137/672 678/135/670 677/124/669 +f 680/124/488 681/137/672 677/124/669 +f 681/137/672 679/134/671 678/135/670 +f 681/137/672 682/136/673 679/134/671 +s 2 +f 687/124/488 683/124/488 680/124/488 +f 685/138/658 686/126/658 682/136/658 +s 1 +f 683/124/674 681/137/672 680/124/488 +f 683/124/674 684/139/675 681/137/672 +f 685/138/676 682/136/673 681/137/672 +f 684/139/675 685/138/676 681/137/672 +s 2 +f 687/124/488 665/124/488 683/124/488 +f 667/125/658 686/126/658 685/138/658 +s 1 +f 666/128/660 684/139/675 683/124/674 +f 665/124/661 666/128/660 683/124/674 +f 666/128/660 685/138/676 684/139/675 +f 666/128/660 667/125/662 685/138/676 +# 42 triangles in group -# Mesh 'klZahn2_klZahn2_klZahn2_klZahn2' with 42 faces -g klZahn2_klZahn2_klZahn2_klZahn2 +g klZahn2 usemtl BeinTex -f 655/140/488 655/140/488 655/140/488 -f 656/143/677 657/142/677 658/141/677 -f 659/145/678 660/144/679 655/140/680 -f 655/140/488 659/145/678 655/140/680 -f 659/145/678 658/141/681 660/144/679 -f 659/145/678 656/143/682 658/141/681 -f 655/140/488 655/140/488 655/140/488 -f 661/146/677 657/142/677 656/143/677 -f 655/140/683 659/145/678 655/140/488 -f 655/140/683 662/147/684 659/145/678 -f 661/146/685 656/143/682 659/145/678 -f 662/147/684 661/146/685 659/145/678 -f 655/140/488 655/140/488 655/140/488 -f 663/148/677 657/142/677 661/146/677 -f 664/149/686 662/147/684 655/140/683 -f 655/140/488 664/149/686 655/140/683 -f 664/149/686 661/146/685 662/147/684 -f 664/149/686 663/148/687 661/146/685 -f 655/140/488 655/140/488 655/140/488 -f 665/150/677 657/142/677 663/148/677 -f 655/140/688 664/149/686 655/140/488 -f 655/140/688 666/151/689 664/149/686 -f 665/150/690 663/148/687 664/149/686 -f 666/151/689 665/150/690 664/149/686 -f 655/140/488 655/140/488 655/140/488 -f 667/152/677 657/142/677 665/150/677 -f 668/153/691 666/151/689 655/140/688 -f 655/140/488 668/153/691 655/140/688 -f 668/153/691 665/150/690 666/151/689 -f 668/153/691 667/152/692 665/150/690 -f 655/140/488 655/140/488 655/140/488 -f 669/154/677 657/142/677 667/152/677 -f 655/140/693 668/153/691 655/140/488 -f 655/140/693 670/155/694 668/153/691 -f 669/154/695 667/152/692 668/153/691 -f 670/155/694 669/154/695 668/153/691 -f 655/140/488 655/140/488 655/140/488 -f 658/141/677 657/142/677 669/154/677 -f 660/144/679 670/155/694 655/140/693 -f 655/140/680 660/144/679 655/140/693 -f 660/144/679 669/154/695 670/155/694 -f 660/144/679 658/141/681 669/154/695 +s 2 +f 710/140/488 691/140/488 688/140/488 +f 693/143/677 709/142/677 690/141/677 +s 1 +f 692/145/678 689/144/679 688/140/680 +f 691/140/488 692/145/678 688/140/680 +f 692/145/678 690/141/681 689/144/679 +f 692/145/678 693/143/682 690/141/681 +s 2 +f 710/140/488 694/140/488 691/140/488 +f 696/146/677 709/142/677 693/143/677 +s 1 +f 694/140/683 692/145/678 691/140/488 +f 694/140/683 695/147/684 692/145/678 +f 696/146/685 693/143/682 692/145/678 +f 695/147/684 696/146/685 692/145/678 +s 2 +f 710/140/488 697/140/488 694/140/488 +f 699/148/677 709/142/677 696/146/677 +s 1 +f 698/149/686 695/147/684 694/140/683 +f 697/140/488 698/149/686 694/140/683 +f 698/149/686 696/146/685 695/147/684 +f 698/149/686 699/148/687 696/146/685 +s 2 +f 710/140/488 700/140/488 697/140/488 +f 702/150/677 709/142/677 699/148/677 +s 1 +f 700/140/688 698/149/686 697/140/488 +f 700/140/688 701/151/689 698/149/686 +f 702/150/690 699/148/687 698/149/686 +f 701/151/689 702/150/690 698/149/686 +s 2 +f 710/140/488 703/140/488 700/140/488 +f 705/152/677 709/142/677 702/150/677 +s 1 +f 704/153/691 701/151/689 700/140/688 +f 703/140/488 704/153/691 700/140/688 +f 704/153/691 702/150/690 701/151/689 +f 704/153/691 705/152/692 702/150/690 +s 2 +f 710/140/488 706/140/488 703/140/488 +f 708/154/677 709/142/677 705/152/677 +s 1 +f 706/140/693 704/153/691 703/140/488 +f 706/140/693 707/155/694 704/153/691 +f 708/154/695 705/152/692 704/153/691 +f 707/155/694 708/154/695 704/153/691 +s 2 +f 710/140/488 688/140/488 706/140/488 +f 690/141/677 709/142/677 708/154/677 +s 1 +f 689/144/679 707/155/694 706/140/693 +f 688/140/680 689/144/679 706/140/693 +f 689/144/679 708/154/695 707/155/694 +f 689/144/679 690/141/681 708/154/695 +# 42 triangles in group -# Mesh 'Auge_Auge_Auge_Auge' with 38 faces -g Auge_Auge_Auge_Auge +g Auge usemtl Augentex -f 671/277/696 672/278/697 673/279/698 -f 671/277/696 673/279/698 674/280/699 -f 675/281/700 674/280/699 676/282/701 -f 674/280/699 673/279/698 676/282/701 -f 675/281/700 676/282/701 677/283/702 -f 678/284/703 679/285/704 680/286/705 -f 681/287/706 680/286/705 682/288/707 -f 683/289/708 682/288/707 679/285/704 -f 680/286/705 679/285/704 682/288/707 -f 681/287/706 682/288/707 684/290/709 -f 685/291/710 684/290/709 686/292/711 -f 683/289/708 686/292/711 682/288/707 -f 684/290/709 682/288/707 686/292/711 -f 685/291/710 687/293/712 688/294/713 -f 689/295/714 688/294/713 690/296/715 -f 691/297/716 690/296/715 687/293/712 -f 688/294/713 687/293/712 690/296/715 -f 689/295/714 690/296/715 692/298/717 -f 671/277/696 692/298/717 693/299/718 -f 691/297/716 693/299/718 690/296/715 -f 692/298/717 690/296/715 693/299/718 -f 671/277/696 693/299/718 672/278/697 -f 675/281/700 694/300/719 674/280/699 -f 671/277/696 674/280/699 692/298/717 -f 689/295/714 692/298/717 694/300/719 -f 674/280/699 694/300/719 692/298/717 -f 675/281/700 695/301/720 694/300/719 -f 689/295/714 694/300/719 696/302/721 -f 681/287/706 696/302/721 695/301/720 -f 694/300/719 695/301/720 696/302/721 -f 675/281/700 677/283/702 695/301/720 -f 681/287/706 695/301/720 680/286/705 -f 678/284/703 680/286/705 677/283/702 -f 695/301/720 677/283/702 680/286/705 -f 685/291/710 688/294/713 684/290/709 -f 681/287/706 684/290/709 696/302/721 -f 689/295/714 696/302/721 688/294/713 -f 684/290/709 688/294/713 696/302/721 +f 711/277/696 712/278/697 713/279/698 +f 711/277/696 713/279/698 714/280/699 +f 715/281/700 714/280/699 716/282/701 +f 714/280/699 713/279/698 716/282/701 +f 715/281/700 716/282/701 717/283/702 +f 718/284/703 720/285/704 721/286/705 +f 722/287/706 721/286/705 723/288/707 +f 719/289/708 723/288/707 720/285/704 +f 721/286/705 720/285/704 723/288/707 +f 722/287/706 723/288/707 724/290/709 +f 725/291/710 724/290/709 726/292/711 +f 719/289/708 726/292/711 723/288/707 +f 724/290/709 723/288/707 726/292/711 +f 725/291/710 727/293/712 729/294/713 +f 730/295/714 729/294/713 731/296/715 +f 728/297/716 731/296/715 727/293/712 +f 729/294/713 727/293/712 731/296/715 +f 730/295/714 731/296/715 732/298/717 +f 711/277/696 732/298/717 733/299/718 +f 728/297/716 733/299/718 731/296/715 +f 732/298/717 731/296/715 733/299/718 +f 711/277/696 733/299/718 712/278/697 +f 715/281/700 734/300/719 714/280/699 +f 711/277/696 714/280/699 732/298/717 +f 730/295/714 732/298/717 734/300/719 +f 714/280/699 734/300/719 732/298/717 +f 715/281/700 735/301/720 734/300/719 +f 730/295/714 734/300/719 736/302/721 +f 722/287/706 736/302/721 735/301/720 +f 734/300/719 735/301/720 736/302/721 +f 715/281/700 717/283/702 735/301/720 +f 722/287/706 735/301/720 721/286/705 +f 718/284/703 721/286/705 717/283/702 +f 735/301/720 717/283/702 721/286/705 +f 725/291/710 729/294/713 724/290/709 +f 722/287/706 724/290/709 736/302/721 +f 730/295/714 736/302/721 729/294/713 +f 724/290/709 729/294/713 736/302/721 +# 38 triangles in group -# Mesh 'Duplicate05_Duplicate05_Duplicate05_Duplicate05' with 38 faces -g Duplicate05_Duplicate05_Duplicate05_Duplicate05 +g Duplicate05 usemtl Augentex -f 697/279/722 698/278/723 699/277/724 -f 700/280/725 697/279/722 699/277/724 -f 701/282/726 700/280/725 702/281/727 -f 701/282/726 697/279/722 700/280/725 -f 703/283/728 701/282/726 702/281/727 -f 704/286/729 705/285/730 706/284/731 -f 707/288/732 704/286/729 708/287/733 -f 705/285/730 707/288/732 709/289/734 -f 707/288/732 705/285/730 704/286/729 -f 710/290/735 707/288/732 708/287/733 -f 711/292/736 710/290/735 712/291/737 -f 707/288/732 711/292/736 709/289/734 -f 711/292/736 707/288/732 710/290/735 -f 713/294/738 714/293/739 712/291/737 -f 715/296/740 713/294/738 716/295/741 -f 714/293/739 715/296/740 717/297/742 -f 715/296/740 714/293/739 713/294/738 -f 718/298/743 715/296/740 716/295/741 -f 719/299/744 718/298/743 699/277/724 -f 715/296/740 719/299/744 717/297/742 -f 719/299/744 715/296/740 718/298/743 -f 698/278/723 719/299/744 699/277/724 -f 700/280/725 720/300/745 702/281/727 -f 718/298/743 700/280/725 699/277/724 -f 720/300/745 718/298/743 716/295/741 -f 718/298/743 720/300/745 700/280/725 -f 720/300/745 721/301/746 702/281/727 -f 722/302/747 720/300/745 716/295/741 -f 721/301/746 722/302/747 708/287/733 -f 722/302/747 721/301/746 720/300/745 -f 721/301/746 703/283/728 702/281/727 -f 704/286/729 721/301/746 708/287/733 -f 703/283/728 704/286/729 706/284/731 -f 704/286/729 703/283/728 721/301/746 -f 710/290/735 713/294/738 712/291/737 -f 722/302/747 710/290/735 708/287/733 -f 713/294/738 722/302/747 716/295/741 -f 722/302/747 713/294/738 710/290/735 +f 739/279/722 738/278/723 737/277/724 +f 740/280/725 739/279/722 737/277/724 +f 742/282/726 740/280/725 741/281/727 +f 742/282/726 739/279/722 740/280/725 +f 743/283/728 742/282/726 741/281/727 +f 747/286/729 746/285/730 744/284/731 +f 749/288/732 747/286/729 748/287/733 +f 746/285/730 749/288/732 745/289/734 +f 749/288/732 746/285/730 747/286/729 +f 750/290/735 749/288/732 748/287/733 +f 752/292/736 750/290/735 751/291/737 +f 749/288/732 752/292/736 745/289/734 +f 752/292/736 749/288/732 750/290/735 +f 755/294/738 753/293/739 751/291/737 +f 757/296/740 755/294/738 756/295/741 +f 753/293/739 757/296/740 754/297/742 +f 757/296/740 753/293/739 755/294/738 +f 758/298/743 757/296/740 756/295/741 +f 759/299/744 758/298/743 737/277/724 +f 757/296/740 759/299/744 754/297/742 +f 759/299/744 757/296/740 758/298/743 +f 738/278/723 759/299/744 737/277/724 +f 740/280/725 760/300/745 741/281/727 +f 758/298/743 740/280/725 737/277/724 +f 760/300/745 758/298/743 756/295/741 +f 758/298/743 760/300/745 740/280/725 +f 760/300/745 761/301/746 741/281/727 +f 762/302/747 760/300/745 756/295/741 +f 761/301/746 762/302/747 748/287/733 +f 762/302/747 761/301/746 760/300/745 +f 761/301/746 743/283/728 741/281/727 +f 747/286/729 761/301/746 748/287/733 +f 743/283/728 747/286/729 744/284/731 +f 747/286/729 743/283/728 761/301/746 +f 750/290/735 755/294/738 751/291/737 +f 762/302/747 750/290/735 748/287/733 +f 755/294/738 762/302/747 756/295/741 +f 762/302/747 755/294/738 750/290/735 +# 38 triangles in group + +# 1368 triangles total diff --git a/test/models/OpenGEX/light_issue1262.ogex b/test/models/OpenGEX/light_issue1262.ogex new file mode 100644 index 000000000..da4723411 --- /dev/null +++ b/test/models/OpenGEX/light_issue1262.ogex @@ -0,0 +1,21 @@ +LightObject (type = "infinite") { + Param (attrib = "intensity") { + float { 3.0 } + } + + Color (attrib = "light") { + float[3] { { 0.7, 1.0, 0.1 } } + } +} + +LightObject (type = "point") { + Param (attrib = "intensity") { + float { 0.5 } + } +} + +LightObject (type = "spot") { + Color (attrib = "light") { + float[4] { { 0.1, 0.0, 0.1, 1.0 } } + } +} \ No newline at end of file diff --git a/test/models/glTF2/BoxTextured-glTF-Binary/BoxTextured.glb b/test/models/glTF2/BoxTextured-glTF-Binary/BoxTextured.glb new file mode 100644 index 000000000..03cd2acf9 Binary files /dev/null and b/test/models/glTF2/BoxTextured-glTF-Binary/BoxTextured.glb differ diff --git a/test/models/glTF2/BoxTextured-glTF-Embedded/BoxTextured.gltf b/test/models/glTF2/BoxTextured-glTF-Embedded/BoxTextured.gltf new file mode 100644 index 000000000..c9c461495 --- /dev/null +++ b/test/models/glTF2/BoxTextured-glTF-Embedded/BoxTextured.gltf @@ -0,0 +1,181 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2, + "TEXCOORD_0": 3 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 6.0, + 1.0 + ], + "min": [ + 0.0, + 0.0 + ], + "type": "VEC2" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + }, + "metallicFactor": 0.0 + }, + "name": "Texture" + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + } + ], + "images": [ + { + "uri": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANMAAADTCAMAAAAs2dbrAAAAsVBMVEXc3Nz8/f3+//9chyf///+VsHP4+/thiy3Z29dyl0R8nlH09vJeiCqzxZ6ft4GLqWatwZXw9vyEpFynvYxmjjTS3cNrkjvu8urn8vre7fjY6ffL08K6yqbEz7XT183K4vTQ5fW62fC/zq3J17fn7d/g6NbC3fLb5c/l5eVsrd+wzOF/t+OWw+WGu+TE099vr+CmyON5tOJ0seG50OHL1t7S2d7Z29yOv+Wdx+emzuyx1O6AHuoWAAAIi0lEQVR4XuzUS3LEIAxF0WznIYk/xun9LyxDRqnqGANq4rODW4L39d88Ho/H43HkZPzJVYgoxhiIpDJ7k2z5wJpizSkBv4vCJn1OWTZMeE9gY/Xfx3DE30Q2WfGBvOAa8lZnEKFH0JZ1GEE/MnpGw54R93Cs41ip4k6SjuWPjnC3YJZWtaJdqhJhlJDWLINgJJm/FoUxGpfJ0xAxnvMTv1UWzEF21pG8wzT+2OZIjeTxScZhLmdGz13FfHXoAGbCCmHgVCSHNVwaleSxjh8z4Yxmj09VBGtRGbAOq1G+OSlgvZC3SwLijVE2Qodot7lS4+xGSS1quyS4O/5UIegSSm/SUaENHZ1NDH1qX5SHRmdPUoJOqWPyInS6Pn6HoNlkJxh68T6fqTFXkkrERPL9en0L3ueufKkf6uxmt1EYiAN4sP7i0pNPABeItEIdeV0vJMTA+z/YaqWo3WSS1gn2lP4ewFHEfNqexLi5hAIAvTgKZZ+4myQxpsSZUtomiD75yPM5Pqg8uDK5cbORZzT+p3JDgfxma16LK3WaceLUkxQPJjj6hnGbo2sHpkkxzB4didFgcgp23OJQ5BS4Pn6TeiM5PThYCva2vQmCHDgYCmZXfCbJfMpc9PXQk6QGTE0PMNv7TDSBmaM/IXqSVeKKdsSsy6gjCfMZLijWSVaXvomkzbiwRF/jR0fS3JThXTbTw8aAVVCcbXFW2wRv8oa+hVmaumoWS88YTgKFXNpBYHrd1GXfaaCfyI0CK7u0g0DoSfMCoSduTBF6Zto3bV033ewdiel/L/9+te3G6HOR35d4p/JmcjI9rVI4e9nd0z9XSStc08tAidkmw4cs6khuK3BK6ZlS6huFC6/xZj23z3BHbSiZOceVIto2aCrcp1N1BteByXe3DfQgq/EZNVMKQwUui5ROPscXFoqvL3HLa5R0sjkg/6eGEjcVMQajXuNraqK4XA3ufoey9AhXIURmUzyDhCbUya0/nFN6SHIbyK0vERMCqZZW4ikcXCQOcQ7nlgT1gVPFjvuz+vCXX4UCl/mEd+tAXhSsSDxT9rq/tJjbasJAFEWJm2QwF6NJVNra0hptoFVsERrp/39YXwTrbDWZOcf1GrLDhrMyF45elUMAVTjlR5NvrctNIsniFDB5HVzstJWEB+MUR/I5PdVRahtQcF3hSNxEkoMGhw+SAidmU1bqLjIFI5wwS670IwhPYvzHNCRweweZBiHOeBH8yik8KnBOtWal9GUqcc4T38D6h49gM0zoNLXTlqmGBQ/fXhDOhKyUskyrChYZ78ol4cyCpn+jKlMUw6bkTpJwxjgqJZ93jHgbIQt3Ukou0zOYkDv5rUw1rpDmtE9685VpYn91ZXp1OjiFs0xMpqXUa795z7mTRnjH0jvxuh77pXkP0a/TRh7erdSDh1ItybTERQruJA5nNJTia4+16dvp4C4Th+srxfOeDKHVaccyUTiRNnan6FNNpm6fvhTCmVlil3JTqh3wvDt1ksvE5PTeu5ZM3evTh0o4MxZcY+4eO2QSdeobzpgpK6UjU/d+b68TzszmvqvUhmRa4Aal05mwdQhnClbKU6bG4AYZn91dwv94t+MepYEgCuDTzhSudIFSgKIHKtwlaIBEe5cTv/8XM8ZEIrPtGxzw9zd5TcO83SbbgjKhSsnJXyZtRZfeHOFAmKut7fgF2siFdMyd1qQ0/nB7pZbN9WUacrcPpOwd4bev1B6USeuTdnA0FZqCF67h6Rae95y0r45wTO9SR0+ZtFCR9uIIx2agUv55H5H26gnHqp7906395W/TXWBkGD/7xOGiw/2VwvNeLxhaU8Qeh6eFCrd7ugxLjsbTrWTM2IPtTbeNIdxu9myr1EnNe8lYThFvL65wLAyilcLzPg+MZRTz6gzHRoaTgWYZKxNWUlRzZbi/UpKc4MNlUrHFI0Udrg73Vyo5oKP10pZseCexeR8J9ztXKvrNfvNR/nHeK2px3jC+T2zh/kql6ebPxnhcCph3VCett/zx7dfYHT6lINxTKWWy2aurqnnHdYqrRdLJu2UiAsId+s8S0XJVmbJNTm0+iwLCPZXC0jkbZdQqkRYq3CETq3rGRltqVUhUqsI9wlYAdbqFzB4IDp8O99Ln19iIHaMHhi/N+KbCohaDFZutqUPhWB9864RnP1yQAoav5NurCrjk9dlsRJ16KnzK9zAAN/XUZ7tH6nQ56cWY7yPvWiiSku3CgAD5yy7newmrRFrUFV9jSEAhZ8Uo8P2EQfyvSoYzVtDmZFwlihJku4VM31Vvm/N1pgQVv6PnWZ//g2pby1m6my5+cls3ubHCQBCASypZbiPbIGDYAF7wXpScYO5/tCxZBgb8g78btKpdbZ6kA/708/Vah35kKrbxy+v7/9frX9dOPE/hb2KYi+V5dsYBjk+icIjhc+gZhyz1xQRp+BQ6ALUF5XFYz2eYBIfNmo/gcILnEzQ4QwzLZ2ecstVTELuWpTOCk8LEwq04batm83Zvz5I1gg+IeczftY7L2+FDHUul8DFVzWPaSc8SjTMuCIblsRt2lfSEw0WLZVmsx2Wu5Mqro9FbwR0GlqMX3OLtyztM16n6RgJ8PYu36+qph52zzEwJ7rZoZjUggnViPtohitAwl2lFLIp5NAHxdDZTO8S0GqY2OkQmqp69220T07EDkggtU2lmpOLSRKUHJCTeMro2IK25Z1xmRXqLYTxjJ8jh7QzjGAdBLhJlKu0DcpLO8F7TEJDd1lrexjhBCd7Bj7yDVivKIe56WL/t2jEKwCAMheEsYirEBgNdohl6CO9/tM6FgrRdFPJNWX/I+BIbTMao/MhKYjAlo/3LE8bCChND5RLfLXxPhNl1wMYhxXHOtktDWInWHMr2mHakkEkRVoXaaiUWyVmEqTY1hOX1+z3mnHPOXX/B0DoXjBYdAAAAAElFTkSuQmCC" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9986, + "wrapS": 10497, + "wrapT": 10497 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 768, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 192, + "byteStride": 8, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 840, + "uri": "data:application/octet-stream;base64,AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AAAAAAAAAAAAAIA/AACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAAAAAAAAgL8AAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAACAvwAAAAAAAAAAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAPwAAAL8AAAA/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAvwAAAD8AAAA/AAAAPwAAAD8AAAA/AAAAvwAAAD8AAAC/AAAAPwAAAD8AAAC/AAAAPwAAAL8AAAA/AAAAvwAAAL8AAAA/AAAAPwAAAL8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAL8AAAA/AAAAvwAAAD8AAAA/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAvwAAAL8AAAC/AAAAvwAAAD8AAAC/AAAAPwAAAL8AAAC/AAAAPwAAAD8AAAC/AADAQAAAAAAAAKBAAAAAAAAAwED+/38/AACgQP7/fz8AAIBAAAAAAAAAoEAAAAAAAACAQAAAgD8AAKBAAACAPwAAAEAAAAAAAACAPwAAAAAAAABAAACAPwAAgD8AAIA/AABAQAAAAAAAAIBAAAAAAAAAQEAAAIA/AACAQAAAgD8AAEBAAAAAAAAAAEAAAAAAAABAQAAAgD8AAABAAACAPwAAAAAAAAAAAAAAAP7/fz8AAIA/AAAAAAAAgD/+/38/AAABAAIAAwACAAEABAAFAAYABwAGAAUACAAJAAoACwAKAAkADAANAA4ADwAOAA0AEAARABIAEwASABEAFAAVABYAFwAWABUA" + } + ] +} diff --git a/test/models/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured.gltf b/test/models/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured.gltf new file mode 100644 index 000000000..b286239fa --- /dev/null +++ b/test/models/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured.gltf @@ -0,0 +1,197 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2, + "TEXCOORD_0": 3 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 6.0, + 1.0 + ], + "min": [ + 0.0, + 0.0 + ], + "type": "VEC2" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + }, + "metallicFactor": 0.0 + }, + "extensions": { + "KHR_materials_pbrSpecularGlossiness": { + "diffuseTexture": { + "index": 0 + }, + "specularFactor": [ + 0.20000000298023225, + 0.20000000298023225, + 0.20000000298023225 + ], + "glossinessFactor": 1.0 + } + }, + "name": "Texture" + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + } + ], + "images": [ + { + "uri": "CesiumLogoFlat.png" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9986, + "wrapS": 10497, + "wrapT": 10497 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 768, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 192, + "byteStride": 8, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 840, + "uri": "BoxTextured0.bin" + } + ], + "extensionsUsed": [ + "KHR_materials_pbrSpecularGlossiness" + ] +} diff --git a/test/models/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured0.bin b/test/models/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured0.bin new file mode 100644 index 000000000..d2a73551f Binary files /dev/null and b/test/models/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured0.bin differ diff --git a/test/models/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/CesiumLogoFlat.png b/test/models/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/CesiumLogoFlat.png new file mode 100644 index 000000000..45d502ed2 Binary files /dev/null and b/test/models/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/CesiumLogoFlat.png differ diff --git a/test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured.gltf b/test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured.gltf new file mode 100644 index 000000000..7401dced1 --- /dev/null +++ b/test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured.gltf @@ -0,0 +1,282 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2, + "TEXCOORD_0": 3 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 6.0, + 1.0 + ], + "min": [ + 0.0, + 0.0 + ], + "type": "VEC2" + } + ], + "materials": [ + { + "values": { + "diffuse": [ + 0 + ], + "specular": [ + 0.20000000298023225, + 0.20000000298023225, + 0.20000000298023225, + 1.0 + ], + "shininess": [ + 256.0 + ], + "transparency": [ + 1.0 + ] + }, + "technique": 0 + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + } + ], + "images": [ + { + "uri": "CesiumLogoFlat.png" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9986, + "wrapS": 10497, + "wrapT": 10497 + } + ], + "techniques": [ + { + "attributes": { + "a_normal": "normal", + "a_position": "position", + "a_texcoord0": "texcoord0" + }, + "parameters": { + "diffuse": { + "type": 35678 + }, + "modelViewMatrix": { + "semantic": "MODELVIEW", + "type": 35676 + }, + "normal": { + "semantic": "NORMAL", + "type": 35665 + }, + "normalMatrix": { + "semantic": "MODELVIEWINVERSETRANSPOSE", + "type": 35675 + }, + "position": { + "semantic": "POSITION", + "type": 35665 + }, + "projectionMatrix": { + "semantic": "PROJECTION", + "type": 35676 + }, + "shininess": { + "type": 5126 + }, + "specular": { + "type": 35666 + }, + "texcoord0": { + "semantic": "TEXCOORD_0", + "type": 35665 + }, + "transparency": { + "type": 5126 + } + }, + "program": 0, + "states": { + "enable": [ + 2884, + 2929 + ] + }, + "uniforms": { + "u_diffuse": "diffuse", + "u_modelViewMatrix": "modelViewMatrix", + "u_normalMatrix": "normalMatrix", + "u_projectionMatrix": "projectionMatrix", + "u_shininess": "shininess", + "u_specular": "specular", + "u_transparency": "transparency" + } + } + ], + "programs": [ + { + "attributes": [ + "a_normal", + "a_position", + "a_texcoord0" + ], + "fragmentShader": 1, + "vertexShader": 0 + } + ], + "shaders": [ + { + "type": 35633, + "uri": "BoxTextured0.vert" + }, + { + "type": 35632, + "uri": "BoxTextured1.frag" + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 768, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 192, + "byteStride": 8, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 840, + "uri": "BoxTextured0.bin" + } + ], + "extensionsRequired": [ + "KHR_technique_webgl" + ], + "extensionsUsed": [ + "KHR_technique_webgl" + ] +} diff --git a/test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured0.bin b/test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured0.bin new file mode 100644 index 000000000..d2a73551f Binary files /dev/null and b/test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured0.bin differ diff --git a/test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured0.vert b/test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured0.vert new file mode 100644 index 000000000..05d5e82c2 --- /dev/null +++ b/test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured0.vert @@ -0,0 +1,17 @@ +precision highp float; +uniform mat4 u_modelViewMatrix; +uniform mat4 u_projectionMatrix; +uniform mat3 u_normalMatrix; +attribute vec3 a_position; +varying vec3 v_position; +attribute vec3 a_normal; +varying vec3 v_normal; +attribute vec2 a_texcoord0; +varying vec2 v_texcoord0; +void main(void) { + vec4 pos = u_modelViewMatrix * vec4(a_position,1.0); + v_position = pos.xyz; + gl_Position = u_projectionMatrix * pos; + v_normal = u_normalMatrix * a_normal; + v_texcoord0 = a_texcoord0; +} diff --git a/test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured1.frag b/test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured1.frag new file mode 100644 index 000000000..3850980a0 --- /dev/null +++ b/test/models/glTF2/BoxTextured-glTF-techniqueWebGL/BoxTextured1.frag @@ -0,0 +1,29 @@ +precision highp float; +uniform sampler2D u_diffuse; +uniform vec4 u_specular; +uniform float u_shininess; +uniform float u_transparency; +varying vec3 v_position; +varying vec3 v_normal; +varying vec2 v_texcoord0; +void main(void) { + vec3 normal = normalize(v_normal); + vec4 diffuse = texture2D(u_diffuse, v_texcoord0); + vec3 diffuseLight = vec3(0.0, 0.0, 0.0); + vec3 specular = u_specular.rgb; + vec3 specularLight = vec3(0.0, 0.0, 0.0); + vec3 ambient = diffuse.rgb; + vec3 viewDir = -normalize(v_position); + vec3 ambientLight = vec3(0.0, 0.0, 0.0); + ambientLight += vec3(0.2, 0.2, 0.2); + vec3 l = vec3(0.0, 0.0, 1.0); + diffuseLight += vec3(1.0, 1.0, 1.0) * max(dot(normal, l), 0.); + vec3 reflectDir = reflect(-l, normal); + float specularIntensity = max(0., pow(max(dot(reflectDir, viewDir), 0.), u_shininess)); + specularLight += vec3(1.0, 1.0, 1.0) * specularIntensity; + vec3 color = vec3(0.0, 0.0, 0.0); + color += diffuse.rgb * diffuseLight; + color += specular * specularLight; + color += ambient * ambientLight; + gl_FragColor = vec4(color * diffuse.a * u_transparency, diffuse.a * u_transparency); +} diff --git a/test/models/glTF2/BoxTextured-glTF-techniqueWebGL/CesiumLogoFlat.png b/test/models/glTF2/BoxTextured-glTF-techniqueWebGL/CesiumLogoFlat.png new file mode 100644 index 000000000..45d502ed2 Binary files /dev/null and b/test/models/glTF2/BoxTextured-glTF-techniqueWebGL/CesiumLogoFlat.png differ diff --git a/test/models/glTF2/BoxTextured-glTF/BoxTextured.gltf b/test/models/glTF2/BoxTextured-glTF/BoxTextured.gltf new file mode 100644 index 000000000..eff658f02 --- /dev/null +++ b/test/models/glTF2/BoxTextured-glTF/BoxTextured.gltf @@ -0,0 +1,181 @@ +{ + "asset": { + "generator": "COLLADA2GLTF", + "version": "2.0" + }, + "scene": 0, + "scenes": [ + { + "nodes": [ + 0 + ] + } + ], + "nodes": [ + { + "children": [ + 1 + ], + "matrix": [ + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + -1.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ] + }, + { + "mesh": 0 + } + ], + "meshes": [ + { + "primitives": [ + { + "attributes": { + "NORMAL": 1, + "POSITION": 2, + "TEXCOORD_0": 3 + }, + "indices": 0, + "mode": 4, + "material": 0 + } + ], + "name": "Mesh" + } + ], + "accessors": [ + { + "bufferView": 0, + "byteOffset": 0, + "componentType": 5123, + "count": 36, + "max": [ + 23 + ], + "min": [ + 0 + ], + "type": "SCALAR" + }, + { + "bufferView": 1, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 1.0, + 1.0, + 1.0 + ], + "min": [ + -1.0, + -1.0, + -1.0 + ], + "type": "VEC3" + }, + { + "bufferView": 1, + "byteOffset": 288, + "componentType": 5126, + "count": 24, + "max": [ + 0.5, + 0.5, + 0.5 + ], + "min": [ + -0.5, + -0.5, + -0.5 + ], + "type": "VEC3" + }, + { + "bufferView": 2, + "byteOffset": 0, + "componentType": 5126, + "count": 24, + "max": [ + 6.0, + 1.0 + ], + "min": [ + 0.0, + 0.0 + ], + "type": "VEC2" + } + ], + "materials": [ + { + "pbrMetallicRoughness": { + "baseColorTexture": { + "index": 0 + }, + "metallicFactor": 0.0 + }, + "name": "Texture" + } + ], + "textures": [ + { + "sampler": 0, + "source": 0 + } + ], + "images": [ + { + "uri": "CesiumLogoFlat.png" + } + ], + "samplers": [ + { + "magFilter": 9729, + "minFilter": 9986, + "wrapS": 10497, + "wrapT": 10497 + } + ], + "bufferViews": [ + { + "buffer": 0, + "byteOffset": 768, + "byteLength": 72, + "target": 34963 + }, + { + "buffer": 0, + "byteOffset": 0, + "byteLength": 576, + "byteStride": 12, + "target": 34962 + }, + { + "buffer": 0, + "byteOffset": 576, + "byteLength": 192, + "byteStride": 8, + "target": 34962 + } + ], + "buffers": [ + { + "byteLength": 840, + "uri": "BoxTextured0.bin" + } + ] +} diff --git a/test/models/glTF2/BoxTextured-glTF/BoxTextured0.bin b/test/models/glTF2/BoxTextured-glTF/BoxTextured0.bin new file mode 100644 index 000000000..d2a73551f Binary files /dev/null and b/test/models/glTF2/BoxTextured-glTF/BoxTextured0.bin differ diff --git a/test/models/glTF2/BoxTextured-glTF/CesiumLogoFlat.png b/test/models/glTF2/BoxTextured-glTF/CesiumLogoFlat.png new file mode 100644 index 000000000..45d502ed2 Binary files /dev/null and b/test/models/glTF2/BoxTextured-glTF/CesiumLogoFlat.png differ diff --git a/test/unit/AbstractImportExportBase.cpp b/test/unit/AbstractImportExportBase.cpp index 27748301f..f3d49b85d 100644 --- a/test/unit/AbstractImportExportBase.cpp +++ b/test/unit/AbstractImportExportBase.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/AssimpAPITest.cpp b/test/unit/AssimpAPITest.cpp index fa78e76a0..a284d385e 100644 --- a/test/unit/AssimpAPITest.cpp +++ b/test/unit/AssimpAPITest.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/SceneDiffer.cpp b/test/unit/SceneDiffer.cpp index 14edeaa5c..401a655cc 100644 --- a/test/unit/SceneDiffer.cpp +++ b/test/unit/SceneDiffer.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/SceneDiffer.h b/test/unit/SceneDiffer.h index f0cc45907..90f0d367c 100644 --- a/test/unit/SceneDiffer.h +++ b/test/unit/SceneDiffer.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/TestIOSystem.h b/test/unit/TestIOSystem.h index e7ed193b8..40d894a21 100644 --- a/test/unit/TestIOSystem.h +++ b/test/unit/TestIOSystem.h @@ -3,7 +3,7 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team All rights reserved. @@ -45,25 +45,39 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include using namespace std; -using namespace Assimp; + +namespace Assimp { static const string Sep = "/"; + class TestIOSystem : public IOSystem { public: - TestIOSystem() : IOSystem() {} - virtual ~TestIOSystem() {} + TestIOSystem() + : IOSystem() { + // empty + } + + virtual ~TestIOSystem() { + // empty + } + virtual bool Exists( const char* ) const { return true; } + virtual char getOsSeparator() const { return Sep[ 0 ]; } virtual IOStream* Open( const char* pFile, const char* pMode = "rb" ) { + EXPECT_NE( nullptr, pFile ); + EXPECT_NE( nullptr, pMode ); return NULL; } virtual void Close( IOStream* pFile ) { - // empty + EXPECT_NE( nullptr, pFile ); } }; + +} // Namespace Assimp diff --git a/test/unit/TestModelFactory.h b/test/unit/TestModelFactory.h index 94dd97036..ca070890d 100644 --- a/test/unit/TestModelFactory.h +++ b/test/unit/TestModelFactory.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -59,7 +60,7 @@ public: static aiScene *createDefaultTestModel( float &opacity ) { aiScene *scene( new aiScene ); scene->mNumMaterials = 1; - scene->mMaterials = new aiMaterial*; + scene->mMaterials = new aiMaterial*[scene->mNumMaterials]; scene->mMaterials[ 0 ] = new aiMaterial; aiColor3D color( 1, 0, 0 ); EXPECT_EQ( AI_SUCCESS, scene->mMaterials[ 0 ]->AddProperty( &color, 1, AI_MATKEY_COLOR_DIFFUSE ) ); @@ -69,7 +70,7 @@ public: EXPECT_EQ( AI_SUCCESS, scene->mMaterials[ 0 ]->AddProperty( &opacity, 1, AI_MATKEY_OPACITY ) ); scene->mNumMeshes = 1; - scene->mMeshes = new aiMesh*; + scene->mMeshes = new aiMesh*[scene->mNumMeshes]; scene->mMeshes[ 0 ] = new aiMesh; scene->mMeshes[ 0 ]->mMaterialIndex = 0; scene->mMeshes[ 0 ]->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; @@ -79,7 +80,7 @@ public: scene->mMeshes[ 0 ]->mVertices[ 1 ] = aiVector3D( 0, 1, 0 ); scene->mMeshes[ 0 ]->mVertices[ 2 ] = aiVector3D( 0, 0, 1 ); scene->mMeshes[ 0 ]->mNumFaces = 1; - scene->mMeshes[ 0 ]->mFaces = new aiFace; + scene->mMeshes[ 0 ]->mFaces = new aiFace[scene->mMeshes[ 0 ]->mNumFaces]; scene->mMeshes[ 0 ]->mFaces[ 0 ].mNumIndices = 3; scene->mMeshes[ 0 ]->mFaces[ 0 ].mIndices = new unsigned int[ 3 ]; scene->mMeshes[ 0 ]->mFaces[ 0 ].mIndices[ 0 ] = 0; @@ -88,7 +89,7 @@ public: scene->mRootNode = new aiNode; scene->mRootNode->mNumMeshes = 1; - scene->mRootNode->mMeshes = new unsigned int( 0 ); + scene->mRootNode->mMeshes = new unsigned int[1]{ 0 }; return scene; } diff --git a/test/unit/UTLogStream.h b/test/unit/UTLogStream.h new file mode 100644 index 000000000..87ebea91d --- /dev/null +++ b/test/unit/UTLogStream.h @@ -0,0 +1,63 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 + +#include + +class UTLogStream : public Assimp::LogStream { +public: + UTLogStream() + : LogStream() { + // empty + } + + virtual ~UTLogStream() { + // empty + } + + virtual void write(const char* message) { + if ( nullptr != message ) { + m_messages.push_back( std::string( message ) ); + } + } + + std::vector m_messages; +}; diff --git a/test/unit/UnitTestFileGenerator.h b/test/unit/UnitTestFileGenerator.h new file mode 100644 index 000000000..2e4aede0f --- /dev/null +++ b/test/unit/UnitTestFileGenerator.h @@ -0,0 +1,76 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 + +#include +#include +#include + +#if defined(__GNUC__) || defined(__clang__) +#define TMP_PATH "/tmp/" +inline FILE* MakeTmpFile(char* tmplate) +{ + auto fd = mkstemp(tmplate); + EXPECT_NE(-1, fd); + if(fd == -1) + { + return nullptr; + } + auto fs = fdopen(fd, "w+"); + EXPECT_NE(nullptr, fs); + return fs; +} +#elif defined(_MSC_VER) +#include +#define TMP_PATH "./" +inline FILE* MakeTmpFile(char* tmplate) +{ + auto pathtemplate = _mktemp(tmplate); + EXPECT_NE(pathtemplate, nullptr); + if(pathtemplate == nullptr) + { + return nullptr; + } + auto* fs = std::fopen(pathtemplate, "w+"); + EXPECT_NE(fs, nullptr); + return fs; +} +#endif diff --git a/test/unit/UnitTestPCH.h b/test/unit/UnitTestPCH.h index 890bedd0c..0d5f08992 100644 --- a/test/unit/UnitTestPCH.h +++ b/test/unit/UnitTestPCH.h @@ -1,8 +1,44 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- +Copyright (c) 2006-2017, assimp team -// #ifndef ASSIMP_BUILD_SINGLETHREADED -// # include -// #endif +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 // We need to be sure to have the same STL settings as Assimp @@ -10,6 +46,7 @@ #include #include #include +#include "UTLogStream.h" #undef min #undef max diff --git a/test/unit/ut3DImportExport.cpp b/test/unit/ut3DImportExport.cpp index 28f1eb433..b55bf9c4c 100644 --- a/test/unit/ut3DImportExport.cpp +++ b/test/unit/ut3DImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/ut3DSImportExport.cpp b/test/unit/ut3DSImportExport.cpp index 9d1052af0..1e9bfe0d0 100644 --- a/test/unit/ut3DSImportExport.cpp +++ b/test/unit/ut3DSImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -52,7 +53,11 @@ public: virtual bool importerTest() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/3DS/fels.3ds", 0 ); +#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER return nullptr != scene; +#else + return nullptr == scene; +#endif // ASSIMP_BUILD_NO_3DS_IMPORTER } }; diff --git a/test/unit/utACImportExport.cpp b/test/unit/utACImportExport.cpp index 757d065f6..3c3dcaa7b 100644 --- a/test/unit/utACImportExport.cpp +++ b/test/unit/utACImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utAMFImportExport.cpp b/test/unit/utAMFImportExport.cpp index fda1df1c9..e4ee5605a 100644 --- a/test/unit/utAMFImportExport.cpp +++ b/test/unit/utAMFImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utASEImportExport.cpp b/test/unit/utASEImportExport.cpp index 4fdbe8e79..841aff549 100644 --- a/test/unit/utASEImportExport.cpp +++ b/test/unit/utASEImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -52,7 +53,11 @@ public: virtual bool importerTest() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/ASE/ThreeCubesGreen.ASE", 0 ); +#ifndef ASSIMP_BUILD_NO_3DS_IMPORTER return nullptr != scene; +#else + return nullptr == scene; +#endif // ASSIMP_BUILD_NO_3DS_IMPORTER } }; diff --git a/test/unit/utAnim.cpp b/test/unit/utAnim.cpp index 90d6d36b3..643730f1b 100644 --- a/test/unit/utAnim.cpp +++ b/test/unit/utAnim.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utB3DImportExport.cpp b/test/unit/utB3DImportExport.cpp index 916a2112d..0a800ccb6 100644 --- a/test/unit/utB3DImportExport.cpp +++ b/test/unit/utB3DImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utBVHImportExport.cpp b/test/unit/utBVHImportExport.cpp index b78d9c2a0..48281c667 100644 --- a/test/unit/utBVHImportExport.cpp +++ b/test/unit/utBVHImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utBatchLoader.cpp b/test/unit/utBatchLoader.cpp index b3d74a0aa..56862f912 100644 --- a/test/unit/utBatchLoader.cpp +++ b/test/unit/utBatchLoader.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -65,6 +66,7 @@ TEST_F( BatchLoaderTest, createTest ) { } catch ( ... ) { ok = false; } + EXPECT_TRUE( ok ); } TEST_F( BatchLoaderTest, validateAccessTest ) { diff --git a/test/unit/utBlendImportAreaLight.cpp b/test/unit/utBlendImportAreaLight.cpp index 603a5e513..04cc8cbcf 100644 --- a/test/unit/utBlendImportAreaLight.cpp +++ b/test/unit/utBlendImportAreaLight.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utBlendImportMaterials.cpp b/test/unit/utBlendImportMaterials.cpp index f45c2a219..6e1033453 100644 --- a/test/unit/utBlendImportMaterials.cpp +++ b/test/unit/utBlendImportMaterials.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -69,7 +70,7 @@ TEST_F(BlendImportMaterials, testImportMaterial) ASSERT_TRUE(pTest != NULL); ASSERT_TRUE(pTest->HasMaterials()); - ASSERT_EQ(1, pTest->mNumMaterials); + ASSERT_EQ(1U, pTest->mNumMaterials); auto alpha = pTest->mMaterials[0]; diff --git a/test/unit/utBlenderImportExport.cpp b/test/unit/utBlenderImportExport.cpp index 2c2b712b1..a120fdcc5 100644 --- a/test/unit/utBlenderImportExport.cpp +++ b/test/unit/utBlenderImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utBlenderIntermediate.cpp b/test/unit/utBlenderIntermediate.cpp index 89b324324..9c9436574 100644 --- a/test/unit/utBlenderIntermediate.cpp +++ b/test/unit/utBlenderIntermediate.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utCSMImportExport.cpp b/test/unit/utCSMImportExport.cpp index 6fc27d597..eb6672a44 100644 --- a/test/unit/utCSMImportExport.cpp +++ b/test/unit/utCSMImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utColladaExportCamera.cpp b/test/unit/utColladaExportCamera.cpp index 1d03b62a1..4949efc83 100644 --- a/test/unit/utColladaExportCamera.cpp +++ b/test/unit/utColladaExportCamera.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utColladaExportLight.cpp b/test/unit/utColladaExportLight.cpp index 2c502b987..ccff1a31e 100644 --- a/test/unit/utColladaExportLight.cpp +++ b/test/unit/utColladaExportLight.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utColladaImportExport.cpp b/test/unit/utColladaImportExport.cpp index 23134d313..997fca188 100644 --- a/test/unit/utColladaImportExport.cpp +++ b/test/unit/utColladaImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utD3MFImportExport.cpp b/test/unit/utD3MFImportExport.cpp index 62de9d156..0c322420c 100644 --- a/test/unit/utD3MFImportExport.cpp +++ b/test/unit/utD3MFImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -42,13 +43,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "AbstractImportExportBase.h" #include +#include class utD3MFImporterExporter : public AbstractImportExportBase { public: virtual bool importerTest() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/3MF/box.3mf", 0); - return nullptr != scene; + EXPECT_EQ( 1u, scene->mNumMeshes ); + aiMesh *mesh = scene->mMeshes[ 0 ]; + EXPECT_NE( nullptr, mesh ); + EXPECT_EQ( 12u, mesh->mNumFaces ); + EXPECT_EQ( 8u, mesh->mNumVertices ); + + return ( nullptr != scene ); } }; diff --git a/test/unit/utDXFImporterExporter.cpp b/test/unit/utDXFImporterExporter.cpp index 74912212c..389284608 100644 --- a/test/unit/utDXFImporterExporter.cpp +++ b/test/unit/utDXFImporterExporter.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utDefaultIOStream.cpp b/test/unit/utDefaultIOStream.cpp index 3f570665f..128e4e6ef 100644 --- a/test/unit/utDefaultIOStream.cpp +++ b/test/unit/utDefaultIOStream.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -38,6 +39,10 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------*/ #include #include "TestIOStream.h" +#include "UnitTestFileGenerator.h" +#include +#include +#include using namespace ::Assimp; @@ -45,16 +50,33 @@ class utDefaultIOStream : public ::testing::Test { // empty }; -TEST_F( utDefaultIOStream, FileSizeTest ) { - char buffer[ L_tmpnam ]; - tmpnam( buffer ); - std::FILE *fs( std::fopen( buffer, "w+" ) ); - size_t written( std::fwrite( buffer, 1, sizeof( char ) * L_tmpnam, fs ) ); - EXPECT_NE( 0U, written ); - std::fflush( fs ); +const char data[]{"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Qui\ +sque luctus sem diam, ut eleifend arcu auctor eu. Vestibulum id est vel nulla l\ +obortis malesuada ut sed turpis. Nulla a volutpat tortor. Nunc vestibulum portt\ +itor sapien ornare sagittis volutpat."}; - TestDefaultIOStream myStream( fs, buffer ); - size_t size = myStream.FileSize(); - EXPECT_EQ( size, sizeof( char ) * L_tmpnam ); - remove( buffer ); +TEST_F( utDefaultIOStream, FileSizeTest ) { + const auto dataSize = sizeof(data); + const auto dataCount = dataSize / sizeof(*data); + + char fpath[] = { TMP_PATH"rndfp.XXXXXX" }; + auto* fs = MakeTmpFile(fpath); + ASSERT_NE(nullptr, fs); + { + auto written = std::fwrite(data, sizeof(*data), dataCount, fs ); + EXPECT_NE( 0U, written ); + + auto vflush = std::fflush( fs ); + ASSERT_EQ(vflush, 0); + + std::fclose(fs); + fs = std::fopen(fpath, "r"); + + ASSERT_NE(nullptr, fs); + + TestDefaultIOStream myStream( fs, fpath); + size_t size = myStream.FileSize(); + EXPECT_EQ( size, dataSize); + } + remove(fpath); } diff --git a/test/unit/utFBXImporterExporter.cpp b/test/unit/utFBXImporterExporter.cpp index d02d06def..f335bc682 100644 --- a/test/unit/utFBXImporterExporter.cpp +++ b/test/unit/utFBXImporterExporter.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utFastAtof.cpp b/test/unit/utFastAtof.cpp index 2b58f6bd7..a9d6fdbd0 100644 --- a/test/unit/utFastAtof.cpp +++ b/test/unit/utFastAtof.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utFindDegenerates.cpp b/test/unit/utFindDegenerates.cpp index 8df160107..8040a83a1 100644 --- a/test/unit/utFindDegenerates.cpp +++ b/test/unit/utFindDegenerates.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utFindInvalidData.cpp b/test/unit/utFindInvalidData.cpp index 0fe291c80..adba32256 100644 --- a/test/unit/utFindInvalidData.cpp +++ b/test/unit/utFindInvalidData.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utFixInfacingNormals.cpp b/test/unit/utFixInfacingNormals.cpp index e55958cd5..66be19807 100644 --- a/test/unit/utFixInfacingNormals.cpp +++ b/test/unit/utFixInfacingNormals.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utGenNormals.cpp b/test/unit/utGenNormals.cpp index b108242da..ec3469f14 100644 --- a/test/unit/utGenNormals.cpp +++ b/test/unit/utGenNormals.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utHMPImportExport.cpp b/test/unit/utHMPImportExport.cpp index 3dcfc387e..2b71c7211 100644 --- a/test/unit/utHMPImportExport.cpp +++ b/test/unit/utHMPImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utIFCImportExport.cpp b/test/unit/utIFCImportExport.cpp index 4b825a36b..79edb8e01 100644 --- a/test/unit/utIFCImportExport.cpp +++ b/test/unit/utIFCImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utIOStreamBuffer.cpp b/test/unit/utIOStreamBuffer.cpp index aa70881a9..f53a9c9d5 100644 --- a/test/unit/utIOStreamBuffer.cpp +++ b/test/unit/utIOStreamBuffer.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -42,6 +43,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitTestPCH.h" #include "IOStreamBuffer.h" #include "TestIOStream.h" +#include "UnitTestFileGenerator.h" class IOStreamBufferTest : public ::testing::Test { // empty @@ -67,40 +69,68 @@ TEST_F( IOStreamBufferTest, accessCacheSizeTest ) { EXPECT_EQ( 100U, myBuffer2.cacheSize() ); } +const char data[]{"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Qui\ +sque luctus sem diam, ut eleifend arcu auctor eu. Vestibulum id est vel nulla l\ +obortis malesuada ut sed turpis. Nulla a volutpat tortor. Nunc vestibulum portt\ +itor sapien ornare sagittis volutpat."}; + + TEST_F( IOStreamBufferTest, open_close_Test ) { IOStreamBuffer myBuffer; EXPECT_FALSE( myBuffer.open( nullptr ) ); EXPECT_FALSE( myBuffer.close() ); + + const auto dataSize = sizeof(data); + const auto dataCount = dataSize / sizeof(*data); - char buffer[ L_tmpnam ]; - tmpnam( buffer ); - std::FILE *fs( std::fopen( buffer, "w+" ) ); - size_t written( std::fwrite( buffer, 1, sizeof( char ) * L_tmpnam, fs ) ); + char fname[]={ "octest.XXXXXX" }; + auto* fs = MakeTmpFile(fname); + ASSERT_NE(nullptr, fs); + + auto written = std::fwrite( data, sizeof(*data), dataCount, fs ); EXPECT_NE( 0U, written ); - std::fflush( fs ); + auto flushResult = std::fflush( fs ); + ASSERT_EQ(0, flushResult); + std::fclose( fs ); + fs = std::fopen(fname, "r"); + ASSERT_NE(nullptr, fs); + { + TestDefaultIOStream myStream( fs, fname ); - TestDefaultIOStream myStream( fs, buffer ); - - EXPECT_TRUE( myBuffer.open( &myStream ) ); - EXPECT_FALSE( myBuffer.open( &myStream ) ); - EXPECT_TRUE( myBuffer.close() ); + EXPECT_TRUE( myBuffer.open( &myStream ) ); + EXPECT_FALSE( myBuffer.open( &myStream ) ); + EXPECT_TRUE( myBuffer.close() ); + } + remove(fname); } TEST_F( IOStreamBufferTest, readlineTest ) { - char buffer[ L_tmpnam ]; - tmpnam( buffer ); - std::FILE *fs( std::fopen( buffer, "w+" ) ); - size_t written( std::fwrite( buffer, 1, sizeof( char ) * L_tmpnam, fs ) ); + + const auto dataSize = sizeof(data); + const auto dataCount = dataSize / sizeof(*data); + + char fname[]={ "readlinetest.XXXXXX" }; + auto* fs = MakeTmpFile(fname); + ASSERT_NE(nullptr, fs); + + auto written = std::fwrite( data, sizeof(*data), dataCount, fs ); EXPECT_NE( 0U, written ); - std::fflush( fs ); - IOStreamBuffer myBuffer( 26 ); - EXPECT_EQ( 26U, myBuffer.cacheSize() ); + auto flushResult = std::fflush(fs); + ASSERT_EQ(0, flushResult); + std::fclose(fs); + fs = std::fopen(fname, "r"); + ASSERT_NE(nullptr, fs); - TestDefaultIOStream myStream( fs, buffer ); - size_t size( myStream.FileSize() ); - size_t numBlocks( size / myBuffer.cacheSize() ); + const auto tCacheSize = 26u; + + IOStreamBuffer myBuffer( tCacheSize ); + EXPECT_EQ(tCacheSize, myBuffer.cacheSize() ); + + TestDefaultIOStream myStream( fs, fname ); + auto size = myStream.FileSize(); + auto numBlocks = size / myBuffer.cacheSize(); if ( size % myBuffer.cacheSize() > 0 ) { numBlocks++; } diff --git a/test/unit/utIOSystem.cpp b/test/unit/utIOSystem.cpp index a2b333ab0..f33b22039 100644 --- a/test/unit/utIOSystem.cpp +++ b/test/unit/utIOSystem.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -62,12 +63,13 @@ protected: TEST_F( IOSystemTest, accessDirectoryStackTest ) { EXPECT_FALSE( pImp->PopDirectory() ); - EXPECT_EQ( 0, pImp->StackSize() ); + EXPECT_EQ( 0U, pImp->StackSize() ); EXPECT_FALSE( pImp->PushDirectory( "" ) ); std::string path = "test/"; EXPECT_TRUE( pImp->PushDirectory( path ) ); - EXPECT_EQ( 1, pImp->StackSize() ); + EXPECT_EQ( 1U, pImp->StackSize() ); EXPECT_EQ( path, pImp->CurrentDirectory() ); EXPECT_TRUE( pImp->PopDirectory() ); - EXPECT_EQ( 0, pImp->StackSize() ); + EXPECT_EQ( 0U, pImp->StackSize() ); } + diff --git a/test/unit/utImporter.cpp b/test/unit/utImporter.cpp index a2ba25ac2..aaf0bd4ec 100644 --- a/test/unit/utImporter.cpp +++ b/test/unit/utImporter.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utImproveCacheLocality.cpp b/test/unit/utImproveCacheLocality.cpp index 630526754..0f08d462c 100644 --- a/test/unit/utImproveCacheLocality.cpp +++ b/test/unit/utImproveCacheLocality.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utIssues.cpp b/test/unit/utIssues.cpp index cae5ee8cc..2feef922b 100644 --- a/test/unit/utIssues.cpp +++ b/test/unit/utIssues.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -73,6 +74,7 @@ TEST_F( utIssues, OpacityBugWhenExporting_727 ) { EXPECT_EQ( AI_SUCCESS, newScene->mMaterials[ 0 ]->Get( AI_MATKEY_OPACITY, newOpacity ) ); EXPECT_EQ( opacity, newOpacity ); } + delete scene; } #endif // ASSIMP_BUILD_NO_EXPORT diff --git a/test/unit/utJoinVertices.cpp b/test/unit/utJoinVertices.cpp index f9ad2cc98..d2add2b90 100644 --- a/test/unit/utJoinVertices.cpp +++ b/test/unit/utJoinVertices.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utLWSImportExport.cpp b/test/unit/utLWSImportExport.cpp index 3a5dc3247..f0252e211 100644 --- a/test/unit/utLWSImportExport.cpp +++ b/test/unit/utLWSImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utLimitBoneWeights.cpp b/test/unit/utLimitBoneWeights.cpp index 9b38a2fa5..022e4bda1 100644 --- a/test/unit/utLimitBoneWeights.cpp +++ b/test/unit/utLimitBoneWeights.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utMaterialSystem.cpp b/test/unit/utMaterialSystem.cpp index af31d19c8..80408db00 100644 --- a/test/unit/utMaterialSystem.cpp +++ b/test/unit/utMaterialSystem.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -72,7 +73,7 @@ TEST_F(MaterialSystemTest, testFloatArrayProperty) { float pf[] = {0.0f,1.0f,2.0f,3.0f}; unsigned int pMax = sizeof(pf) / sizeof(float); - this->pcMat->AddProperty(&pf,pMax,"testKey2"); + this->pcMat->AddProperty(pf,pMax,"testKey2"); pf[0] = pf[1] = pf[2] = pf[3] = 12.0f; EXPECT_EQ(AI_SUCCESS, pcMat->Get("testKey2",0,0,pf,&pMax)); @@ -96,7 +97,7 @@ TEST_F(MaterialSystemTest, testIntArrayProperty) { int pf[] = {0,1,2,3}; unsigned int pMax = sizeof(pf) / sizeof(int); - this->pcMat->AddProperty(&pf,pMax,"testKey4"); + this->pcMat->AddProperty(pf,pMax,"testKey4"); pf[0] = pf[1] = pf[2] = pf[3] = 12; EXPECT_EQ(AI_SUCCESS, pcMat->Get("testKey4",0,0,pf,&pMax)); diff --git a/test/unit/utMatrix3x3.cpp b/test/unit/utMatrix3x3.cpp index 7ece5449b..47c20acf6 100644 --- a/test/unit/utMatrix3x3.cpp +++ b/test/unit/utMatrix3x3.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utMatrix4x4.cpp b/test/unit/utMatrix4x4.cpp index 64ab2e499..92d430c0f 100644 --- a/test/unit/utMatrix4x4.cpp +++ b/test/unit/utMatrix4x4.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utMetadata.cpp b/test/unit/utMetadata.cpp index 08255d716..4109b068c 100644 --- a/test/unit/utMetadata.cpp +++ b/test/unit/utMetadata.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -54,7 +55,7 @@ protected: } virtual void TearDown() { - delete m_data; + aiMetadata::Dealloc( m_data ); } }; @@ -78,6 +79,7 @@ TEST_F( utMetadata, allocTest ) { EXPECT_EQ( 1U, data->mNumProperties ); EXPECT_NE( nullptr, data->mKeys ); EXPECT_NE( nullptr, data->mValues ); + aiMetadata::Dealloc( data ); } TEST_F( utMetadata, get_set_pod_Test ) { diff --git a/test/unit/utObjImportExport.cpp b/test/unit/utObjImportExport.cpp index 37b89ba48..7099252bb 100644 --- a/test/unit/utObjImportExport.cpp +++ b/test/unit/utObjImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -202,7 +203,7 @@ protected: ::Assimp::Exporter exporter; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", 0 ); EXPECT_NE( nullptr, scene ); - EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "obj", ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj" ) ); + EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "obj", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_test.obj" ) ); return true; } @@ -236,6 +237,15 @@ TEST_F( utObjImportExport, obj_import_test ) { differ.showReport(); m_im->FreeScene(); + for(unsigned int i = 0; i < expected->mNumMeshes; ++i) + { + delete expected->mMeshes[i]; + } + delete[] expected->mMeshes; + expected->mMeshes = nullptr; + delete[] expected->mMaterials; + expected->mMaterials = nullptr; + delete expected; } TEST_F( utObjImportExport, issue1111_no_mat_name_Test ) { diff --git a/test/unit/utObjTools.cpp b/test/unit/utObjTools.cpp new file mode 100644 index 000000000..2d9e2779f --- /dev/null +++ b/test/unit/utObjTools.cpp @@ -0,0 +1,117 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 "ObjTools.h" +#include "ObjFileParser.h" + +using namespace ::Assimp; + +class utObjTools : public ::testing::Test { + // empty +}; + +class TestObjFileParser : public ObjFileParser { +public: + TestObjFileParser() : ObjFileParser(){ + // empty + } + + ~TestObjFileParser() { + // empty + } + + void testCopyNextWord( char *pBuffer, size_t length ) { + copyNextWord( pBuffer, length ); + } + + size_t testGetNumComponentsInDataDefinition() { + return getNumComponentsInDataDefinition(); + } +}; + +TEST_F( utObjTools, skipDataLine_OneLine_Success ) { + std::vector buffer; + std::string data( "v -0.5 -0.5 0.5\nend" ); + buffer.resize( data.size() ); + ::memcpy( &buffer[ 0 ], &data[ 0 ], data.size() ); + std::vector::iterator itBegin( buffer.begin() ), itEnd( buffer.end() ); + unsigned int line = 0; + std::vector::iterator current = skipLine::iterator>( itBegin, itEnd, line ); + EXPECT_EQ( 'e', *current ); +} + +TEST_F( utObjTools, skipDataLine_TwoLines_Success ) { + TestObjFileParser test_parser; + std::string data( "vn -2.061493116917992e-15 -0.9009688496589661 \\\n-0.4338837265968323" ); + std::vector buffer; + buffer.resize( data.size() ); + ::memcpy( &buffer[ 0 ], &data[ 0 ], data.size() ); + test_parser.setBuffer( buffer ); + static const size_t Size = 4096UL; + char data_buffer[ Size ]; + + test_parser.testCopyNextWord( data_buffer, Size ); + EXPECT_EQ( 0, strncmp( data_buffer, "vn", 2 ) ); + + test_parser.testCopyNextWord( data_buffer, Size ); + EXPECT_EQ( data_buffer[0], '-' ); + + test_parser.testCopyNextWord( data_buffer, Size ); + EXPECT_EQ( data_buffer[0], '-' ); + + test_parser.testCopyNextWord( data_buffer, Size ); + EXPECT_EQ( data_buffer[ 0 ], '-' ); +} + +TEST_F( utObjTools, countComponents_TwoLines_Success ) { + TestObjFileParser test_parser; + std::string data( "-2.061493116917992e-15 -0.9009688496589661 \\\n-0.4338837265968323" ); + std::vector buffer; + buffer.resize( data.size() + 1 ); + ::memcpy( &buffer[ 0 ], &data[ 0 ], data.size() ); + buffer[ buffer.size() - 1 ] = '\0'; + test_parser.setBuffer( buffer ); + + size_t numComps = test_parser.testGetNumComponentsInDataDefinition(); + EXPECT_EQ( 3U, numComps ); +} + diff --git a/test/unit/utOpenGEXImportExport.cpp b/test/unit/utOpenGEXImportExport.cpp new file mode 100644 index 000000000..021a7bf81 --- /dev/null +++ b/test/unit/utOpenGEXImportExport.cpp @@ -0,0 +1,69 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 + +using namespace Assimp; + + +class utOpenGEXImportExport : public AbstractImportExportBase { +public: + virtual bool importerTest() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OpenGEX/Example.ogex", 0 ); + return nullptr != scene; + } +}; + +TEST_F( utOpenGEXImportExport, importLWSFromFileTest ) { + EXPECT_TRUE( importerTest() ); +} + +TEST_F( utOpenGEXImportExport, Importissue1262_NoCrash ) { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/OpenGEX/light_issue1262.ogex", 0 ); + EXPECT_NE( nullptr, scene ); + +} diff --git a/test/unit/utPLYImportExport.cpp b/test/unit/utPLYImportExport.cpp index e9458038f..82cc54bdb 100644 --- a/test/unit/utPLYImportExport.cpp +++ b/test/unit/utPLYImportExport.cpp @@ -41,6 +41,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "UnitTestPCH.h" #include +#include +#include #include "AbstractImportExportBase.h" using namespace ::Assimp; @@ -50,15 +52,41 @@ public: virtual bool importerTest() { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", 0 ); - return nullptr != scene; + EXPECT_EQ( 1u, scene->mNumMeshes ); + EXPECT_NE( nullptr, scene->mMeshes[0] ); + EXPECT_EQ( 8u, scene->mMeshes[0]->mNumVertices ); + EXPECT_EQ( 6u, scene->mMeshes[0]->mNumFaces ); + + return (nullptr != scene); } + +#ifndef ASSIMP_BUILD_NO_EXPORT + virtual bool exporterTest() { + Importer importer; + Exporter exporter; + const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/PLY/cube.ply", 0); + EXPECT_NE(nullptr, scene); + EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "ply", ASSIMP_TEST_MODELS_DIR "/PLY/cube_test.ply")); + + return true; + } +#endif // ASSIMP_BUILD_NO_EXPORT }; -TEST_F( utPLYImportExport, importTest ) { +TEST_F( utPLYImportExport, importTest_Success ) { EXPECT_TRUE( importerTest() ); } +#ifndef ASSIMP_BUILD_NO_EXPORT + +TEST_F(utPLYImportExport, exportTest_Success ) { + EXPECT_TRUE(exporterTest()); +} + +#endif // ASSIMP_BUILD_NO_EXPORT + TEST_F( utPLYImportExport, vertexColorTest ) { Assimp::Importer importer; const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/PLY/float-color.ply", 0 ); -} \ No newline at end of file + EXPECT_NE( nullptr, scene ); +} diff --git a/test/unit/utPMXImporter.cpp b/test/unit/utPMXImporter.cpp new file mode 100644 index 000000000..72916b8ef --- /dev/null +++ b/test/unit/utPMXImporter.cpp @@ -0,0 +1,63 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2016, 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 "SceneDiffer.h" +#include "AbstractImportExportBase.h" +#include "MMDImporter.h" + +#include + +using namespace ::Assimp; + +class utPMXImporter : public AbstractImportExportBase { +public: + virtual bool importerTest() { + Assimp::Importer importer; + /*const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/../models-nonbsd/MMD/Alicia_blade.pmx", 0 ); + return nullptr != scene;*/ + return true; + } +}; + +TEST_F( utPMXImporter, importTest ) { + EXPECT_TRUE( importerTest() ); +} diff --git a/test/unit/utPretransformVertices.cpp b/test/unit/utPretransformVertices.cpp index dd1062ad4..9f40f3ddc 100644 --- a/test/unit/utPretransformVertices.cpp +++ b/test/unit/utPretransformVertices.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utProfiler.cpp b/test/unit/utProfiler.cpp new file mode 100644 index 000000000..ea71dd688 --- /dev/null +++ b/test/unit/utProfiler.cpp @@ -0,0 +1,76 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 "UTLogStream.h" +#include "code/Profiler.h" +#include + +using namespace ::Assimp; +using namespace ::Assimp::Profiling; + +class utProfiler : public ::testing::Test { +public: + LogStream *m_stream; + + /*virtual void SetUp() { + m_stream = new UTLogStream; + DefaultLogger::create(); + DefaultLogger::get()->attachStream( m_stream ); + } + + virtual void TearDown() { + DefaultLogger::get()->detatchStream( m_stream ); + m_stream = nullptr; + }*/ +}; + +TEST_F( utProfiler, addRegion_success ) { + Profiler myProfiler; + myProfiler.BeginRegion( "t1" ); + for ( int i=0; i<10; i++ ) { + volatile int j=0; + j++; + } + myProfiler.EndRegion( "t1" ); + //UTLogStream *stream( (UTLogStream*) m_stream ); + //EXPECT_FALSE( stream->m_messages.empty() ); +} diff --git a/test/unit/utQ3DImportExport.cpp b/test/unit/utQ3DImportExport.cpp new file mode 100644 index 000000000..d8195309f --- /dev/null +++ b/test/unit/utQ3DImportExport.cpp @@ -0,0 +1,61 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 + +using namespace Assimp; + +class utQ3DImportExport : public AbstractImportExportBase { +public: + virtual bool importerTest() { + Assimp::Importer importer; + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/Q3D/earth.q3o", 0 ); + return nullptr != scene; + } +}; + +TEST_F(utQ3DImportExport, importTest) { + EXPECT_TRUE( importerTest() ); +} diff --git a/test/unit/utRemoveComments.cpp b/test/unit/utRemoveComments.cpp index 12ff158aa..5bce51126 100644 --- a/test/unit/utRemoveComments.cpp +++ b/test/unit/utRemoveComments.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utRemoveComponent.cpp b/test/unit/utRemoveComponent.cpp index fc3bbbd49..31e47b77c 100644 --- a/test/unit/utRemoveComponent.cpp +++ b/test/unit/utRemoveComponent.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utRemoveRedundantMaterials.cpp b/test/unit/utRemoveRedundantMaterials.cpp index c683d4643..072ca6060 100644 --- a/test/unit/utRemoveRedundantMaterials.cpp +++ b/test/unit/utRemoveRedundantMaterials.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utRemoveVCProcess.cpp b/test/unit/utRemoveVCProcess.cpp new file mode 100644 index 000000000..6caa72c11 --- /dev/null +++ b/test/unit/utRemoveVCProcess.cpp @@ -0,0 +1,76 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 "code/RemoveVCProcess.h" +#include +#include + +using namespace ::Assimp; + +class utRevmoveVCProcess : public ::testing::Test { + // empty +}; + +TEST_F( utRevmoveVCProcess, createTest ) { + bool ok = true; + try { + RemoveVCProcess *process = new RemoveVCProcess; + delete process; + } catch ( ... ) { + ok = false; + } + EXPECT_TRUE( ok ); +} + +TEST_F( utRevmoveVCProcess, issue1266_ProcessMeshTest_NoCrash ) { + aiScene *scene = new aiScene; + scene->mNumMeshes = 1; + scene->mMeshes = new aiMesh*[ 1 ]; + + aiMesh *mesh = new aiMesh; + mesh->mNumVertices = 1; + mesh->mColors[ 0 ] = new aiColor4D[ 2 ]; + scene->mMeshes[ 0 ] = mesh; + std::unique_ptr process(new RemoveVCProcess); + process->Execute( scene ); + delete scene; +} diff --git a/test/unit/utSIBImporter.cpp b/test/unit/utSIBImporter.cpp index b201537ce..ecaa92f26 100644 --- a/test/unit/utSIBImporter.cpp +++ b/test/unit/utSIBImporter.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utSMDImportExport.cpp b/test/unit/utSMDImportExport.cpp index d26885e47..9139bb922 100644 --- a/test/unit/utSMDImportExport.cpp +++ b/test/unit/utSMDImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utSceneCombiner.cpp b/test/unit/utSceneCombiner.cpp new file mode 100644 index 000000000..3a283515e --- /dev/null +++ b/test/unit/utSceneCombiner.cpp @@ -0,0 +1,73 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 ::Assimp; + +class utSceneCombiner : public ::testing::Test { + // empty +}; + +TEST_F( utSceneCombiner, MergeMeshes_ValidNames_Test ) { + std::vector merge_list; + aiMesh *mesh1 = new aiMesh; + mesh1->mName.Set( "mesh_1" ); + merge_list.push_back( mesh1 ); + + aiMesh *mesh2 = new aiMesh; + mesh2->mName.Set( "mesh_2" ); + merge_list.push_back( mesh2 ); + + aiMesh *mesh3 = new aiMesh; + mesh3->mName.Set( "mesh_3" ); + merge_list.push_back( mesh3 ); + + std::unique_ptr out; + aiMesh* ptr = nullptr; + SceneCombiner::MergeMeshes( &ptr, 0, merge_list.begin(), merge_list.end() ); + out.reset(ptr); + std::string outName = out->mName.C_Str(); + EXPECT_EQ( "mesh_1.mesh_2.mesh_3", outName ); +} diff --git a/test/unit/utScenePreprocessor.cpp b/test/unit/utScenePreprocessor.cpp index 732990f9a..ce3716baf 100644 --- a/test/unit/utScenePreprocessor.cpp +++ b/test/unit/utScenePreprocessor.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utSharedPPData.cpp b/test/unit/utSharedPPData.cpp index fe7841b3d..495faa7ac 100644 --- a/test/unit/utSharedPPData.cpp +++ b/test/unit/utSharedPPData.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -91,7 +92,7 @@ TEST_F(SharedPPDataTest, testPODProperty) // ------------------------------------------------------------------------------------------------ TEST_F(SharedPPDataTest, testPropertyPointer) { - int *i = new int[35]; + int *i = new int; shared->AddProperty("test16",i); int* o; EXPECT_TRUE(shared->GetProperty("test16",o)); diff --git a/test/unit/utSortByPType.cpp b/test/unit/utSortByPType.cpp index 4dd26f983..13c46bd42 100644 --- a/test/unit/utSortByPType.cpp +++ b/test/unit/utSortByPType.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utSplitLargeMeshes.cpp b/test/unit/utSplitLargeMeshes.cpp index 47876caea..af6ed14ef 100644 --- a/test/unit/utSplitLargeMeshes.cpp +++ b/test/unit/utSplitLargeMeshes.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utStringUtils.cpp b/test/unit/utStringUtils.cpp index e75ff8d4b..3b45075eb 100644 --- a/test/unit/utStringUtils.cpp +++ b/test/unit/utStringUtils.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utTargetAnimation.cpp b/test/unit/utTargetAnimation.cpp index 1c039aa90..6742543a6 100644 --- a/test/unit/utTargetAnimation.cpp +++ b/test/unit/utTargetAnimation.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utTextureTransform.cpp b/test/unit/utTextureTransform.cpp index 1c039aa90..6742543a6 100644 --- a/test/unit/utTextureTransform.cpp +++ b/test/unit/utTextureTransform.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utTriangulate.cpp b/test/unit/utTriangulate.cpp index e9677d3e4..8908b9703 100644 --- a/test/unit/utTriangulate.cpp +++ b/test/unit/utTriangulate.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utTypes.cpp b/test/unit/utTypes.cpp index 875f66240..70a734082 100644 --- a/test/unit/utTypes.cpp +++ b/test/unit/utTypes.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utVersion.cpp b/test/unit/utVersion.cpp index 84177dbce..677a131c9 100644 --- a/test/unit/utVersion.cpp +++ b/test/unit/utVersion.cpp @@ -2,7 +2,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -53,11 +54,11 @@ TEST_F( utVersion, aiGetLegalStringTest ) { } TEST_F( utVersion, aiGetVersionMinorTest ) { - EXPECT_EQ( aiGetVersionMinor(), 3U ); + EXPECT_EQ( aiGetVersionMinor(), 0U ); } TEST_F( utVersion, aiGetVersionMajorTest ) { - EXPECT_EQ( aiGetVersionMajor(), 3U ); + EXPECT_EQ( aiGetVersionMajor(), 4U ); } TEST_F( utVersion, aiGetCompileFlagsTest ) { diff --git a/test/unit/utVertexTriangleAdjacency.cpp b/test/unit/utVertexTriangleAdjacency.cpp index ec729bac5..29067fead 100644 --- a/test/unit/utVertexTriangleAdjacency.cpp +++ b/test/unit/utVertexTriangleAdjacency.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utXImporterExporter.cpp b/test/unit/utXImporterExporter.cpp index 9293e042e..042853d3d 100644 --- a/test/unit/utXImporterExporter.cpp +++ b/test/unit/utXImporterExporter.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/test/unit/utglTF2ImportExport.cpp b/test/unit/utglTF2ImportExport.cpp new file mode 100644 index 000000000..fa69d648a --- /dev/null +++ b/test/unit/utglTF2ImportExport.cpp @@ -0,0 +1,80 @@ +/* +--------------------------------------------------------------------------- +Open Asset Import Library (assimp) +--------------------------------------------------------------------------- + +Copyright (c) 2006-2017, 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 + +using namespace Assimp; + +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", 0); + return nullptr != scene; + } + +#ifndef ASSIMP_BUILD_NO_EXPORT + virtual bool exporterTest() { + Assimp::Importer importer; + Assimp::Exporter exporter; + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", 0 ); + EXPECT_NE( nullptr, scene ); + EXPECT_EQ( aiReturn_SUCCESS, exporter.Export( scene, "gltf2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured_out.gltf" ) ); + + return true; + } +#endif // ASSIMP_BUILD_NO_EXPORT + +}; + +TEST_F( utglTF2ImportExport, importglTF2FromFileTest ) { + EXPECT_TRUE( importerTest() ); +} + +#ifndef ASSIMP_BUILD_NO_EXPORT +TEST_F( utglTF2ImportExport, exportglTF2FromFileTest ) { + EXPECT_TRUE( exporterTest() ); +} +#endif // ASSIMP_BUILD_NO_EXPORT diff --git a/test/unit/utglTFImportExport.cpp b/test/unit/utglTFImportExport.cpp index 1ae365037..18c348299 100644 --- a/test/unit/utglTFImportExport.cpp +++ b/test/unit/utglTFImportExport.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -49,13 +50,11 @@ class utglTFImportExport : public AbstractImportExportBase { public: virtual bool importerTest() { Assimp::Importer importer; - const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glFT/TwoBoxes/TwoBoxes.gltf", 0 ); - //return nullptr != scene; - - return true; + const aiScene *scene = importer.ReadFile( ASSIMP_TEST_MODELS_DIR "/glTF/TwoBoxes/TwoBoxes.gltf", 0 ); + return nullptr != scene; } }; -TEST_F( utglTFImportExport, importglTFromFileTest ) { +TEST_F( utglTFImportExport, importglTFFromFileTest ) { EXPECT_TRUE( importerTest() ); } diff --git a/tools/assimp_cmd/CMakeLists.txt b/tools/assimp_cmd/CMakeLists.txt index f8af93a10..cb78942d7 100644 --- a/tools/assimp_cmd/CMakeLists.txt +++ b/tools/assimp_cmd/CMakeLists.txt @@ -1,7 +1,8 @@ # Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # -# Copyright (c) 2006-2016, assimp team +# Copyright (c) 2006-2017, assimp team + # All rights reserved. # # Redistribution and use of this software in source and binary forms, diff --git a/tools/assimp_cmd/CompareDump.cpp b/tools/assimp_cmd/CompareDump.cpp index 1821ff6ec..2db11ef25 100644 --- a/tools/assimp_cmd/CompareDump.cpp +++ b/tools/assimp_cmd/CompareDump.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/tools/assimp_cmd/Export.cpp b/tools/assimp_cmd/Export.cpp index d83f5272a..3752db5e5 100644 --- a/tools/assimp_cmd/Export.cpp +++ b/tools/assimp_cmd/Export.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/tools/assimp_cmd/ImageExtractor.cpp b/tools/assimp_cmd/ImageExtractor.cpp index 7e7b9b439..691f62929 100644 --- a/tools/assimp_cmd/ImageExtractor.cpp +++ b/tools/assimp_cmd/ImageExtractor.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/tools/assimp_cmd/Info.cpp b/tools/assimp_cmd/Info.cpp index 3eb0e9d10..d116f04d2 100644 --- a/tools/assimp_cmd/Info.cpp +++ b/tools/assimp_cmd/Info.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/tools/assimp_cmd/Main.cpp b/tools/assimp_cmd/Main.cpp index 9c5368bf5..587e111d5 100644 --- a/tools/assimp_cmd/Main.cpp +++ b/tools/assimp_cmd/Main.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -47,7 +48,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. const char* AICMD_MSG_ABOUT = "------------------------------------------------------ \n" -"Open Asset Import Library (\"Assimp\", http://assimp.sourceforge.net) \n" +"Open Asset Import Library (\"Assimp\", https://github.com/assimp/assimp) \n" " -- Commandline toolchain --\n" "------------------------------------------------------ \n\n" diff --git a/tools/assimp_cmd/WriteDumb.cpp b/tools/assimp_cmd/WriteDumb.cpp index 44b0c6926..3fe8b2c77 100644 --- a/tools/assimp_cmd/WriteDumb.cpp +++ b/tools/assimp_cmd/WriteDumb.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/tools/assimp_qt_viewer/CMakeLists.txt b/tools/assimp_qt_viewer/CMakeLists.txt index 2985d6e30..42ef0fb34 100644 --- a/tools/assimp_qt_viewer/CMakeLists.txt +++ b/tools/assimp_qt_viewer/CMakeLists.txt @@ -1,5 +1,5 @@ -project(assimp_qt_viewer) set(PROJECT_VERSION "") +project(assimp_qt_viewer) cmake_minimum_required(VERSION 2.6) diff --git a/tools/assimp_qt_viewer/glview.cpp b/tools/assimp_qt_viewer/glview.cpp index 1de8199fa..429f2ca99 100644 --- a/tools/assimp_qt_viewer/glview.cpp +++ b/tools/assimp_qt_viewer/glview.cpp @@ -6,7 +6,11 @@ #include "glview.hpp" // Header files, OpenGL. -#include +#if defined(__APPLE__) +# include +#else +# include +#endif // Header files, DevIL. #include @@ -142,8 +146,8 @@ void CGLView::Material_Apply(const aiMaterial* pMaterial) void CGLView::Matrix_NodeToRoot(const aiNode* pNode, aiMatrix4x4& pOutMatrix) { -const aiNode* node_cur; -std::list mat_list; + const aiNode* node_cur; + std::list mat_list; pOutMatrix = aiMatrix4x4(); // starting walk from current element to root diff --git a/tools/assimp_qt_viewer/mainwindow.cpp b/tools/assimp_qt_viewer/mainwindow.cpp index cb4c4a67e..9b6e231bd 100644 --- a/tools/assimp_qt_viewer/mainwindow.cpp +++ b/tools/assimp_qt_viewer/mainwindow.cpp @@ -295,7 +295,7 @@ aiReturn rv; // begin export time_begin = QTime::currentTime(); - rv = exporter.Export(mScene, format_id.toLocal8Bit(), filename.toLocal8Bit()); + rv = exporter.Export(mScene, format_id.toLocal8Bit(), filename.toLocal8Bit(), aiProcess_FlipUVs); ui->lblExportTime->setText(QString("%1").arg(time_begin.secsTo(QTime::currentTime()))); if(rv == aiReturn_SUCCESS) LogInfo("Export done: " + filename); diff --git a/tools/assimp_view/CMakeLists.txt b/tools/assimp_view/CMakeLists.txt index 23e648b5b..adf2ae877 100644 --- a/tools/assimp_view/CMakeLists.txt +++ b/tools/assimp_view/CMakeLists.txt @@ -1,7 +1,8 @@ # Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # -# Copyright (c) 2006-2016, assimp team +# Copyright (c) 2006-2017, assimp team + # All rights reserved. # # Redistribution and use of this software in source and binary forms, diff --git a/tools/assimp_view/Display.cpp b/tools/assimp_view/Display.cpp index 91ea9573b..21c0c022a 100644 --- a/tools/assimp_view/Display.cpp +++ b/tools/assimp_view/Display.cpp @@ -43,6 +43,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "SceneAnimator.h" #include "StringUtils.h" +#include + namespace AssimpView { using namespace Assimp; diff --git a/tools/assimp_view/LogWindow.cpp b/tools/assimp_view/LogWindow.cpp index c21c2802e..dba70ee71 100644 --- a/tools/assimp_view/LogWindow.cpp +++ b/tools/assimp_view/LogWindow.cpp @@ -41,6 +41,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "assimp_view.h" #include "richedit.h" +#include +#include namespace AssimpView { diff --git a/tools/assimp_view/MessageProc.cpp b/tools/assimp_view/MessageProc.cpp index 4595c58cd..b8c56503b 100644 --- a/tools/assimp_view/MessageProc.cpp +++ b/tools/assimp_view/MessageProc.cpp @@ -44,6 +44,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include +#include namespace AssimpView { diff --git a/tools/assimp_view/SceneAnimator.h b/tools/assimp_view/SceneAnimator.h index ba79b4faa..afcbac925 100644 --- a/tools/assimp_view/SceneAnimator.h +++ b/tools/assimp_view/SceneAnimator.h @@ -72,20 +72,26 @@ struct SceneAnimNode size_t mChannelIndex; //! Default construction - SceneAnimNode() { - mChannelIndex = -1; mParent = NULL; + SceneAnimNode() + : mName() + , mParent(NULL) + , mChannelIndex(-1) { + // empty } //! Construction from a given name SceneAnimNode( const std::string& pName) - : mName( pName) { - mChannelIndex = -1; mParent = NULL; + : mName( pName) + , mParent(NULL) + , mChannelIndex( -1 ) { + // empty } //! Destruct all children recursively ~SceneAnimNode() { - for( std::vector::iterator it = mChildren.begin(); it != mChildren.end(); ++it) + for (std::vector::iterator it = mChildren.begin(); it != mChildren.end(); ++it) { delete *it; + } } }; diff --git a/tools/assimp_view/assimp_view.cpp b/tools/assimp_view/assimp_view.cpp index 811fe47e7..283761e88 100644 --- a/tools/assimp_view/assimp_view.cpp +++ b/tools/assimp_view/assimp_view.cpp @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. @@ -41,6 +42,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "assimp_view.h" +#include #include "StringUtils.h" #include diff --git a/tools/assimp_view/assimp_view.h b/tools/assimp_view/assimp_view.h index 6300c1a87..73c7d7947 100644 --- a/tools/assimp_view/assimp_view.h +++ b/tools/assimp_view/assimp_view.h @@ -3,7 +3,8 @@ Open Asset Import Library (assimp) --------------------------------------------------------------------------- -Copyright (c) 2006-2016, assimp team +Copyright (c) 2006-2017, assimp team + All rights reserved. diff --git a/tools/assimp_view/stdafx.h b/tools/assimp_view/stdafx.h index 3c78d385c..35104d4b0 100644 --- a/tools/assimp_view/stdafx.h +++ b/tools/assimp_view/stdafx.h @@ -23,7 +23,6 @@ #define _WIN32_IE 0x0600 // Ändern Sie dies in den geeigneten Wert für andere Versionen von IE. #endif -#define WIN32_LEAN_AND_MEAN // Selten verwendete Teile der Windows-Header nicht einbinden. // Windows-Headerdateien: #include