| @@ -0,0 +1,60 @@ | |||||
| # External binary software for Lol Engine | |||||
| Main repository: https://github.com/lolengine/lol.git | |||||
| If any name change occurs, update: | |||||
| - `configure.ac` | |||||
| - `build/lol-build` | |||||
| - `build/msbuild/lol.vars.props` | |||||
| OpenSSL | |||||
| ------- | |||||
| - `./conan-install.sh ssl` | |||||
| Glew | |||||
| ---- | |||||
| Download page: http://sourceforge.net/projects/glew/files/glew | |||||
| - take the pre-compiled `glew32s.lib` (`s` is for “static”) versions, | |||||
| both the win32 and the win64 ones. | |||||
| - copy `include/GL` in the glew directory. | |||||
| SDL, SDL\_Image, SDL\_Mixer | |||||
| --------------------------- | |||||
| - Download both VC (Visual Studio) and mingw32 *devel* releases: | |||||
| - http://www.libsdl.org/release/ | |||||
| - http://www.libsdl.org/projects/SDL_image/release/ | |||||
| - http://www.libsdl.org/projects/SDL_mixer/release/ | |||||
| - Copy headers from any version of the package | |||||
| - Copy all `.lib` and `.a` files in their respective directories | |||||
| - Copy the `.dll` support DLLs into the Visual Studio directories | |||||
| Libcaca | |||||
| ------- | |||||
| Ran `build-win32` and `build-win64` on a Debian installation, copied the | |||||
| resulting `.lib` files and some headers. | |||||
| Ffmpeg | |||||
| ------ | |||||
| Use the two provided scripts on a fresh ffmpeg Git checkout: | |||||
| - `build-ffmpeg-msvc.sh` | |||||
| - `build-ffmpeg-mingw32.sh` | |||||
| Phased out | |||||
| ---------- | |||||
| - libgcc (can’t remember why it was used, maybe to link mingw32-compiled | |||||
| libraries with MSVC, because they may miss `vsprintf` etc.) | |||||
| @@ -0,0 +1,34 @@ | |||||
| build | |||||
| .project | |||||
| *.kdev4* | |||||
| # Visual Studio | |||||
| *.sln | |||||
| *.ncb | |||||
| *.vcproj | |||||
| # Output | |||||
| bin/ | |||||
| lib/ | |||||
| contrib/ | |||||
| # Generated | |||||
| assimp.pc | |||||
| revision.h | |||||
| contrib/zlib/zconf.h | |||||
| contrib/zlib/zlib.pc | |||||
| # CMake | |||||
| CMakeCache.txt | |||||
| CMakeFiles | |||||
| cmake_install.cmake | |||||
| cmake_uninstall.cmake | |||||
| *.dir/ | |||||
| assimp-config.cmake | |||||
| assimp-config-version.cmake | |||||
| # Tests | |||||
| test/results | |||||
| # Python | |||||
| __pycache__ | |||||
| @@ -0,0 +1,19 @@ | |||||
| before_install: | |||||
| - sudo apt-get install cmake | |||||
| env: | |||||
| - TRAVIS_NO_EXPORT=YES | |||||
| - TRAVIS_NO_EXPORT=NO | |||||
| - TRAVIS_STATIC_BUILD=ON | |||||
| - TRAVIS_STATIC_BUILD=OFF | |||||
| language: cpp | |||||
| compiler: | |||||
| - gcc | |||||
| - clang | |||||
| script: cmake -G "Unix Makefiles" -DASSIMP_ENABLE_BOOST_WORKAROUND=YES -DASSIMP_NO_EXPORT=$TRAVIS_NO_EXPORT -STATIC_BUILD=$TRAVIS_STATIC_BUILD && make | |||||
| @@ -0,0 +1,3 @@ | |||||
| set(ASSIMP_INCLUDE_DIRS | |||||
| "@PROJECT_SOURCE_DIR@" | |||||
| "@PROJECT_BINARY_DIR@") | |||||
| @@ -0,0 +1,21 @@ | |||||
| # - Config file for the FooBar package | |||||
| # It defines the following variables | |||||
| # FOOBAR_INCLUDE_DIRS - include directories for FooBar | |||||
| # FOOBAR_LIBRARIES - libraries to link against | |||||
| # FOOBAR_EXECUTABLE - the bar executable | |||||
| # Compute paths | |||||
| get_filename_component(FOOBAR_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) | |||||
| if(EXISTS "${FOOBAR_CMAKE_DIR}/CMakeCache.txt") | |||||
| # In build tree | |||||
| include("${FOOBAR_CMAKE_DIR}/FooBarBuildTreeSettings.cmake") | |||||
| else() | |||||
| set(FOOBAR_INCLUDE_DIRS "${FOOBAR_CMAKE_DIR}/@CONF_REL_INCLUDE_DIR@") | |||||
| endif() | |||||
| # Our library dependencies (contains definitions for IMPORTED targets) | |||||
| include("${FOOBAR_CMAKE_DIR}/FooBarLibraryDepends.cmake") | |||||
| # These are IMPORTED targets created by FooBarLibraryDepends.cmake | |||||
| set(FOOBAR_LIBRARIES foo) | |||||
| set(FOOBAR_EXECUTABLE bar) | |||||
| @@ -0,0 +1,11 @@ | |||||
| set(ASSIMP_PACKAGE_VERSION "@ASSIMP_SOVERSION@") | |||||
| # Check whether the requested PACKAGE_FIND_VERSION is compatible | |||||
| if("${ASSIMP_PACKAGE_VERSION}" VERSION_LESS "${ASSIMP_PACKAGE_FIND_VERSION}") | |||||
| set(ASSIMP_PACKAGE_VERSION_COMPATIBLE FALSE) | |||||
| else() | |||||
| set(ASSIMP_PACKAGE_VERSION_COMPATIBLE TRUE) | |||||
| if ("${ASSIMP_PACKAGE_VERSION}" VERSION_EQUAL "${ASSIMP_PACKAGE_FIND_VERSION}") | |||||
| set(ASSIMP_PACKAGE_VERSION_EXACT TRUE) | |||||
| endif() | |||||
| endif() | |||||
| @@ -0,0 +1,116 @@ | |||||
| ---------------------------------------------------------------------- | |||||
| CHANGELOG | |||||
| ---------------------------------------------------------------------- | |||||
| 3.0 (2012-07-07) | |||||
| FEATURES: | |||||
| - new export interface similar to the import API. | |||||
| - Supported export formats: Collada, OBJ, PLY and STL | |||||
| - added new import formats: XGL/ZGL, M3 (experimental) | |||||
| - new postprocessing steps: Debone | |||||
| - vastly improved IFC (Industry Foundation Classes) support | |||||
| - introduced API to query importer meta information (such as supported | |||||
| format versions, full name, maintainer info). | |||||
| - reworked Ogre XML import | |||||
| - C-API now supports per-import properties | |||||
| FIXES/HOUSEKEEPING: | |||||
| - hundreds of bugfixes in all parts of the library | |||||
| - unified naming and cleanup of public headers | |||||
| - improved CMake build system | |||||
| - templatized math library | |||||
| - reduce dependency on boost.thread, only remaining spot | |||||
| is synchronization for the C logging API | |||||
| API COMPATIBILITY: | |||||
| - renamed headers, export interface, C API properties and meta data | |||||
| prevent compatibility with code written for 2.0, but in | |||||
| most cases these can be easily resolved | |||||
| - Note: 3.0 is not binary compatible with 2.0 | |||||
| 2.0 (2010-11-21) | |||||
| FEATURES: | |||||
| - Add support for static Blender (*.blend) scenes | |||||
| - Add support for Q3BSP scenes | |||||
| - Add a windows-based OpenGL sample featuring texturing & basic materials | |||||
| - Add an experimental progress feedback interface. | |||||
| - Vastly improved performance (up to 500%, depending on mesh size and | |||||
| spatial structure) in some expensive postprocessing steps | |||||
| - AssimpView now uses a reworked layout which leaves more space | |||||
| to the scene hierarchy window | |||||
| - Add C# bindings ('Assimp.NET') | |||||
| - Keep BSD-licensed and otherwise free test files in separate | |||||
| folders (./test/models and ./test/models-nonbsd). | |||||
| FIXES: | |||||
| - Many Collada bugfixes, improve fault tolerance | |||||
| - Fix possible crashes in the Obj loader | |||||
| - Improve the Ogre XML loader | |||||
| - OpenGL-sample now works with MinGW | |||||
| - Fix Importer::FindLoader failing on uppercase file extensions | |||||
| - Fix flawed path handling when locating external files | |||||
| - Limit the maximum number of vertices, faces, face indices and | |||||
| weights that Assimp is able to handle. This is to avoid | |||||
| crashes due to overflowing counters. | |||||
| - Updated XCode project files | |||||
| - Further CMAKE build improvements | |||||
| API CHANGES: | |||||
| - Add data structures for vertex-based animations (These are not | |||||
| 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). | |||||
| FEATURES: | |||||
| - Vastly improved Collada support | |||||
| - Add MS3D (Milkshape 3D) support | |||||
| - Add support for Ogre XML static meshes | |||||
| - Add experimental COB (TrueSpace) support | |||||
| - Automatic test suite to quickly locate regressions | |||||
| - D bindings (`dAssimp`) | |||||
| - Python 2.n bindings (`PyAssimp`) | |||||
| - Add basic support for Unicode input files (utf8, utf16 and utf32) | |||||
| - Add further utilities to the `assimp` tool (xml/binary dumps, quick file stats) | |||||
| - Switch to a CMAKE-based build system including an install target for unix'es | |||||
| - Automatic evaluation of subdivision surfaces for some formats. | |||||
| - Add `Importer::ReadFileFromMemory` and the corresponding C-API `aiReadFileFromMemory` | |||||
| - Expose further math utilities via the C-API (i.e. `aiMultiplyMatrix4`) | |||||
| - Move noboost files away from the public include directory | |||||
| - Many, many bugfixes and improvements in existing loaders and postprocessing steps | |||||
| - Documentation improved and clarified in many places. | |||||
| - Add a sample on using Assimp in conjunction with OpenGL | |||||
| - Distribution/packaging: comfortable SDK installer for Windows | |||||
| - Distribution/packaging: improved release packages for other architectures | |||||
| CRITICAL FIXES: | |||||
| - Resolve problems with clashing heap managers, STL ABIs and runtime libraries (win32) | |||||
| - Fix automatic detection of file type if no file extension is given | |||||
| - Improved exception safety and robustness, prevent leaking of exceptions through the C interface | |||||
| - Fix possible heap corruption due to material properties pulled in incorrectly | |||||
| - Avoid leaking in certain error scenarios | |||||
| - Fix 64 bit compatibility problems in some loaders (i.e. MDL) | |||||
| BREAKING API CHANGES: | |||||
| - None - | |||||
| MINOR API BEHAVIOUR CHANGES: | |||||
| - Change quaternion orientation to suit to the more common convention (-w). | |||||
| - aiString is utf8 now. Not yet consistent, however. | |||||
| @@ -0,0 +1,274 @@ | |||||
| cmake_minimum_required( VERSION 2.6 ) | |||||
| PROJECT( Assimp ) | |||||
| # Define here the needed parameters | |||||
| set (ASSIMP_VERSION_MAJOR 3) | |||||
| set (ASSIMP_VERSION_MINOR 1) | |||||
| set (ASSIMP_VERSION_PATCH 1) # subversion revision? | |||||
| set (ASSIMP_VERSION ${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}.${ASSIMP_VERSION_PATCH}) | |||||
| set (ASSIMP_SOVERSION 3) | |||||
| set (PROJECT_VERSION "${ASSIMP_VERSION}") | |||||
| set(ASSIMP_PACKAGE_VERSION "0" CACHE STRING "the package-specific version used for uploading the sources") | |||||
| # Get the current working branch | |||||
| execute_process( | |||||
| COMMAND git rev-parse --abbrev-ref HEAD | |||||
| WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | |||||
| OUTPUT_VARIABLE GIT_BRANCH | |||||
| OUTPUT_STRIP_TRAILING_WHITESPACE | |||||
| ) | |||||
| # Get the latest abbreviated commit hash of the working branch | |||||
| execute_process( | |||||
| COMMAND git log -1 --format=%h | |||||
| WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} | |||||
| OUTPUT_VARIABLE GIT_COMMIT_HASH | |||||
| OUTPUT_STRIP_TRAILING_WHITESPACE | |||||
| ) | |||||
| if(NOT GIT_COMMIT_HASH) | |||||
| set(GIT_COMMIT_HASH 0) | |||||
| endif(NOT GIT_COMMIT_HASH) | |||||
| configure_file( | |||||
| ${CMAKE_SOURCE_DIR}/revision.h.in | |||||
| ${CMAKE_BINARY_DIR}/revision.h | |||||
| ) | |||||
| include_directories(${CMAKE_BINARY_DIR}) | |||||
| option(ASSIMP_OPT_BUILD_PACKAGES "Set to ON to generate CPack configuration files and packaging targets" OFF) | |||||
| set(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") | |||||
| if((CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) AND NOT CMAKE_COMPILER_IS_MINGW) | |||||
| add_definitions(-fPIC) # this is a very important switch and some libraries seem now to have it.... | |||||
| # hide all not-exported symbols | |||||
| add_definitions( -fvisibility=hidden -Wall ) | |||||
| elseif(MSVC) | |||||
| # enable multi-core compilation with MSVC | |||||
| add_definitions(/MP) | |||||
| endif() | |||||
| INCLUDE (FindPkgConfig) | |||||
| INCLUDE_DIRECTORIES( include ) | |||||
| INCLUDE (PrecompiledHeader) | |||||
| # If this is an in-source build (CMAKE_SOURCE_DIR == CMAKE_BINARY_DIR), | |||||
| # write the library/executable files to the respective directories in the | |||||
| # source tree. During an out-of-source build, however, do not litter this | |||||
| # directory, since that is probably what the user wanted to avoid. | |||||
| IF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR ) | |||||
| 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" ) | |||||
| ENDIF ( CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR ) | |||||
| # Cache these to allow the user to override them manually. | |||||
| SET( ASSIMP_LIB_INSTALL_DIR "lib" CACHE PATH | |||||
| "Path the built library files are installed to." ) | |||||
| SET( ASSIMP_INCLUDE_INSTALL_DIR "include" CACHE PATH | |||||
| "Path the header files are installed to." ) | |||||
| SET( ASSIMP_BIN_INSTALL_DIR "bin" CACHE PATH | |||||
| "Path the tool executables are installed to." ) | |||||
| SET ( ASSIMP_BUILD_STATIC_LIB OFF CACHE BOOL | |||||
| "Build a static (.a) version of the library" ) | |||||
| SET(ASSIMP_DEBUG_POSTFIX "d" CACHE STRING "Debug Postfitx for lib, samples and tools") | |||||
| # Allow the user to build a static library | |||||
| option ( BUILD_SHARED_LIBS "Build a shared version of the library" ON ) | |||||
| IF ( ASSIMP_BUILD_STATIC_LIB ) | |||||
| option ( BUILD_SHARED_LIBS "Build a shared version of the library" OFF ) | |||||
| ELSE ( ASSIMP_BUILD_STATIC_LIB ) | |||||
| option ( BUILD_SHARED_LIBS "Build a shared version of the library" ON ) | |||||
| ENDIF ( ASSIMP_BUILD_STATIC_LIB ) | |||||
| # Generate a pkg-config .pc for the Assimp library. | |||||
| CONFIGURE_FILE( "${PROJECT_SOURCE_DIR}/assimp.pc.in" "${PROJECT_BINARY_DIR}/assimp.pc" @ONLY ) | |||||
| INSTALL( FILES "${PROJECT_BINARY_DIR}/assimp.pc" DESTINATION ${ASSIMP_LIB_INSTALL_DIR}/pkgconfig/ COMPONENT ${LIBASSIMP-DEV_COMPONENT}) | |||||
| # 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) | |||||
| add_custom_target(uninstall "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") | |||||
| ENDIF() | |||||
| # Globally enable Boost resp. the Boost workaround – it is also needed by the | |||||
| # tools which include the Assimp headers. | |||||
| SET ( ASSIMP_ENABLE_BOOST_WORKAROUND ON CACHE BOOL | |||||
| "If a simple implementation of the used Boost functions is used. Slightly reduces functionality, but enables builds without Boost available." | |||||
| ) | |||||
| IF ( ASSIMP_ENABLE_BOOST_WORKAROUND ) | |||||
| INCLUDE_DIRECTORIES( code/BoostWorkaround ) | |||||
| ADD_DEFINITIONS( -DASSIMP_BUILD_BOOST_WORKAROUND ) | |||||
| MESSAGE( STATUS "Building a non-boost version of Assimp." ) | |||||
| ELSE ( ASSIMP_ENABLE_BOOST_WORKAROUND ) | |||||
| SET( Boost_DETAILED_FAILURE_MSG ON ) | |||||
| SET( Boost_ADDITIONAL_VERSIONS "1.47" "1.47.0" "1.48.0" "1.48" "1.49" "1.49.0" "1.50" "1.50.0" "1.51" "1.51.0" "1.52.0" "1.53.0" "1.54.0" "1.55" ) | |||||
| FIND_PACKAGE( Boost ) | |||||
| IF ( NOT Boost_FOUND ) | |||||
| MESSAGE( FATAL_ERROR | |||||
| "Boost libraries (http://www.boost.org/) not found. " | |||||
| "You can build a non-boost version of Assimp with slightly reduced " | |||||
| "functionality by specifying -DASSIMP_ENABLE_BOOST_WORKAROUND=ON." | |||||
| ) | |||||
| ENDIF ( NOT Boost_FOUND ) | |||||
| INCLUDE_DIRECTORIES( ${Boost_INCLUDE_DIRS} ) | |||||
| ENDIF ( ASSIMP_ENABLE_BOOST_WORKAROUND ) | |||||
| # 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) | |||||
| 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}) | |||||
| SET ( ASSIMP_NO_EXPORT OFF CACHE BOOL | |||||
| "Disable Assimp's export functionality." | |||||
| ) | |||||
| # Search for external dependencies, and build them from source if not found | |||||
| # Search for zlib | |||||
| find_package(ZLIB) | |||||
| if( NOT ZLIB_FOUND ) | |||||
| message(STATUS "compiling zlib from souces") | |||||
| include(CheckIncludeFile) | |||||
| include(CheckTypeSize) | |||||
| include(CheckFunctionExists) | |||||
| # compile from sources | |||||
| add_subdirectory(contrib/zlib) | |||||
| set(ZLIB_FOUND 1) | |||||
| set(ZLIB_LIBRARIES zlibstatic) | |||||
| set(ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/contrib/zlib ${CMAKE_CURRENT_BINARY_DIR}/contrib/zlib) | |||||
| else(NOT ZLIB_FOUND) | |||||
| ADD_DEFINITIONS(-DASSIMP_BUILD_NO_OWN_ZLIB) | |||||
| endif(NOT ZLIB_FOUND) | |||||
| INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIR}) | |||||
| # Search for unzip | |||||
| if (PKG_CONFIG_FOUND) | |||||
| PKG_CHECK_MODULES(UNZIP minizip) | |||||
| endif (PKG_CONFIG_FOUND) | |||||
| IF ( ASSIMP_NO_EXPORT ) | |||||
| ADD_DEFINITIONS( -DASSIMP_BUILD_NO_EXPORT) | |||||
| MESSAGE( STATUS "Build an import-only version of Assimp." ) | |||||
| ENDIF( ASSIMP_NO_EXPORT ) | |||||
| # if(CMAKE_CL_64) | |||||
| # set(ASSIMP_BUILD_ARCHITECTURE "amd64") | |||||
| # else(CMAKE_CL_64) | |||||
| # set(ASSIMP_BUILD_ARCHITECTURE "x86") | |||||
| # endif(CMAKE_CL_64) | |||||
| SET ( ASSIMP_BUILD_ARCHITECTURE "" CACHE STRING | |||||
| "describe the current architecture." | |||||
| ) | |||||
| IF ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "") | |||||
| ELSE ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "") | |||||
| ADD_DEFINITIONS ( -D'ASSIMP_BUILD_ARCHITECTURE="${ASSIMP_BUILD_ARCHITECTURE}"' ) | |||||
| ENDIF ( ASSIMP_BUILD_ARCHITECTURE STREQUAL "") | |||||
| # ${CMAKE_GENERATOR} | |||||
| SET ( ASSIMP_BUILD_COMPILER "" CACHE STRING | |||||
| "describe the current compiler." | |||||
| ) | |||||
| IF ( ASSIMP_BUILD_COMPILER STREQUAL "") | |||||
| ELSE ( ASSIMP_BUILD_COMPILER STREQUAL "") | |||||
| ADD_DEFINITIONS ( -D'ASSIMP_BUILD_COMPILER="${ASSIMP_BUILD_COMPILER}"' ) | |||||
| ENDIF ( ASSIMP_BUILD_COMPILER STREQUAL "") | |||||
| MARK_AS_ADVANCED ( ASSIMP_BUILD_ARCHITECTURE ASSIMP_BUILD_COMPILER ) | |||||
| ADD_SUBDIRECTORY( code/ ) | |||||
| SET ( ASSIMP_BUILD_ASSIMP_TOOLS ON CACHE BOOL | |||||
| "If the supplementary tools for Assimp are built in addition to the library." | |||||
| ) | |||||
| IF ( ASSIMP_BUILD_ASSIMP_TOOLS ) | |||||
| IF ( WIN32 ) | |||||
| ADD_SUBDIRECTORY( tools/assimp_view/ ) | |||||
| ENDIF ( WIN32 ) | |||||
| ADD_SUBDIRECTORY( tools/assimp_cmd/ ) | |||||
| ENDIF ( ASSIMP_BUILD_ASSIMP_TOOLS ) | |||||
| SET ( ASSIMP_BUILD_SAMPLES OFF CACHE BOOL | |||||
| "If the official samples are built as well (needs Glut)." | |||||
| ) | |||||
| IF ( ASSIMP_BUILD_SAMPLES) | |||||
| IF ( WIN32 ) | |||||
| ADD_SUBDIRECTORY( samples/SimpleTexturedOpenGL/ ) | |||||
| ENDIF ( WIN32 ) | |||||
| ADD_SUBDIRECTORY( samples/SimpleOpenGL/ ) | |||||
| ENDIF ( ASSIMP_BUILD_SAMPLES ) | |||||
| IF ( WIN32 ) | |||||
| SET ( ASSIMP_BUILD_TESTS ON CACHE BOOL | |||||
| "If the test suite for Assimp is built in addition to the library." | |||||
| ) | |||||
| IF ( ASSIMP_BUILD_TESTS ) | |||||
| ADD_SUBDIRECTORY( test/ ) | |||||
| ENDIF ( ASSIMP_BUILD_TESTS ) | |||||
| ENDIF ( WIN32 ) | |||||
| IF(MSVC) | |||||
| SET ( ASSIMP_INSTALL_PDB ON CACHE BOOL | |||||
| "Install MSVC debug files." | |||||
| ) | |||||
| ENDIF(MSVC) | |||||
| if(CMAKE_CPACK_COMMAND AND UNIX AND ASSIMP_OPT_BUILD_PACKAGES) | |||||
| # Packing information | |||||
| set(CPACK_PACKAGE_NAME "assimp{ASSIMP_VERSION_MAJOR}") | |||||
| set(CPACK_PACKAGE_CONTACT "" CACHE STRING "Package maintainer and PGP signer.") | |||||
| set(CPACK_PACKAGE_VENDOR "http://assimp.sourceforge.net/") | |||||
| set(CPACK_PACKAGE_DISPLAY_NAME "Assimp ${ASSIMP_VERSION}") | |||||
| set(CPACK_PACKAGE_DESCRIPTION_SUMMARY " - Open Asset Import Library ${ASSIMP_VERSION}") | |||||
| set(CPACK_PACKAGE_VERSION "${ASSIMP_VERSION}.${ASSIMP_PACKAGE_VERSION}" ) | |||||
| set(CPACK_PACKAGE_VERSION_MAJOR "${ASSIMP_VERSION_MAJOR}") | |||||
| set(CPACK_PACKAGE_VERSION_MINOR "${ASSIMP_VERSION_MINOR}") | |||||
| set(CPACK_PACKAGE_VERSION_PATCH "${ASSIMP_VERSION_PATCH}") | |||||
| set(CPACK_PACKAGE_INSTALL_DIRECTORY "assimp${ASSIMP_VERSION_MAJOR}.${ASSIMP_VERSION_MINOR}") | |||||
| #set(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/description") | |||||
| set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") | |||||
| string(TOUPPER ${LIBASSIMP_COMPONENT} "LIBASSIMP_COMPONENT_UPPER") | |||||
| string(TOUPPER ${LIBASSIMP-DEV_COMPONENT} "LIBASSIMP-DEV_COMPONENT_UPPER") | |||||
| set(CPACK_COMPONENT_ASSIMP-BIN_DISPLAY_NAME "tools") | |||||
| set(CPACK_COMPONENT_ASSIMP-BIN_DEPENDS "${LIBASSIMP_COMPONENT}" ) | |||||
| set(CPACK_COMPONENT_${LIBASSIMP_COMPONENT_UPPER}_DISPLAY_NAME "libraries") | |||||
| set(CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT_UPPER}_DISPLAY_NAME "common headers and installs") | |||||
| set(CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT_UPPER}_DEPENDS $ "{LIBASSIMP_COMPONENT}" ) | |||||
| set(CPACK_COMPONENT_ASSIMP-DEV_DISPLAY_NAME "${CPACK_COMPONENT_${LIBASSIMP-DEV_COMPONENT}_DISPLAY_NAME}" ) | |||||
| set(CPACK_COMPONENT_ASSIMP-DEV_DEPENDS "${LIBASSIMP-DEV_COMPONENT}" ) | |||||
| set(CPACK_DEBIAN_BUILD_DEPENDS debhelper cmake libboost-dev libboost-thread-dev libboost-math-dev zlib1g-dev pkg-config) | |||||
| # debian | |||||
| set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") | |||||
| set(CPACK_DEBIAN_CMAKE_OPTIONS "-DBUILD_ASSIMP_SAMPLES:BOOL=${ASSIMP_BUILD_SAMPLES}") | |||||
| set(CPACK_DEBIAN_PACKAGE_SECTION "libs" ) | |||||
| set(CPACK_DEBIAN_PACKAGE_DEPENDS "${CPACK_COMPONENTS_ALL}") | |||||
| set(CPACK_DEBIAN_PACKAGE_SUGGESTS) | |||||
| set(CPACK_DEBIAN_PACKAGE_NAME "assimp") | |||||
| set(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES contrib/cppunit-1.12.1 contrib/cppunit_note.txt contrib/zlib workspaces test doc obj samples packaging) | |||||
| set(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force) | |||||
| set(CPACK_DEBIAN_CHANGELOG) | |||||
| execute_process(COMMAND lsb_release -is | |||||
| OUTPUT_VARIABLE _lsb_distribution OUTPUT_STRIP_TRAILING_WHITESPACE | |||||
| RESULT_VARIABLE _lsb_release_failed) | |||||
| set(CPACK_DEBIAN_DISTRIBUTION_NAME ${_lsb_distribution} CACHE STRING "Name of the distrubiton") | |||||
| string(TOLOWER ${CPACK_DEBIAN_DISTRIBUTION_NAME} CPACK_DEBIAN_DISTRIBUTION_NAME) | |||||
| if( ${CPACK_DEBIAN_DISTRIBUTION_NAME} STREQUAL "ubuntu" ) | |||||
| set(CPACK_DEBIAN_DISTRIBUTION_RELEASES lucid maverick natty oneiric precise CACHE STRING "Release code-names of the distrubiton release") | |||||
| endif() | |||||
| set(DPUT_HOST "" CACHE STRING "PPA repository to upload the debian sources") | |||||
| include(CPack) | |||||
| include(DebSourcePPA) | |||||
| endif() | |||||
| @@ -0,0 +1,11 @@ | |||||
| copy /Y ".\workspaces\vs2013\x64\code\Release\assimp.lib" ".\lib\x64\assimp.lib" | |||||
| copy /Y ".\workspaces\vs2013\x64\code\Debug\assimpd.lib" ".\lib\x64\assimpd.lib" | |||||
| copy /Y ".\workspaces\vs2013\x64\contrib\zlib\Release\zlibstatic.lib" ".\lib\x64\zlibstatic.lib" | |||||
| copy /Y ".\workspaces\vs2013\x64\contrib\zlib\Debug\zlibstaticd.lib" ".\lib\x64\zlibstaticd.lib" | |||||
| copy /Y ".\workspaces\vs2013\win32\code\Release\assimp.lib" ".\lib\win32\assimp.lib" | |||||
| copy /Y ".\workspaces\vs2013\win32\code\Debug\assimpd.lib" ".\lib\win32\assimpd.lib" | |||||
| copy /Y ".\workspaces\vs2013\win32\contrib\zlib\Release\zlibstatic.lib" ".\lib\win32\zlibstatic.lib" | |||||
| copy /Y ".\workspaces\vs2013\win32\contrib\zlib\Debug\zlibstaticd.lib" ".\lib\win32\zlibstaticd.lib" | |||||
| pause | |||||
| @@ -0,0 +1,150 @@ | |||||
| =============================================================== | |||||
| Open Asset Import Library (Assimp) | |||||
| Developers and Contributors | |||||
| =============================================================== | |||||
| The following is a non-exhaustive list of all constributors over the years. | |||||
| If you think your name should be listed here, drop us a line and we'll add you. | |||||
| - Alexander Gessler, | |||||
| 3DS-, BLEND-, ASE-, DXF-, HMP-, MDL-, MD2-, MD3-, MD5-, MDC-, NFF-, PLY-, STL-, RAW-, OFF-, MS3D-, Q3D- and LWO-Loader, Assimp-Viewer, assimp-cmd, -noboost, Website (Admin and Design). | |||||
| - Thomas Schulze, | |||||
| X-, Collada-, BVH-Loader, Postprocessing framework. Data structure & Interface design, documentation. | |||||
| - Kim Kulling, | |||||
| Obj-Loader, Logging system, Scons-build environment, CMake build environment, Linux build. | |||||
| - R.Schmidt, | |||||
| Linux build, eclipse support. | |||||
| - Matthias Gubisch, | |||||
| Assimp.net | |||||
| Visual Studio 9 support, bugfixes. | |||||
| - Mark Sibly | |||||
| B3D-Loader, Assimp testing | |||||
| - Jonathan Klein | |||||
| Ogre Loader, VC2010 fixes and CMake fixes. | |||||
| - Sebastian Hempel, | |||||
| PyAssimp (first version) | |||||
| Compile-Bugfixes for mingw, add enviroment for static library support in make. | |||||
| - Jonathan Pokrass | |||||
| Supplied a bugfix concerning the scaling in the md3 loader. | |||||
| - Andrew Galante, | |||||
| Submitted patches to make Assimp compile with GCC-4, a makefile and the xcode3 workspace. | |||||
| - Andreas Nagel | |||||
| First Assimp testing & verification under Windows Vista 64 Bit. | |||||
| - Marius Schr�der | |||||
| Allowed us to use many of his models for screenshots and testing. | |||||
| - Christian Schubert | |||||
| Supplied various XFiles for testing purposes. | |||||
| - Tizian Wieland | |||||
| Searched the web for hundreds of test models for internal use | |||||
| - John Connors | |||||
| Supplied patches for linux and SCons. | |||||
| - T. R. | |||||
| The GUY who performed some of the CSM mocaps. | |||||
| - Andy Maloney | |||||
| Contributed fixes for the documentation and the doxygen markup | |||||
| - Zhao Lei | |||||
| Contributed several bugfixes fixing memory leaks and improving float parsing | |||||
| - sueastside | |||||
| Updated PyAssimp to the latest Assimp data structures and provided a script to keep the Python binding up-to-date. | |||||
| - Tobias Rittig | |||||
| Collada testing with Cinema 4D | |||||
| - Brad Grantham | |||||
| Improvements in OpenGL-Sample. | |||||
| - Robert Ramirez | |||||
| Add group loading feature to Obj-Loader. | |||||
| - Chris Maiwald | |||||
| Many bugreports, improving Assimp's portability, regular testing & feedback. | |||||
| - Stepan Hrbek | |||||
| Bugreport and fix for a obj-materialloader crash. | |||||
| - David Nadlinger | |||||
| D bindings, CMake install support. | |||||
| - Dario Accornero | |||||
| Contributed several patches regarding Mac OS/XCode targets, bug reports. | |||||
| - Martin Walser (Samhayne) | |||||
| Contributed the 'SimpleTexturedOpenGl' sample. | |||||
| - Matthias Fauconneau | |||||
| Contributed a fix for the Q3-BSP loader. | |||||
| - J�rgen P. Tjern� | |||||
| Contributed updated and improved xcode workspaces | |||||
| - drparallax | |||||
| Contributed the /samples/SimpleAssimpViewX sample | |||||
| - Carsten Fuchs | |||||
| Contributed a fix for the Normalize method in aiQuaternion. | |||||
| - dbburgess | |||||
| Contributes a Android-specific build issue: log the hardware architecture for ARM. | |||||
| - alfiereinre7 | |||||
| Contributes a obj-fileparser fix: missing tokens in the obj-token list. | |||||
| - Roman Kharitonov | |||||
| Contributes a fix for the configure script environment. | |||||
| - Ed Diana | |||||
| Contributed AssimpDelphi (/port/AssimpDelphi). | |||||
| - rdb | |||||
| Contributes a bundle of fixes and improvments for the bsp-importer. | |||||
| - Mick P | |||||
| For contributing the De-bone postprocessing step and filing various bug reports. | |||||
| - Rosen Diankov | |||||
| Contributed patches to build assimp debian packages using cmake. | |||||
| - Mark Page | |||||
| Contributed a patch to fix the VertexTriangleAdjacency postprocessing step. | |||||
| - IOhannes | |||||
| Contributed the Debian build fixes ( architecture macro ). | |||||
| - gellule | |||||
| Several LWO and LWS fixes (pivoting). | |||||
| - Marcel Metz | |||||
| GCC/Linux fixes for the SimpleOpenGL sample. | |||||
| - Brian Miller | |||||
| Bugfix for a compiler fix for iOS on arm. | |||||
| - S�verin Lemaignan | |||||
| Rewrite of PyAssimp, distutils and Python3 support | |||||
| - albert-wang | |||||
| Bugfixes for the collada parser | |||||
| - Ya ping Jin | |||||
| Bugfixes for uv-tanget calculation. | |||||
| - Jonne Nauha | |||||
| Ogre Binary format support | |||||
| @@ -0,0 +1,14 @@ | |||||
| =============================================== | |||||
| The Asset-Importer-Library Coding conventions | |||||
| =============================================== | |||||
| If you want to participate to the Asset-Importer_Library please have a look | |||||
| onto these coding conventions and try to follow them. They are more or less | |||||
| some kind of guide line to help others coming into the code and help all | |||||
| the Asset-Importer-Library users. | |||||
| Tab width | |||||
| =========== | |||||
| The tab width shall be 4 spaces. | |||||
| @@ -0,0 +1,45 @@ | |||||
| ======================================================================== | |||||
| Open Asset Import Library (assimp) INSTALL | |||||
| ======================================================================== | |||||
| ------------------------------ | |||||
| Getting the documentation | |||||
| ------------------------------ | |||||
| A regularly-updated copy is available at | |||||
| http://assimp.sourceforge.net/lib_html/index.html | |||||
| A CHM file is included in the SVN repos: ./doc/AssimpDoc_Html/AssimpDoc.chm. | |||||
| To build the doxygen documentation on your own, follow these steps: | |||||
| a) download & install latest doxygen | |||||
| b) make sure doxygen is in the executable search path | |||||
| c) navigate to ./doc | |||||
| d) and run 'doxygen' | |||||
| Open the generated HTML (AssimpDoc_Html/index.html) in the browser of your choice. | |||||
| Windows only: To generate the CHM doc, install 'Microsoft HTML Workshop' | |||||
| and configure the path to it in the DOXYFILE first. | |||||
| ------------------------------ | |||||
| Building Assimp | |||||
| ------------------------------ | |||||
| More detailed build instructions can be found in the documentation, | |||||
| this section is just for the inpatient among you. | |||||
| CMake is the preferred build system for Assimp. The minimum required version | |||||
| is 2.6. If you don't have it yet, downloads for CMake can be found on | |||||
| http://www.cmake.org/. | |||||
| Building Assimp with CMake is 'business as usual' if you've used CMake | |||||
| before. All steps can be done either on the command line / shell or | |||||
| by using the CMake GUI tool, the choice is up to you. | |||||
| First, invoke CMake to generate build files for a particular | |||||
| toolchain (for standard GNU makefiles: cmake -G 'Unix Makefiles'). | |||||
| Afterwards, use the generated build files to perform the actual | |||||
| build. | |||||
| @@ -0,0 +1,84 @@ | |||||
| Open Asset Import Library (assimp) | |||||
| 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. | |||||
| ****************************************************************************** | |||||
| AN EXCEPTION applies to all files in the ./test/models-nonbsd folder. | |||||
| These are 3d models for testing purposes, from various free sources | |||||
| on the internet. They are - unless otherwise stated - copyright of | |||||
| their respective creators, which may impose additional requirements | |||||
| on the use of their work. For any of these models, see | |||||
| <model-name>.source.txt for more legal information. Contact us if you | |||||
| are a copyright holder and believe that we credited you inproperly or | |||||
| if you don't want your files to appear in the repository. | |||||
| ****************************************************************************** | |||||
| Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors | |||||
| http://code.google.com/p/poly2tri/ | |||||
| All rights reserved. | |||||
| Redistribution and use in source and binary forms, with or without modification, | |||||
| are permitted provided that the following conditions are met: | |||||
| * Redistributions of source code must retain the above copyright notice, | |||||
| this list of conditions and the following disclaimer. | |||||
| * Redistributions in binary form must reproduce the above copyright notice, | |||||
| this list of conditions and the following disclaimer in the documentation | |||||
| and/or other materials provided with the distribution. | |||||
| * Neither the name of Poly2Tri nor the names of its contributors may be | |||||
| used to endorse or promote products derived from this software without specific | |||||
| prior written permission. | |||||
| 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. | |||||
| @@ -0,0 +1 @@ | |||||
| See Readme.md | |||||
| @@ -0,0 +1,120 @@ | |||||
| Open Asset Import Library (assimp) | |||||
| ======== | |||||
| Open Asset Import Library is a Open Source library designed to load various __3d file formats and convert them into a shared, in-memory format__. It supports more than __30 file formats__ for import and a growing selection of file formats for export. Additionally, assimp features various __post processing tools__ to refine the imported data: _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 of assimp 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. According to [Travis-CI] (https://travis-ci.org/), the current build status of the trunk is [](https://travis-ci.org/assimp/assimp) | |||||
| #### Supported file formats #### | |||||
| The library provides importers for a lot of file formats, including: | |||||
| - 3DS | |||||
| - BLEND (Blender 3D) | |||||
| - DAE/Collada | |||||
| - FBX | |||||
| - IFC-STEP | |||||
| - ASE | |||||
| - DXF | |||||
| - HMP | |||||
| - MD2 | |||||
| - MD3 | |||||
| - MD5 | |||||
| - MDC | |||||
| - MDL | |||||
| - NFF | |||||
| - PLY | |||||
| - STL | |||||
| - X | |||||
| - OBJ | |||||
| - SMD | |||||
| - LWO | |||||
| - LXO | |||||
| - LWS | |||||
| - TER | |||||
| - AC3D | |||||
| - MS3D | |||||
| - COB | |||||
| - Q3BSP | |||||
| - XGL | |||||
| - CSM | |||||
| - BVH | |||||
| - B3D | |||||
| - NDO | |||||
| - Ogre Binary | |||||
| - Ogre XML | |||||
| - Q3D | |||||
| Additionally, the following formats are also supported, but not part of the core library as they depend on proprietary libraries. | |||||
| - C4D (https://github.com/acgessler/assimp-cinema4d) | |||||
| Exporters include: | |||||
| - DAE (Collada) | |||||
| - STL | |||||
| - OBJ | |||||
| - PLY | |||||
| - JSON (for WebGl, via https://github.com/acgessler/assimp2json) | |||||
| See [the full list here](http://assimp.sourceforge.net/main_features_formats.html). | |||||
| #### Repository structure #### | |||||
| Open Asset Import Library is implemented in C++ (but provides both a C and a | |||||
| C++ish interface). The directory structure is: | |||||
| /bin Folder for binaries, only used on Windows | |||||
| /code Source code | |||||
| /contrib Third-party libraries | |||||
| /doc Documentation (doxysource and pre-compiled docs) | |||||
| /include Public header C and C++ header files | |||||
| /lib Static library location for Windows | |||||
| /obj Object file location for Windows | |||||
| /scripts Scripts used to generate the loading code for some formats | |||||
| /port Ports to other languages and scripts to maintain those. | |||||
| /test Unit- and regression tests, test suite of models | |||||
| /tools Tools (viewer, command line `assimp`) | |||||
| /samples A small number of samples to illustrate possible | |||||
| use cases for Assimp | |||||
| /workspaces Build enviroments for vc,xcode,... (deprecated, | |||||
| CMake has superseeded all legacy build options!) | |||||
| ### Building ### | |||||
| Take a look into the `INSTALL` file. Our build system is CMake, if you already used CMake before there is a good chance you know what to do. | |||||
| ### Where to get help ### | |||||
| For more information, visit [our website](http://assimp.sourceforge.net/). Or check out the `./doc`- folder, which contains the official documentation in HTML format. | |||||
| (CHMs for Windows are included in some release packages and should be located right here in the root folder). | |||||
| If the documentation doesn't solve your problems, | |||||
| [try our forums at SF.net](http://sourceforge.net/p/assimp/discussion/817654) or ask on | |||||
| [StackOverflow](http://stackoverflow.com/questions/tagged/assimp?sort=newest). | |||||
| For development discussions, there is also a mailing list, _assimp-discussions_ | |||||
| [(subscribe here)]( https://lists.sourceforge.net/lists/listinfo/assimp-discussions) | |||||
| ### Contributing ### | |||||
| 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. | |||||
| ### License ### | |||||
| Our license is based on the modified, __3-clause BSD__-License, which is very liberal. | |||||
| An _informal_ summary is: do whatever you want, but include Assimp's license text with your product - | |||||
| and don't sue us if our code doesn't work. Note that, unlike LGPLed code, you may link statically to Assimp. | |||||
| For the legal details, see the `LICENSE` file. | |||||
| @@ -0,0 +1,13 @@ | |||||
| set( PACKAGE_VERSION "@ASSIMP_VERSION@" ) | |||||
| if( "${PACKAGE_FIND_VERSION}" VERSION_EQUAL "@ASSIMP_VERSION@") | |||||
| set(PACKAGE_VERSION_EXACT 1) | |||||
| endif() | |||||
| if( "${PACKAGE_FIND_VERSION_MAJOR}.${PACKAGE_FIND_VERSION_MINOR}" EQUAL "@ASSIMP_SOVERSION@" ) | |||||
| set(PACKAGE_VERSION_COMPATIBLE 1) | |||||
| elseif( "${PACKAGE_FIND_VERSION_MAJOR}" EQUAL "@ASSIMP_VERSION_MAJOR@" ) | |||||
| # for now backward compatible if minor version is less | |||||
| if( ${PACKAGE_FIND_VERSION_MINOR} LESS @ASSIMP_VERSION_MINOR@ ) | |||||
| set(PACKAGE_VERSION_COMPATIBLE 1) | |||||
| endif() | |||||
| endif() | |||||
| set( ASSIMP_STATIC_LIB "@ASSIMP_BUILD_STATIC_LIB@") | |||||
| @@ -0,0 +1,75 @@ | |||||
| # - Find Assimp Installation | |||||
| # | |||||
| # Users can set the following variables before calling the module: | |||||
| # ASSIMP_DIR - The preferred installation prefix for searching for ASSIMP. Set by the user. | |||||
| # | |||||
| # ASSIMP_ROOT_DIR - the root directory where the installation can be found | |||||
| # ASSIMP_CXX_FLAGS - extra flags for compilation | |||||
| # ASSIMP_LINK_FLAGS - extra flags for linking | |||||
| # ASSIMP_INCLUDE_DIRS - include directories | |||||
| # ASSIMP_LIBRARY_DIRS - link directories | |||||
| # ASSIMP_LIBRARIES - libraries to link plugins with | |||||
| # ASSIMP_Boost_VERSION - the boost version assimp was compiled with | |||||
| get_filename_component(_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) | |||||
| get_filename_component(_PREFIX "${_PREFIX}" PATH) | |||||
| get_filename_component(_PREFIX "${_PREFIX}" PATH) | |||||
| get_filename_component(ASSIMP_ROOT_DIR "${_PREFIX}" PATH) | |||||
| if( MSVC ) | |||||
| # in order to prevent DLL hell, each of the DLLs have to be suffixed with the major version and msvc prefix | |||||
| if( MSVC70 OR MSVC71 ) | |||||
| set(MSVC_PREFIX "vc70") | |||||
| elseif( MSVC80 ) | |||||
| set(MSVC_PREFIX "vc80") | |||||
| elseif( MSVC90 ) | |||||
| set(MSVC_PREFIX "vc90") | |||||
| else() | |||||
| set(MSVC_PREFIX "vc100") | |||||
| endif() | |||||
| set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@-${MSVC_PREFIX}-mt" CACHE STRING "the suffix for the assimp windows library" FORCE) | |||||
| else() | |||||
| set(ASSIMP_LIBRARY_SUFFIX "@ASSIMP_LIBRARY_SUFFIX@" CACHE STRING "the suffix for the openrave libraries" FORCE) | |||||
| endif() | |||||
| set( ASSIMP_CXX_FLAGS ) # dynamically linked library | |||||
| if( WIN32 ) | |||||
| # for visual studio linking, most of the time boost dlls will be used | |||||
| set( ASSIMP_CXX_FLAGS " -DBOOST_ALL_DYN_LINK -DBOOST_ALL_NO_LIB") | |||||
| endif() | |||||
| set( ASSIMP_LINK_FLAGS "" ) | |||||
| set( ASSIMP_LIBRARY_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_LIB_INSTALL_DIR@") | |||||
| set( ASSIMP_INCLUDE_DIRS "${ASSIMP_ROOT_DIR}/@ASSIMP_INCLUDE_INSTALL_DIR@") | |||||
| set( ASSIMP_LIBRARIES assimp${ASSIMP_LIBRARY_SUFFIX}) | |||||
| if (CMAKE_BUILD_TYPE EQUAL "DEBUG") | |||||
| set( ASSIMP_LIBRARIES ${ASSIMP_LIBRARIES}D) | |||||
| endif (CMAKE_BUILD_TYPE EQUAL "DEBUG") | |||||
| # search for the boost version assimp was compiled with | |||||
| #set(Boost_USE_MULTITHREAD ON) | |||||
| #set(Boost_USE_STATIC_LIBS OFF) | |||||
| #set(Boost_USE_STATIC_RUNTIME OFF) | |||||
| #find_package(Boost ${ASSIMP_Boost_VERSION} EXACT COMPONENTS thread date_time) | |||||
| #if(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") | |||||
| # set( ASSIMP_INCLUDE_DIRS "${ASSIMP_INCLUDE_DIRS}" ${Boost_INCLUDE_DIRS}) | |||||
| #else(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") | |||||
| # message(WARNING "Failed to find Boost ${ASSIMP_Boost_VERSION} necessary for assimp") | |||||
| #endif(Boost_VERSION AND NOT "${Boost_VERSION}" STREQUAL "0") | |||||
| # the boost version assimp was compiled with | |||||
| set( ASSIMP_Boost_VERSION "@Boost_MAJOR_VERSION@.@Boost_MINOR_VERSION@") | |||||
| # for compatibility wiht pkg-config | |||||
| set(ASSIMP_CFLAGS_OTHER "${ASSIMP_CXX_FLAGS}") | |||||
| set(ASSIMP_LDFLAGS_OTHER "${ASSIMP_LINK_FLAGS}") | |||||
| MARK_AS_ADVANCED( | |||||
| ASSIMP_ROOT_DIR | |||||
| ASSIMP_CXX_FLAGS | |||||
| ASSIMP_LINK_FLAGS | |||||
| ASSIMP_INCLUDE_DIRS | |||||
| ASSIMP_LIBRARIES | |||||
| ASSIMP_Boost_VERSION | |||||
| ASSIMP_CFLAGS_OTHER | |||||
| ASSIMP_LDFLAGS_OTHER | |||||
| ASSIMP_LIBRARY_SUFFIX | |||||
| ) | |||||
| @@ -0,0 +1,10 @@ | |||||
| prefix=@CMAKE_INSTALL_PREFIX@ | |||||
| exec_prefix=@CMAKE_INSTALL_PREFIX@/@ASSIMP_BIN_INSTALL_DIR@ | |||||
| libdir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_LIB_INSTALL_DIR@ | |||||
| includedir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_INCLUDE_INSTALL_DIR@/assimp | |||||
| Name: @CMAKE_PROJECT_NAME@ | |||||
| Description: Import various well-known 3D model formats in an uniform manner. | |||||
| Version: @PROJECT_VERSION@ | |||||
| Libs: -L${libdir} -lassimp@ASSIMP_LIBRARY_SUFFIX@ | |||||
| Cflags: -I${includedir} | |||||
| @@ -0,0 +1,347 @@ | |||||
| ## Debian Source Package Generator | |||||
| # | |||||
| # Copyright (c) 2010 Daniel Pfeifer <daniel@pfeifer-mail.de> | |||||
| # Many modifications by Rosen Diankov <rosen.diankov@gmail.com> | |||||
| # | |||||
| # Creates source debian files and manages library dependencies | |||||
| # | |||||
| # Features: | |||||
| # | |||||
| # - Automatically generates symbols and run-time dependencies from the build dependencies | |||||
| # - Custom copy of source directory via CPACK_DEBIAN_PACKAGE_SOURCE_COPY | |||||
| # - Simultaneous output of multiple debian source packages for each distribution | |||||
| # - Can specificy distribution-specific dependencies by suffixing DEPENDS with _${DISTRO_NAME}, for example: CPACK_DEBIAN_PACKAGE_DEPENDS_LUCID, CPACK_COMPONENT_MYCOMP0_DEPENDS_LUCID | |||||
| # | |||||
| # Usage: | |||||
| # | |||||
| # set(CPACK_DEBIAN_BUILD_DEPENDS debhelper cmake) | |||||
| # set(CPACK_DEBIAN_PACKAGE_PRIORITY optional) | |||||
| # set(CPACK_DEBIAN_PACKAGE_SECTION devel) | |||||
| # set(CPACK_DEBIAN_CMAKE_OPTIONS "-DMYOPTION=myvalue") | |||||
| # set(CPACK_DEBIAN_PACKAGE_DEPENDS mycomp0 mycomp1 some_ubuntu_package) | |||||
| # set(CPACK_DEBIAN_PACKAGE_DEPENDS_UBUNTU_LUCID mycomp0 mycomp1 lucid_specific_package) | |||||
| # set(CPACK_DEBIAN_PACKAGE_NAME mypackage) | |||||
| # set(CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES unnecessary_file unnecessary_dir/file0) | |||||
| # set(CPACK_DEBIAN_PACKAGE_SOURCE_COPY svn export --force) # if using subversion | |||||
| # set(CPACK_DEBIAN_DISTRIBUTION_NAME ubuntu) | |||||
| # set(CPACK_DEBIAN_DISTRIBUTION_RELEASES karmic lucid maverick natty) | |||||
| # set(CPACK_DEBIAN_CHANGELOG " * Extra change log lines") | |||||
| # set(CPACK_DEBIAN_PACKAGE_SUGGESTS "ipython") | |||||
| # set(CPACK_COMPONENT_X_RECOMMENDS "recommended-package") | |||||
| ## | |||||
| find_program(DEBUILD_EXECUTABLE debuild) | |||||
| find_program(DPUT_EXECUTABLE dput) | |||||
| if(NOT DEBUILD_EXECUTABLE OR NOT DPUT_EXECUTABLE) | |||||
| return() | |||||
| endif(NOT DEBUILD_EXECUTABLE OR NOT DPUT_EXECUTABLE) | |||||
| # DEBIAN/control | |||||
| # debian policy enforce lower case for package name | |||||
| # Package: (mandatory) | |||||
| IF(NOT CPACK_DEBIAN_PACKAGE_NAME) | |||||
| STRING(TOLOWER "${CPACK_PACKAGE_NAME}" CPACK_DEBIAN_PACKAGE_NAME) | |||||
| ENDIF(NOT CPACK_DEBIAN_PACKAGE_NAME) | |||||
| # Section: (recommended) | |||||
| IF(NOT CPACK_DEBIAN_PACKAGE_SECTION) | |||||
| SET(CPACK_DEBIAN_PACKAGE_SECTION "devel") | |||||
| ENDIF(NOT CPACK_DEBIAN_PACKAGE_SECTION) | |||||
| # Priority: (recommended) | |||||
| IF(NOT CPACK_DEBIAN_PACKAGE_PRIORITY) | |||||
| SET(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") | |||||
| ENDIF(NOT CPACK_DEBIAN_PACKAGE_PRIORITY) | |||||
| file(STRINGS ${CPACK_PACKAGE_DESCRIPTION_FILE} DESC_LINES) | |||||
| foreach(LINE ${DESC_LINES}) | |||||
| set(DEB_LONG_DESCRIPTION "${DEB_LONG_DESCRIPTION} ${LINE}\n") | |||||
| endforeach(LINE ${DESC_LINES}) | |||||
| file(REMOVE_RECURSE "${CMAKE_BINARY_DIR}/Debian") | |||||
| file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/Debian") | |||||
| set(DEBIAN_SOURCE_ORIG_DIR "${CMAKE_BINARY_DIR}/Debian/${CPACK_DEBIAN_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}") | |||||
| if( CPACK_DEBIAN_PACKAGE_SOURCE_COPY ) | |||||
| execute_process(COMMAND ${CPACK_DEBIAN_PACKAGE_SOURCE_COPY} "${CMAKE_SOURCE_DIR}" "${DEBIAN_SOURCE_ORIG_DIR}.orig") | |||||
| else() | |||||
| execute_process(COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR} "${DEBIAN_SOURCE_ORIG_DIR}.orig") | |||||
| execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${DEBIAN_SOURCE_ORIG_DIR}.orig/.git") | |||||
| execute_process(COMMAND ${CMAKE_COMMAND} -E remove_directory "${DEBIAN_SOURCE_ORIG_DIR}.orig/.svn") | |||||
| endif() | |||||
| # remove unnecessary folders | |||||
| foreach(REMOVE_DIR ${CPACK_DEBIAN_PACKAGE_REMOVE_SOURCE_FILES}) | |||||
| file(REMOVE_RECURSE ${DEBIAN_SOURCE_ORIG_DIR}.orig/${REMOVE_DIR}) | |||||
| endforeach() | |||||
| # create the original source tar | |||||
| execute_process(COMMAND ${CMAKE_COMMAND} -E tar czf "${CPACK_DEBIAN_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}.orig.tar.gz" "${CPACK_DEBIAN_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}.orig" WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debian) | |||||
| set(DEB_SOURCE_CHANGES) | |||||
| foreach(RELEASE ${CPACK_DEBIAN_DISTRIBUTION_RELEASES}) | |||||
| set(DEBIAN_SOURCE_DIR "${DEBIAN_SOURCE_ORIG_DIR}-${CPACK_DEBIAN_DISTRIBUTION_NAME}1~${RELEASE}1") | |||||
| set(RELEASE_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION}-${CPACK_DEBIAN_DISTRIBUTION_NAME}1~${RELEASE}1") | |||||
| string(TOUPPER ${RELEASE} RELEASE_UPPER) | |||||
| string(TOUPPER ${CPACK_DEBIAN_DISTRIBUTION_NAME} DISTRIBUTION_NAME_UPPER) | |||||
| file(MAKE_DIRECTORY ${DEBIAN_SOURCE_DIR}/debian) | |||||
| ############################################################################## | |||||
| # debian/control | |||||
| set(DEBIAN_CONTROL ${DEBIAN_SOURCE_DIR}/debian/control) | |||||
| file(WRITE ${DEBIAN_CONTROL} | |||||
| "Source: ${CPACK_DEBIAN_PACKAGE_NAME}\n" | |||||
| "Section: ${CPACK_DEBIAN_PACKAGE_SECTION}\n" | |||||
| "Priority: ${CPACK_DEBIAN_PACKAGE_PRIORITY}\n" | |||||
| "DM-Upload-Allowed: yes\n" | |||||
| "Maintainer: ${CPACK_PACKAGE_CONTACT}\n" | |||||
| "Build-Depends: " | |||||
| ) | |||||
| if( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| foreach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) | |||||
| file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") | |||||
| endforeach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) | |||||
| else( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| if( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| foreach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) | |||||
| file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") | |||||
| endforeach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) | |||||
| else( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| foreach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS}) | |||||
| file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") | |||||
| endforeach(DEP ${CPACK_DEBIAN_BUILD_DEPENDS}) | |||||
| endif( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| endif( CPACK_DEBIAN_BUILD_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| file(APPEND ${DEBIAN_CONTROL} "\n" | |||||
| "Standards-Version: 3.8.4\n" | |||||
| "Homepage: ${CPACK_PACKAGE_VENDOR}\n" | |||||
| "\n" | |||||
| "Package: ${CPACK_DEBIAN_PACKAGE_NAME}\n" | |||||
| "Architecture: any\n" | |||||
| "Depends: " | |||||
| ) | |||||
| if( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| foreach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) | |||||
| file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") | |||||
| endforeach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) | |||||
| else( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| if( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| foreach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) | |||||
| file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") | |||||
| endforeach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) | |||||
| else( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| foreach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS}) | |||||
| file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") | |||||
| endforeach(DEP ${CPACK_DEBIAN_PACKAGE_DEPENDS}) | |||||
| endif( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| endif( CPACK_DEBIAN_PACKAGE_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| file(APPEND ${DEBIAN_CONTROL} "\nRecommends: ") | |||||
| if( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| foreach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) | |||||
| file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") | |||||
| endforeach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) | |||||
| else( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| if( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| foreach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}}) | |||||
| file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") | |||||
| endforeach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}}) | |||||
| else( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| foreach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS}) | |||||
| file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") | |||||
| endforeach(DEP ${CPACK_DEBIAN_PACKAGE_RECOMMENDS}) | |||||
| endif( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| endif( CPACK_DEBIAN_PACKAGE_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| file(APPEND ${DEBIAN_CONTROL} "\nSuggests: ") | |||||
| if( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| foreach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) | |||||
| file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") | |||||
| endforeach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) | |||||
| else( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| if( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| foreach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}}) | |||||
| file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") | |||||
| endforeach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}}) | |||||
| else( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| foreach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS}) | |||||
| file(APPEND ${DEBIAN_CONTROL} "${DEP}, ") | |||||
| endforeach(DEP ${CPACK_DEBIAN_PACKAGE_SUGGESTS}) | |||||
| endif( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| endif( CPACK_DEBIAN_PACKAGE_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| file(APPEND ${DEBIAN_CONTROL} "\n" | |||||
| "Description: ${CPACK_PACKAGE_DISPLAY_NAME} ${CPACK_PACKAGE_DESCRIPTION_SUMMARY}\n" | |||||
| "${DEB_LONG_DESCRIPTION}" | |||||
| ) | |||||
| foreach(COMPONENT ${CPACK_COMPONENTS_ALL}) | |||||
| string(TOUPPER ${COMPONENT} UPPER_COMPONENT) | |||||
| set(DEPENDS "\${shlibs:Depends}") | |||||
| if( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) | |||||
| set(DEPENDS "${DEPENDS}, ${DEP}") | |||||
| endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) | |||||
| else( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| if( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) | |||||
| set(DEPENDS "${DEPENDS}, ${DEP}") | |||||
| endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}}) | |||||
| else( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS}) | |||||
| set(DEPENDS "${DEPENDS}, ${DEP}") | |||||
| endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS}) | |||||
| endif( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| endif( CPACK_COMPONENT_${UPPER_COMPONENT}_DEPENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| set(RECOMMENDS) | |||||
| if( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) | |||||
| set(RECOMMENDS "${RECOMMENDS} ${DEP}, ") | |||||
| endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) | |||||
| else( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| if( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}}) | |||||
| set(RECOMMENDS "${RECOMMENDS} ${DEP}, ") | |||||
| endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}}) | |||||
| else( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS}) | |||||
| set(RECOMMENDS "${RECOMMENDS} ${DEP}, ") | |||||
| endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS}) | |||||
| endif( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| endif( CPACK_COMPONENT_${UPPER_COMPONENT}_RECOMMENDS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| set(SUGGESTS) | |||||
| if( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) | |||||
| set(SUGGESTS "${SUGGESTS} ${DEP}, ") | |||||
| endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER}}) | |||||
| else( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| if( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}}) | |||||
| set(SUGGESTS "${SUGGESTS} ${DEP}, ") | |||||
| endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}}) | |||||
| else( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| foreach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS}) | |||||
| set(SUGGESTS "${SUGGESTS} ${DEP}, ") | |||||
| endforeach(DEP ${CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS}) | |||||
| endif( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER} ) | |||||
| endif( CPACK_COMPONENT_${UPPER_COMPONENT}_SUGGESTS_${DISTRIBUTION_NAME_UPPER}_${RELEASE_UPPER} ) | |||||
| file(APPEND ${DEBIAN_CONTROL} "\n" | |||||
| "Package: ${COMPONENT}\n" | |||||
| "Architecture: any\n" | |||||
| "Depends: ${DEPENDS}\n" | |||||
| "Recommends: ${RECOMMENDS}\n" | |||||
| "Suggests: ${SUGGESTS}\n" | |||||
| "Description: ${CPACK_PACKAGE_DISPLAY_NAME} ${CPACK_COMPONENT_${UPPER_COMPONENT}_DISPLAY_NAME}\n" | |||||
| "${DEB_LONG_DESCRIPTION}" | |||||
| " .\n" | |||||
| " ${CPACK_COMPONENT_${UPPER_COMPONENT}_DESCRIPTION}\n" | |||||
| ) | |||||
| endforeach(COMPONENT ${CPACK_COMPONENTS_ALL}) | |||||
| ############################################################################## | |||||
| # debian/copyright | |||||
| set(DEBIAN_COPYRIGHT ${DEBIAN_SOURCE_DIR}/debian/copyright) | |||||
| execute_process(COMMAND ${CMAKE_COMMAND} -E | |||||
| copy ${CPACK_RESOURCE_FILE_LICENSE} ${DEBIAN_COPYRIGHT} | |||||
| ) | |||||
| ############################################################################## | |||||
| # debian/rules | |||||
| set(DEBIAN_RULES ${DEBIAN_SOURCE_DIR}/debian/rules) | |||||
| file(WRITE ${DEBIAN_RULES} | |||||
| "#!/usr/bin/make -f\n" | |||||
| "\n" | |||||
| "BUILDDIR = build_dir\n" | |||||
| "\n" | |||||
| "build:\n" | |||||
| " mkdir $(BUILDDIR)\n" | |||||
| " cd $(BUILDDIR); cmake -DCMAKE_BUILD_TYPE=Release ${CPACK_DEBIAN_CMAKE_OPTIONS} -DCMAKE_INSTALL_PREFIX=/usr ..\n" | |||||
| " $(MAKE) -C $(BUILDDIR) preinstall\n" | |||||
| " touch build\n" | |||||
| "\n" | |||||
| "binary: binary-indep binary-arch\n" | |||||
| "\n" | |||||
| "binary-indep: build\n" | |||||
| "\n" | |||||
| "binary-arch: build\n" | |||||
| " cd $(BUILDDIR); cmake -DCOMPONENT=Unspecified -DCMAKE_INSTALL_PREFIX=../debian/tmp/usr -P cmake_install.cmake\n" | |||||
| " mkdir -p debian/tmp/DEBIAN\n" | |||||
| " dpkg-gensymbols -p${CPACK_DEBIAN_PACKAGE_NAME}\n" | |||||
| ) | |||||
| foreach(COMPONENT ${CPACK_COMPONENTS_ALL}) | |||||
| set(PATH debian/${COMPONENT}) | |||||
| file(APPEND ${DEBIAN_RULES} | |||||
| " cd $(BUILDDIR); cmake -DCOMPONENT=${COMPONENT} -DCMAKE_INSTALL_PREFIX=../${PATH}/usr -P cmake_install.cmake\n" | |||||
| " mkdir -p ${PATH}/DEBIAN\n" | |||||
| " dpkg-gensymbols -p${COMPONENT} -P${PATH}\n" | |||||
| ) | |||||
| endforeach(COMPONENT ${CPACK_COMPONENTS_ALL}) | |||||
| file(APPEND ${DEBIAN_RULES} | |||||
| " dh_shlibdeps\n" | |||||
| " dh_strip\n" # for reducing size | |||||
| " dpkg-gencontrol -p${CPACK_DEBIAN_PACKAGE_NAME}\n" | |||||
| " dpkg --build debian/tmp ..\n" | |||||
| ) | |||||
| foreach(COMPONENT ${CPACK_COMPONENTS_ALL}) | |||||
| set(PATH debian/${COMPONENT}) | |||||
| file(APPEND ${DEBIAN_RULES} | |||||
| " dpkg-gencontrol -p${COMPONENT} -P${PATH} -Tdebian/${COMPONENT}.substvars\n" | |||||
| " dpkg --build ${PATH} ..\n" | |||||
| ) | |||||
| endforeach(COMPONENT ${CPACK_COMPONENTS_ALL}) | |||||
| file(APPEND ${DEBIAN_RULES} | |||||
| "\n" | |||||
| "clean:\n" | |||||
| " rm -f build\n" | |||||
| " rm -rf $(BUILDDIR)\n" | |||||
| "\n" | |||||
| ".PHONY: binary binary-arch binary-indep clean\n" | |||||
| ) | |||||
| execute_process(COMMAND chmod +x ${DEBIAN_RULES}) | |||||
| ############################################################################## | |||||
| # debian/compat | |||||
| file(WRITE ${DEBIAN_SOURCE_DIR}/debian/compat "7") | |||||
| ############################################################################## | |||||
| # debian/source/format | |||||
| file(WRITE ${DEBIAN_SOURCE_DIR}/debian/source/format "3.0 (quilt)") | |||||
| ############################################################################## | |||||
| # debian/changelog | |||||
| set(DEBIAN_CHANGELOG ${DEBIAN_SOURCE_DIR}/debian/changelog) | |||||
| execute_process(COMMAND date -R OUTPUT_VARIABLE DATE_TIME) | |||||
| file(WRITE ${DEBIAN_CHANGELOG} | |||||
| "${CPACK_DEBIAN_PACKAGE_NAME} (${RELEASE_PACKAGE_VERSION}) ${RELEASE}; urgency=medium\n\n" | |||||
| " * Package built with CMake\n\n" | |||||
| "${CPACK_DEBIAN_CHANGELOG}" | |||||
| " -- ${CPACK_PACKAGE_CONTACT} ${DATE_TIME}" | |||||
| ) | |||||
| ############################################################################## | |||||
| # debuild -S | |||||
| if( DEB_SOURCE_CHANGES ) | |||||
| set(DEBUILD_OPTIONS "-sd") | |||||
| else() | |||||
| set(DEBUILD_OPTIONS "-sa") | |||||
| endif() | |||||
| set(SOURCE_CHANGES_FILE "${CPACK_DEBIAN_PACKAGE_NAME}_${RELEASE_PACKAGE_VERSION}_source.changes") | |||||
| set(DEB_SOURCE_CHANGES ${DEB_SOURCE_CHANGES} "${SOURCE_CHANGES_FILE}") | |||||
| add_custom_command(OUTPUT "${SOURCE_CHANGES_FILE}" COMMAND ${DEBUILD_EXECUTABLE} -S ${DEBUILD_OPTIONS} WORKING_DIRECTORY ${DEBIAN_SOURCE_DIR}) | |||||
| endforeach(RELEASE ${CPACK_DEBIAN_DISTRIBUTION_RELEASES}) | |||||
| ############################################################################## | |||||
| # dput ppa:your-lp-id/ppa <source.changes> | |||||
| add_custom_target(dput ${DPUT_EXECUTABLE} ${DPUT_HOST} ${DEB_SOURCE_CHANGES} DEPENDS ${DEB_SOURCE_CHANGES} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/Debian) | |||||
| @@ -0,0 +1,100 @@ | |||||
| #------------------------------------------------------------------- | |||||
| # This file is part of the CMake build system for OGRE | |||||
| # (Object-oriented Graphics Rendering Engine) | |||||
| # For the latest info, see http://www.ogre3d.org/ | |||||
| # | |||||
| # The contents of this file are placed in the public domain. Feel | |||||
| # free to make use of it in any way you like. | |||||
| #------------------------------------------------------------------- | |||||
| # ----------------------------------------------------------------------------- | |||||
| # Find DirectX SDK | |||||
| # Define: | |||||
| # DirectX_FOUND | |||||
| # DirectX_INCLUDE_DIR | |||||
| # DirectX_LIBRARY | |||||
| # DirectX_ROOT_DIR | |||||
| if(WIN32) # The only platform it makes sense to check for DirectX SDK | |||||
| include(FindPkgMacros) | |||||
| findpkg_begin(DirectX) | |||||
| # Get path, convert backslashes as ${ENV_DXSDK_DIR} | |||||
| getenv_path(DXSDK_DIR) | |||||
| getenv_path(DIRECTX_HOME) | |||||
| getenv_path(DIRECTX_ROOT) | |||||
| getenv_path(DIRECTX_BASE) | |||||
| # construct search paths | |||||
| set(DirectX_PREFIX_PATH | |||||
| "${DXSDK_DIR}" "${ENV_DXSDK_DIR}" | |||||
| "${DIRECTX_HOME}" "${ENV_DIRECTX_HOME}" | |||||
| "${DIRECTX_ROOT}" "${ENV_DIRECTX_ROOT}" | |||||
| "${DIRECTX_BASE}" "${ENV_DIRECTX_BASE}" | |||||
| "C:/apps_x86/Microsoft DirectX SDK*" | |||||
| "C:/Program Files (x86)/Microsoft DirectX SDK*" | |||||
| "C:/apps/Microsoft DirectX SDK*" | |||||
| "C:/Program Files/Microsoft DirectX SDK*" | |||||
| "$ENV{ProgramFiles}/Microsoft DirectX SDK*" | |||||
| ) | |||||
| create_search_paths(DirectX) | |||||
| # redo search if prefix path changed | |||||
| clear_if_changed(DirectX_PREFIX_PATH | |||||
| DirectX_LIBRARY | |||||
| DirectX_INCLUDE_DIR | |||||
| ) | |||||
| find_path(DirectX_INCLUDE_DIR NAMES d3d9.h HINTS ${DirectX_INC_SEARCH_PATH}) | |||||
| # dlls are in DirectX_ROOT_DIR/Developer Runtime/x64|x86 | |||||
| # lib files are in DirectX_ROOT_DIR/Lib/x64|x86 | |||||
| if(CMAKE_CL_64) | |||||
| set(DirectX_LIBPATH_SUFFIX "x64") | |||||
| else(CMAKE_CL_64) | |||||
| set(DirectX_LIBPATH_SUFFIX "x86") | |||||
| endif(CMAKE_CL_64) | |||||
| find_library(DirectX_LIBRARY NAMES d3d9 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) | |||||
| find_library(DirectX_D3DX9_LIBRARY NAMES d3dx9 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) | |||||
| find_library(DirectX_DXERR_LIBRARY NAMES DxErr HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) | |||||
| find_library(DirectX_DXGUID_LIBRARY NAMES dxguid HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) | |||||
| # look for dxgi (needed by both 10 and 11) | |||||
| find_library(DirectX_DXGI_LIBRARY NAMES dxgi HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) | |||||
| # look for d3dcompiler (needed by 11) | |||||
| find_library(DirectX_D3DCOMPILER_LIBRARY NAMES d3dcompiler HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) | |||||
| findpkg_finish(DirectX) | |||||
| set(DirectX_LIBRARIES ${DirectX_LIBRARIES} | |||||
| ${DirectX_D3DX9_LIBRARY} | |||||
| ${DirectX_DXERR_LIBRARY} | |||||
| ${DirectX_DXGUID_LIBRARY} | |||||
| ) | |||||
| mark_as_advanced(DirectX_D3DX9_LIBRARY DirectX_DXERR_LIBRARY DirectX_DXGUID_LIBRARY | |||||
| DirectX_DXGI_LIBRARY DirectX_D3DCOMPILER_LIBRARY) | |||||
| # look for D3D11 components | |||||
| if (DirectX_FOUND) | |||||
| find_path(DirectX_D3D11_INCLUDE_DIR NAMES D3D11Shader.h HINTS ${DirectX_INC_SEARCH_PATH}) | |||||
| get_filename_component(DirectX_LIBRARY_DIR "${DirectX_LIBRARY}" PATH) | |||||
| message(STATUS "DX lib dir: ${DirectX_LIBRARY_DIR}") | |||||
| find_library(DirectX_D3D11_LIBRARY NAMES d3d11 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) | |||||
| find_library(DirectX_D3DX11_LIBRARY NAMES d3dx11 HINTS ${DirectX_LIB_SEARCH_PATH} PATH_SUFFIXES ${DirectX_LIBPATH_SUFFIX}) | |||||
| if (DirectX_D3D11_INCLUDE_DIR AND DirectX_D3D11_LIBRARY) | |||||
| set(DirectX_D3D11_FOUND TRUE) | |||||
| set(DirectX_D3D11_INCLUDE_DIR ${DirectX_D3D11_INCLUDE_DIR}) | |||||
| set(DirectX_D3D11_LIBRARIES ${DirectX_D3D11_LIBRARIES} | |||||
| ${DirectX_D3D11_LIBRARY} | |||||
| ${DirectX_D3DX11_LIBRARY} | |||||
| ${DirectX_DXGI_LIBRARY} | |||||
| ${DirectX_DXERR_LIBRARY} | |||||
| ${DirectX_DXGUID_LIBRARY} | |||||
| ${DirectX_D3DCOMPILER_LIBRARY} | |||||
| ) | |||||
| endif () | |||||
| mark_as_advanced(DirectX_D3D11_INCLUDE_DIR DirectX_D3D11_LIBRARY DirectX_D3DX11_LIBRARY) | |||||
| endif () | |||||
| endif(WIN32) | |||||
| @@ -0,0 +1,142 @@ | |||||
| #------------------------------------------------------------------- | |||||
| # This file is part of the CMake build system for OGRE | |||||
| # (Object-oriented Graphics Rendering Engine) | |||||
| # For the latest info, see http://www.ogre3d.org/ | |||||
| # | |||||
| # The contents of this file are placed in the public domain. Feel | |||||
| # free to make use of it in any way you like. | |||||
| #------------------------------------------------------------------- | |||||
| ################################################################## | |||||
| # Provides some common functionality for the FindPackage modules | |||||
| ################################################################## | |||||
| # Begin processing of package | |||||
| macro(findpkg_begin PREFIX) | |||||
| if (NOT ${PREFIX}_FIND_QUIETLY) | |||||
| message(STATUS "Looking for ${PREFIX}...") | |||||
| endif () | |||||
| endmacro(findpkg_begin) | |||||
| # Display a status message unless FIND_QUIETLY is set | |||||
| macro(pkg_message PREFIX) | |||||
| if (NOT ${PREFIX}_FIND_QUIETLY) | |||||
| message(STATUS ${ARGN}) | |||||
| endif () | |||||
| endmacro(pkg_message) | |||||
| # Get environment variable, define it as ENV_$var and make sure backslashes are converted to forward slashes | |||||
| macro(getenv_path VAR) | |||||
| set(ENV_${VAR} $ENV{${VAR}}) | |||||
| # replace won't work if var is blank | |||||
| if (ENV_${VAR}) | |||||
| string( REGEX REPLACE "\\\\" "/" ENV_${VAR} ${ENV_${VAR}} ) | |||||
| endif () | |||||
| endmacro(getenv_path) | |||||
| # Construct search paths for includes and libraries from a PREFIX_PATH | |||||
| macro(create_search_paths PREFIX) | |||||
| foreach(dir ${${PREFIX}_PREFIX_PATH}) | |||||
| set(${PREFIX}_INC_SEARCH_PATH ${${PREFIX}_INC_SEARCH_PATH} | |||||
| ${dir}/include ${dir}/include/${PREFIX} ${dir}/Headers) | |||||
| set(${PREFIX}_LIB_SEARCH_PATH ${${PREFIX}_LIB_SEARCH_PATH} | |||||
| ${dir}/lib ${dir}/lib/${PREFIX} ${dir}/Libs) | |||||
| endforeach(dir) | |||||
| set(${PREFIX}_FRAMEWORK_SEARCH_PATH ${${PREFIX}_PREFIX_PATH}) | |||||
| endmacro(create_search_paths) | |||||
| # clear cache variables if a certain variable changed | |||||
| macro(clear_if_changed TESTVAR) | |||||
| # test against internal check variable | |||||
| if (NOT "${${TESTVAR}}" STREQUAL "${${TESTVAR}_INT_CHECK}") | |||||
| message(STATUS "${TESTVAR} changed.") | |||||
| foreach(var ${ARGN}) | |||||
| set(${var} "NOTFOUND" CACHE STRING "x" FORCE) | |||||
| endforeach(var) | |||||
| endif () | |||||
| set(${TESTVAR}_INT_CHECK ${${TESTVAR}} CACHE INTERNAL "x" FORCE) | |||||
| endmacro(clear_if_changed) | |||||
| # Try to get some hints from pkg-config, if available | |||||
| macro(use_pkgconfig PREFIX PKGNAME) | |||||
| find_package(PkgConfig) | |||||
| if (PKG_CONFIG_FOUND) | |||||
| pkg_check_modules(${PREFIX} ${PKGNAME}) | |||||
| endif () | |||||
| endmacro (use_pkgconfig) | |||||
| # Couple a set of release AND debug libraries (or frameworks) | |||||
| macro(make_library_set PREFIX) | |||||
| if (${PREFIX}_FWK) | |||||
| set(${PREFIX} ${${PREFIX}_FWK}) | |||||
| elseif (${PREFIX}_REL AND ${PREFIX}_DBG) | |||||
| set(${PREFIX} optimized ${${PREFIX}_REL} debug ${${PREFIX}_DBG}) | |||||
| elseif (${PREFIX}_REL) | |||||
| set(${PREFIX} ${${PREFIX}_REL}) | |||||
| elseif (${PREFIX}_DBG) | |||||
| set(${PREFIX} ${${PREFIX}_DBG}) | |||||
| endif () | |||||
| endmacro(make_library_set) | |||||
| # Generate debug names from given release names | |||||
| macro(get_debug_names PREFIX) | |||||
| foreach(i ${${PREFIX}}) | |||||
| set(${PREFIX}_DBG ${${PREFIX}_DBG} ${i}d ${i}D ${i}_d ${i}_D ${i}_debug ${i}) | |||||
| endforeach(i) | |||||
| endmacro(get_debug_names) | |||||
| # Add the parent dir from DIR to VAR | |||||
| macro(add_parent_dir VAR DIR) | |||||
| get_filename_component(${DIR}_TEMP "${${DIR}}/.." ABSOLUTE) | |||||
| set(${VAR} ${${VAR}} ${${DIR}_TEMP}) | |||||
| endmacro(add_parent_dir) | |||||
| # Do the final processing for the package find. | |||||
| macro(findpkg_finish PREFIX) | |||||
| # skip if already processed during this run | |||||
| if (NOT ${PREFIX}_FOUND) | |||||
| if (${PREFIX}_INCLUDE_DIR AND ${PREFIX}_LIBRARY) | |||||
| set(${PREFIX}_FOUND TRUE) | |||||
| set(${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIR}) | |||||
| set(${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARY}) | |||||
| if (NOT ${PREFIX}_FIND_QUIETLY) | |||||
| message(STATUS "Found ${PREFIX}: ${${PREFIX}_LIBRARIES}") | |||||
| endif () | |||||
| else () | |||||
| if (NOT ${PREFIX}_FIND_QUIETLY) | |||||
| message(STATUS "Could not locate ${PREFIX}") | |||||
| endif () | |||||
| if (${PREFIX}_FIND_REQUIRED) | |||||
| message(FATAL_ERROR "Required library ${PREFIX} not found! Install the library (including dev packages) and try again. If the library is already installed, set the missing variables manually in cmake.") | |||||
| endif () | |||||
| endif () | |||||
| mark_as_advanced(${PREFIX}_INCLUDE_DIR ${PREFIX}_LIBRARY ${PREFIX}_LIBRARY_REL ${PREFIX}_LIBRARY_DBG ${PREFIX}_LIBRARY_FWK) | |||||
| endif () | |||||
| endmacro(findpkg_finish) | |||||
| # Slightly customised framework finder | |||||
| MACRO(findpkg_framework fwk) | |||||
| IF(APPLE) | |||||
| SET(${fwk}_FRAMEWORK_PATH | |||||
| ${${fwk}_FRAMEWORK_SEARCH_PATH} | |||||
| ${CMAKE_FRAMEWORK_PATH} | |||||
| ~/Library/Frameworks | |||||
| /Library/Frameworks | |||||
| /System/Library/Frameworks | |||||
| /Network/Library/Frameworks | |||||
| /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS3.0.sdk/System/Library/Frameworks/ | |||||
| ) | |||||
| FOREACH(dir ${${fwk}_FRAMEWORK_PATH}) | |||||
| SET(fwkpath ${dir}/${fwk}.framework) | |||||
| IF(EXISTS ${fwkpath}) | |||||
| SET(${fwk}_FRAMEWORK_INCLUDES ${${fwk}_FRAMEWORK_INCLUDES} | |||||
| ${fwkpath}/Headers ${fwkpath}/PrivateHeaders) | |||||
| if (NOT ${fwk}_LIBRARY_FWK) | |||||
| SET(${fwk}_LIBRARY_FWK "-framework ${fwk}") | |||||
| endif () | |||||
| ENDIF(EXISTS ${fwkpath}) | |||||
| ENDFOREACH(dir) | |||||
| ENDIF(APPLE) | |||||
| ENDMACRO(findpkg_framework) | |||||
| @@ -0,0 +1,48 @@ | |||||
| #------------------------------------------------------------------- | |||||
| # This file is part of the CMake build system for OGRE | |||||
| # (Object-oriented Graphics Rendering Engine) | |||||
| # For the latest info, see http://www.ogre3d.org/ | |||||
| # | |||||
| # The contents of this file are placed in the public domain. Feel | |||||
| # free to make use of it in any way you like. | |||||
| #------------------------------------------------------------------- | |||||
| # - Try to find ZLIB | |||||
| # Once done, this will define | |||||
| # | |||||
| # ZLIB_FOUND - system has ZLIB | |||||
| # ZLIB_INCLUDE_DIRS - the ZLIB include directories | |||||
| # ZLIB_LIBRARIES - link these to use ZLIB | |||||
| include(FindPkgMacros) | |||||
| findpkg_begin(ZLIB) | |||||
| # Get path, convert backslashes as ${ENV_${var}} | |||||
| getenv_path(ZLIB_HOME) | |||||
| # construct search paths | |||||
| set(ZLIB_PREFIX_PATH ${ZLIB_HOME} ${ENV_ZLIB_HOME}) | |||||
| create_search_paths(ZLIB) | |||||
| # redo search if prefix path changed | |||||
| clear_if_changed(ZLIB_PREFIX_PATH | |||||
| ZLIB_LIBRARY_FWK | |||||
| ZLIB_LIBRARY_REL | |||||
| ZLIB_LIBRARY_DBG | |||||
| ZLIB_INCLUDE_DIR | |||||
| ) | |||||
| set(ZLIB_LIBRARY_NAMES z zlib zdll) | |||||
| get_debug_names(ZLIB_LIBRARY_NAMES) | |||||
| use_pkgconfig(ZLIB_PKGC zzip-zlib-config) | |||||
| findpkg_framework(ZLIB) | |||||
| find_path(ZLIB_INCLUDE_DIR NAMES zlib.h HINTS ${ZLIB_INC_SEARCH_PATH} ${ZLIB_PKGC_INCLUDE_DIRS}) | |||||
| find_library(ZLIB_LIBRARY_REL NAMES ${ZLIB_LIBRARY_NAMES} HINTS ${ZLIB_LIB_SEARCH_PATH} ${ZLIB_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" release relwithdebinfo minsizerel) | |||||
| find_library(ZLIB_LIBRARY_DBG NAMES ${ZLIB_LIBRARY_NAMES_DBG} HINTS ${ZLIB_LIB_SEARCH_PATH} ${ZLIB_PKGC_LIBRARY_DIRS} PATH_SUFFIXES "" debug) | |||||
| make_library_set(ZLIB_LIBRARY) | |||||
| findpkg_finish(ZLIB) | |||||
| @@ -0,0 +1,25 @@ | |||||
| FIND_PATH( | |||||
| assimp_INCLUDE_DIRS | |||||
| NAMES postprocess.h scene.h version.h config.h cimport.h | |||||
| PATHS /usr/local/include/ | |||||
| ) | |||||
| FIND_LIBRARY( | |||||
| assimp_LIBRARIES | |||||
| NAMES assimp | |||||
| PATHS /usr/local/lib/ | |||||
| ) | |||||
| IF (assimp_INCLUDE_DIRS AND assimp_LIBRARIES) | |||||
| SET(assimp_FOUND TRUE) | |||||
| ENDIF (assimp_INCLUDE_DIRS AND assimp_LIBRARIES) | |||||
| IF (assimp_FOUND) | |||||
| IF (NOT assimp_FIND_QUIETLY) | |||||
| MESSAGE(STATUS "Found asset importer library: ${assimp_LIBRARIES}") | |||||
| ENDIF (NOT assimp_FIND_QUIETLY) | |||||
| ELSE (assimp_FOUND) | |||||
| IF (assimp_FIND_REQUIRED) | |||||
| MESSAGE(FATAL_ERROR "Could not find asset importer library") | |||||
| ENDIF (assimp_FIND_REQUIRED) | |||||
| ENDIF (assimp_FOUND) | |||||
| @@ -0,0 +1,25 @@ | |||||
| MACRO(ADD_MSVC_PRECOMPILED_HEADER PrecompiledHeader PrecompiledSource SourcesVar) | |||||
| IF(MSVC) | |||||
| GET_FILENAME_COMPONENT(PrecompiledBasename ${PrecompiledHeader} NAME_WE) | |||||
| SET(PrecompiledBinary "${CMAKE_CFG_INTDIR}/${PrecompiledBasename}.pch") | |||||
| SET(Sources ${${SourcesVar}}) | |||||
| SET_SOURCE_FILES_PROPERTIES(${PrecompiledSource} | |||||
| PROPERTIES COMPILE_FLAGS "/Yc\"${PrecompiledHeader}\" /Fp\"${PrecompiledBinary}\"" | |||||
| OBJECT_OUTPUTS "${PrecompiledBinary}") | |||||
| # Do not consider .c files | |||||
| foreach(fname ${Sources}) | |||||
| GET_FILENAME_COMPONENT(fext ${fname} EXT) | |||||
| if(fext STREQUAL ".cpp") | |||||
| SET_SOURCE_FILES_PROPERTIES(${fname} | |||||
| PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledBinary}\" /FI\"${PrecompiledBinary}\" /Fp\"${PrecompiledBinary}\"" | |||||
| OBJECT_DEPENDS "${PrecompiledBinary}") | |||||
| endif(fext STREQUAL ".cpp") | |||||
| endforeach(fname) | |||||
| ENDIF(MSVC) | |||||
| # Add precompiled header to SourcesVar | |||||
| LIST(APPEND ${SourcesVar} ${PrecompiledSource}) | |||||
| ENDMACRO(ADD_MSVC_PRECOMPILED_HEADER) | |||||
| @@ -0,0 +1,17 @@ | |||||
| IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") | |||||
| MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") | |||||
| ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") | |||||
| FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) | |||||
| STRING(REGEX REPLACE "\n" ";" files "${files}") | |||||
| FOREACH(file ${files}) | |||||
| MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") | |||||
| EXEC_PROGRAM( | |||||
| "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" | |||||
| OUTPUT_VARIABLE rm_out | |||||
| RETURN_VALUE rm_retval | |||||
| ) | |||||
| IF(NOT "${rm_retval}" STREQUAL 0) | |||||
| MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") | |||||
| ENDIF(NOT "${rm_retval}" STREQUAL 0) | |||||
| ENDFOREACH(file) | |||||
| @@ -0,0 +1,861 @@ | |||||
| /* | |||||
| --------------------------------------------------------------------------- | |||||
| Open Asset Import Library (assimp) | |||||
| --------------------------------------------------------------------------- | |||||
| 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. | |||||
| --------------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file Implementation of the 3ds importer class */ | |||||
| #include "AssimpPCH.h" | |||||
| #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER | |||||
| // internal headers | |||||
| #include "3DSLoader.h" | |||||
| #include "TargetAnimation.h" | |||||
| using namespace Assimp; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // 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; | |||||
| for (unsigned int i = 0; i < mScene->mMaterials.size();++i) | |||||
| { | |||||
| std::string s = mScene->mMaterials[i].mName; | |||||
| for (std::string::iterator it = s.begin(); it != s.end(); ++it) | |||||
| *it = ::tolower(*it); | |||||
| if (std::string::npos == s.find("default"))continue; | |||||
| if (mScene->mMaterials[i].mDiffuse.r != | |||||
| mScene->mMaterials[i].mDiffuse.g || | |||||
| mScene->mMaterials[i].mDiffuse.r != | |||||
| mScene->mMaterials[i].mDiffuse.b)continue; | |||||
| if (mScene->mMaterials[i].sTexDiffuse.mMapName.length() != 0 || | |||||
| mScene->mMaterials[i].sTexBump.mMapName.length() != 0 || | |||||
| mScene->mMaterials[i].sTexOpacity.mMapName.length() != 0 || | |||||
| mScene->mMaterials[i].sTexEmissive.mMapName.length() != 0 || | |||||
| mScene->mMaterials[i].sTexSpecular.mMapName.length() != 0 || | |||||
| mScene->mMaterials[i].sTexShininess.mMapName.length() != 0 ) | |||||
| { | |||||
| continue; | |||||
| } | |||||
| idx = i; | |||||
| } | |||||
| if (0xcdcdcdcd == 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 | |||||
| unsigned int cnt = 0; | |||||
| for (std::vector<D3DS::Mesh>::iterator | |||||
| i = mScene->mMeshes.begin(); | |||||
| i != mScene->mMeshes.end();++i) | |||||
| { | |||||
| for (std::vector<unsigned int>::iterator | |||||
| a = (*i).mFaceMaterials.begin(); | |||||
| a != (*i).mFaceMaterials.end();++a) | |||||
| { | |||||
| // NOTE: The additional check seems to be necessary, | |||||
| // some exporters seem to generate invalid data here | |||||
| if (0xcdcdcdcd == (*a)) | |||||
| { | |||||
| (*a) = idx; | |||||
| ++cnt; | |||||
| } | |||||
| else if ( (*a) >= mScene->mMaterials.size()) | |||||
| { | |||||
| (*a) = idx; | |||||
| DefaultLogger::get()->warn("Material index overflow in 3DS file. Using default material"); | |||||
| ++cnt; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (cnt && idx == mScene->mMaterials.size()) | |||||
| { | |||||
| // We need to create our own default material | |||||
| D3DS::Material sMat; | |||||
| sMat.mDiffuse = aiColor3D(0.3f,0.3f,0.3f); | |||||
| sMat.mName = "%%%DEFAULT"; | |||||
| mScene->mMaterials.push_back(sMat); | |||||
| DefaultLogger::get()->info("3DS: Generating default material"); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Check whether all indices are valid. Otherwise we'd crash before the validation step is reached | |||||
| void Discreet3DSImporter::CheckIndices(D3DS::Mesh& sMesh) | |||||
| { | |||||
| for (std::vector< D3DS::Face >::iterator i = sMesh.mFaces.begin(); i != sMesh.mFaces.end();++i) | |||||
| { | |||||
| // check whether all indices are in range | |||||
| for (unsigned int a = 0; a < 3;++a) | |||||
| { | |||||
| if ((*i).mIndices[a] >= sMesh.mPositions.size()) | |||||
| { | |||||
| DefaultLogger::get()->warn("3DS: Vertex index overflow)"); | |||||
| (*i).mIndices[a] = (uint32_t)sMesh.mPositions.size()-1; | |||||
| } | |||||
| if ( !sMesh.mTexCoords.empty() && (*i).mIndices[a] >= sMesh.mTexCoords.size()) | |||||
| { | |||||
| DefaultLogger::get()->warn("3DS: Texture coordinate index overflow)"); | |||||
| (*i).mIndices[a] = (uint32_t)sMesh.mTexCoords.size()-1; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Generate out unique verbose format representation | |||||
| void Discreet3DSImporter::MakeUnique(D3DS::Mesh& sMesh) | |||||
| { | |||||
| // TODO: really necessary? I don't think. Just a waste of memory and time | |||||
| // to do it now in a separate buffer. | |||||
| // Allocate output storage | |||||
| std::vector<aiVector3D> vNew (sMesh.mFaces.size() * 3); | |||||
| std::vector<aiVector3D> vNew2; | |||||
| if (sMesh.mTexCoords.size()) | |||||
| vNew2.resize(sMesh.mFaces.size() * 3); | |||||
| for (unsigned int i = 0, base = 0; i < sMesh.mFaces.size();++i) | |||||
| { | |||||
| D3DS::Face& face = sMesh.mFaces[i]; | |||||
| // Positions | |||||
| for (unsigned int a = 0; a < 3;++a,++base) | |||||
| { | |||||
| vNew[base] = sMesh.mPositions[face.mIndices[a]]; | |||||
| if (sMesh.mTexCoords.size()) | |||||
| vNew2[base] = sMesh.mTexCoords[face.mIndices[a]]; | |||||
| face.mIndices[a] = base; | |||||
| } | |||||
| } | |||||
| sMesh.mPositions = vNew; | |||||
| sMesh.mTexCoords = vNew2; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Convert a 3DS texture to texture keys in an aiMaterial | |||||
| void CopyTexture(aiMaterial& mat, D3DS::Texture& texture, aiTextureType type) | |||||
| { | |||||
| // Setup the texture name | |||||
| aiString tex; | |||||
| tex.Set( texture.mMapName); | |||||
| mat.AddProperty( &tex, AI_MATKEY_TEXTURE(type,0)); | |||||
| // Setup the texture blend factor | |||||
| if (is_not_qnan(texture.mTextureBlend)) | |||||
| mat.AddProperty<float>( &texture.mTextureBlend, 1, AI_MATKEY_TEXBLEND(type,0)); | |||||
| // Setup the texture mapping mode | |||||
| mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_U(type,0)); | |||||
| mat.AddProperty<int>((int*)&texture.mMapMode,1,AI_MATKEY_MAPPINGMODE_V(type,0)); | |||||
| // Mirroring - double the scaling values | |||||
| // FIXME: this is not really correct ... | |||||
| if (texture.mMapMode == aiTextureMapMode_Mirror) | |||||
| { | |||||
| texture.mScaleU *= 2.f; | |||||
| texture.mScaleV *= 2.f; | |||||
| texture.mOffsetU /= 2.f; | |||||
| texture.mOffsetV /= 2.f; | |||||
| } | |||||
| // Setup texture UV transformations | |||||
| mat.AddProperty<float>(&texture.mOffsetU,5,AI_MATKEY_UVTRANSFORM(type,0)); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Convert a 3DS material to an aiMaterial | |||||
| void Discreet3DSImporter::ConvertMaterial(D3DS::Material& oldMat, | |||||
| aiMaterial& mat) | |||||
| { | |||||
| // NOTE: Pass the background image to the viewer by bypassing the | |||||
| // material system. This is an evil hack, never do it again! | |||||
| if (0 != mBackgroundImage.length() && bHasBG) | |||||
| { | |||||
| aiString tex; | |||||
| tex.Set( mBackgroundImage); | |||||
| mat.AddProperty( &tex, AI_MATKEY_GLOBAL_BACKGROUND_IMAGE); | |||||
| // Be sure this is only done for the first material | |||||
| mBackgroundImage = std::string(""); | |||||
| } | |||||
| // At first add the base ambient color of the scene to the material | |||||
| oldMat.mAmbient.r += mClrAmbient.r; | |||||
| oldMat.mAmbient.g += mClrAmbient.g; | |||||
| oldMat.mAmbient.b += mClrAmbient.b; | |||||
| aiString name; | |||||
| name.Set( oldMat.mName); | |||||
| mat.AddProperty( &name, AI_MATKEY_NAME); | |||||
| // Material colors | |||||
| mat.AddProperty( &oldMat.mAmbient, 1, AI_MATKEY_COLOR_AMBIENT); | |||||
| mat.AddProperty( &oldMat.mDiffuse, 1, AI_MATKEY_COLOR_DIFFUSE); | |||||
| mat.AddProperty( &oldMat.mSpecular, 1, AI_MATKEY_COLOR_SPECULAR); | |||||
| mat.AddProperty( &oldMat.mEmissive, 1, AI_MATKEY_COLOR_EMISSIVE); | |||||
| // Phong shininess and shininess strength | |||||
| if (D3DS::Discreet3DS::Phong == oldMat.mShading || | |||||
| D3DS::Discreet3DS::Metal == oldMat.mShading) | |||||
| { | |||||
| if (!oldMat.mSpecularExponent || !oldMat.mShininessStrength) | |||||
| { | |||||
| oldMat.mShading = D3DS::Discreet3DS::Gouraud; | |||||
| } | |||||
| else | |||||
| { | |||||
| mat.AddProperty( &oldMat.mSpecularExponent, 1, AI_MATKEY_SHININESS); | |||||
| mat.AddProperty( &oldMat.mShininessStrength, 1, AI_MATKEY_SHININESS_STRENGTH); | |||||
| } | |||||
| } | |||||
| // Opacity | |||||
| mat.AddProperty<float>( &oldMat.mTransparency,1,AI_MATKEY_OPACITY); | |||||
| // Bump height scaling | |||||
| mat.AddProperty<float>( &oldMat.mBumpHeight,1,AI_MATKEY_BUMPSCALING); | |||||
| // Two sided rendering? | |||||
| if (oldMat.mTwoSided) | |||||
| { | |||||
| int i = 1; | |||||
| mat.AddProperty<int>(&i,1,AI_MATKEY_TWOSIDED); | |||||
| } | |||||
| // Shading mode | |||||
| aiShadingMode eShading = aiShadingMode_NoShading; | |||||
| switch (oldMat.mShading) | |||||
| { | |||||
| case D3DS::Discreet3DS::Flat: | |||||
| eShading = aiShadingMode_Flat; break; | |||||
| // I don't know what "Wire" shading should be, | |||||
| // assume it is simple lambertian diffuse shading | |||||
| case D3DS::Discreet3DS::Wire: | |||||
| { | |||||
| // Set the wireframe flag | |||||
| unsigned int iWire = 1; | |||||
| mat.AddProperty<int>( (int*)&iWire,1,AI_MATKEY_ENABLE_WIREFRAME); | |||||
| } | |||||
| case D3DS::Discreet3DS::Gouraud: | |||||
| eShading = aiShadingMode_Gouraud; break; | |||||
| // assume cook-torrance shading for metals. | |||||
| case D3DS::Discreet3DS::Phong : | |||||
| eShading = aiShadingMode_Phong; break; | |||||
| case D3DS::Discreet3DS::Metal : | |||||
| eShading = aiShadingMode_CookTorrance; break; | |||||
| // FIX to workaround a warning with GCC 4 who complained | |||||
| // about a missing case Blinn: here - Blinn isn't a valid | |||||
| // value in the 3DS Loader, it is just needed for ASE | |||||
| case D3DS::Discreet3DS::Blinn : | |||||
| eShading = aiShadingMode_Blinn; break; | |||||
| } | |||||
| mat.AddProperty<int>( (int*)&eShading,1,AI_MATKEY_SHADING_MODEL); | |||||
| // DIFFUSE texture | |||||
| if( oldMat.sTexDiffuse.mMapName.length() > 0) | |||||
| CopyTexture(mat,oldMat.sTexDiffuse, aiTextureType_DIFFUSE); | |||||
| // SPECULAR texture | |||||
| if( oldMat.sTexSpecular.mMapName.length() > 0) | |||||
| CopyTexture(mat,oldMat.sTexSpecular, aiTextureType_SPECULAR); | |||||
| // OPACITY texture | |||||
| if( oldMat.sTexOpacity.mMapName.length() > 0) | |||||
| CopyTexture(mat,oldMat.sTexOpacity, aiTextureType_OPACITY); | |||||
| // EMISSIVE texture | |||||
| if( oldMat.sTexEmissive.mMapName.length() > 0) | |||||
| CopyTexture(mat,oldMat.sTexEmissive, aiTextureType_EMISSIVE); | |||||
| // BUMP texture | |||||
| if( oldMat.sTexBump.mMapName.length() > 0) | |||||
| CopyTexture(mat,oldMat.sTexBump, aiTextureType_HEIGHT); | |||||
| // SHININESS texture | |||||
| if( oldMat.sTexShininess.mMapName.length() > 0) | |||||
| CopyTexture(mat,oldMat.sTexShininess, aiTextureType_SHININESS); | |||||
| // REFLECTION texture | |||||
| if( oldMat.sTexReflective.mMapName.length() > 0) | |||||
| CopyTexture(mat,oldMat.sTexReflective, aiTextureType_REFLECTION); | |||||
| // Store the name of the material itself, too | |||||
| if( oldMat.mName.length()) { | |||||
| aiString tex; | |||||
| tex.Set( oldMat.mName); | |||||
| mat.AddProperty( &tex, AI_MATKEY_NAME); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Split meshes by their materials and generate output aiMesh'es | |||||
| void Discreet3DSImporter::ConvertMeshes(aiScene* pcOut) | |||||
| { | |||||
| std::vector<aiMesh*> avOutMeshes; | |||||
| avOutMeshes.reserve(mScene->mMeshes.size() * 2); | |||||
| unsigned int iFaceCnt = 0,num = 0; | |||||
| aiString name; | |||||
| // we need to split all meshes by their materials | |||||
| for (std::vector<D3DS::Mesh>::iterator i = mScene->mMeshes.begin(); i != mScene->mMeshes.end();++i) { | |||||
| boost::scoped_array< std::vector<unsigned int> > aiSplit(new std::vector<unsigned int>[mScene->mMaterials.size()]); | |||||
| name.length = ASSIMP_itoa10(name.data,num++); | |||||
| unsigned int iNum = 0; | |||||
| for (std::vector<unsigned int>::const_iterator a = (*i).mFaceMaterials.begin(); | |||||
| a != (*i).mFaceMaterials.end();++a,++iNum) | |||||
| { | |||||
| aiSplit[*a].push_back(iNum); | |||||
| } | |||||
| // now generate submeshes | |||||
| for (unsigned int p = 0; p < mScene->mMaterials.size();++p) | |||||
| { | |||||
| if (aiSplit[p].empty()) { | |||||
| continue; | |||||
| } | |||||
| aiMesh* meshOut = new aiMesh(); | |||||
| meshOut->mName = name; | |||||
| meshOut->mPrimitiveTypes = aiPrimitiveType_TRIANGLE; | |||||
| // be sure to setup the correct material index | |||||
| meshOut->mMaterialIndex = p; | |||||
| // use the color data as temporary storage | |||||
| meshOut->mColors[0] = (aiColor4D*)(&*i); | |||||
| avOutMeshes.push_back(meshOut); | |||||
| // convert vertices | |||||
| meshOut->mNumFaces = (unsigned int)aiSplit[p].size(); | |||||
| meshOut->mNumVertices = meshOut->mNumFaces*3; | |||||
| // allocate enough storage for faces | |||||
| meshOut->mFaces = new aiFace[meshOut->mNumFaces]; | |||||
| iFaceCnt += meshOut->mNumFaces; | |||||
| meshOut->mVertices = new aiVector3D[meshOut->mNumVertices]; | |||||
| meshOut->mNormals = new aiVector3D[meshOut->mNumVertices]; | |||||
| if ((*i).mTexCoords.size()) | |||||
| { | |||||
| meshOut->mTextureCoords[0] = new aiVector3D[meshOut->mNumVertices]; | |||||
| } | |||||
| for (unsigned int q = 0, base = 0; q < aiSplit[p].size();++q) | |||||
| { | |||||
| register unsigned int index = aiSplit[p][q]; | |||||
| aiFace& face = meshOut->mFaces[q]; | |||||
| face.mIndices = new unsigned int[3]; | |||||
| face.mNumIndices = 3; | |||||
| for (unsigned int a = 0; a < 3;++a,++base) | |||||
| { | |||||
| unsigned int idx = (*i).mFaces[index].mIndices[a]; | |||||
| meshOut->mVertices[base] = (*i).mPositions[idx]; | |||||
| meshOut->mNormals [base] = (*i).mNormals[idx]; | |||||
| if ((*i).mTexCoords.size()) | |||||
| meshOut->mTextureCoords[0][base] = (*i).mTexCoords[idx]; | |||||
| face.mIndices[a] = base; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| // Copy them to the output array | |||||
| pcOut->mNumMeshes = (unsigned int)avOutMeshes.size(); | |||||
| pcOut->mMeshes = new aiMesh*[pcOut->mNumMeshes](); | |||||
| for (unsigned int a = 0; a < pcOut->mNumMeshes;++a) { | |||||
| pcOut->mMeshes[a] = avOutMeshes[a]; | |||||
| } | |||||
| // We should have at least one face here | |||||
| if (!iFaceCnt) { | |||||
| throw DeadlyImportError("No faces loaded. The mesh is empty"); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Add a node to the scenegraph and setup its final transformation | |||||
| void Discreet3DSImporter::AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut, | |||||
| D3DS::Node* pcIn, aiMatrix4x4& /*absTrafo*/) | |||||
| { | |||||
| std::vector<unsigned int> iArray; | |||||
| iArray.reserve(3); | |||||
| aiMatrix4x4 abs; | |||||
| // Find all meshes with the same name as the node | |||||
| for (unsigned int a = 0; a < pcSOut->mNumMeshes;++a) | |||||
| { | |||||
| const D3DS::Mesh* pcMesh = (const D3DS::Mesh*)pcSOut->mMeshes[a]->mColors[0]; | |||||
| ai_assert(NULL != pcMesh); | |||||
| if (pcIn->mName == pcMesh->mName) | |||||
| iArray.push_back(a); | |||||
| } | |||||
| if (!iArray.empty()) | |||||
| { | |||||
| // The matrix should be identical for all meshes with the | |||||
| // same name. It HAS to be identical for all meshes ..... | |||||
| D3DS::Mesh* imesh = ((D3DS::Mesh*)pcSOut->mMeshes[iArray[0]]->mColors[0]); | |||||
| // Compute the inverse of the transformation matrix to move the | |||||
| // vertices back to their relative and local space | |||||
| aiMatrix4x4 mInv = imesh->mMat, mInvTransposed = imesh->mMat; | |||||
| mInv.Inverse();mInvTransposed.Transpose(); | |||||
| aiVector3D pivot = pcIn->vPivot; | |||||
| pcOut->mNumMeshes = (unsigned int)iArray.size(); | |||||
| pcOut->mMeshes = new unsigned int[iArray.size()]; | |||||
| for (unsigned int i = 0;i < iArray.size();++i) { | |||||
| const unsigned int iIndex = iArray[i]; | |||||
| aiMesh* const mesh = pcSOut->mMeshes[iIndex]; | |||||
| if (mesh->mColors[1] == NULL) | |||||
| { | |||||
| // Transform the vertices back into their local space | |||||
| // fixme: consider computing normals after this, so we don't need to transform them | |||||
| const aiVector3D* const pvEnd = mesh->mVertices + mesh->mNumVertices; | |||||
| aiVector3D* pvCurrent = mesh->mVertices, *t2 = mesh->mNormals; | |||||
| for (; pvCurrent != pvEnd; ++pvCurrent, ++t2) { | |||||
| *pvCurrent = mInv * (*pvCurrent); | |||||
| *t2 = mInvTransposed * (*t2); | |||||
| } | |||||
| // Handle negative transformation matrix determinant -> invert vertex x | |||||
| if (imesh->mMat.Determinant() < 0.0f) | |||||
| { | |||||
| /* we *must* have normals */ | |||||
| for (pvCurrent = mesh->mVertices, t2 = mesh->mNormals; pvCurrent != pvEnd; ++pvCurrent, ++t2) { | |||||
| pvCurrent->x *= -1.f; | |||||
| t2->x *= -1.f; | |||||
| } | |||||
| DefaultLogger::get()->info("3DS: Flipping mesh X-Axis"); | |||||
| } | |||||
| // Handle pivot point | |||||
| if (pivot.x || pivot.y || pivot.z) | |||||
| { | |||||
| for (pvCurrent = mesh->mVertices; pvCurrent != pvEnd; ++pvCurrent) { | |||||
| *pvCurrent -= pivot; | |||||
| } | |||||
| } | |||||
| mesh->mColors[1] = (aiColor4D*)1; | |||||
| } | |||||
| else | |||||
| mesh->mColors[1] = (aiColor4D*)1; | |||||
| // Setup the mesh index | |||||
| pcOut->mMeshes[i] = iIndex; | |||||
| } | |||||
| } | |||||
| // Setup the name of the node | |||||
| // First instance keeps its name otherwise something might break, all others will be postfixed with their instance number | |||||
| if (pcIn->mInstanceNumber > 1) | |||||
| { | |||||
| char tmp[12]; | |||||
| ASSIMP_itoa10(tmp, pcIn->mInstanceNumber); | |||||
| std::string tempStr = pcIn->mName + "_inst_"; | |||||
| tempStr += tmp; | |||||
| pcOut->mName.Set(tempStr); | |||||
| } | |||||
| else | |||||
| pcOut->mName.Set(pcIn->mName); | |||||
| // Now build the transformation matrix of the node | |||||
| // ROTATION | |||||
| if (pcIn->aRotationKeys.size()){ | |||||
| // FIX to get to Assimp's quaternion conventions | |||||
| for (std::vector<aiQuatKey>::iterator it = pcIn->aRotationKeys.begin(); it != pcIn->aRotationKeys.end(); ++it) { | |||||
| (*it).mValue.w *= -1.f; | |||||
| } | |||||
| pcOut->mTransformation = aiMatrix4x4( pcIn->aRotationKeys[0].mValue.GetMatrix() ); | |||||
| } | |||||
| else if (pcIn->aCameraRollKeys.size()) | |||||
| { | |||||
| aiMatrix4x4::RotationZ(AI_DEG_TO_RAD(- pcIn->aCameraRollKeys[0].mValue), | |||||
| pcOut->mTransformation); | |||||
| } | |||||
| // SCALING | |||||
| aiMatrix4x4& m = pcOut->mTransformation; | |||||
| if (pcIn->aScalingKeys.size()) | |||||
| { | |||||
| const aiVector3D& v = pcIn->aScalingKeys[0].mValue; | |||||
| m.a1 *= v.x; m.b1 *= v.x; m.c1 *= v.x; | |||||
| m.a2 *= v.y; m.b2 *= v.y; m.c2 *= v.y; | |||||
| m.a3 *= v.z; m.b3 *= v.z; m.c3 *= v.z; | |||||
| } | |||||
| // TRANSLATION | |||||
| if (pcIn->aPositionKeys.size()) | |||||
| { | |||||
| const aiVector3D& v = pcIn->aPositionKeys[0].mValue; | |||||
| m.a4 += v.x; | |||||
| m.b4 += v.y; | |||||
| m.c4 += v.z; | |||||
| } | |||||
| // Generate animation channels for the node | |||||
| if (pcIn->aPositionKeys.size() > 1 || pcIn->aRotationKeys.size() > 1 || | |||||
| pcIn->aScalingKeys.size() > 1 || pcIn->aCameraRollKeys.size() > 1 || | |||||
| pcIn->aTargetPositionKeys.size() > 1) | |||||
| { | |||||
| aiAnimation* anim = pcSOut->mAnimations[0]; | |||||
| ai_assert(NULL != anim); | |||||
| if (pcIn->aCameraRollKeys.size() > 1) | |||||
| { | |||||
| DefaultLogger::get()->debug("3DS: Converting camera roll track ..."); | |||||
| // Camera roll keys - in fact they're just rotations | |||||
| // around the camera's z axis. The angles are given | |||||
| // in degrees (and they're clockwise). | |||||
| pcIn->aRotationKeys.resize(pcIn->aCameraRollKeys.size()); | |||||
| for (unsigned int i = 0; i < pcIn->aCameraRollKeys.size();++i) | |||||
| { | |||||
| aiQuatKey& q = pcIn->aRotationKeys[i]; | |||||
| aiFloatKey& f = pcIn->aCameraRollKeys[i]; | |||||
| q.mTime = f.mTime; | |||||
| // FIX to get to Assimp quaternion conventions | |||||
| q.mValue = aiQuaternion(0.f,0.f,AI_DEG_TO_RAD( /*-*/ f.mValue)); | |||||
| } | |||||
| } | |||||
| #if 0 | |||||
| if (pcIn->aTargetPositionKeys.size() > 1) | |||||
| { | |||||
| DefaultLogger::get()->debug("3DS: Converting target track ..."); | |||||
| // Camera or spot light - need to convert the separate | |||||
| // target position channel to our representation | |||||
| TargetAnimationHelper helper; | |||||
| if (pcIn->aPositionKeys.empty()) | |||||
| { | |||||
| // We can just pass zero here ... | |||||
| helper.SetFixedMainAnimationChannel(aiVector3D()); | |||||
| } | |||||
| else helper.SetMainAnimationChannel(&pcIn->aPositionKeys); | |||||
| helper.SetTargetAnimationChannel(&pcIn->aTargetPositionKeys); | |||||
| // Do the conversion | |||||
| std::vector<aiVectorKey> distanceTrack; | |||||
| helper.Process(&distanceTrack); | |||||
| // Now add a new node as child, name it <ourName>.Target | |||||
| // and assign the distance track to it. This is that the | |||||
| // information where the target is and how it moves is | |||||
| // not lost | |||||
| D3DS::Node* nd = new D3DS::Node(); | |||||
| pcIn->push_back(nd); | |||||
| nd->mName = pcIn->mName + ".Target"; | |||||
| aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); | |||||
| nda->mNodeName.Set(nd->mName); | |||||
| nda->mNumPositionKeys = (unsigned int)distanceTrack.size(); | |||||
| nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; | |||||
| ::memcpy(nda->mPositionKeys,&distanceTrack[0], | |||||
| sizeof(aiVectorKey)*nda->mNumPositionKeys); | |||||
| } | |||||
| #endif | |||||
| // Cameras or lights define their transformation in their parent node and in the | |||||
| // corresponding light or camera chunks. However, we read and process the latter | |||||
| // to to be able to return valid cameras/lights even if no scenegraph is given. | |||||
| for (unsigned int n = 0; n < pcSOut->mNumCameras;++n) { | |||||
| if (pcSOut->mCameras[n]->mName == pcOut->mName) { | |||||
| pcSOut->mCameras[n]->mLookAt = aiVector3D(0.f,0.f,1.f); | |||||
| } | |||||
| } | |||||
| for (unsigned int n = 0; n < pcSOut->mNumLights;++n) { | |||||
| if (pcSOut->mLights[n]->mName == pcOut->mName) { | |||||
| pcSOut->mLights[n]->mDirection = aiVector3D(0.f,0.f,1.f); | |||||
| } | |||||
| } | |||||
| // Allocate a new node anim and setup its name | |||||
| aiNodeAnim* nda = anim->mChannels[anim->mNumChannels++] = new aiNodeAnim(); | |||||
| nda->mNodeName.Set(pcIn->mName); | |||||
| // POSITION keys | |||||
| if (pcIn->aPositionKeys.size() > 0) | |||||
| { | |||||
| nda->mNumPositionKeys = (unsigned int)pcIn->aPositionKeys.size(); | |||||
| nda->mPositionKeys = new aiVectorKey[nda->mNumPositionKeys]; | |||||
| ::memcpy(nda->mPositionKeys,&pcIn->aPositionKeys[0], | |||||
| sizeof(aiVectorKey)*nda->mNumPositionKeys); | |||||
| } | |||||
| // ROTATION keys | |||||
| if (pcIn->aRotationKeys.size() > 0) | |||||
| { | |||||
| nda->mNumRotationKeys = (unsigned int)pcIn->aRotationKeys.size(); | |||||
| nda->mRotationKeys = new aiQuatKey[nda->mNumRotationKeys]; | |||||
| // Rotations are quaternion offsets | |||||
| aiQuaternion abs; | |||||
| for (unsigned int n = 0; n < nda->mNumRotationKeys;++n) | |||||
| { | |||||
| const aiQuatKey& q = pcIn->aRotationKeys[n]; | |||||
| abs = (n ? abs * q.mValue : q.mValue); | |||||
| nda->mRotationKeys[n].mTime = q.mTime; | |||||
| nda->mRotationKeys[n].mValue = abs.Normalize(); | |||||
| } | |||||
| } | |||||
| // SCALING keys | |||||
| if (pcIn->aScalingKeys.size() > 0) | |||||
| { | |||||
| nda->mNumScalingKeys = (unsigned int)pcIn->aScalingKeys.size(); | |||||
| nda->mScalingKeys = new aiVectorKey[nda->mNumScalingKeys]; | |||||
| ::memcpy(nda->mScalingKeys,&pcIn->aScalingKeys[0], | |||||
| sizeof(aiVectorKey)*nda->mNumScalingKeys); | |||||
| } | |||||
| } | |||||
| // Allocate storage for children | |||||
| pcOut->mNumChildren = (unsigned int)pcIn->mChildren.size(); | |||||
| pcOut->mChildren = new aiNode*[pcIn->mChildren.size()]; | |||||
| // Recursively process all children | |||||
| const unsigned int size = pcIn->mChildren.size(); | |||||
| for (unsigned int i = 0; i < size;++i) | |||||
| { | |||||
| pcOut->mChildren[i] = new aiNode(); | |||||
| pcOut->mChildren[i]->mParent = pcOut; | |||||
| AddNodeToGraph(pcSOut,pcOut->mChildren[i],pcIn->mChildren[i],abs); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Find out how many node animation channels we'll have finally | |||||
| void CountTracks(D3DS::Node* node, unsigned int& cnt) | |||||
| { | |||||
| ////////////////////////////////////////////////////////////////////////////// | |||||
| // We will never generate more than one channel for a node, so | |||||
| // this is rather easy here. | |||||
| if (node->aPositionKeys.size() > 1 || node->aRotationKeys.size() > 1 || | |||||
| node->aScalingKeys.size() > 1 || node->aCameraRollKeys.size() > 1 || | |||||
| node->aTargetPositionKeys.size() > 1) | |||||
| { | |||||
| ++cnt; | |||||
| // account for the additional channel for the camera/spotlight target position | |||||
| if (node->aTargetPositionKeys.size() > 1)++cnt; | |||||
| } | |||||
| // Recursively process all children | |||||
| for (unsigned int i = 0; i < node->mChildren.size();++i) | |||||
| CountTracks(node->mChildren[i],cnt); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Generate the output node graph | |||||
| void Discreet3DSImporter::GenerateNodeGraph(aiScene* pcOut) | |||||
| { | |||||
| pcOut->mRootNode = new aiNode(); | |||||
| if (0 == mRootNode->mChildren.size()) | |||||
| { | |||||
| ////////////////////////////////////////////////////////////////////////////// | |||||
| // It seems the file is so messed up that it has not even a hierarchy. | |||||
| // generate a flat hiearachy which looks like this: | |||||
| // | |||||
| // ROOT_NODE | |||||
| // | | |||||
| // ---------------------------------------- | |||||
| // | | | | | | |||||
| // MESH_0 MESH_1 MESH_2 ... MESH_N CAMERA_0 .... | |||||
| // | |||||
| DefaultLogger::get()->warn("No hierarchy information has been found in the file. "); | |||||
| pcOut->mRootNode->mNumChildren = pcOut->mNumMeshes + | |||||
| mScene->mCameras.size() + mScene->mLights.size(); | |||||
| pcOut->mRootNode->mChildren = new aiNode* [ pcOut->mRootNode->mNumChildren ]; | |||||
| pcOut->mRootNode->mName.Set("<3DSDummyRoot>"); | |||||
| // Build dummy nodes for all meshes | |||||
| unsigned int a = 0; | |||||
| for (unsigned int i = 0; i < pcOut->mNumMeshes;++i,++a) | |||||
| { | |||||
| aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); | |||||
| pcNode->mParent = pcOut->mRootNode; | |||||
| pcNode->mMeshes = new unsigned int[1]; | |||||
| pcNode->mMeshes[0] = i; | |||||
| pcNode->mNumMeshes = 1; | |||||
| // Build a name for the node | |||||
| pcNode->mName.length = sprintf(pcNode->mName.data,"3DSMesh_%i",i); | |||||
| } | |||||
| // Build dummy nodes for all cameras | |||||
| for (unsigned int i = 0; i < (unsigned int )mScene->mCameras.size();++i,++a) | |||||
| { | |||||
| aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); | |||||
| pcNode->mParent = pcOut->mRootNode; | |||||
| // Build a name for the node | |||||
| pcNode->mName = mScene->mCameras[i]->mName; | |||||
| } | |||||
| // Build dummy nodes for all lights | |||||
| for (unsigned int i = 0; i < (unsigned int )mScene->mLights.size();++i,++a) | |||||
| { | |||||
| aiNode* pcNode = pcOut->mRootNode->mChildren[a] = new aiNode(); | |||||
| pcNode->mParent = pcOut->mRootNode; | |||||
| // Build a name for the node | |||||
| pcNode->mName = mScene->mLights[i]->mName; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| // First of all: find out how many scaling, rotation and translation | |||||
| // animation tracks we'll have afterwards | |||||
| unsigned int numChannel = 0; | |||||
| CountTracks(mRootNode,numChannel); | |||||
| if (numChannel) | |||||
| { | |||||
| // Allocate a primary animation channel | |||||
| pcOut->mNumAnimations = 1; | |||||
| pcOut->mAnimations = new aiAnimation*[1]; | |||||
| aiAnimation* anim = pcOut->mAnimations[0] = new aiAnimation(); | |||||
| anim->mName.Set("3DSMasterAnim"); | |||||
| // Allocate enough storage for all node animation channels, | |||||
| // but don't set the mNumChannels member - we'll use it to | |||||
| // index into the array | |||||
| anim->mChannels = new aiNodeAnim*[numChannel]; | |||||
| } | |||||
| aiMatrix4x4 m; | |||||
| AddNodeToGraph(pcOut, pcOut->mRootNode, mRootNode,m); | |||||
| } | |||||
| // We used the first and second vertex color set to store some temporary values so we need to cleanup here | |||||
| for (unsigned int a = 0; a < pcOut->mNumMeshes; ++a) | |||||
| { | |||||
| pcOut->mMeshes[a]->mColors[0] = NULL; | |||||
| pcOut->mMeshes[a]->mColors[1] = NULL; | |||||
| } | |||||
| pcOut->mRootNode->mTransformation = aiMatrix4x4( | |||||
| 1.f,0.f,0.f,0.f, | |||||
| 0.f,0.f,1.f,0.f, | |||||
| 0.f,-1.f,0.f,0.f, | |||||
| 0.f,0.f,0.f,1.f) * pcOut->mRootNode->mTransformation; | |||||
| // If the root node is unnamed name it "<3DSRoot>" | |||||
| if (::strstr( pcOut->mRootNode->mName.data, "UNNAMED" ) || | |||||
| (pcOut->mRootNode->mName.data[0] == '$' && pcOut->mRootNode->mName.data[1] == '$') ) | |||||
| { | |||||
| pcOut->mRootNode->mName.Set("<3DSRoot>"); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Convert all meshes in the scene and generate the final output scene. | |||||
| void Discreet3DSImporter::ConvertScene(aiScene* pcOut) | |||||
| { | |||||
| // Allocate enough storage for all output materials | |||||
| pcOut->mNumMaterials = (unsigned int)mScene->mMaterials.size(); | |||||
| pcOut->mMaterials = new aiMaterial*[pcOut->mNumMaterials]; | |||||
| // ... and convert the 3DS materials to aiMaterial's | |||||
| for (unsigned int i = 0; i < pcOut->mNumMaterials;++i) | |||||
| { | |||||
| aiMaterial* pcNew = new aiMaterial(); | |||||
| ConvertMaterial(mScene->mMaterials[i],*pcNew); | |||||
| pcOut->mMaterials[i] = pcNew; | |||||
| } | |||||
| // Generate the output mesh list | |||||
| ConvertMeshes(pcOut); | |||||
| // Now copy all light sources to the output scene | |||||
| pcOut->mNumLights = (unsigned int)mScene->mLights.size(); | |||||
| if (pcOut->mNumLights) | |||||
| { | |||||
| pcOut->mLights = new aiLight*[pcOut->mNumLights]; | |||||
| ::memcpy(pcOut->mLights,&mScene->mLights[0],sizeof(void*)*pcOut->mNumLights); | |||||
| } | |||||
| // Now copy all cameras to the output scene | |||||
| pcOut->mNumCameras = (unsigned int)mScene->mCameras.size(); | |||||
| if (pcOut->mNumCameras) | |||||
| { | |||||
| pcOut->mCameras = new aiCamera*[pcOut->mNumCameras]; | |||||
| ::memcpy(pcOut->mCameras,&mScene->mCameras[0],sizeof(void*)*pcOut->mNumCameras); | |||||
| } | |||||
| } | |||||
| #endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER | |||||
| @@ -0,0 +1,584 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file Defines helper data structures for the import of 3DS files */ | |||||
| #ifndef AI_3DSFILEHELPER_H_INC | |||||
| #define AI_3DSFILEHELPER_H_INC | |||||
| #include "SpatialSort.h" | |||||
| #include "SmoothingGroups.h" | |||||
| namespace Assimp { | |||||
| namespace D3DS { | |||||
| #include "./../include/assimp/Compiler/pushpack1.h" | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Discreet3DS class: Helper class for loading 3ds files. Defines chunks | |||||
| * and data structures. | |||||
| */ | |||||
| class Discreet3DS | |||||
| { | |||||
| private: | |||||
| inline Discreet3DS() {} | |||||
| public: | |||||
| //! data structure for a single chunk in a .3ds file | |||||
| struct Chunk | |||||
| { | |||||
| uint16_t Flag; | |||||
| uint32_t Size; | |||||
| } PACK_STRUCT; | |||||
| //! Used for shading field in material3ds structure | |||||
| //! From AutoDesk 3ds SDK | |||||
| typedef enum | |||||
| { | |||||
| // translated to gouraud shading with wireframe active | |||||
| Wire = 0x0, | |||||
| // if this material is set, no vertex normals will | |||||
| // be calculated for the model. Face normals + gouraud | |||||
| Flat = 0x1, | |||||
| // standard gouraud shading | |||||
| Gouraud = 0x2, | |||||
| // phong shading | |||||
| Phong = 0x3, | |||||
| // cooktorrance or anistropic phong shading ... | |||||
| // the exact meaning is unknown, if you know it | |||||
| // feel free to tell me ;-) | |||||
| Metal = 0x4, | |||||
| // required by the ASE loader | |||||
| Blinn = 0x5 | |||||
| } shadetype3ds; | |||||
| // Flags for animated keys | |||||
| enum | |||||
| { | |||||
| KEY_USE_TENS = 0x1, | |||||
| KEY_USE_CONT = 0x2, | |||||
| KEY_USE_BIAS = 0x4, | |||||
| KEY_USE_EASE_TO = 0x8, | |||||
| KEY_USE_EASE_FROM = 0x10 | |||||
| } ; | |||||
| enum | |||||
| { | |||||
| // ******************************************************************** | |||||
| // Basic chunks which can be found everywhere in the file | |||||
| CHUNK_VERSION = 0x0002, | |||||
| CHUNK_RGBF = 0x0010, // float4 R; float4 G; float4 B | |||||
| CHUNK_RGBB = 0x0011, // int1 R; int1 G; int B | |||||
| // Linear color values (gamma = 2.2?) | |||||
| CHUNK_LINRGBF = 0x0013, // float4 R; float4 G; float4 B | |||||
| CHUNK_LINRGBB = 0x0012, // int1 R; int1 G; int B | |||||
| CHUNK_PERCENTW = 0x0030, // int2 percentage | |||||
| CHUNK_PERCENTF = 0x0031, // float4 percentage | |||||
| // ******************************************************************** | |||||
| // Prj master chunk | |||||
| CHUNK_PRJ = 0xC23D, | |||||
| // MDLI master chunk | |||||
| CHUNK_MLI = 0x3DAA, | |||||
| // Primary main chunk of the .3ds file | |||||
| CHUNK_MAIN = 0x4D4D, | |||||
| // Mesh main chunk | |||||
| CHUNK_OBJMESH = 0x3D3D, | |||||
| // Specifies the background color of the .3ds file | |||||
| // This is passed through the material system for | |||||
| // viewing purposes. | |||||
| CHUNK_BKGCOLOR = 0x1200, | |||||
| // Specifies the ambient base color of the scene. | |||||
| // This is added to all materials in the file | |||||
| CHUNK_AMBCOLOR = 0x2100, | |||||
| // Specifies the background image for the whole scene | |||||
| // This value is passed through the material system | |||||
| // to the viewer | |||||
| CHUNK_BIT_MAP = 0x1100, | |||||
| CHUNK_BIT_MAP_EXISTS = 0x1101, | |||||
| // ******************************************************************** | |||||
| // Viewport related stuff. Ignored | |||||
| CHUNK_DEFAULT_VIEW = 0x3000, | |||||
| CHUNK_VIEW_TOP = 0x3010, | |||||
| CHUNK_VIEW_BOTTOM = 0x3020, | |||||
| CHUNK_VIEW_LEFT = 0x3030, | |||||
| CHUNK_VIEW_RIGHT = 0x3040, | |||||
| CHUNK_VIEW_FRONT = 0x3050, | |||||
| CHUNK_VIEW_BACK = 0x3060, | |||||
| CHUNK_VIEW_USER = 0x3070, | |||||
| CHUNK_VIEW_CAMERA = 0x3080, | |||||
| // ******************************************************************** | |||||
| // Mesh chunks | |||||
| CHUNK_OBJBLOCK = 0x4000, | |||||
| CHUNK_TRIMESH = 0x4100, | |||||
| CHUNK_VERTLIST = 0x4110, | |||||
| CHUNK_VERTFLAGS = 0x4111, | |||||
| CHUNK_FACELIST = 0x4120, | |||||
| CHUNK_FACEMAT = 0x4130, | |||||
| CHUNK_MAPLIST = 0x4140, | |||||
| CHUNK_SMOOLIST = 0x4150, | |||||
| CHUNK_TRMATRIX = 0x4160, | |||||
| CHUNK_MESHCOLOR = 0x4165, | |||||
| CHUNK_TXTINFO = 0x4170, | |||||
| CHUNK_LIGHT = 0x4600, | |||||
| CHUNK_CAMERA = 0x4700, | |||||
| CHUNK_HIERARCHY = 0x4F00, | |||||
| // Specifies the global scaling factor. This is applied | |||||
| // to the root node's transformation matrix | |||||
| CHUNK_MASTER_SCALE = 0x0100, | |||||
| // ******************************************************************** | |||||
| // Material chunks | |||||
| CHUNK_MAT_MATERIAL = 0xAFFF, | |||||
| // asciiz containing the name of the material | |||||
| CHUNK_MAT_MATNAME = 0xA000, | |||||
| CHUNK_MAT_AMBIENT = 0xA010, // followed by color chunk | |||||
| CHUNK_MAT_DIFFUSE = 0xA020, // followed by color chunk | |||||
| CHUNK_MAT_SPECULAR = 0xA030, // followed by color chunk | |||||
| // Specifies the shininess of the material | |||||
| // followed by percentage chunk | |||||
| CHUNK_MAT_SHININESS = 0xA040, | |||||
| CHUNK_MAT_SHININESS_PERCENT = 0xA041 , | |||||
| // Specifies the shading mode to be used | |||||
| // followed by a short | |||||
| CHUNK_MAT_SHADING = 0xA100, | |||||
| // NOTE: Emissive color (self illumination) seems not | |||||
| // to be a color but a single value, type is unknown. | |||||
| // Make the parser accept both of them. | |||||
| // followed by percentage chunk (?) | |||||
| CHUNK_MAT_SELF_ILLUM = 0xA080, | |||||
| // Always followed by percentage chunk (?) | |||||
| CHUNK_MAT_SELF_ILPCT = 0xA084, | |||||
| // Always followed by percentage chunk | |||||
| CHUNK_MAT_TRANSPARENCY = 0xA050, | |||||
| // Diffuse texture channel 0 | |||||
| CHUNK_MAT_TEXTURE = 0xA200, | |||||
| // Contains opacity information for each texel | |||||
| CHUNK_MAT_OPACMAP = 0xA210, | |||||
| // Contains a reflection map to be used to reflect | |||||
| // the environment. This is partially supported. | |||||
| CHUNK_MAT_REFLMAP = 0xA220, | |||||
| // Self Illumination map (emissive colors) | |||||
| CHUNK_MAT_SELFIMAP = 0xA33d, | |||||
| // Bumpmap. Not specified whether it is a heightmap | |||||
| // or a normal map. Assme it is a heightmap since | |||||
| // artist normally prefer this format. | |||||
| CHUNK_MAT_BUMPMAP = 0xA230, | |||||
| // Specular map. Seems to influence the specular color | |||||
| CHUNK_MAT_SPECMAP = 0xA204, | |||||
| // Holds shininess data. | |||||
| CHUNK_MAT_MAT_SHINMAP = 0xA33C, | |||||
| // Scaling in U/V direction. | |||||
| // (need to gen separate UV coordinate set | |||||
| // and do this by hand) | |||||
| CHUNK_MAT_MAP_USCALE = 0xA354, | |||||
| CHUNK_MAT_MAP_VSCALE = 0xA356, | |||||
| // Translation in U/V direction. | |||||
| // (need to gen separate UV coordinate set | |||||
| // and do this by hand) | |||||
| CHUNK_MAT_MAP_UOFFSET = 0xA358, | |||||
| CHUNK_MAT_MAP_VOFFSET = 0xA35a, | |||||
| // UV-coordinates rotation around the z-axis | |||||
| // Assumed to be in radians. | |||||
| CHUNK_MAT_MAP_ANG = 0xA35C, | |||||
| // Tiling flags for 3DS files | |||||
| CHUNK_MAT_MAP_TILING = 0xa351, | |||||
| // Specifies the file name of a texture | |||||
| CHUNK_MAPFILE = 0xA300, | |||||
| // Specifies whether a materail requires two-sided rendering | |||||
| CHUNK_MAT_TWO_SIDE = 0xA081, | |||||
| // ******************************************************************** | |||||
| // Main keyframer chunk. Contains translation/rotation/scaling data | |||||
| CHUNK_KEYFRAMER = 0xB000, | |||||
| // Supported sub chunks | |||||
| CHUNK_TRACKINFO = 0xB002, | |||||
| CHUNK_TRACKOBJNAME = 0xB010, | |||||
| CHUNK_TRACKDUMMYOBJNAME = 0xB011, | |||||
| CHUNK_TRACKPIVOT = 0xB013, | |||||
| CHUNK_TRACKPOS = 0xB020, | |||||
| CHUNK_TRACKROTATE = 0xB021, | |||||
| CHUNK_TRACKSCALE = 0xB022, | |||||
| // ******************************************************************** | |||||
| // Keyframes for various other stuff in the file | |||||
| // Partially ignored | |||||
| CHUNK_AMBIENTKEY = 0xB001, | |||||
| CHUNK_TRACKMORPH = 0xB026, | |||||
| CHUNK_TRACKHIDE = 0xB029, | |||||
| CHUNK_OBJNUMBER = 0xB030, | |||||
| CHUNK_TRACKCAMERA = 0xB003, | |||||
| CHUNK_TRACKFOV = 0xB023, | |||||
| CHUNK_TRACKROLL = 0xB024, | |||||
| CHUNK_TRACKCAMTGT = 0xB004, | |||||
| CHUNK_TRACKLIGHT = 0xB005, | |||||
| CHUNK_TRACKLIGTGT = 0xB006, | |||||
| CHUNK_TRACKSPOTL = 0xB007, | |||||
| CHUNK_FRAMES = 0xB008, | |||||
| // ******************************************************************** | |||||
| // light sub-chunks | |||||
| CHUNK_DL_OFF = 0x4620, | |||||
| CHUNK_DL_OUTER_RANGE = 0x465A, | |||||
| CHUNK_DL_INNER_RANGE = 0x4659, | |||||
| CHUNK_DL_MULTIPLIER = 0x465B, | |||||
| CHUNK_DL_EXCLUDE = 0x4654, | |||||
| CHUNK_DL_ATTENUATE = 0x4625, | |||||
| CHUNK_DL_SPOTLIGHT = 0x4610, | |||||
| // camera sub-chunks | |||||
| CHUNK_CAM_RANGES = 0x4720 | |||||
| }; | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper structure representing a 3ds mesh face */ | |||||
| struct Face : public FaceWithSmoothingGroup | |||||
| { | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper structure representing a texture */ | |||||
| struct Texture | |||||
| { | |||||
| //! Default constructor | |||||
| Texture() | |||||
| : mOffsetU (0.0f) | |||||
| , mOffsetV (0.0f) | |||||
| , mScaleU (1.0f) | |||||
| , mScaleV (1.0f) | |||||
| , mRotation (0.0f) | |||||
| , mMapMode (aiTextureMapMode_Wrap) | |||||
| , iUVSrc (0) | |||||
| { | |||||
| mTextureBlend = get_qnan(); | |||||
| } | |||||
| //! Specifies the blend factor for the texture | |||||
| float mTextureBlend; | |||||
| //! Specifies the filename of the texture | |||||
| std::string mMapName; | |||||
| //! Specifies texture coordinate offsets/scaling/rotations | |||||
| float mOffsetU; | |||||
| float mOffsetV; | |||||
| float mScaleU; | |||||
| float mScaleV; | |||||
| float mRotation; | |||||
| //! Specifies the mapping mode to be used for the texture | |||||
| aiTextureMapMode mMapMode; | |||||
| //! Used internally | |||||
| bool bPrivate; | |||||
| int iUVSrc; | |||||
| }; | |||||
| #include "./../include/assimp/Compiler/poppack1.h" | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper structure representing a 3ds material */ | |||||
| struct Material | |||||
| { | |||||
| //! Default constructor. Builds a default name for the material | |||||
| Material() | |||||
| : | |||||
| mDiffuse (0.6f,0.6f,0.6f), // FIX ... we won't want object to be black | |||||
| mSpecularExponent (0.0f), | |||||
| mShininessStrength (1.0f), | |||||
| mShading(Discreet3DS::Gouraud), | |||||
| mTransparency (1.0f), | |||||
| mBumpHeight (1.0f), | |||||
| mTwoSided (false) | |||||
| { | |||||
| static int iCnt = 0; | |||||
| char szTemp[128]; | |||||
| sprintf(szTemp,"UNNAMED_%i",iCnt++); | |||||
| mName = szTemp; | |||||
| } | |||||
| //! Name of the material | |||||
| std::string mName; | |||||
| //! Diffuse color of the material | |||||
| aiColor3D mDiffuse; | |||||
| //! Specular exponent | |||||
| float mSpecularExponent; | |||||
| //! Shininess strength, in percent | |||||
| float mShininessStrength; | |||||
| //! Specular color of the material | |||||
| aiColor3D mSpecular; | |||||
| //! Ambient color of the material | |||||
| aiColor3D mAmbient; | |||||
| //! Shading type to be used | |||||
| Discreet3DS::shadetype3ds mShading; | |||||
| //! Opacity of the material | |||||
| float mTransparency; | |||||
| //! Diffuse texture channel | |||||
| Texture sTexDiffuse; | |||||
| //! Opacity texture channel | |||||
| Texture sTexOpacity; | |||||
| //! Specular texture channel | |||||
| Texture sTexSpecular; | |||||
| //! Reflective texture channel | |||||
| Texture sTexReflective; | |||||
| //! Bump texture channel | |||||
| Texture sTexBump; | |||||
| //! Emissive texture channel | |||||
| Texture sTexEmissive; | |||||
| //! Shininess texture channel | |||||
| Texture sTexShininess; | |||||
| //! Scaling factor for the bump values | |||||
| float mBumpHeight; | |||||
| //! Emissive color | |||||
| aiColor3D mEmissive; | |||||
| //! Ambient texture channel | |||||
| //! (used by the ASE format) | |||||
| Texture sTexAmbient; | |||||
| //! True if the material must be rendered from two sides | |||||
| bool mTwoSided; | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper structure to represent a 3ds file mesh */ | |||||
| struct Mesh : public MeshWithSmoothingGroups<D3DS::Face> | |||||
| { | |||||
| //! Default constructor | |||||
| Mesh() | |||||
| { | |||||
| static int iCnt = 0; | |||||
| // Generate a default name for the mesh | |||||
| char szTemp[128]; | |||||
| ::sprintf(szTemp,"UNNAMED_%i",iCnt++); | |||||
| mName = szTemp; | |||||
| } | |||||
| //! Name of the mesh | |||||
| std::string mName; | |||||
| //! Texture coordinates | |||||
| std::vector<aiVector3D> mTexCoords; | |||||
| //! Face materials | |||||
| std::vector<unsigned int> mFaceMaterials; | |||||
| //! Local transformation matrix | |||||
| aiMatrix4x4 mMat; | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Float key - quite similar to aiVectorKey and aiQuatKey. Both are in the | |||||
| C-API, so it would be difficult to make them a template. */ | |||||
| struct aiFloatKey | |||||
| { | |||||
| double mTime; ///< The time of this key | |||||
| float mValue; ///< The value of this key | |||||
| #ifdef __cplusplus | |||||
| // time is not compared | |||||
| bool operator == (const aiFloatKey& o) const | |||||
| {return o.mValue == this->mValue;} | |||||
| bool operator != (const aiFloatKey& o) const | |||||
| {return o.mValue != this->mValue;} | |||||
| // Only time is compared. This operator is defined | |||||
| // for use with std::sort | |||||
| bool operator < (const aiFloatKey& o) const | |||||
| {return mTime < o.mTime;} | |||||
| bool operator > (const aiFloatKey& o) const | |||||
| {return mTime < o.mTime;} | |||||
| #endif | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper structure to represent a 3ds file node */ | |||||
| struct Node | |||||
| { | |||||
| Node() | |||||
| : mHierarchyPos (0) | |||||
| , mHierarchyIndex (0) | |||||
| , mInstanceCount (1) | |||||
| { | |||||
| static int iCnt = 0; | |||||
| // Generate a default name for the node | |||||
| char szTemp[128]; | |||||
| ::sprintf(szTemp,"UNNAMED_%i",iCnt++); | |||||
| mName = szTemp; | |||||
| aRotationKeys.reserve (20); | |||||
| aPositionKeys.reserve (20); | |||||
| aScalingKeys.reserve (20); | |||||
| } | |||||
| ~Node() | |||||
| { | |||||
| for (unsigned int i = 0; i < mChildren.size();++i) | |||||
| delete mChildren[i]; | |||||
| } | |||||
| //! Pointer to the parent node | |||||
| Node* mParent; | |||||
| //! Holds all child nodes | |||||
| std::vector<Node*> mChildren; | |||||
| //! Name of the node | |||||
| std::string mName; | |||||
| //! InstanceNumber of the node | |||||
| int32_t mInstanceNumber; | |||||
| //! Dummy nodes: real name to be combined with the $$$DUMMY | |||||
| std::string mDummyName; | |||||
| //! Position of the node in the hierarchy (tree depth) | |||||
| int16_t mHierarchyPos; | |||||
| //! Index of the node | |||||
| int16_t mHierarchyIndex; | |||||
| //! Rotation keys loaded from the file | |||||
| std::vector<aiQuatKey> aRotationKeys; | |||||
| //! Position keys loaded from the file | |||||
| std::vector<aiVectorKey> aPositionKeys; | |||||
| //! Scaling keys loaded from the file | |||||
| std::vector<aiVectorKey> aScalingKeys; | |||||
| // For target lights (spot lights and directional lights): | |||||
| // The position of the target | |||||
| std::vector< aiVectorKey > aTargetPositionKeys; | |||||
| // For cameras: the camera roll angle | |||||
| std::vector< aiFloatKey > aCameraRollKeys; | |||||
| //! Pivot position loaded from the file | |||||
| aiVector3D vPivot; | |||||
| //instance count, will be kept only for the first node | |||||
| int32_t mInstanceCount; | |||||
| //! Add a child node, setup the right parent node for it | |||||
| //! \param pc Node to be 'adopted' | |||||
| inline Node& push_back(Node* pc) | |||||
| { | |||||
| mChildren.push_back(pc); | |||||
| pc->mParent = this; | |||||
| return *this; | |||||
| } | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper structure analogue to aiScene */ | |||||
| struct Scene | |||||
| { | |||||
| //! List of all materials loaded | |||||
| //! NOTE: 3ds references materials globally | |||||
| std::vector<Material> mMaterials; | |||||
| //! List of all meshes loaded | |||||
| std::vector<Mesh> mMeshes; | |||||
| //! List of all cameras loaded | |||||
| std::vector<aiCamera*> mCameras; | |||||
| //! List of all lights loaded | |||||
| std::vector<aiLight*> mLights; | |||||
| //! Pointer to the root node of the scene | |||||
| // --- moved to main class | |||||
| // Node* pcRootNode; | |||||
| }; | |||||
| } // end of namespace D3DS | |||||
| } // end of namespace Assimp | |||||
| #endif // AI_XFILEHELPER_H_INC | |||||
| @@ -0,0 +1,280 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file 3DSLoader.h | |||||
| * @brief 3DS File format loader | |||||
| */ | |||||
| #ifndef AI_3DSIMPORTER_H_INC | |||||
| #define AI_3DSIMPORTER_H_INC | |||||
| #include "BaseImporter.h" | |||||
| #include "../include/assimp/types.h" | |||||
| #ifndef ASSIMP_BUILD_NO_3DS_IMPORTER | |||||
| struct aiNode; | |||||
| #include "3DSHelper.h" | |||||
| namespace Assimp { | |||||
| using namespace D3DS; | |||||
| // --------------------------------------------------------------------------------- | |||||
| /** Importer class for 3D Studio r3 and r4 3DS files | |||||
| */ | |||||
| class Discreet3DSImporter : public BaseImporter | |||||
| { | |||||
| public: | |||||
| Discreet3DSImporter(); | |||||
| ~Discreet3DSImporter(); | |||||
| public: | |||||
| // ------------------------------------------------------------------- | |||||
| /** Returns whether the class can handle the format of the given file. | |||||
| * See BaseImporter::CanRead() for details. | |||||
| */ | |||||
| bool CanRead( const std::string& pFile, IOSystem* pIOHandler, | |||||
| bool checkSig) const; | |||||
| // ------------------------------------------------------------------- | |||||
| /** Called prior to ReadFile(). | |||||
| * The function is a request to the importer to update its configuration | |||||
| * basing on the Importer's configuration property list. | |||||
| */ | |||||
| void SetupProperties(const Importer* pImp); | |||||
| protected: | |||||
| // ------------------------------------------------------------------- | |||||
| /** Return importer meta information. | |||||
| * See #BaseImporter::GetInfo for the details | |||||
| */ | |||||
| const aiImporterDesc* GetInfo () const; | |||||
| // ------------------------------------------------------------------- | |||||
| /** Imports the given file into the given scene structure. | |||||
| * See BaseImporter::InternReadFile() for details | |||||
| */ | |||||
| void InternReadFile( const std::string& pFile, aiScene* pScene, | |||||
| IOSystem* pIOHandler); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Converts a temporary material to the outer representation | |||||
| */ | |||||
| void ConvertMaterial(D3DS::Material& p_cMat, | |||||
| aiMaterial& p_pcOut); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Read a chunk | |||||
| * | |||||
| * @param pcOut Receives the current chunk | |||||
| */ | |||||
| void ReadChunk(Discreet3DS::Chunk* pcOut); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Parse a percentage chunk. mCurrent will point to the next | |||||
| * chunk behind afterwards. If no percentage chunk is found | |||||
| * QNAN is returned. | |||||
| */ | |||||
| float ParsePercentageChunk(); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Parse a color chunk. mCurrent will point to the next | |||||
| * chunk behind afterwards. If no color chunk is found | |||||
| * QNAN is returned in all members. | |||||
| */ | |||||
| void ParseColorChunk(aiColor3D* p_pcOut, | |||||
| bool p_bAcceptPercent = true); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Skip a chunk in the file | |||||
| */ | |||||
| void SkipChunk(); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Generate the nodegraph | |||||
| */ | |||||
| void GenerateNodeGraph(aiScene* pcOut); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Parse a main top-level chunk in the file | |||||
| */ | |||||
| void ParseMainChunk(); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Parse a top-level chunk in the file | |||||
| */ | |||||
| void ParseChunk(const char* name, unsigned int num); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Parse a top-level editor chunk in the file | |||||
| */ | |||||
| void ParseEditorChunk(); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Parse a top-level object chunk in the file | |||||
| */ | |||||
| void ParseObjectChunk(); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Parse a material chunk in the file | |||||
| */ | |||||
| void ParseMaterialChunk(); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Parse a mesh chunk in the file | |||||
| */ | |||||
| void ParseMeshChunk(); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Parse a light chunk in the file | |||||
| */ | |||||
| void ParseLightChunk(); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Parse a camera chunk in the file | |||||
| */ | |||||
| void ParseCameraChunk(); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Parse a face list chunk in the file | |||||
| */ | |||||
| void ParseFaceChunk(); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Parse a keyframe chunk in the file | |||||
| */ | |||||
| void ParseKeyframeChunk(); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Parse a hierarchy chunk in the file | |||||
| */ | |||||
| void ParseHierarchyChunk(uint16_t parent); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Parse a texture chunk in the file | |||||
| */ | |||||
| void ParseTextureChunk(D3DS::Texture* pcOut); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Convert the meshes in the file | |||||
| */ | |||||
| void ConvertMeshes(aiScene* pcOut); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Replace the default material in the scene | |||||
| */ | |||||
| void ReplaceDefaultMaterial(); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Convert the whole scene | |||||
| */ | |||||
| void ConvertScene(aiScene* pcOut); | |||||
| // ------------------------------------------------------------------- | |||||
| /** generate unique vertices for a mesh | |||||
| */ | |||||
| void MakeUnique(D3DS::Mesh& sMesh); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Add a node to the node graph | |||||
| */ | |||||
| void AddNodeToGraph(aiScene* pcSOut,aiNode* pcOut,D3DS::Node* pcIn, | |||||
| aiMatrix4x4& absTrafo); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Search for a node in the graph. | |||||
| * Called recursively | |||||
| */ | |||||
| void InverseNodeSearch(D3DS::Node* pcNode,D3DS::Node* pcCurrent); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Apply the master scaling factor to the mesh | |||||
| */ | |||||
| void ApplyMasterScale(aiScene* pScene); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Clamp all indices in the file to a valid range | |||||
| */ | |||||
| void CheckIndices(D3DS::Mesh& sMesh); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Skip the TCB info in a track key | |||||
| */ | |||||
| void SkipTCBInfo(); | |||||
| protected: | |||||
| /** Stream to read from */ | |||||
| StreamReaderLE* stream; | |||||
| /** Last touched node index */ | |||||
| short mLastNodeIndex; | |||||
| /** Current node, root node */ | |||||
| D3DS::Node* mCurrentNode, *mRootNode; | |||||
| /** Scene under construction */ | |||||
| D3DS::Scene* mScene; | |||||
| /** Ambient base color of the scene */ | |||||
| aiColor3D mClrAmbient; | |||||
| /** Master scaling factor of the scene */ | |||||
| float mMasterScale; | |||||
| /** Path to the background image of the scene */ | |||||
| std::string mBackgroundImage; | |||||
| bool bHasBG; | |||||
| /** true if PRJ file */ | |||||
| bool bIsPrj; | |||||
| }; | |||||
| #endif // !! ASSIMP_BUILD_NO_3DS_IMPORTER | |||||
| } // end of namespace Assimp | |||||
| #endif // AI_3DSIMPORTER_H_INC | |||||
| @@ -0,0 +1,866 @@ | |||||
| /* | |||||
| --------------------------------------------------------------------------- | |||||
| Open Asset Import Library (assimp) | |||||
| --------------------------------------------------------------------------- | |||||
| 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. | |||||
| --------------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file Implementation of the AC3D importer class */ | |||||
| #include "AssimpPCH.h" | |||||
| #ifndef ASSIMP_BUILD_NO_AC_IMPORTER | |||||
| // internal headers | |||||
| #include "ACLoader.h" | |||||
| #include "ParsingUtils.h" | |||||
| #include "fast_atof.h" | |||||
| #include "Subdivision.h" | |||||
| using namespace Assimp; | |||||
| static const aiImporterDesc desc = { | |||||
| "AC3D Importer", | |||||
| "", | |||||
| "", | |||||
| "", | |||||
| aiImporterFlags_SupportTextFlavour, | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| "ac acc ac3d" | |||||
| }; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // skip to the next token | |||||
| #define AI_AC_SKIP_TO_NEXT_TOKEN() \ | |||||
| if (!SkipSpaces(&buffer)) \ | |||||
| { \ | |||||
| DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL"); \ | |||||
| continue; \ | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // read a string (may be enclosed in double quotation marks). buffer must point to " | |||||
| #define AI_AC_GET_STRING(out) \ | |||||
| ++buffer; \ | |||||
| const char* sz = buffer; \ | |||||
| while ('\"' != *buffer) \ | |||||
| { \ | |||||
| if (IsLineEnd( *buffer )) \ | |||||
| { \ | |||||
| DefaultLogger::get()->error("AC3D: Unexpected EOF/EOL in string"); \ | |||||
| out = "ERROR"; \ | |||||
| break; \ | |||||
| } \ | |||||
| ++buffer; \ | |||||
| } \ | |||||
| if (IsLineEnd( *buffer ))continue; \ | |||||
| out = std::string(sz,(unsigned int)(buffer-sz)); \ | |||||
| ++buffer; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // read 1 to n floats prefixed with an optional predefined identifier | |||||
| #define AI_AC_CHECKED_LOAD_FLOAT_ARRAY(name,name_length,num,out) \ | |||||
| AI_AC_SKIP_TO_NEXT_TOKEN(); \ | |||||
| if (name_length) \ | |||||
| { \ | |||||
| if (strncmp(buffer,name,name_length) || !IsSpace(buffer[name_length])) \ | |||||
| { \ | |||||
| DefaultLogger::get()->error("AC3D: Unexpexted token. " name " was expected."); \ | |||||
| continue; \ | |||||
| } \ | |||||
| buffer += name_length+1; \ | |||||
| } \ | |||||
| for (unsigned int i = 0; i < num;++i) \ | |||||
| { \ | |||||
| AI_AC_SKIP_TO_NEXT_TOKEN(); \ | |||||
| buffer = fast_atoreal_move<float>(buffer,((float*)out)[i]); \ | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Constructor to be privately used by Importer | |||||
| AC3DImporter::AC3DImporter() | |||||
| { | |||||
| // nothing to be done here | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Destructor, private as well | |||||
| AC3DImporter::~AC3DImporter() | |||||
| { | |||||
| // nothing to be done here | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Returns whether the class can handle the format of the given file. | |||||
| bool AC3DImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const | |||||
| { | |||||
| std::string extension = GetExtension(pFile); | |||||
| // fixme: are acc and ac3d *really* used? Some sources say they are | |||||
| if(extension == "ac" || extension == "ac3d" || extension == "acc") { | |||||
| return true; | |||||
| } | |||||
| if (!extension.length() || checkSig) { | |||||
| uint32_t token = AI_MAKE_MAGIC("AC3D"); | |||||
| return CheckMagicToken(pIOHandler,pFile,&token,1,0); | |||||
| } | |||||
| return false; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Loader meta information | |||||
| const aiImporterDesc* AC3DImporter::GetInfo () const | |||||
| { | |||||
| return &desc; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Get a pointer to the next line from the file | |||||
| bool AC3DImporter::GetNextLine( ) | |||||
| { | |||||
| SkipLine(&buffer); | |||||
| return SkipSpaces(&buffer); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Parse an object section in an AC file | |||||
| void AC3DImporter::LoadObjectSection(std::vector<Object>& objects) | |||||
| { | |||||
| if (!TokenMatch(buffer,"OBJECT",6)) | |||||
| return; | |||||
| SkipSpaces(&buffer); | |||||
| ++mNumMeshes; | |||||
| objects.push_back(Object()); | |||||
| Object& obj = objects.back(); | |||||
| aiLight* light = NULL; | |||||
| if (!ASSIMP_strincmp(buffer,"light",5)) | |||||
| { | |||||
| // This is a light source. Add it to the list | |||||
| mLights->push_back(light = new aiLight()); | |||||
| // Return a point light with no attenuation | |||||
| light->mType = aiLightSource_POINT; | |||||
| light->mColorDiffuse = light->mColorSpecular = aiColor3D(1.f,1.f,1.f); | |||||
| light->mAttenuationConstant = 1.f; | |||||
| // Generate a default name for both the light source and the node | |||||
| // FIXME - what's the right way to print a size_t? Is 'zu' universally available? stick with the safe version. | |||||
| light->mName.length = ::sprintf(light->mName.data,"ACLight_%i",static_cast<unsigned int>(mLights->size())-1); | |||||
| obj.name = std::string( light->mName.data ); | |||||
| DefaultLogger::get()->debug("AC3D: Light source encountered"); | |||||
| obj.type = Object::Light; | |||||
| } | |||||
| else if (!ASSIMP_strincmp(buffer,"group",5)) | |||||
| { | |||||
| obj.type = Object::Group; | |||||
| } | |||||
| else if (!ASSIMP_strincmp(buffer,"world",5)) | |||||
| { | |||||
| obj.type = Object::World; | |||||
| } | |||||
| else obj.type = Object::Poly; | |||||
| while (GetNextLine()) | |||||
| { | |||||
| if (TokenMatch(buffer,"kids",4)) | |||||
| { | |||||
| SkipSpaces(&buffer); | |||||
| unsigned int num = strtoul10(buffer,&buffer); | |||||
| GetNextLine(); | |||||
| if (num) | |||||
| { | |||||
| // load the children of this object recursively | |||||
| obj.children.reserve(num); | |||||
| for (unsigned int i = 0; i < num; ++i) | |||||
| LoadObjectSection(obj.children); | |||||
| } | |||||
| return; | |||||
| } | |||||
| else if (TokenMatch(buffer,"name",4)) | |||||
| { | |||||
| SkipSpaces(&buffer); | |||||
| AI_AC_GET_STRING(obj.name); | |||||
| // If this is a light source, we'll also need to store | |||||
| // the name of the node in it. | |||||
| if (light) | |||||
| { | |||||
| light->mName.Set(obj.name); | |||||
| } | |||||
| } | |||||
| else if (TokenMatch(buffer,"texture",7)) | |||||
| { | |||||
| SkipSpaces(&buffer); | |||||
| AI_AC_GET_STRING(obj.texture); | |||||
| } | |||||
| else if (TokenMatch(buffer,"texrep",6)) | |||||
| { | |||||
| SkipSpaces(&buffer); | |||||
| AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texRepeat); | |||||
| if (!obj.texRepeat.x || !obj.texRepeat.y) | |||||
| obj.texRepeat = aiVector2D (1.f,1.f); | |||||
| } | |||||
| else if (TokenMatch(buffer,"texoff",6)) | |||||
| { | |||||
| SkipSpaces(&buffer); | |||||
| AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&obj.texOffset); | |||||
| } | |||||
| else if (TokenMatch(buffer,"rot",3)) | |||||
| { | |||||
| SkipSpaces(&buffer); | |||||
| AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,9,&obj.rotation); | |||||
| } | |||||
| else if (TokenMatch(buffer,"loc",3)) | |||||
| { | |||||
| SkipSpaces(&buffer); | |||||
| AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&obj.translation); | |||||
| } | |||||
| else if (TokenMatch(buffer,"subdiv",6)) | |||||
| { | |||||
| SkipSpaces(&buffer); | |||||
| obj.subDiv = strtoul10(buffer,&buffer); | |||||
| } | |||||
| else if (TokenMatch(buffer,"crease",6)) | |||||
| { | |||||
| SkipSpaces(&buffer); | |||||
| obj.crease = fast_atof(buffer); | |||||
| } | |||||
| else if (TokenMatch(buffer,"numvert",7)) | |||||
| { | |||||
| SkipSpaces(&buffer); | |||||
| unsigned int t = strtoul10(buffer,&buffer); | |||||
| obj.vertices.reserve(t); | |||||
| for (unsigned int i = 0; i < t;++i) | |||||
| { | |||||
| if (!GetNextLine()) | |||||
| { | |||||
| DefaultLogger::get()->error("AC3D: Unexpected EOF: not all vertices have been parsed yet"); | |||||
| break; | |||||
| } | |||||
| else if (!IsNumeric(*buffer)) | |||||
| { | |||||
| DefaultLogger::get()->error("AC3D: Unexpected token: not all vertices have been parsed yet"); | |||||
| --buffer; // make sure the line is processed a second time | |||||
| break; | |||||
| } | |||||
| obj.vertices.push_back(aiVector3D()); | |||||
| aiVector3D& v = obj.vertices.back(); | |||||
| AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,3,&v.x); | |||||
| } | |||||
| } | |||||
| else if (TokenMatch(buffer,"numsurf",7)) | |||||
| { | |||||
| SkipSpaces(&buffer); | |||||
| bool Q3DWorkAround = false; | |||||
| const unsigned int t = strtoul10(buffer,&buffer); | |||||
| obj.surfaces.reserve(t); | |||||
| for (unsigned int i = 0; i < t;++i) | |||||
| { | |||||
| GetNextLine(); | |||||
| if (!TokenMatch(buffer,"SURF",4)) | |||||
| { | |||||
| // FIX: this can occur for some files - Quick 3D for | |||||
| // example writes no surf chunks | |||||
| if (!Q3DWorkAround) | |||||
| { | |||||
| DefaultLogger::get()->warn("AC3D: SURF token was expected"); | |||||
| DefaultLogger::get()->debug("Continuing with Quick3D Workaround enabled"); | |||||
| } | |||||
| --buffer; // make sure the line is processed a second time | |||||
| // break; --- see fix notes above | |||||
| Q3DWorkAround = true; | |||||
| } | |||||
| SkipSpaces(&buffer); | |||||
| obj.surfaces.push_back(Surface()); | |||||
| Surface& surf = obj.surfaces.back(); | |||||
| surf.flags = strtoul_cppstyle(buffer); | |||||
| while (1) | |||||
| { | |||||
| if(!GetNextLine()) | |||||
| { | |||||
| DefaultLogger::get()->error("AC3D: Unexpected EOF: surface is incomplete"); | |||||
| break; | |||||
| } | |||||
| if (TokenMatch(buffer,"mat",3)) | |||||
| { | |||||
| SkipSpaces(&buffer); | |||||
| surf.mat = strtoul10(buffer); | |||||
| } | |||||
| else if (TokenMatch(buffer,"refs",4)) | |||||
| { | |||||
| // --- see fix notes above | |||||
| if (Q3DWorkAround) | |||||
| { | |||||
| if (!surf.entries.empty()) | |||||
| { | |||||
| buffer -= 6; | |||||
| break; | |||||
| } | |||||
| } | |||||
| SkipSpaces(&buffer); | |||||
| const unsigned int m = strtoul10(buffer); | |||||
| surf.entries.reserve(m); | |||||
| obj.numRefs += m; | |||||
| for (unsigned int k = 0; k < m; ++k) | |||||
| { | |||||
| if(!GetNextLine()) | |||||
| { | |||||
| DefaultLogger::get()->error("AC3D: Unexpected EOF: surface references are incomplete"); | |||||
| break; | |||||
| } | |||||
| surf.entries.push_back(Surface::SurfaceEntry()); | |||||
| Surface::SurfaceEntry& entry = surf.entries.back(); | |||||
| entry.first = strtoul10(buffer,&buffer); | |||||
| SkipSpaces(&buffer); | |||||
| AI_AC_CHECKED_LOAD_FLOAT_ARRAY("",0,2,&entry.second); | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| --buffer; // make sure the line is processed a second time | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| DefaultLogger::get()->error("AC3D: Unexpected EOF: \'kids\' line was expected"); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Convert a material from AC3DImporter::Material to aiMaterial | |||||
| void AC3DImporter::ConvertMaterial(const Object& object, | |||||
| const Material& matSrc, | |||||
| aiMaterial& matDest) | |||||
| { | |||||
| aiString s; | |||||
| if (matSrc.name.length()) | |||||
| { | |||||
| s.Set(matSrc.name); | |||||
| matDest.AddProperty(&s,AI_MATKEY_NAME); | |||||
| } | |||||
| if (object.texture.length()) | |||||
| { | |||||
| s.Set(object.texture); | |||||
| matDest.AddProperty(&s,AI_MATKEY_TEXTURE_DIFFUSE(0)); | |||||
| // UV transformation | |||||
| if (1.f != object.texRepeat.x || 1.f != object.texRepeat.y || | |||||
| object.texOffset.x || object.texOffset.y) | |||||
| { | |||||
| aiUVTransform transform; | |||||
| transform.mScaling = object.texRepeat; | |||||
| transform.mTranslation = object.texOffset; | |||||
| matDest.AddProperty(&transform,1,AI_MATKEY_UVTRANSFORM_DIFFUSE(0)); | |||||
| } | |||||
| } | |||||
| matDest.AddProperty<aiColor3D>(&matSrc.rgb,1, AI_MATKEY_COLOR_DIFFUSE); | |||||
| matDest.AddProperty<aiColor3D>(&matSrc.amb,1, AI_MATKEY_COLOR_AMBIENT); | |||||
| matDest.AddProperty<aiColor3D>(&matSrc.emis,1,AI_MATKEY_COLOR_EMISSIVE); | |||||
| matDest.AddProperty<aiColor3D>(&matSrc.spec,1,AI_MATKEY_COLOR_SPECULAR); | |||||
| int n; | |||||
| if (matSrc.shin) | |||||
| { | |||||
| n = aiShadingMode_Phong; | |||||
| matDest.AddProperty<float>(&matSrc.shin,1,AI_MATKEY_SHININESS); | |||||
| } | |||||
| else n = aiShadingMode_Gouraud; | |||||
| matDest.AddProperty<int>(&n,1,AI_MATKEY_SHADING_MODEL); | |||||
| float f = 1.f - matSrc.trans; | |||||
| matDest.AddProperty<float>(&f,1,AI_MATKEY_OPACITY); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Converts the loaded data to the internal verbose representation | |||||
| aiNode* AC3DImporter::ConvertObjectSection(Object& object, | |||||
| std::vector<aiMesh*>& meshes, | |||||
| std::vector<aiMaterial*>& outMaterials, | |||||
| const std::vector<Material>& materials, | |||||
| aiNode* parent) | |||||
| { | |||||
| aiNode* node = new aiNode(); | |||||
| node->mParent = parent; | |||||
| if (object.vertices.size()) | |||||
| { | |||||
| if (!object.surfaces.size() || !object.numRefs) | |||||
| { | |||||
| /* " An object with 7 vertices (no surfaces, no materials defined). | |||||
| This is a good way of getting point data into AC3D. | |||||
| The Vertex->create convex-surface/object can be used on these | |||||
| vertices to 'wrap' a 3d shape around them " | |||||
| (http://www.opencity.info/html/ac3dfileformat.html) | |||||
| therefore: if no surfaces are defined return point data only | |||||
| */ | |||||
| DefaultLogger::get()->info("AC3D: No surfaces defined in object definition, " | |||||
| "a point list is returned"); | |||||
| meshes.push_back(new aiMesh()); | |||||
| aiMesh* mesh = meshes.back(); | |||||
| mesh->mNumFaces = mesh->mNumVertices = (unsigned int)object.vertices.size(); | |||||
| aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces]; | |||||
| aiVector3D* verts = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; | |||||
| for (unsigned int i = 0; i < mesh->mNumVertices;++i,++faces,++verts) | |||||
| { | |||||
| *verts = object.vertices[i]; | |||||
| faces->mNumIndices = 1; | |||||
| faces->mIndices = new unsigned int[1]; | |||||
| faces->mIndices[0] = i; | |||||
| } | |||||
| // use the primary material in this case. this should be the | |||||
| // default material if all objects of the file contain points | |||||
| // and no faces. | |||||
| mesh->mMaterialIndex = 0; | |||||
| outMaterials.push_back(new aiMaterial()); | |||||
| ConvertMaterial(object, materials[0], *outMaterials.back()); | |||||
| } | |||||
| else | |||||
| { | |||||
| // need to generate one or more meshes for this object. | |||||
| // find out how many different materials we have | |||||
| typedef std::pair< unsigned int, unsigned int > IntPair; | |||||
| typedef std::vector< IntPair > MatTable; | |||||
| MatTable needMat(materials.size(),IntPair(0,0)); | |||||
| std::vector<Surface>::iterator it,end = object.surfaces.end(); | |||||
| std::vector<Surface::SurfaceEntry>::iterator it2,end2; | |||||
| for (it = object.surfaces.begin(); it != end; ++it) | |||||
| { | |||||
| register unsigned int idx = (*it).mat; | |||||
| if (idx >= needMat.size()) | |||||
| { | |||||
| DefaultLogger::get()->error("AC3D: material index is out of range"); | |||||
| idx = 0; | |||||
| } | |||||
| if ((*it).entries.empty()) | |||||
| { | |||||
| DefaultLogger::get()->warn("AC3D: surface her zero vertex references"); | |||||
| } | |||||
| // validate all vertex indices to make sure we won't crash here | |||||
| for (it2 = (*it).entries.begin(), | |||||
| end2 = (*it).entries.end(); it2 != end2; ++it2) | |||||
| { | |||||
| if ((*it2).first >= object.vertices.size()) | |||||
| { | |||||
| DefaultLogger::get()->warn("AC3D: Invalid vertex reference"); | |||||
| (*it2).first = 0; | |||||
| } | |||||
| } | |||||
| if (!needMat[idx].first)++node->mNumMeshes; | |||||
| switch ((*it).flags & 0xf) | |||||
| { | |||||
| // closed line | |||||
| case 0x1: | |||||
| needMat[idx].first += (unsigned int)(*it).entries.size(); | |||||
| needMat[idx].second += (unsigned int)(*it).entries.size()<<1u; | |||||
| break; | |||||
| // unclosed line | |||||
| case 0x2: | |||||
| needMat[idx].first += (unsigned int)(*it).entries.size()-1; | |||||
| needMat[idx].second += ((unsigned int)(*it).entries.size()-1)<<1u; | |||||
| break; | |||||
| // 0 == polygon, else unknown | |||||
| default: | |||||
| if ((*it).flags & 0xf) | |||||
| { | |||||
| DefaultLogger::get()->warn("AC3D: The type flag of a surface is unknown"); | |||||
| (*it).flags &= ~(0xf); | |||||
| } | |||||
| // the number of faces increments by one, the number | |||||
| // of vertices by surface.numref. | |||||
| needMat[idx].first++; | |||||
| needMat[idx].second += (unsigned int)(*it).entries.size(); | |||||
| }; | |||||
| } | |||||
| unsigned int* pip = node->mMeshes = new unsigned int[node->mNumMeshes]; | |||||
| unsigned int mat = 0; | |||||
| const size_t oldm = meshes.size(); | |||||
| for (MatTable::const_iterator cit = needMat.begin(), cend = needMat.end(); | |||||
| cit != cend; ++cit, ++mat) | |||||
| { | |||||
| if (!(*cit).first)continue; | |||||
| // allocate a new aiMesh object | |||||
| *pip++ = (unsigned int)meshes.size(); | |||||
| aiMesh* mesh = new aiMesh(); | |||||
| meshes.push_back(mesh); | |||||
| mesh->mMaterialIndex = (unsigned int)outMaterials.size(); | |||||
| outMaterials.push_back(new aiMaterial()); | |||||
| ConvertMaterial(object, materials[mat], *outMaterials.back()); | |||||
| // allocate storage for vertices and normals | |||||
| mesh->mNumFaces = (*cit).first; | |||||
| aiFace* faces = mesh->mFaces = new aiFace[mesh->mNumFaces]; | |||||
| mesh->mNumVertices = (*cit).second; | |||||
| aiVector3D* vertices = mesh->mVertices = new aiVector3D[mesh->mNumVertices]; | |||||
| unsigned int cur = 0; | |||||
| // allocate UV coordinates, but only if the texture name for the | |||||
| // surface is not empty | |||||
| aiVector3D* uv = NULL; | |||||
| if(object.texture.length()) | |||||
| { | |||||
| uv = mesh->mTextureCoords[0] = new aiVector3D[mesh->mNumVertices]; | |||||
| mesh->mNumUVComponents[0] = 2; | |||||
| } | |||||
| for (it = object.surfaces.begin(); it != end; ++it) | |||||
| { | |||||
| if (mat == (*it).mat) | |||||
| { | |||||
| const Surface& src = *it; | |||||
| // closed polygon | |||||
| unsigned int type = (*it).flags & 0xf; | |||||
| if (!type) | |||||
| { | |||||
| aiFace& face = *faces++; | |||||
| if((face.mNumIndices = (unsigned int)src.entries.size())) | |||||
| { | |||||
| face.mIndices = new unsigned int[face.mNumIndices]; | |||||
| for (unsigned int i = 0; i < face.mNumIndices;++i,++vertices) | |||||
| { | |||||
| const Surface::SurfaceEntry& entry = src.entries[i]; | |||||
| face.mIndices[i] = cur++; | |||||
| // copy vertex positions | |||||
| *vertices = object.vertices[entry.first] + object.translation; | |||||
| // copy texture coordinates | |||||
| if (uv) | |||||
| { | |||||
| uv->x = entry.second.x; | |||||
| uv->y = entry.second.y; | |||||
| ++uv; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| it2 = (*it).entries.begin(); | |||||
| // either a closed or an unclosed line | |||||
| register unsigned int tmp = (unsigned int)(*it).entries.size(); | |||||
| if (0x2 == type)--tmp; | |||||
| for (unsigned int m = 0; m < tmp;++m) | |||||
| { | |||||
| aiFace& face = *faces++; | |||||
| face.mNumIndices = 2; | |||||
| face.mIndices = new unsigned int[2]; | |||||
| face.mIndices[0] = cur++; | |||||
| face.mIndices[1] = cur++; | |||||
| // copy vertex positions | |||||
| *vertices++ = object.vertices[(*it2).first]; | |||||
| // copy texture coordinates | |||||
| if (uv) | |||||
| { | |||||
| uv->x = (*it2).second.x; | |||||
| uv->y = (*it2).second.y; | |||||
| ++uv; | |||||
| } | |||||
| if (0x1 == type && tmp-1 == m) | |||||
| { | |||||
| // if this is a closed line repeat its beginning now | |||||
| it2 = (*it).entries.begin(); | |||||
| } | |||||
| else ++it2; | |||||
| // second point | |||||
| *vertices++ = object.vertices[(*it2).first]; | |||||
| if (uv) | |||||
| { | |||||
| uv->x = (*it2).second.x; | |||||
| uv->y = (*it2).second.y; | |||||
| ++uv; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| // Now apply catmull clark subdivision if necessary. We split meshes into | |||||
| // materials which is not done by AC3D during smoothing, so we need to | |||||
| // collect all meshes using the same material group. | |||||
| if (object.subDiv) { | |||||
| if (configEvalSubdivision) { | |||||
| boost::scoped_ptr<Subdivider> div(Subdivider::Create(Subdivider::CATMULL_CLARKE)); | |||||
| DefaultLogger::get()->info("AC3D: Evaluating subdivision surface: "+object.name); | |||||
| std::vector<aiMesh*> cpy(meshes.size()-oldm,NULL); | |||||
| div->Subdivide(&meshes[oldm],cpy.size(),&cpy.front(),object.subDiv,true); | |||||
| std::copy(cpy.begin(),cpy.end(),meshes.begin()+oldm); | |||||
| // previous meshes are deleted vy Subdivide(). | |||||
| } | |||||
| else { | |||||
| DefaultLogger::get()->info("AC3D: Letting the subdivision surface untouched due to my configuration: " | |||||
| +object.name); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| if (object.name.length()) | |||||
| node->mName.Set(object.name); | |||||
| else | |||||
| { | |||||
| // generate a name depending on the type of the node | |||||
| switch (object.type) | |||||
| { | |||||
| case Object::Group: | |||||
| node->mName.length = ::sprintf(node->mName.data,"ACGroup_%i",groups++); | |||||
| break; | |||||
| case Object::Poly: | |||||
| node->mName.length = ::sprintf(node->mName.data,"ACPoly_%i",polys++); | |||||
| break; | |||||
| case Object::Light: | |||||
| node->mName.length = ::sprintf(node->mName.data,"ACLight_%i",lights++); | |||||
| break; | |||||
| // there shouldn't be more than one world, but we don't care | |||||
| case Object::World: | |||||
| node->mName.length = ::sprintf(node->mName.data,"ACWorld_%i",worlds++); | |||||
| break; | |||||
| } | |||||
| } | |||||
| // setup the local transformation matrix of the object | |||||
| // compute the transformation offset to the parent node | |||||
| node->mTransformation = aiMatrix4x4 ( object.rotation ); | |||||
| if (object.type == Object::Group || !object.numRefs) | |||||
| { | |||||
| node->mTransformation.a4 = object.translation.x; | |||||
| node->mTransformation.b4 = object.translation.y; | |||||
| node->mTransformation.c4 = object.translation.z; | |||||
| } | |||||
| // add children to the object | |||||
| if (object.children.size()) | |||||
| { | |||||
| node->mNumChildren = (unsigned int)object.children.size(); | |||||
| node->mChildren = new aiNode*[node->mNumChildren]; | |||||
| for (unsigned int i = 0; i < node->mNumChildren;++i) | |||||
| { | |||||
| node->mChildren[i] = ConvertObjectSection(object.children[i],meshes,outMaterials,materials,node); | |||||
| } | |||||
| } | |||||
| return node; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void AC3DImporter::SetupProperties(const Importer* pImp) | |||||
| { | |||||
| configSplitBFCull = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL,1) ? true : false; | |||||
| configEvalSubdivision = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_AC_EVAL_SUBDIVISION,1) ? true : false; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Imports the given file into the given scene structure. | |||||
| void AC3DImporter::InternReadFile( const std::string& pFile, | |||||
| aiScene* pScene, IOSystem* pIOHandler) | |||||
| { | |||||
| boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb")); | |||||
| // Check whether we can read from the file | |||||
| if( file.get() == NULL) | |||||
| throw DeadlyImportError( "Failed to open AC3D file " + pFile + "."); | |||||
| // allocate storage and copy the contents of the file to a memory buffer | |||||
| std::vector<char> mBuffer2; | |||||
| TextFileToBuffer(file.get(),mBuffer2); | |||||
| buffer = &mBuffer2[0]; | |||||
| mNumMeshes = 0; | |||||
| lights = polys = worlds = groups = 0; | |||||
| if (::strncmp(buffer,"AC3D",4)) { | |||||
| throw DeadlyImportError("AC3D: No valid AC3D file, magic sequence not found"); | |||||
| } | |||||
| // print the file format version to the console | |||||
| unsigned int version = HexDigitToDecimal( buffer[4] ); | |||||
| char msg[3]; | |||||
| ASSIMP_itoa10(msg,3,version); | |||||
| DefaultLogger::get()->info(std::string("AC3D file format version: ") + msg); | |||||
| std::vector<Material> materials; | |||||
| materials.reserve(5); | |||||
| std::vector<Object> rootObjects; | |||||
| rootObjects.reserve(5); | |||||
| std::vector<aiLight*> lights; | |||||
| mLights = & lights; | |||||
| while (GetNextLine()) | |||||
| { | |||||
| if (TokenMatch(buffer,"MATERIAL",8)) | |||||
| { | |||||
| materials.push_back(Material()); | |||||
| Material& mat = materials.back(); | |||||
| // manually parse the material ... sscanf would use the buldin atof ... | |||||
| // Format: (name) rgb %f %f %f amb %f %f %f emis %f %f %f spec %f %f %f shi %d trans %f | |||||
| AI_AC_SKIP_TO_NEXT_TOKEN(); | |||||
| if ('\"' == *buffer) | |||||
| { | |||||
| AI_AC_GET_STRING(mat.name); | |||||
| AI_AC_SKIP_TO_NEXT_TOKEN(); | |||||
| } | |||||
| AI_AC_CHECKED_LOAD_FLOAT_ARRAY("rgb",3,3,&mat.rgb); | |||||
| AI_AC_CHECKED_LOAD_FLOAT_ARRAY("amb",3,3,&mat.amb); | |||||
| AI_AC_CHECKED_LOAD_FLOAT_ARRAY("emis",4,3,&mat.emis); | |||||
| AI_AC_CHECKED_LOAD_FLOAT_ARRAY("spec",4,3,&mat.spec); | |||||
| AI_AC_CHECKED_LOAD_FLOAT_ARRAY("shi",3,1,&mat.shin); | |||||
| AI_AC_CHECKED_LOAD_FLOAT_ARRAY("trans",5,1,&mat.trans); | |||||
| } | |||||
| LoadObjectSection(rootObjects); | |||||
| } | |||||
| if (rootObjects.empty() || !mNumMeshes) | |||||
| { | |||||
| throw DeadlyImportError("AC3D: No meshes have been loaded"); | |||||
| } | |||||
| if (materials.empty()) | |||||
| { | |||||
| DefaultLogger::get()->warn("AC3D: No material has been found"); | |||||
| materials.push_back(Material()); | |||||
| } | |||||
| mNumMeshes += (mNumMeshes>>2u) + 1; | |||||
| std::vector<aiMesh*> meshes; | |||||
| meshes.reserve(mNumMeshes); | |||||
| std::vector<aiMaterial*> omaterials; | |||||
| materials.reserve(mNumMeshes); | |||||
| // generate a dummy root if there are multiple objects on the top layer | |||||
| Object* root; | |||||
| if (1 == rootObjects.size()) | |||||
| root = &rootObjects[0]; | |||||
| else | |||||
| { | |||||
| root = new Object(); | |||||
| } | |||||
| // now convert the imported stuff to our output data structure | |||||
| pScene->mRootNode = ConvertObjectSection(*root,meshes,omaterials,materials); | |||||
| if (1 != rootObjects.size())delete root; | |||||
| if (!::strncmp( pScene->mRootNode->mName.data, "Node", 4)) | |||||
| pScene->mRootNode->mName.Set("<AC3DWorld>"); | |||||
| // copy meshes | |||||
| if (meshes.empty()) | |||||
| { | |||||
| throw DeadlyImportError("An unknown error occured during converting"); | |||||
| } | |||||
| pScene->mNumMeshes = (unsigned int)meshes.size(); | |||||
| pScene->mMeshes = new aiMesh*[pScene->mNumMeshes]; | |||||
| ::memcpy(pScene->mMeshes,&meshes[0],pScene->mNumMeshes*sizeof(void*)); | |||||
| // copy materials | |||||
| pScene->mNumMaterials = (unsigned int)omaterials.size(); | |||||
| pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials]; | |||||
| ::memcpy(pScene->mMaterials,&omaterials[0],pScene->mNumMaterials*sizeof(void*)); | |||||
| // copy lights | |||||
| pScene->mNumLights = (unsigned int)lights.size(); | |||||
| if (lights.size()) | |||||
| { | |||||
| pScene->mLights = new aiLight*[lights.size()]; | |||||
| ::memcpy(pScene->mLights,&lights[0],lights.size()*sizeof(void*)); | |||||
| } | |||||
| } | |||||
| #endif //!defined ASSIMP_BUILD_NO_AC_IMPORTER | |||||
| @@ -0,0 +1,267 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file ACLoader.h | |||||
| * @brief Declaration of the .ac importer class. | |||||
| */ | |||||
| #ifndef AI_AC3DLOADER_H_INCLUDED | |||||
| #define AI_AC3DLOADER_H_INCLUDED | |||||
| #include <vector> | |||||
| #include "BaseImporter.h" | |||||
| #include "../include/assimp/types.h" | |||||
| namespace Assimp { | |||||
| // --------------------------------------------------------------------------- | |||||
| /** AC3D (*.ac) importer class | |||||
| */ | |||||
| class AC3DImporter : public BaseImporter | |||||
| { | |||||
| public: | |||||
| AC3DImporter(); | |||||
| ~AC3DImporter(); | |||||
| // Represents an AC3D material | |||||
| struct Material | |||||
| { | |||||
| Material() | |||||
| : rgb (0.6f,0.6f,0.6f) | |||||
| , spec (1.f,1.f,1.f) | |||||
| , shin (0.f) | |||||
| , trans (0.f) | |||||
| {} | |||||
| // base color of the material | |||||
| aiColor3D rgb; | |||||
| // ambient color of the material | |||||
| aiColor3D amb; | |||||
| // emissive color of the material | |||||
| aiColor3D emis; | |||||
| // specular color of the material | |||||
| aiColor3D spec; | |||||
| // shininess exponent | |||||
| float shin; | |||||
| // transparency. 0 == opaque | |||||
| float trans; | |||||
| // name of the material. optional. | |||||
| std::string name; | |||||
| }; | |||||
| // Represents an AC3D surface | |||||
| struct Surface | |||||
| { | |||||
| Surface() | |||||
| : mat (0) | |||||
| , flags (0) | |||||
| {} | |||||
| unsigned int mat,flags; | |||||
| typedef std::pair<unsigned int, aiVector2D > SurfaceEntry; | |||||
| std::vector< SurfaceEntry > entries; | |||||
| }; | |||||
| // Represents an AC3D object | |||||
| struct Object | |||||
| { | |||||
| Object() | |||||
| : type (World) | |||||
| , name( "" ) | |||||
| , children() | |||||
| , texture( "" ) | |||||
| , texRepeat( 1.f, 1.f ) | |||||
| , texOffset( 0.0f, 0.0f ) | |||||
| , rotation() | |||||
| , translation() | |||||
| , vertices() | |||||
| , surfaces() | |||||
| , numRefs (0) | |||||
| , subDiv (0) | |||||
| {} | |||||
| // Type description | |||||
| enum Type | |||||
| { | |||||
| World = 0x0, | |||||
| Poly = 0x1, | |||||
| Group = 0x2, | |||||
| Light = 0x4 | |||||
| } type; | |||||
| // name of the object | |||||
| std::string name; | |||||
| // object children | |||||
| std::vector<Object> children; | |||||
| // texture to be assigned to all surfaces of the object | |||||
| std::string texture; | |||||
| // texture repat factors (scaling for all coordinates) | |||||
| aiVector2D texRepeat, texOffset; | |||||
| // rotation matrix | |||||
| aiMatrix3x3 rotation; | |||||
| // translation vector | |||||
| aiVector3D translation; | |||||
| // vertices | |||||
| std::vector<aiVector3D> vertices; | |||||
| // surfaces | |||||
| std::vector<Surface> surfaces; | |||||
| // number of indices (= num verts in verbose format) | |||||
| unsigned int numRefs; | |||||
| // number of subdivisions to be performed on the | |||||
| // imported data | |||||
| unsigned int subDiv; | |||||
| // max angle limit for smoothing | |||||
| float crease; | |||||
| }; | |||||
| public: | |||||
| // ------------------------------------------------------------------- | |||||
| /** Returns whether the class can handle the format of the given file. | |||||
| * See BaseImporter::CanRead() for details. | |||||
| */ | |||||
| bool CanRead( const std::string& pFile, IOSystem* pIOHandler, | |||||
| bool checkSig) const; | |||||
| protected: | |||||
| // ------------------------------------------------------------------- | |||||
| /** Return importer meta information. | |||||
| * See #BaseImporter::GetInfo for the details */ | |||||
| const aiImporterDesc* GetInfo () const; | |||||
| // ------------------------------------------------------------------- | |||||
| /** Imports the given file into the given scene structure. | |||||
| * See BaseImporter::InternReadFile() for details*/ | |||||
| void InternReadFile( const std::string& pFile, aiScene* pScene, | |||||
| IOSystem* pIOHandler); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Called prior to ReadFile(). | |||||
| * The function is a request to the importer to update its configuration | |||||
| * basing on the Importer's configuration property list.*/ | |||||
| void SetupProperties(const Importer* pImp); | |||||
| private: | |||||
| // ------------------------------------------------------------------- | |||||
| /** Get the next line from the file. | |||||
| * @return false if the end of the file was reached*/ | |||||
| bool GetNextLine(); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Load the object section. This method is called recursively to | |||||
| * load subobjects, the method returns after a 'kids 0' was | |||||
| * encountered. | |||||
| * @objects List of output objects*/ | |||||
| void LoadObjectSection(std::vector<Object>& objects); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Convert all objects into meshes and nodes. | |||||
| * @param object Current object to work on | |||||
| * @param meshes Pointer to the list of output meshes | |||||
| * @param outMaterials List of output materials | |||||
| * @param materials Material list | |||||
| * @param Scenegraph node for the object */ | |||||
| aiNode* ConvertObjectSection(Object& object, | |||||
| std::vector<aiMesh*>& meshes, | |||||
| std::vector<aiMaterial*>& outMaterials, | |||||
| const std::vector<Material>& materials, | |||||
| aiNode* parent = NULL); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Convert a material | |||||
| * @param object Current object | |||||
| * @param matSrc Source material description | |||||
| * @param matDest Destination material to be filled */ | |||||
| void ConvertMaterial(const Object& object, | |||||
| const Material& matSrc, | |||||
| aiMaterial& matDest); | |||||
| private: | |||||
| // points to the next data line | |||||
| const char* buffer; | |||||
| // Configuration option: if enabled, up to two meshes | |||||
| // are generated per material: those faces who have | |||||
| // their bf cull flags set are separated. | |||||
| bool configSplitBFCull; | |||||
| // Configuration switch: subdivision surfaces are only | |||||
| // evaluated if the value is true. | |||||
| bool configEvalSubdivision; | |||||
| // counts how many objects we have in the tree. | |||||
| // basing on this information we can find a | |||||
| // good estimate how many meshes we'll have in the final scene. | |||||
| unsigned int mNumMeshes; | |||||
| // current list of light sources | |||||
| std::vector<aiLight*>* mLights; | |||||
| // name counters | |||||
| unsigned int lights, groups, polys, worlds; | |||||
| }; | |||||
| } // end of namespace Assimp | |||||
| #endif // AI_AC3DIMPORTER_H_INC | |||||
| @@ -0,0 +1,205 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file ASELoader.h | |||||
| * @brief Definition of the .ASE importer class. | |||||
| */ | |||||
| #ifndef AI_ASELOADER_H_INCLUDED | |||||
| #define AI_ASELOADER_H_INCLUDED | |||||
| #include "BaseImporter.h" | |||||
| #include "../include/assimp/types.h" | |||||
| struct aiNode; | |||||
| #include "ASEParser.h" | |||||
| namespace Assimp { | |||||
| // -------------------------------------------------------------------------------- | |||||
| /** Importer class for the 3DS ASE ASCII format. | |||||
| * | |||||
| */ | |||||
| class ASEImporter : public BaseImporter { | |||||
| public: | |||||
| ASEImporter(); | |||||
| ~ASEImporter(); | |||||
| public: | |||||
| // ------------------------------------------------------------------- | |||||
| /** Returns whether the class can handle the format of the given file. | |||||
| * See BaseImporter::CanRead() for details. | |||||
| */ | |||||
| bool CanRead( const std::string& pFile, IOSystem* pIOHandler, | |||||
| bool checkSig) const; | |||||
| protected: | |||||
| // ------------------------------------------------------------------- | |||||
| /** Return importer meta information. | |||||
| * See #BaseImporter::GetInfo for the details | |||||
| */ | |||||
| const aiImporterDesc* GetInfo () const; | |||||
| // ------------------------------------------------------------------- | |||||
| /** Imports the given file into the given scene structure. | |||||
| * See BaseImporter::InternReadFile() for details | |||||
| */ | |||||
| void InternReadFile( const std::string& pFile, aiScene* pScene, | |||||
| IOSystem* pIOHandler); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Called prior to ReadFile(). | |||||
| * The function is a request to the importer to update its configuration | |||||
| * basing on the Importer's configuration property list. | |||||
| */ | |||||
| void SetupProperties(const Importer* pImp); | |||||
| private: | |||||
| // ------------------------------------------------------------------- | |||||
| /** Generate normal vectors basing on smoothing groups | |||||
| * (in some cases the normal are already contained in the file) | |||||
| * \param mesh Mesh to work on | |||||
| * \return false if the normals have been recomputed | |||||
| */ | |||||
| bool GenerateNormals(ASE::Mesh& mesh); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Create valid vertex/normal/UV/color/face lists. | |||||
| * All elements are unique, faces have only one set of indices | |||||
| * after this step occurs. | |||||
| * \param mesh Mesh to work on | |||||
| */ | |||||
| void BuildUniqueRepresentation(ASE::Mesh& mesh); | |||||
| /** Create one-material-per-mesh meshes ;-) | |||||
| * \param mesh Mesh to work with | |||||
| * \param Receives the list of all created meshes | |||||
| */ | |||||
| void ConvertMeshes(ASE::Mesh& mesh, std::vector<aiMesh*>& avOut); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Convert a material to a aiMaterial object | |||||
| * \param mat Input material | |||||
| */ | |||||
| void ConvertMaterial(ASE::Material& mat); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Setup the final material indices for each mesh | |||||
| */ | |||||
| void BuildMaterialIndices(); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Build the node graph | |||||
| */ | |||||
| void BuildNodes(std::vector<ASE::BaseNode*>& nodes); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Build output cameras | |||||
| */ | |||||
| void BuildCameras(); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Build output lights | |||||
| */ | |||||
| void BuildLights(); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Build output animations | |||||
| */ | |||||
| void BuildAnimations(const std::vector<ASE::BaseNode*>& nodes); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Add sub nodes to a node | |||||
| * \param pcParent parent node to be filled | |||||
| * \param szName Name of the parent node | |||||
| * \param matrix Current transform | |||||
| */ | |||||
| void AddNodes(const std::vector<ASE::BaseNode*>& nodes, | |||||
| aiNode* pcParent,const char* szName); | |||||
| void AddNodes(const std::vector<ASE::BaseNode*>& nodes, | |||||
| aiNode* pcParent,const char* szName, | |||||
| const aiMatrix4x4& matrix); | |||||
| void AddMeshes(const ASE::BaseNode* snode,aiNode* node); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Generate a default material and add it to the parser's list | |||||
| * Called if no material has been found in the file (rare for ASE, | |||||
| * but not impossible) | |||||
| */ | |||||
| void GenerateDefaultMaterial(); | |||||
| protected: | |||||
| /** Parser instance */ | |||||
| ASE::Parser* mParser; | |||||
| /** Buffer to hold the loaded file */ | |||||
| char* mBuffer; | |||||
| /** Scene to be filled */ | |||||
| aiScene* pcScene; | |||||
| /** Config options: Recompute the normals in every case - WA | |||||
| for 3DS Max broken ASE normal export */ | |||||
| bool configRecomputeNormals; | |||||
| bool noSkeletonMesh; | |||||
| }; | |||||
| } // end of namespace Assimp | |||||
| #endif // AI_3DSIMPORTER_H_INC | |||||
| @@ -0,0 +1,669 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file Defines the helper data structures for importing ASE files */ | |||||
| #ifndef AI_ASEFILEHELPER_H_INC | |||||
| #define AI_ASEFILEHELPER_H_INC | |||||
| // STL/CRT headers | |||||
| #include <string> | |||||
| #include <vector> | |||||
| #include <list> | |||||
| // public ASSIMP headers | |||||
| #include "../include/assimp/types.h" | |||||
| #include "../include/assimp/mesh.h" | |||||
| #include "../include/assimp/anim.h" | |||||
| // for some helper routines like IsSpace() | |||||
| #include "ParsingUtils.h" | |||||
| #include "qnan.h" | |||||
| // ASE is quite similar to 3ds. We can reuse some structures | |||||
| #include "3DSLoader.h" | |||||
| namespace Assimp { | |||||
| namespace ASE { | |||||
| using namespace D3DS; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper structure representing an ASE material */ | |||||
| struct Material : public D3DS::Material | |||||
| { | |||||
| //! Default constructor | |||||
| Material() : pcInstance(NULL), bNeed (false) | |||||
| {} | |||||
| //! Contains all sub materials of this material | |||||
| std::vector<Material> avSubMaterials; | |||||
| //! aiMaterial object | |||||
| aiMaterial* pcInstance; | |||||
| //! Can we remove this material? | |||||
| bool bNeed; | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper structure to represent an ASE file face */ | |||||
| struct Face : public FaceWithSmoothingGroup | |||||
| { | |||||
| //! Default constructor. Initializes everything with 0 | |||||
| Face() | |||||
| { | |||||
| mColorIndices[0] = mColorIndices[1] = mColorIndices[2] = 0; | |||||
| for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) | |||||
| { | |||||
| amUVIndices[i][0] = amUVIndices[i][1] = amUVIndices[i][2] = 0; | |||||
| } | |||||
| iMaterial = DEFAULT_MATINDEX; | |||||
| iFace = 0; | |||||
| } | |||||
| //! special value to indicate that no material index has | |||||
| //! been assigned to a face. The default material index | |||||
| //! will replace this value later. | |||||
| static const unsigned int DEFAULT_MATINDEX = 0xFFFFFFFF; | |||||
| //! Indices into each list of texture coordinates | |||||
| unsigned int amUVIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS][3]; | |||||
| //! Index into the list of vertex colors | |||||
| unsigned int mColorIndices[3]; | |||||
| //! (Sub)Material index to be assigned to this face | |||||
| unsigned int iMaterial; | |||||
| //! Index of the face. It is not specified whether it is | |||||
| //! a requirement of the file format that all faces are | |||||
| //! written in sequential order, so we have to expect this case | |||||
| unsigned int iFace; | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper structure to represent an ASE file bone */ | |||||
| struct Bone | |||||
| { | |||||
| //! Constructor | |||||
| Bone() | |||||
| { | |||||
| static int iCnt = 0; | |||||
| // Generate a default name for the bone | |||||
| char szTemp[128]; | |||||
| ::sprintf(szTemp,"UNNAMED_%i",iCnt++); | |||||
| mName = szTemp; | |||||
| } | |||||
| //! Construction from an existing name | |||||
| Bone( const std::string& name) | |||||
| : mName (name) | |||||
| {} | |||||
| //! Name of the bone | |||||
| std::string mName; | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper structure to represent an ASE file bone vertex */ | |||||
| struct BoneVertex | |||||
| { | |||||
| //! Bone and corresponding vertex weight. | |||||
| //! -1 for unrequired bones .... | |||||
| std::vector<std::pair<int,float> > mBoneWeights; | |||||
| //! Position of the bone vertex. | |||||
| //! MUST be identical to the vertex position | |||||
| //aiVector3D mPosition; | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper structure to represent an ASE file animation */ | |||||
| struct Animation | |||||
| { | |||||
| enum Type | |||||
| { | |||||
| TRACK = 0x0, | |||||
| BEZIER = 0x1, | |||||
| TCB = 0x2 | |||||
| } mRotationType, mScalingType, mPositionType; | |||||
| Animation() | |||||
| : mRotationType (TRACK) | |||||
| , mScalingType (TRACK) | |||||
| , mPositionType (TRACK) | |||||
| {} | |||||
| //! List of track rotation keyframes | |||||
| std::vector< aiQuatKey > akeyRotations; | |||||
| //! List of track position keyframes | |||||
| std::vector< aiVectorKey > akeyPositions; | |||||
| //! List of track scaling keyframes | |||||
| std::vector< aiVectorKey > akeyScaling; | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper structure to represent the inheritance information of an ASE node */ | |||||
| struct InheritanceInfo | |||||
| { | |||||
| //! Default constructor | |||||
| InheritanceInfo() | |||||
| { | |||||
| // set the inheritance flag for all axes by default to true | |||||
| for (unsigned int i = 0; i < 3;++i) | |||||
| abInheritPosition[i] = abInheritRotation[i] = abInheritScaling[i] = true; | |||||
| } | |||||
| //! Inherit the parent's position?, axis order is x,y,z | |||||
| bool abInheritPosition[3]; | |||||
| //! Inherit the parent's rotation?, axis order is x,y,z | |||||
| bool abInheritRotation[3]; | |||||
| //! Inherit the parent's scaling?, axis order is x,y,z | |||||
| bool abInheritScaling[3]; | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Represents an ASE file node. Base class for mesh, light and cameras */ | |||||
| struct BaseNode | |||||
| { | |||||
| enum Type {Light, Camera, Mesh, Dummy} mType; | |||||
| //! Constructor. Creates a default name for the node | |||||
| BaseNode(Type _mType) | |||||
| : mType (_mType) | |||||
| , mProcessed (false) | |||||
| { | |||||
| // generate a default name for the node | |||||
| static int iCnt = 0; | |||||
| char szTemp[128]; // should be sufficiently large | |||||
| ::sprintf(szTemp,"UNNAMED_%i",iCnt++); | |||||
| mName = szTemp; | |||||
| // Set mTargetPosition to qnan | |||||
| const float qnan = get_qnan(); | |||||
| mTargetPosition.x = qnan; | |||||
| } | |||||
| //! Name of the mesh | |||||
| std::string mName; | |||||
| //! Name of the parent of the node | |||||
| //! "" if there is no parent ... | |||||
| std::string mParent; | |||||
| //! Transformation matrix of the node | |||||
| aiMatrix4x4 mTransform; | |||||
| //! Target position (target lights and cameras) | |||||
| aiVector3D mTargetPosition; | |||||
| //! Specifies which axes transformations a node inherits | |||||
| //! from its parent ... | |||||
| InheritanceInfo inherit; | |||||
| //! Animation channels for the node | |||||
| Animation mAnim; | |||||
| //! Needed for lights and cameras: target animation channel | |||||
| //! Should contain position keys only. | |||||
| Animation mTargetAnim; | |||||
| bool mProcessed; | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper structure to represent an ASE file mesh */ | |||||
| struct Mesh : public MeshWithSmoothingGroups<ASE::Face>, public BaseNode | |||||
| { | |||||
| //! Constructor. | |||||
| Mesh() | |||||
| : BaseNode (BaseNode::Mesh) | |||||
| , bSkip (false) | |||||
| { | |||||
| // use 2 texture vertex components by default | |||||
| for (unsigned int c = 0; c < AI_MAX_NUMBER_OF_TEXTURECOORDS;++c) | |||||
| this->mNumUVComponents[c] = 2; | |||||
| // setup the default material index by default | |||||
| iMaterialIndex = Face::DEFAULT_MATINDEX; | |||||
| } | |||||
| //! List of all texture coordinate sets | |||||
| std::vector<aiVector3D> amTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; | |||||
| //! List of all vertex color sets. | |||||
| std::vector<aiColor4D> mVertexColors; | |||||
| //! List of all bone vertices | |||||
| std::vector<BoneVertex> mBoneVertices; | |||||
| //! List of all bones | |||||
| std::vector<Bone> mBones; | |||||
| //! Material index of the mesh | |||||
| unsigned int iMaterialIndex; | |||||
| //! Number of vertex components for each UVW set | |||||
| unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS]; | |||||
| //! used internally | |||||
| bool bSkip; | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper structure to represent an ASE light source */ | |||||
| struct Light : public BaseNode | |||||
| { | |||||
| enum LightType | |||||
| { | |||||
| OMNI, | |||||
| TARGET, | |||||
| FREE, | |||||
| DIRECTIONAL | |||||
| }; | |||||
| //! Constructor. | |||||
| Light() | |||||
| : BaseNode (BaseNode::Light) | |||||
| , mLightType (OMNI) | |||||
| , mColor (1.f,1.f,1.f) | |||||
| , mIntensity (1.f) // light is white by default | |||||
| , mAngle (45.f) | |||||
| , mFalloff (0.f) | |||||
| { | |||||
| } | |||||
| LightType mLightType; | |||||
| aiColor3D mColor; | |||||
| float mIntensity; | |||||
| float mAngle; // in degrees | |||||
| float mFalloff; | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper structure to represent an ASE camera */ | |||||
| struct Camera : public BaseNode | |||||
| { | |||||
| enum CameraType | |||||
| { | |||||
| FREE, | |||||
| TARGET | |||||
| }; | |||||
| //! Constructor | |||||
| Camera() | |||||
| : BaseNode (BaseNode::Camera) | |||||
| , mFOV (0.75f) // in radians | |||||
| , mNear (0.1f) | |||||
| , mFar (1000.f) // could be zero | |||||
| , mCameraType (FREE) | |||||
| { | |||||
| } | |||||
| float mFOV, mNear, mFar; | |||||
| CameraType mCameraType; | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper structure to represent an ASE helper object (dummy) */ | |||||
| struct Dummy : public BaseNode | |||||
| { | |||||
| //! Constructor | |||||
| Dummy() | |||||
| : BaseNode (BaseNode::Dummy) | |||||
| { | |||||
| } | |||||
| }; | |||||
| // Parameters to Parser::Parse() | |||||
| #define AI_ASE_NEW_FILE_FORMAT 200 | |||||
| #define AI_ASE_OLD_FILE_FORMAT 110 | |||||
| // Internally we're a little bit more tolerant | |||||
| #define AI_ASE_IS_NEW_FILE_FORMAT() (iFileFormat >= 200) | |||||
| #define AI_ASE_IS_OLD_FILE_FORMAT() (iFileFormat < 200) | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** \brief Class to parse ASE files | |||||
| */ | |||||
| class Parser | |||||
| { | |||||
| private: | |||||
| Parser() {} | |||||
| public: | |||||
| // ------------------------------------------------------------------- | |||||
| //! Construct a parser from a given input file which is | |||||
| //! guaranted to be terminated with zero. | |||||
| //! @param szFile Input file | |||||
| //! @param fileFormatDefault Assumed file format version. If the | |||||
| //! file format is specified in the file the new value replaces | |||||
| //! the default value. | |||||
| Parser (const char* szFile, unsigned int fileFormatDefault); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parses the file into the parsers internal representation | |||||
| void Parse(); | |||||
| private: | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse the *SCENE block in a file | |||||
| void ParseLV1SceneBlock(); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse the *MESH_SOFTSKINVERTS block in a file | |||||
| void ParseLV1SoftSkinBlock(); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse the *MATERIAL_LIST block in a file | |||||
| void ParseLV1MaterialListBlock(); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *<xxx>OBJECT block in a file | |||||
| //! \param mesh Node to be filled | |||||
| void ParseLV1ObjectBlock(BaseNode& mesh); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *MATERIAL blocks in a material list | |||||
| //! \param mat Material structure to be filled | |||||
| void ParseLV2MaterialBlock(Material& mat); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *NODE_TM block in a file | |||||
| //! \param mesh Node (!) object to be filled | |||||
| void ParseLV2NodeTransformBlock(BaseNode& mesh); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *TM_ANIMATION block in a file | |||||
| //! \param mesh Mesh object to be filled | |||||
| void ParseLV2AnimationBlock(BaseNode& mesh); | |||||
| void ParseLV3PosAnimationBlock(ASE::Animation& anim); | |||||
| void ParseLV3ScaleAnimationBlock(ASE::Animation& anim); | |||||
| void ParseLV3RotAnimationBlock(ASE::Animation& anim); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *MESH block in a file | |||||
| //! \param mesh Mesh object to be filled | |||||
| void ParseLV2MeshBlock(Mesh& mesh); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *LIGHT_SETTINGS block in a file | |||||
| //! \param light Light object to be filled | |||||
| void ParseLV2LightSettingsBlock(Light& light); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *CAMERA_SETTINGS block in a file | |||||
| //! \param cam Camera object to be filled | |||||
| void ParseLV2CameraSettingsBlock(Camera& cam); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse the *MAP_XXXXXX blocks in a material | |||||
| //! \param map Texture structure to be filled | |||||
| void ParseLV3MapBlock(Texture& map); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *MESH_VERTEX_LIST block in a file | |||||
| //! \param iNumVertices Value of *MESH_NUMVERTEX, if present. | |||||
| //! Otherwise zero. This is used to check the consistency of the file. | |||||
| //! A warning is sent to the logger if the validations fails. | |||||
| //! \param mesh Mesh object to be filled | |||||
| void ParseLV3MeshVertexListBlock( | |||||
| unsigned int iNumVertices,Mesh& mesh); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *MESH_FACE_LIST block in a file | |||||
| //! \param iNumFaces Value of *MESH_NUMFACES, if present. | |||||
| //! Otherwise zero. This is used to check the consistency of the file. | |||||
| //! A warning is sent to the logger if the validations fails. | |||||
| //! \param mesh Mesh object to be filled | |||||
| void ParseLV3MeshFaceListBlock( | |||||
| unsigned int iNumFaces,Mesh& mesh); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *MESH_TVERT_LIST block in a file | |||||
| //! \param iNumVertices Value of *MESH_NUMTVERTEX, if present. | |||||
| //! Otherwise zero. This is used to check the consistency of the file. | |||||
| //! A warning is sent to the logger if the validations fails. | |||||
| //! \param mesh Mesh object to be filled | |||||
| //! \param iChannel Output UVW channel | |||||
| void ParseLV3MeshTListBlock( | |||||
| unsigned int iNumVertices,Mesh& mesh, unsigned int iChannel = 0); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *MESH_TFACELIST block in a file | |||||
| //! \param iNumFaces Value of *MESH_NUMTVFACES, if present. | |||||
| //! Otherwise zero. This is used to check the consistency of the file. | |||||
| //! A warning is sent to the logger if the validations fails. | |||||
| //! \param mesh Mesh object to be filled | |||||
| //! \param iChannel Output UVW channel | |||||
| void ParseLV3MeshTFaceListBlock( | |||||
| unsigned int iNumFaces,Mesh& mesh, unsigned int iChannel = 0); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse an additional mapping channel | |||||
| //! (specified via *MESH_MAPPINGCHANNEL) | |||||
| //! \param iChannel Channel index to be filled | |||||
| //! \param mesh Mesh object to be filled | |||||
| void ParseLV3MappingChannel( | |||||
| unsigned int iChannel, Mesh& mesh); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *MESH_CVERTLIST block in a file | |||||
| //! \param iNumVertices Value of *MESH_NUMCVERTEX, if present. | |||||
| //! Otherwise zero. This is used to check the consistency of the file. | |||||
| //! A warning is sent to the logger if the validations fails. | |||||
| //! \param mesh Mesh object to be filled | |||||
| void ParseLV3MeshCListBlock( | |||||
| unsigned int iNumVertices, Mesh& mesh); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *MESH_CFACELIST block in a file | |||||
| //! \param iNumFaces Value of *MESH_NUMCVFACES, if present. | |||||
| //! Otherwise zero. This is used to check the consistency of the file. | |||||
| //! A warning is sent to the logger if the validations fails. | |||||
| //! \param mesh Mesh object to be filled | |||||
| void ParseLV3MeshCFaceListBlock( | |||||
| unsigned int iNumFaces, Mesh& mesh); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *MESH_NORMALS block in a file | |||||
| //! \param mesh Mesh object to be filled | |||||
| void ParseLV3MeshNormalListBlock(Mesh& mesh); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *MESH_WEIGHTSblock in a file | |||||
| //! \param mesh Mesh object to be filled | |||||
| void ParseLV3MeshWeightsBlock(Mesh& mesh); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse the bone list of a file | |||||
| //! \param mesh Mesh object to be filled | |||||
| //! \param iNumBones Number of bones in the mesh | |||||
| void ParseLV4MeshBones(unsigned int iNumBones,Mesh& mesh); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse the bone vertices list of a file | |||||
| //! \param mesh Mesh object to be filled | |||||
| //! \param iNumVertices Number of vertices to be parsed | |||||
| void ParseLV4MeshBonesVertices(unsigned int iNumVertices,Mesh& mesh); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *MESH_FACE block in a file | |||||
| //! \param out receive the face data | |||||
| void ParseLV4MeshFace(ASE::Face& out); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *MESH_VERT block in a file | |||||
| //! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL ...) | |||||
| //! \param apOut Output buffer (3 floats) | |||||
| //! \param rIndexOut Output index | |||||
| void ParseLV4MeshFloatTriple(float* apOut, unsigned int& rIndexOut); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *MESH_VERT block in a file | |||||
| //! (also works for MESH_TVERT, MESH_CFACE, MESH_VERTCOL ...) | |||||
| //! \param apOut Output buffer (3 floats) | |||||
| void ParseLV4MeshFloatTriple(float* apOut); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *MESH_TFACE block in a file | |||||
| //! (also works for MESH_CFACE) | |||||
| //! \param apOut Output buffer (3 ints) | |||||
| //! \param rIndexOut Output index | |||||
| void ParseLV4MeshLongTriple(unsigned int* apOut, unsigned int& rIndexOut); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a *MESH_TFACE block in a file | |||||
| //! (also works for MESH_CFACE) | |||||
| //! \param apOut Output buffer (3 ints) | |||||
| void ParseLV4MeshLongTriple(unsigned int* apOut); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a single float element | |||||
| //! \param fOut Output float | |||||
| void ParseLV4MeshFloat(float& fOut); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a single int element | |||||
| //! \param iOut Output integer | |||||
| void ParseLV4MeshLong(unsigned int& iOut); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Skip everything to the next: '*' or '\0' | |||||
| bool SkipToNextToken(); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Skip the current section until the token after the closing }. | |||||
| //! This function handles embedded subsections correctly | |||||
| bool SkipSection(); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Output a warning to the logger | |||||
| //! \param szWarn Warn message | |||||
| void LogWarning(const char* szWarn); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Output a message to the logger | |||||
| //! \param szWarn Message | |||||
| void LogInfo(const char* szWarn); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Output an error to the logger | |||||
| //! \param szWarn Error message | |||||
| void LogError(const char* szWarn); | |||||
| // ------------------------------------------------------------------- | |||||
| //! Parse a string, enclosed in double quotation marks | |||||
| //! \param out Output string | |||||
| //! \param szName Name of the enclosing element -> used in error | |||||
| //! messages. | |||||
| //! \return false if an error occured | |||||
| bool ParseString(std::string& out,const char* szName); | |||||
| public: | |||||
| //! Pointer to current data | |||||
| const char* filePtr; | |||||
| //! background color to be passed to the viewer | |||||
| //! QNAN if none was found | |||||
| aiColor3D m_clrBackground; | |||||
| //! Base ambient color to be passed to all materials | |||||
| //! QNAN if none was found | |||||
| aiColor3D m_clrAmbient; | |||||
| //! List of all materials found in the file | |||||
| std::vector<Material> m_vMaterials; | |||||
| //! List of all meshes found in the file | |||||
| std::vector<Mesh> m_vMeshes; | |||||
| //! List of all dummies found in the file | |||||
| std::vector<Dummy> m_vDummies; | |||||
| //! List of all lights found in the file | |||||
| std::vector<Light> m_vLights; | |||||
| //! List of all cameras found in the file | |||||
| std::vector<Camera> m_vCameras; | |||||
| //! Current line in the file | |||||
| unsigned int iLineNumber; | |||||
| //! First frame | |||||
| unsigned int iFirstFrame; | |||||
| //! Last frame | |||||
| unsigned int iLastFrame; | |||||
| //! Frame speed - frames per second | |||||
| unsigned int iFrameSpeed; | |||||
| //! Ticks per frame | |||||
| unsigned int iTicksPerFrame; | |||||
| //! true if the last character read was an end-line character | |||||
| bool bLastWasEndLine; | |||||
| //! File format version | |||||
| unsigned int iFileFormat; | |||||
| }; | |||||
| } // Namespace ASE | |||||
| } // Namespace ASSIMP | |||||
| #endif // !! include guard | |||||
| @@ -0,0 +1,609 @@ | |||||
| /* | |||||
| --------------------------------------------------------------------------- | |||||
| Open Asset Import Library (assimp) | |||||
| --------------------------------------------------------------------------- | |||||
| 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. | |||||
| --------------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file Assimp.cpp | |||||
| * @brief Implementation of the Plain-C API | |||||
| */ | |||||
| #include "AssimpPCH.h" | |||||
| #include "../include/assimp/cimport.h" | |||||
| #include "GenericProperty.h" | |||||
| #include "CInterfaceIOWrapper.h" | |||||
| #include "Importer.h" | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| #ifndef ASSIMP_BUILD_SINGLETHREADED | |||||
| # include <boost/thread/thread.hpp> | |||||
| # include <boost/thread/mutex.hpp> | |||||
| #endif | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| using namespace Assimp; | |||||
| namespace Assimp | |||||
| { | |||||
| // underlying structure for aiPropertyStore | |||||
| typedef BatchLoader::PropertyMap PropertyMap; | |||||
| /** Stores the LogStream objects for all active C log streams */ | |||||
| struct mpred { | |||||
| bool operator () (const aiLogStream& s0, const aiLogStream& s1) const { | |||||
| return s0.callback<s1.callback&&s0.user<s1.user; | |||||
| } | |||||
| }; | |||||
| typedef std::map<aiLogStream, Assimp::LogStream*, mpred> LogStreamMap; | |||||
| /** Stores the LogStream objects allocated by #aiGetPredefinedLogStream */ | |||||
| typedef std::list<Assimp::LogStream*> PredefLogStreamMap; | |||||
| /** Local storage of all active log streams */ | |||||
| static LogStreamMap gActiveLogStreams; | |||||
| /** Local storage of LogStreams allocated by #aiGetPredefinedLogStream */ | |||||
| static PredefLogStreamMap gPredefinedStreams; | |||||
| /** Error message of the last failed import process */ | |||||
| static std::string gLastErrorString; | |||||
| /** Verbose logging active or not? */ | |||||
| static aiBool gVerboseLogging = false; | |||||
| } | |||||
| #ifndef ASSIMP_BUILD_SINGLETHREADED | |||||
| /** Global mutex to manage the access to the logstream map */ | |||||
| static boost::mutex gLogStreamMutex; | |||||
| #endif | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Custom LogStream implementation for the C-API | |||||
| class LogToCallbackRedirector : public LogStream | |||||
| { | |||||
| public: | |||||
| LogToCallbackRedirector(const aiLogStream& s) | |||||
| : stream (s) { | |||||
| ai_assert(NULL != s.callback); | |||||
| } | |||||
| ~LogToCallbackRedirector() { | |||||
| #ifndef ASSIMP_BUILD_SINGLETHREADED | |||||
| boost::mutex::scoped_lock lock(gLogStreamMutex); | |||||
| #endif | |||||
| // (HACK) Check whether the 'stream.user' pointer points to a | |||||
| // custom LogStream allocated by #aiGetPredefinedLogStream. | |||||
| // In this case, we need to delete it, too. Of course, this | |||||
| // might cause strange problems, but the chance is quite low. | |||||
| PredefLogStreamMap::iterator it = std::find(gPredefinedStreams.begin(), | |||||
| gPredefinedStreams.end(), (Assimp::LogStream*)stream.user); | |||||
| if (it != gPredefinedStreams.end()) { | |||||
| delete *it; | |||||
| gPredefinedStreams.erase(it); | |||||
| } | |||||
| } | |||||
| /** @copydoc LogStream::write */ | |||||
| void write(const char* message) { | |||||
| stream.callback(message,stream.user); | |||||
| } | |||||
| private: | |||||
| aiLogStream stream; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| 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"); | |||||
| assert(false); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Reads the given file and returns its content. | |||||
| 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) | |||||
| { | |||||
| return aiImportFileExWithProperties(pFile, pFlags, pFS, NULL); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| const aiScene* aiImportFileExWithProperties( const char* pFile, unsigned int pFlags, | |||||
| aiFileIO* pFS, | |||||
| const aiPropertyStore* props) | |||||
| { | |||||
| ai_assert(NULL != pFile); | |||||
| const aiScene* scene = NULL; | |||||
| ASSIMP_BEGIN_EXCEPTION_REGION(); | |||||
| // create an Importer for this file | |||||
| Assimp::Importer* imp = new Assimp::Importer(); | |||||
| // copy properties | |||||
| if(props) { | |||||
| const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props); | |||||
| ImporterPimpl* pimpl = imp->Pimpl(); | |||||
| pimpl->mIntProperties = pp->ints; | |||||
| pimpl->mFloatProperties = pp->floats; | |||||
| pimpl->mStringProperties = pp->strings; | |||||
| pimpl->mMatrixProperties = pp->matrices; | |||||
| } | |||||
| // setup a custom IO system if necessary | |||||
| if (pFS) { | |||||
| imp->SetIOHandler( new CIOSystemWrapper (pFS) ); | |||||
| } | |||||
| // and have it read the file | |||||
| scene = imp->ReadFile( pFile, pFlags); | |||||
| // if succeeded, store the importer in the scene and keep it alive | |||||
| if( scene) { | |||||
| ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) ); | |||||
| priv->mOrigImporter = imp; | |||||
| } | |||||
| else { | |||||
| // if failed, extract error code and destroy the import | |||||
| gLastErrorString = imp->GetErrorString(); | |||||
| delete imp; | |||||
| } | |||||
| // return imported data. If the import failed the pointer is NULL anyways | |||||
| ASSIMP_END_EXCEPTION_REGION(const aiScene*); | |||||
| return scene; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| const aiScene* aiImportFileFromMemory( | |||||
| const char* pBuffer, | |||||
| unsigned int pLength, | |||||
| unsigned int pFlags, | |||||
| const char* pHint) | |||||
| { | |||||
| return aiImportFileFromMemoryWithProperties(pBuffer, pLength, pFlags, pHint, NULL); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| const aiScene* aiImportFileFromMemoryWithProperties( | |||||
| const char* pBuffer, | |||||
| unsigned int pLength, | |||||
| unsigned int pFlags, | |||||
| const char* pHint, | |||||
| const aiPropertyStore* props) | |||||
| { | |||||
| ai_assert(NULL != pBuffer && 0 != pLength); | |||||
| const aiScene* scene = NULL; | |||||
| ASSIMP_BEGIN_EXCEPTION_REGION(); | |||||
| // create an Importer for this file | |||||
| Assimp::Importer* imp = new Assimp::Importer(); | |||||
| // copy properties | |||||
| if(props) { | |||||
| const PropertyMap* pp = reinterpret_cast<const PropertyMap*>(props); | |||||
| ImporterPimpl* pimpl = imp->Pimpl(); | |||||
| pimpl->mIntProperties = pp->ints; | |||||
| pimpl->mFloatProperties = pp->floats; | |||||
| pimpl->mStringProperties = pp->strings; | |||||
| pimpl->mMatrixProperties = pp->matrices; | |||||
| } | |||||
| // and have it read the file from the memory buffer | |||||
| scene = imp->ReadFileFromMemory( pBuffer, pLength, pFlags,pHint); | |||||
| // if succeeded, store the importer in the scene and keep it alive | |||||
| if( scene) { | |||||
| ScenePrivateData* priv = const_cast<ScenePrivateData*>( ScenePriv(scene) ); | |||||
| priv->mOrigImporter = imp; | |||||
| } | |||||
| else { | |||||
| // if failed, extract error code and destroy the import | |||||
| gLastErrorString = imp->GetErrorString(); | |||||
| delete imp; | |||||
| } | |||||
| // return imported data. If the import failed the pointer is NULL anyways | |||||
| ASSIMP_END_EXCEPTION_REGION(const aiScene*); | |||||
| return scene; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Releases all resources associated with the given import process. | |||||
| void aiReleaseImport( const aiScene* pScene) | |||||
| { | |||||
| if (!pScene) { | |||||
| return; | |||||
| } | |||||
| ASSIMP_BEGIN_EXCEPTION_REGION(); | |||||
| // find the importer associated with this data | |||||
| const ScenePrivateData* priv = ScenePriv(pScene); | |||||
| if( !priv || !priv->mOrigImporter) { | |||||
| delete pScene; | |||||
| } | |||||
| else { | |||||
| // deleting the Importer also deletes the scene | |||||
| // Note: the reason that this is not written as 'delete priv->mOrigImporter' | |||||
| // is a suspected bug in gcc 4.4+ (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52339) | |||||
| Importer* importer = priv->mOrigImporter; | |||||
| delete importer; | |||||
| } | |||||
| ASSIMP_END_EXCEPTION_REGION(void); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API const aiScene* aiApplyPostProcessing(const aiScene* pScene, | |||||
| unsigned int pFlags) | |||||
| { | |||||
| const aiScene* sc = NULL; | |||||
| ASSIMP_BEGIN_EXCEPTION_REGION(); | |||||
| // find the importer associated with this data | |||||
| const ScenePrivateData* priv = ScenePriv(pScene); | |||||
| if( !priv || !priv->mOrigImporter) { | |||||
| ReportSceneNotFoundError(); | |||||
| return NULL; | |||||
| } | |||||
| sc = priv->mOrigImporter->ApplyPostProcessing(pFlags); | |||||
| if (!sc) { | |||||
| aiReleaseImport(pScene); | |||||
| return NULL; | |||||
| } | |||||
| ASSIMP_END_EXCEPTION_REGION(const aiScene*); | |||||
| return sc; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void CallbackToLogRedirector (const char* msg, char* dt) | |||||
| { | |||||
| ai_assert(NULL != msg && NULL != dt); | |||||
| LogStream* s = (LogStream*)dt; | |||||
| s->write(msg); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API aiLogStream aiGetPredefinedLogStream(aiDefaultLogStream pStream,const char* file) | |||||
| { | |||||
| aiLogStream sout; | |||||
| ASSIMP_BEGIN_EXCEPTION_REGION(); | |||||
| LogStream* stream = LogStream::createDefaultStream(pStream,file); | |||||
| if (!stream) { | |||||
| sout.callback = NULL; | |||||
| sout.user = NULL; | |||||
| } | |||||
| else { | |||||
| sout.callback = &CallbackToLogRedirector; | |||||
| sout.user = (char*)stream; | |||||
| } | |||||
| gPredefinedStreams.push_back(stream); | |||||
| ASSIMP_END_EXCEPTION_REGION(aiLogStream); | |||||
| return sout; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API void aiAttachLogStream( const aiLogStream* stream ) | |||||
| { | |||||
| ASSIMP_BEGIN_EXCEPTION_REGION(); | |||||
| #ifndef ASSIMP_BUILD_SINGLETHREADED | |||||
| boost::mutex::scoped_lock lock(gLogStreamMutex); | |||||
| #endif | |||||
| LogStream* lg = new LogToCallbackRedirector(*stream); | |||||
| gActiveLogStreams[*stream] = lg; | |||||
| if (DefaultLogger::isNullLogger()) { | |||||
| DefaultLogger::create(NULL,(gVerboseLogging == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL)); | |||||
| } | |||||
| DefaultLogger::get()->attachStream(lg); | |||||
| ASSIMP_END_EXCEPTION_REGION(void); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API aiReturn aiDetachLogStream( const aiLogStream* stream) | |||||
| { | |||||
| ASSIMP_BEGIN_EXCEPTION_REGION(); | |||||
| #ifndef ASSIMP_BUILD_SINGLETHREADED | |||||
| boost::mutex::scoped_lock lock(gLogStreamMutex); | |||||
| #endif | |||||
| // find the logstream associated with this data | |||||
| LogStreamMap::iterator it = gActiveLogStreams.find( *stream); | |||||
| // it should be there... else the user is playing fools with us | |||||
| if( it == gActiveLogStreams.end()) { | |||||
| return AI_FAILURE; | |||||
| } | |||||
| DefaultLogger::get()->detatchStream( it->second ); | |||||
| delete it->second; | |||||
| gActiveLogStreams.erase( it); | |||||
| if (gActiveLogStreams.empty()) { | |||||
| DefaultLogger::kill(); | |||||
| } | |||||
| ASSIMP_END_EXCEPTION_REGION(aiReturn); | |||||
| return AI_SUCCESS; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API void aiDetachAllLogStreams(void) | |||||
| { | |||||
| ASSIMP_BEGIN_EXCEPTION_REGION(); | |||||
| #ifndef ASSIMP_BUILD_SINGLETHREADED | |||||
| boost::mutex::scoped_lock lock(gLogStreamMutex); | |||||
| #endif | |||||
| for (LogStreamMap::iterator it = gActiveLogStreams.begin(); it != gActiveLogStreams.end(); ++it) { | |||||
| DefaultLogger::get()->detatchStream( it->second ); | |||||
| delete it->second; | |||||
| } | |||||
| gActiveLogStreams.clear(); | |||||
| DefaultLogger::kill(); | |||||
| ASSIMP_END_EXCEPTION_REGION(void); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API void aiEnableVerboseLogging(aiBool d) | |||||
| { | |||||
| if (!DefaultLogger::isNullLogger()) { | |||||
| DefaultLogger::get()->setLogSeverity((d == AI_TRUE ? Logger::VERBOSE : Logger::NORMAL)); | |||||
| } | |||||
| gVerboseLogging = d; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Returns the error text of the last failed import process. | |||||
| const char* aiGetErrorString() | |||||
| { | |||||
| return gLastErrorString.c_str(); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Returns the error text of the last failed import process. | |||||
| aiBool aiIsExtensionSupported(const char* szExtension) | |||||
| { | |||||
| ai_assert(NULL != szExtension); | |||||
| aiBool candoit=AI_FALSE; | |||||
| ASSIMP_BEGIN_EXCEPTION_REGION(); | |||||
| // FIXME: no need to create a temporary Importer instance just for that .. | |||||
| Assimp::Importer tmp; | |||||
| candoit = tmp.IsExtensionSupported(std::string(szExtension)) ? AI_TRUE : AI_FALSE; | |||||
| ASSIMP_END_EXCEPTION_REGION(aiBool); | |||||
| return candoit; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Get a list of all file extensions supported by ASSIMP | |||||
| void aiGetExtensionList(aiString* szOut) | |||||
| { | |||||
| ai_assert(NULL != szOut); | |||||
| ASSIMP_BEGIN_EXCEPTION_REGION(); | |||||
| // FIXME: no need to create a temporary Importer instance just for that .. | |||||
| Assimp::Importer tmp; | |||||
| tmp.GetExtensionList(*szOut); | |||||
| ASSIMP_END_EXCEPTION_REGION(void); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Get the memory requirements for a particular import. | |||||
| void aiGetMemoryRequirements(const C_STRUCT aiScene* pIn, | |||||
| C_STRUCT aiMemoryInfo* in) | |||||
| { | |||||
| ASSIMP_BEGIN_EXCEPTION_REGION(); | |||||
| // find the importer associated with this data | |||||
| const ScenePrivateData* priv = ScenePriv(pIn); | |||||
| if( !priv || !priv->mOrigImporter) { | |||||
| ReportSceneNotFoundError(); | |||||
| return; | |||||
| } | |||||
| return priv->mOrigImporter->GetMemoryRequirements(*in); | |||||
| ASSIMP_END_EXCEPTION_REGION(void); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API aiPropertyStore* aiCreatePropertyStore(void) | |||||
| { | |||||
| return reinterpret_cast<aiPropertyStore*>( new PropertyMap() ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API void aiReleasePropertyStore(aiPropertyStore* p) | |||||
| { | |||||
| delete reinterpret_cast<PropertyMap*>(p); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Importer::SetPropertyInteger | |||||
| ASSIMP_API void aiSetImportPropertyInteger(aiPropertyStore* p, const char* szName, int value) | |||||
| { | |||||
| ASSIMP_BEGIN_EXCEPTION_REGION(); | |||||
| PropertyMap* pp = reinterpret_cast<PropertyMap*>(p); | |||||
| SetGenericProperty<int>(pp->ints,szName,value,NULL); | |||||
| ASSIMP_END_EXCEPTION_REGION(void); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Importer::SetPropertyFloat | |||||
| ASSIMP_API void aiSetImportPropertyFloat(aiPropertyStore* p, const char* szName, float value) | |||||
| { | |||||
| ASSIMP_BEGIN_EXCEPTION_REGION(); | |||||
| PropertyMap* pp = reinterpret_cast<PropertyMap*>(p); | |||||
| SetGenericProperty<float>(pp->floats,szName,value,NULL); | |||||
| ASSIMP_END_EXCEPTION_REGION(void); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Importer::SetPropertyString | |||||
| ASSIMP_API void aiSetImportPropertyString(aiPropertyStore* p, const char* szName, | |||||
| const C_STRUCT aiString* st) | |||||
| { | |||||
| if (!st) { | |||||
| return; | |||||
| } | |||||
| ASSIMP_BEGIN_EXCEPTION_REGION(); | |||||
| PropertyMap* pp = reinterpret_cast<PropertyMap*>(p); | |||||
| SetGenericProperty<std::string>(pp->strings,szName,std::string(st->C_Str()),NULL); | |||||
| ASSIMP_END_EXCEPTION_REGION(void); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Importer::SetPropertyMatrix | |||||
| ASSIMP_API void aiSetImportPropertyMatrix(aiPropertyStore* p, const char* szName, | |||||
| const C_STRUCT aiMatrix4x4* mat) | |||||
| { | |||||
| if (!mat) { | |||||
| return; | |||||
| } | |||||
| ASSIMP_BEGIN_EXCEPTION_REGION(); | |||||
| PropertyMap* pp = reinterpret_cast<PropertyMap*>(p); | |||||
| SetGenericProperty<aiMatrix4x4>(pp->matrices,szName,*mat,NULL); | |||||
| ASSIMP_END_EXCEPTION_REGION(void); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Rotation matrix to quaternion | |||||
| ASSIMP_API void aiCreateQuaternionFromMatrix(aiQuaternion* quat,const aiMatrix3x3* mat) | |||||
| { | |||||
| ai_assert(NULL != quat && NULL != mat); | |||||
| *quat = aiQuaternion(*mat); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Matrix decomposition | |||||
| ASSIMP_API void aiDecomposeMatrix(const aiMatrix4x4* mat,aiVector3D* scaling, | |||||
| aiQuaternion* rotation, | |||||
| aiVector3D* position) | |||||
| { | |||||
| ai_assert(NULL != rotation && NULL != position && NULL != scaling && NULL != mat); | |||||
| mat->Decompose(*scaling,*rotation,*position); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Matrix transpose | |||||
| ASSIMP_API void aiTransposeMatrix3(aiMatrix3x3* mat) | |||||
| { | |||||
| ai_assert(NULL != mat); | |||||
| mat->Transpose(); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API void aiTransposeMatrix4(aiMatrix4x4* mat) | |||||
| { | |||||
| ai_assert(NULL != mat); | |||||
| mat->Transpose(); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Vector transformation | |||||
| ASSIMP_API void aiTransformVecByMatrix3(aiVector3D* vec, | |||||
| const aiMatrix3x3* mat) | |||||
| { | |||||
| ai_assert(NULL != mat && NULL != vec); | |||||
| *vec *= (*mat); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API void aiTransformVecByMatrix4(aiVector3D* vec, | |||||
| const aiMatrix4x4* mat) | |||||
| { | |||||
| ai_assert(NULL != mat && NULL != vec); | |||||
| *vec *= (*mat); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Matrix multiplication | |||||
| ASSIMP_API void aiMultiplyMatrix4( | |||||
| aiMatrix4x4* dst, | |||||
| const aiMatrix4x4* src) | |||||
| { | |||||
| ai_assert(NULL != dst && NULL != src); | |||||
| *dst = (*dst) * (*src); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API void aiMultiplyMatrix3( | |||||
| aiMatrix3x3* dst, | |||||
| const aiMatrix3x3* src) | |||||
| { | |||||
| ai_assert(NULL != dst && NULL != src); | |||||
| *dst = (*dst) * (*src); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Matrix identity | |||||
| ASSIMP_API void aiIdentityMatrix3( | |||||
| aiMatrix3x3* mat) | |||||
| { | |||||
| ai_assert(NULL != mat); | |||||
| *mat = aiMatrix3x3(); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API void aiIdentityMatrix4( | |||||
| aiMatrix4x4* mat) | |||||
| { | |||||
| ai_assert(NULL != mat); | |||||
| *mat = aiMatrix4x4(); | |||||
| } | |||||
| @@ -0,0 +1,127 @@ | |||||
| /* | |||||
| --------------------------------------------------------------------------- | |||||
| Open Asset Import Library (assimp) | |||||
| --------------------------------------------------------------------------- | |||||
| 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. | |||||
| --------------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file AssimpCExport.cpp | |||||
| Assimp C export interface. See Exporter.cpp for some notes. | |||||
| */ | |||||
| #include "AssimpPCH.h" | |||||
| #ifndef ASSIMP_BUILD_NO_EXPORT | |||||
| #include "CInterfaceIOWrapper.h" | |||||
| #include "SceneCombiner.h" | |||||
| using namespace Assimp; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API size_t aiGetExportFormatCount(void) | |||||
| { | |||||
| return Exporter().GetExportFormatCount(); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API const aiExportFormatDesc* aiGetExportFormatDescription( size_t pIndex) | |||||
| { | |||||
| return Exporter().GetExportFormatDescription(pIndex); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API void aiCopyScene(const aiScene* pIn, aiScene** pOut) | |||||
| { | |||||
| if (!pOut || !pIn) { | |||||
| return; | |||||
| } | |||||
| SceneCombiner::CopyScene(pOut,pIn,true); | |||||
| ScenePriv(*pOut)->mIsCopy = true; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API void aiFreeScene(const C_STRUCT aiScene* pIn) | |||||
| { | |||||
| // note: aiReleaseImport() is also able to delete scene copies, but in addition | |||||
| // it also handles scenes with import metadata. | |||||
| delete pIn; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API aiReturn aiExportScene( const aiScene* pScene, const char* pFormatId, const char* pFileName, unsigned int pPreprocessing ) | |||||
| { | |||||
| return ::aiExportSceneEx(pScene,pFormatId,pFileName,NULL,pPreprocessing); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API aiReturn aiExportSceneEx( const aiScene* pScene, const char* pFormatId, const char* pFileName, aiFileIO* pIO, unsigned int pPreprocessing ) | |||||
| { | |||||
| Exporter exp; | |||||
| if (pIO) { | |||||
| exp.SetIOHandler(new CIOSystemWrapper(pIO)); | |||||
| } | |||||
| return exp.Export(pScene,pFormatId,pFileName,pPreprocessing); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API const C_STRUCT aiExportDataBlob* aiExportSceneToBlob( const aiScene* pScene, const char* pFormatId, unsigned int pPreprocessing ) | |||||
| { | |||||
| Exporter exp; | |||||
| if (!exp.ExportToBlob(pScene,pFormatId,pPreprocessing)) { | |||||
| return NULL; | |||||
| } | |||||
| const aiExportDataBlob* blob = exp.GetOrphanedBlob(); | |||||
| ai_assert(blob); | |||||
| return blob; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API C_STRUCT void aiReleaseExportBlob( const aiExportDataBlob* pData ) | |||||
| { | |||||
| delete pData; | |||||
| } | |||||
| #endif // !ASSIMP_BUILD_NO_EXPORT | |||||
| @@ -0,0 +1,135 @@ | |||||
| // Actually just a dummy, used by the compiler to build the precompiled header. | |||||
| #include "AssimpPCH.h" | |||||
| #include "./../include/assimp/version.h" | |||||
| static const unsigned int MajorVersion = 3; | |||||
| static const unsigned int MinorVersion = 1; | |||||
| // -------------------------------------------------------------------------------- | |||||
| // Legal information string - dont't remove this. | |||||
| static const char* LEGAL_INFORMATION = | |||||
| "Open Asset Import Library (Assimp).\n" | |||||
| "A free C/C++ library to import various 3D file formats into applications\n\n" | |||||
| "(c) 2008-2010, assimp team\n" | |||||
| "License under the terms and conditions of the 3-clause BSD license\n" | |||||
| "http://assimp.sourceforge.net\n" | |||||
| ; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Get legal string | |||||
| ASSIMP_API const char* aiGetLegalString () { | |||||
| return LEGAL_INFORMATION; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Get Assimp minor version | |||||
| ASSIMP_API unsigned int aiGetVersionMinor () { | |||||
| return MinorVersion; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Get Assimp major version | |||||
| ASSIMP_API unsigned int aiGetVersionMajor () { | |||||
| return MajorVersion; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Get flags used for compilation | |||||
| ASSIMP_API unsigned int aiGetCompileFlags () { | |||||
| unsigned int flags = 0; | |||||
| #ifdef ASSIMP_BUILD_BOOST_WORKAROUND | |||||
| flags |= ASSIMP_CFLAGS_NOBOOST; | |||||
| #endif | |||||
| #ifdef ASSIMP_BUILD_SINGLETHREADED | |||||
| flags |= ASSIMP_CFLAGS_SINGLETHREADED; | |||||
| #endif | |||||
| #ifdef ASSIMP_BUILD_DEBUG | |||||
| flags |= ASSIMP_CFLAGS_DEBUG; | |||||
| #endif | |||||
| #ifdef ASSIMP_BUILD_DLL_EXPORT | |||||
| flags |= ASSIMP_CFLAGS_SHARED; | |||||
| #endif | |||||
| #ifdef _STLPORT_VERSION | |||||
| flags |= ASSIMP_CFLAGS_STLPORT; | |||||
| #endif | |||||
| return flags; | |||||
| } | |||||
| // include current build revision, which is even updated from time to time -- :-) | |||||
| #include "revision.h" | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| 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()) | |||||
| { | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| ASSIMP_API aiScene::~aiScene() | |||||
| { | |||||
| // delete all sub-objects recursively | |||||
| delete mRootNode; | |||||
| // To make sure we won't crash if the data is invalid it's | |||||
| // much better to check whether both mNumXXX and mXXX are | |||||
| // valid instead of relying on just one of them. | |||||
| if (mNumMeshes && mMeshes) | |||||
| for( unsigned int a = 0; a < mNumMeshes; a++) | |||||
| delete mMeshes[a]; | |||||
| delete [] mMeshes; | |||||
| if (mNumMaterials && mMaterials) | |||||
| for( unsigned int a = 0; a < mNumMaterials; a++) | |||||
| delete mMaterials[a]; | |||||
| delete [] mMaterials; | |||||
| if (mNumAnimations && mAnimations) | |||||
| for( unsigned int a = 0; a < mNumAnimations; a++) | |||||
| delete mAnimations[a]; | |||||
| delete [] mAnimations; | |||||
| if (mNumTextures && mTextures) | |||||
| for( unsigned int a = 0; a < mNumTextures; a++) | |||||
| delete mTextures[a]; | |||||
| delete [] mTextures; | |||||
| if (mNumLights && mLights) | |||||
| for( unsigned int a = 0; a < mNumLights; a++) | |||||
| delete mLights[a]; | |||||
| delete [] mLights; | |||||
| if (mNumCameras && mCameras) | |||||
| for( unsigned int a = 0; a < mNumCameras; a++) | |||||
| delete mCameras[a]; | |||||
| delete [] mCameras; | |||||
| delete static_cast<Assimp::ScenePrivateData*>( mPrivate ); | |||||
| } | |||||
| @@ -0,0 +1,162 @@ | |||||
| /* | |||||
| --------------------------------------------------------------------------- | |||||
| Open Asset Import Library (assimp) | |||||
| --------------------------------------------------------------------------- | |||||
| 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. | |||||
| --------------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file AssimpPCH.h | |||||
| * PCH master include. Every unit in Assimp has to include it. | |||||
| */ | |||||
| #ifndef ASSIMP_PCH_INCLUDED | |||||
| #define ASSIMP_PCH_INCLUDED | |||||
| #define ASSIMP_INTERNAL_BUILD | |||||
| // ---------------------------------------------------------------------------------------- | |||||
| /* General compile config taken from defs.h. It is important that the user compiles | |||||
| * using exactly the same settings in defs.h. Settings in AssimpPCH.h may differ, | |||||
| * they won't affect the public API. | |||||
| */ | |||||
| #include "../include/assimp/defs.h" | |||||
| // Include our stdint.h replacement header for MSVC, take the global header for gcc/mingw | |||||
| #if defined( _MSC_VER) && (_MSC_VER < 1600) | |||||
| # include "../include/assimp/Compiler/pstdint.h" | |||||
| #else | |||||
| # include <stdint.h> | |||||
| #endif | |||||
| /* Undefine the min/max macros defined by some platform headers (namely Windows.h) to | |||||
| * avoid obvious conflicts with std::min() and std::max(). | |||||
| */ | |||||
| #undef min | |||||
| #undef max | |||||
| /* Concatenate two tokens after evaluating them | |||||
| */ | |||||
| #define _AI_CONCAT(a,b) a ## b | |||||
| #define AI_CONCAT(a,b) _AI_CONCAT(a,b) | |||||
| /* Helper macro to set a pointer to NULL in debug builds | |||||
| */ | |||||
| #if (defined ASSIMP_BUILD_DEBUG) | |||||
| # define AI_DEBUG_INVALIDATE_PTR(x) x = NULL; | |||||
| #else | |||||
| # define AI_DEBUG_INVALIDATE_PTR(x) | |||||
| #endif | |||||
| /* Beginning with MSVC8 some C string manipulation functions are mapped to their _safe_ | |||||
| * counterparts (e.g. _itoa_s). This avoids a lot of trouble with deprecation warnings. | |||||
| */ | |||||
| #if _MSC_VER >= 1400 && !(defined _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES) | |||||
| # define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 | |||||
| #endif | |||||
| /* size_t to unsigned int, possible loss of data. The compiler is right with his warning | |||||
| * but this loss of data won't be a problem for us. So shut up, little boy. | |||||
| */ | |||||
| #ifdef _MSC_VER | |||||
| # pragma warning (disable : 4267) | |||||
| #endif | |||||
| // ---------------------------------------------------------------------------------------- | |||||
| /* Actually that's not required for MSVC. It is included somewhere in the deeper parts of | |||||
| * the MSVC STL but it's necessary for proper build with STLport. | |||||
| */ | |||||
| #include <ctype.h> | |||||
| // Runtime/STL headers | |||||
| #include <vector> | |||||
| #include <list> | |||||
| #include <map> | |||||
| #include <set> | |||||
| #include <string> | |||||
| #include <sstream> | |||||
| #include <iomanip> | |||||
| #include <cassert> | |||||
| #include <stack> | |||||
| #include <queue> | |||||
| #include <iostream> | |||||
| #include <algorithm> | |||||
| #include <numeric> | |||||
| #include <new> | |||||
| #include <cstdio> | |||||
| #include <limits.h> | |||||
| #include <memory> | |||||
| // Boost headers | |||||
| #include <boost/pointer_cast.hpp> | |||||
| #include <boost/scoped_ptr.hpp> | |||||
| #include <boost/scoped_array.hpp> | |||||
| #include <boost/shared_ptr.hpp> | |||||
| #include <boost/shared_array.hpp> | |||||
| #include <boost/make_shared.hpp> | |||||
| #include <boost/format.hpp> | |||||
| #include <boost/foreach.hpp> | |||||
| #include <boost/static_assert.hpp> | |||||
| #include <boost/lexical_cast.hpp> | |||||
| // Public ASSIMP headers | |||||
| #include "../include/assimp/DefaultLogger.hpp" | |||||
| #include "../include/assimp/IOStream.hpp" | |||||
| #include "../include/assimp/IOSystem.hpp" | |||||
| #include "../include/assimp/scene.h" | |||||
| #include "../include/assimp/importerdesc.h" | |||||
| #include "../include/assimp/postprocess.h" | |||||
| #include "../include/assimp/Importer.hpp" | |||||
| #include "../include/assimp/Exporter.hpp" | |||||
| // Internal utility headers | |||||
| #include "BaseImporter.h" | |||||
| #include "StringComparison.h" | |||||
| #include "StreamReader.h" | |||||
| #include "qnan.h" | |||||
| #include "ScenePrivate.h" | |||||
| // We need those constants, workaround for any platforms where nobody defined them yet | |||||
| #if (!defined SIZE_MAX) | |||||
| # define SIZE_MAX (~((size_t)0)) | |||||
| #endif | |||||
| #if (!defined UINT_MAX) | |||||
| # define UINT_MAX (~((unsigned int)0)) | |||||
| #endif | |||||
| #endif // !! ASSIMP_PCH_INCLUDED | |||||
| @@ -0,0 +1,687 @@ | |||||
| /* | |||||
| --------------------------------------------------------------------------- | |||||
| Open Asset Import Library (assimp) | |||||
| --------------------------------------------------------------------------- | |||||
| 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. | |||||
| --------------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file B3DImporter.cpp | |||||
| * @brief Implementation of the b3d importer class | |||||
| */ | |||||
| #include "AssimpPCH.h" | |||||
| #ifndef ASSIMP_BUILD_NO_B3D_IMPORTER | |||||
| // internal headers | |||||
| #include "B3DImporter.h" | |||||
| #include "TextureTransform.h" | |||||
| #include "ConvertToLHProcess.h" | |||||
| using namespace Assimp; | |||||
| using namespace std; | |||||
| static const aiImporterDesc desc = { | |||||
| "BlitzBasic 3D Importer", | |||||
| "", | |||||
| "", | |||||
| "http://www.blitzbasic.com/", | |||||
| aiImporterFlags_SupportBinaryFlavour, | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| "b3d" | |||||
| }; | |||||
| // (fixme, Aramis) quick workaround to get rid of all those signed to unsigned warnings | |||||
| #ifdef _MSC_VER | |||||
| # pragma warning (disable: 4018) | |||||
| #endif | |||||
| //#define DEBUG_B3D | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| bool B3DImporter::CanRead( const std::string& pFile, IOSystem* /*pIOHandler*/, bool /*checkSig*/) const{ | |||||
| size_t pos=pFile.find_last_of( '.' ); | |||||
| if( pos==string::npos ) return false; | |||||
| string ext=pFile.substr( pos+1 ); | |||||
| if( ext.size()!=3 ) return false; | |||||
| return (ext[0]=='b' || ext[0]=='B') && (ext[1]=='3') && (ext[2]=='d' || ext[2]=='D'); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Loader meta information | |||||
| const aiImporterDesc* B3DImporter::GetInfo () const | |||||
| { | |||||
| return &desc; | |||||
| } | |||||
| #ifdef DEBUG_B3D | |||||
| extern "C"{ void _stdcall AllocConsole(); } | |||||
| #endif | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void B3DImporter::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler){ | |||||
| #ifdef DEBUG_B3D | |||||
| AllocConsole(); | |||||
| freopen( "conin$","r",stdin ); | |||||
| freopen( "conout$","w",stdout ); | |||||
| freopen( "conout$","w",stderr ); | |||||
| cout<<"Hello world from the B3DImporter!"<<endl; | |||||
| #endif | |||||
| boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile)); | |||||
| // Check whether we can read from the file | |||||
| if( file.get() == NULL) | |||||
| throw DeadlyImportError( "Failed to open B3D file " + pFile + "."); | |||||
| // check whether the .b3d file is large enough to contain | |||||
| // at least one chunk. | |||||
| size_t fileSize = file->FileSize(); | |||||
| if( fileSize<8 ) throw DeadlyImportError( "B3D File is too small."); | |||||
| _pos=0; | |||||
| _buf.resize( fileSize ); | |||||
| file->Read( &_buf[0],1,fileSize ); | |||||
| _stack.clear(); | |||||
| ReadBB3D( pScene ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void B3DImporter::Oops(){ | |||||
| throw DeadlyImportError( "B3D Importer - INTERNAL ERROR" ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void B3DImporter::Fail( string str ){ | |||||
| #ifdef DEBUG_B3D | |||||
| cout<<"Error in B3D file data: "<<str<<endl; | |||||
| #endif | |||||
| throw DeadlyImportError( "B3D Importer - error in B3D file data: "+str ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| int B3DImporter::ReadByte(){ | |||||
| if( _pos<_buf.size() ) return _buf[_pos++]; | |||||
| Fail( "EOF" ); | |||||
| return 0; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| int B3DImporter::ReadInt(){ | |||||
| if( _pos+4<=_buf.size() ){ | |||||
| int n=*(int*)&_buf[_pos]; | |||||
| _pos+=4; | |||||
| return n; | |||||
| } | |||||
| Fail( "EOF" ); | |||||
| return 0; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| float B3DImporter::ReadFloat(){ | |||||
| if( _pos+4<=_buf.size() ){ | |||||
| float n=*(float*)&_buf[_pos]; | |||||
| _pos+=4; | |||||
| return n; | |||||
| } | |||||
| Fail( "EOF" ); | |||||
| return 0.0f; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| aiVector2D B3DImporter::ReadVec2(){ | |||||
| float x=ReadFloat(); | |||||
| float y=ReadFloat(); | |||||
| return aiVector2D( x,y ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| aiVector3D B3DImporter::ReadVec3(){ | |||||
| float x=ReadFloat(); | |||||
| float y=ReadFloat(); | |||||
| float z=ReadFloat(); | |||||
| return aiVector3D( x,y,z ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| aiQuaternion B3DImporter::ReadQuat(){ | |||||
| // (aramis_acg) Fix to adapt the loader to changed quat orientation | |||||
| float w=-ReadFloat(); | |||||
| float x=ReadFloat(); | |||||
| float y=ReadFloat(); | |||||
| float z=ReadFloat(); | |||||
| return aiQuaternion( w,x,y,z ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| string B3DImporter::ReadString(){ | |||||
| string str; | |||||
| while( _pos<_buf.size() ){ | |||||
| char c=(char)ReadByte(); | |||||
| if( !c ) return str; | |||||
| str+=c; | |||||
| } | |||||
| Fail( "EOF" ); | |||||
| return string(); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| string B3DImporter::ReadChunk(){ | |||||
| string tag; | |||||
| for( int i=0;i<4;++i ){ | |||||
| tag+=char( ReadByte() ); | |||||
| } | |||||
| #ifdef DEBUG_B3D | |||||
| // cout<<"ReadChunk:"<<tag<<endl; | |||||
| #endif | |||||
| unsigned sz=(unsigned)ReadInt(); | |||||
| _stack.push_back( _pos+sz ); | |||||
| return tag; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void B3DImporter::ExitChunk(){ | |||||
| _pos=_stack.back(); | |||||
| _stack.pop_back(); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| unsigned B3DImporter::ChunkSize(){ | |||||
| return _stack.back()-_pos; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| template<class T> | |||||
| T *B3DImporter::to_array( const vector<T> &v ){ | |||||
| if( !v.size() ) return 0; | |||||
| T *p=new T[v.size()]; | |||||
| for( size_t i=0;i<v.size();++i ){ | |||||
| p[i]=v[i]; | |||||
| } | |||||
| return p; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void B3DImporter::ReadTEXS(){ | |||||
| while( ChunkSize() ){ | |||||
| string name=ReadString(); | |||||
| /*int flags=*/ReadInt(); | |||||
| /*int blend=*/ReadInt(); | |||||
| /*aiVector2D pos=*/ReadVec2(); | |||||
| /*aiVector2D scale=*/ReadVec2(); | |||||
| /*float rot=*/ReadFloat(); | |||||
| _textures.push_back( name ); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void B3DImporter::ReadBRUS(){ | |||||
| int n_texs=ReadInt(); | |||||
| if( n_texs<0 || n_texs>8 ){ | |||||
| Fail( "Bad texture count" ); | |||||
| } | |||||
| while( ChunkSize() ){ | |||||
| string name=ReadString(); | |||||
| aiVector3D color=ReadVec3(); | |||||
| float alpha=ReadFloat(); | |||||
| float shiny=ReadFloat(); | |||||
| /*int blend=**/ReadInt(); | |||||
| int fx=ReadInt(); | |||||
| aiMaterial *mat=new aiMaterial; | |||||
| _materials.push_back( mat ); | |||||
| // Name | |||||
| aiString ainame( name ); | |||||
| mat->AddProperty( &ainame,AI_MATKEY_NAME ); | |||||
| // Diffuse color | |||||
| mat->AddProperty( &color,1,AI_MATKEY_COLOR_DIFFUSE ); | |||||
| // Opacity | |||||
| mat->AddProperty( &alpha,1,AI_MATKEY_OPACITY ); | |||||
| // Specular color | |||||
| aiColor3D speccolor( shiny,shiny,shiny ); | |||||
| mat->AddProperty( &speccolor,1,AI_MATKEY_COLOR_SPECULAR ); | |||||
| // Specular power | |||||
| float specpow=shiny*128; | |||||
| mat->AddProperty( &specpow,1,AI_MATKEY_SHININESS ); | |||||
| // Double sided | |||||
| if( fx & 0x10 ){ | |||||
| int i=1; | |||||
| mat->AddProperty( &i,1,AI_MATKEY_TWOSIDED ); | |||||
| } | |||||
| //Textures | |||||
| for( int i=0;i<n_texs;++i ){ | |||||
| int texid=ReadInt(); | |||||
| if( texid<-1 || (texid>=0 && texid>=static_cast<int>(_textures.size())) ){ | |||||
| Fail( "Bad texture id" ); | |||||
| } | |||||
| if( i==0 && texid>=0 ){ | |||||
| aiString texname( _textures[texid] ); | |||||
| mat->AddProperty( &texname,AI_MATKEY_TEXTURE_DIFFUSE(0) ); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void B3DImporter::ReadVRTS(){ | |||||
| _vflags=ReadInt(); | |||||
| _tcsets=ReadInt(); | |||||
| _tcsize=ReadInt(); | |||||
| if( _tcsets<0 || _tcsets>4 || _tcsize<0 || _tcsize>4 ){ | |||||
| Fail( "Bad texcoord data" ); | |||||
| } | |||||
| int sz=12+(_vflags&1?12:0)+(_vflags&2?16:0)+(_tcsets*_tcsize*4); | |||||
| int n_verts=ChunkSize()/sz; | |||||
| int v0=_vertices.size(); | |||||
| _vertices.resize( v0+n_verts ); | |||||
| for( int i=0;i<n_verts;++i ){ | |||||
| Vertex &v=_vertices[v0+i]; | |||||
| memset( v.bones,0,sizeof(v.bones) ); | |||||
| memset( v.weights,0,sizeof(v.weights) ); | |||||
| v.vertex=ReadVec3(); | |||||
| if( _vflags & 1 ) v.normal=ReadVec3(); | |||||
| if( _vflags & 2 ) ReadQuat(); //skip v 4bytes... | |||||
| for( int i=0;i<_tcsets;++i ){ | |||||
| float t[4]={0,0,0,0}; | |||||
| for( int j=0;j<_tcsize;++j ){ | |||||
| t[j]=ReadFloat(); | |||||
| } | |||||
| t[1]=1-t[1]; | |||||
| if( !i ) v.texcoords=aiVector3D( t[0],t[1],t[2] ); | |||||
| } | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void B3DImporter::ReadTRIS( int v0 ){ | |||||
| int matid=ReadInt(); | |||||
| if( matid==-1 ){ | |||||
| matid=0; | |||||
| }else if( matid<0 || matid>=(int)_materials.size() ){ | |||||
| #ifdef DEBUG_B3D | |||||
| cout<<"material id="<<matid<<endl; | |||||
| #endif | |||||
| Fail( "Bad material id" ); | |||||
| } | |||||
| aiMesh *mesh=new aiMesh; | |||||
| _meshes.push_back( mesh ); | |||||
| mesh->mMaterialIndex=matid; | |||||
| mesh->mNumFaces=0; | |||||
| mesh->mPrimitiveTypes=aiPrimitiveType_TRIANGLE; | |||||
| int n_tris=ChunkSize()/12; | |||||
| aiFace *face=mesh->mFaces=new aiFace[n_tris]; | |||||
| for( int i=0;i<n_tris;++i ){ | |||||
| int i0=ReadInt()+v0; | |||||
| int i1=ReadInt()+v0; | |||||
| int i2=ReadInt()+v0; | |||||
| if( i0<0 || i0>=(int)_vertices.size() || i1<0 || i1>=(int)_vertices.size() || i2<0 || i2>=(int)_vertices.size() ){ | |||||
| #ifdef DEBUG_B3D | |||||
| cout<<"Bad triangle index: i0="<<i0<<", i1="<<i1<<", i2="<<i2<<endl; | |||||
| #endif | |||||
| Fail( "Bad triangle index" ); | |||||
| continue; | |||||
| } | |||||
| face->mNumIndices=3; | |||||
| face->mIndices=new unsigned[3]; | |||||
| face->mIndices[0]=i0; | |||||
| face->mIndices[1]=i1; | |||||
| face->mIndices[2]=i2; | |||||
| ++mesh->mNumFaces; | |||||
| ++face; | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void B3DImporter::ReadMESH(){ | |||||
| /*int matid=*/ReadInt(); | |||||
| int v0=_vertices.size(); | |||||
| while( ChunkSize() ){ | |||||
| string t=ReadChunk(); | |||||
| if( t=="VRTS" ){ | |||||
| ReadVRTS(); | |||||
| }else if( t=="TRIS" ){ | |||||
| ReadTRIS( v0 ); | |||||
| } | |||||
| ExitChunk(); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void B3DImporter::ReadBONE( int id ){ | |||||
| while( ChunkSize() ){ | |||||
| int vertex=ReadInt(); | |||||
| float weight=ReadFloat(); | |||||
| if( vertex<0 || vertex>=(int)_vertices.size() ){ | |||||
| Fail( "Bad vertex index" ); | |||||
| } | |||||
| Vertex &v=_vertices[vertex]; | |||||
| int i; | |||||
| for( i=0;i<4;++i ){ | |||||
| if( !v.weights[i] ){ | |||||
| v.bones[i]=id; | |||||
| v.weights[i]=weight; | |||||
| break; | |||||
| } | |||||
| } | |||||
| #ifdef DEBUG_B3D | |||||
| if( i==4 ){ | |||||
| cout<<"Too many bone weights"<<endl; | |||||
| } | |||||
| #endif | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void B3DImporter::ReadKEYS( aiNodeAnim *nodeAnim ){ | |||||
| vector<aiVectorKey> trans,scale; | |||||
| vector<aiQuatKey> rot; | |||||
| int flags=ReadInt(); | |||||
| while( ChunkSize() ){ | |||||
| int frame=ReadInt(); | |||||
| if( flags & 1 ){ | |||||
| trans.push_back( aiVectorKey( frame,ReadVec3() ) ); | |||||
| } | |||||
| if( flags & 2 ){ | |||||
| scale.push_back( aiVectorKey( frame,ReadVec3() ) ); | |||||
| } | |||||
| if( flags & 4 ){ | |||||
| rot.push_back( aiQuatKey( frame,ReadQuat() ) ); | |||||
| } | |||||
| } | |||||
| if( flags & 1 ){ | |||||
| nodeAnim->mNumPositionKeys=trans.size(); | |||||
| nodeAnim->mPositionKeys=to_array( trans ); | |||||
| } | |||||
| if( flags & 2 ){ | |||||
| nodeAnim->mNumScalingKeys=scale.size(); | |||||
| nodeAnim->mScalingKeys=to_array( scale ); | |||||
| } | |||||
| if( flags & 4 ){ | |||||
| nodeAnim->mNumRotationKeys=rot.size(); | |||||
| nodeAnim->mRotationKeys=to_array( rot ); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void B3DImporter::ReadANIM(){ | |||||
| /*int flags=*/ReadInt(); | |||||
| int frames=ReadInt(); | |||||
| float fps=ReadFloat(); | |||||
| aiAnimation *anim=new aiAnimation; | |||||
| _animations.push_back( anim ); | |||||
| anim->mDuration=frames; | |||||
| anim->mTicksPerSecond=fps; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| aiNode *B3DImporter::ReadNODE( aiNode *parent ){ | |||||
| string name=ReadString(); | |||||
| aiVector3D t=ReadVec3(); | |||||
| aiVector3D s=ReadVec3(); | |||||
| aiQuaternion r=ReadQuat(); | |||||
| aiMatrix4x4 trans,scale,rot; | |||||
| aiMatrix4x4::Translation( t,trans ); | |||||
| aiMatrix4x4::Scaling( s,scale ); | |||||
| rot=aiMatrix4x4( r.GetMatrix() ); | |||||
| aiMatrix4x4 tform=trans * rot * scale; | |||||
| int nodeid=_nodes.size(); | |||||
| aiNode *node=new aiNode( name ); | |||||
| _nodes.push_back( node ); | |||||
| node->mParent=parent; | |||||
| node->mTransformation=tform; | |||||
| aiNodeAnim *nodeAnim=0; | |||||
| vector<unsigned> meshes; | |||||
| vector<aiNode*> children; | |||||
| while( ChunkSize() ){ | |||||
| string t=ReadChunk(); | |||||
| if( t=="MESH" ){ | |||||
| int n=_meshes.size(); | |||||
| ReadMESH(); | |||||
| for( int i=n;i<(int)_meshes.size();++i ){ | |||||
| meshes.push_back( i ); | |||||
| } | |||||
| }else if( t=="BONE" ){ | |||||
| ReadBONE( nodeid ); | |||||
| }else if( t=="ANIM" ){ | |||||
| ReadANIM(); | |||||
| }else if( t=="KEYS" ){ | |||||
| if( !nodeAnim ){ | |||||
| nodeAnim=new aiNodeAnim; | |||||
| _nodeAnims.push_back( nodeAnim ); | |||||
| nodeAnim->mNodeName=node->mName; | |||||
| } | |||||
| ReadKEYS( nodeAnim ); | |||||
| }else if( t=="NODE" ){ | |||||
| aiNode *child=ReadNODE( node ); | |||||
| children.push_back( child ); | |||||
| } | |||||
| ExitChunk(); | |||||
| } | |||||
| node->mNumMeshes=meshes.size(); | |||||
| node->mMeshes=to_array( meshes ); | |||||
| node->mNumChildren=children.size(); | |||||
| node->mChildren=to_array( children ); | |||||
| return node; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void B3DImporter::ReadBB3D( aiScene *scene ){ | |||||
| _textures.clear(); | |||||
| _materials.size(); | |||||
| _vertices.clear(); | |||||
| _meshes.clear(); | |||||
| _nodes.clear(); | |||||
| _nodeAnims.clear(); | |||||
| _animations.clear(); | |||||
| string t=ReadChunk(); | |||||
| if( t=="BB3D" ){ | |||||
| int version=ReadInt(); | |||||
| if (!DefaultLogger::isNullLogger()) { | |||||
| char dmp[128]; | |||||
| sprintf(dmp,"B3D file format version: %i",version); | |||||
| DefaultLogger::get()->info(dmp); | |||||
| } | |||||
| while( ChunkSize() ){ | |||||
| string t=ReadChunk(); | |||||
| if( t=="TEXS" ){ | |||||
| ReadTEXS(); | |||||
| }else if( t=="BRUS" ){ | |||||
| ReadBRUS(); | |||||
| }else if( t=="NODE" ){ | |||||
| ReadNODE( 0 ); | |||||
| } | |||||
| ExitChunk(); | |||||
| } | |||||
| } | |||||
| ExitChunk(); | |||||
| if( !_nodes.size() ) Fail( "No nodes" ); | |||||
| if( !_meshes.size() ) Fail( "No meshes" ); | |||||
| //Fix nodes/meshes/bones | |||||
| for(size_t i=0;i<_nodes.size();++i ){ | |||||
| aiNode *node=_nodes[i]; | |||||
| for( size_t j=0;j<node->mNumMeshes;++j ){ | |||||
| aiMesh *mesh=_meshes[node->mMeshes[j]]; | |||||
| int n_tris=mesh->mNumFaces; | |||||
| int n_verts=mesh->mNumVertices=n_tris * 3; | |||||
| aiVector3D *mv=mesh->mVertices=new aiVector3D[ n_verts ],*mn=0,*mc=0; | |||||
| if( _vflags & 1 ) mn=mesh->mNormals=new aiVector3D[ n_verts ]; | |||||
| if( _tcsets ) mc=mesh->mTextureCoords[0]=new aiVector3D[ n_verts ]; | |||||
| aiFace *face=mesh->mFaces; | |||||
| vector< vector<aiVertexWeight> > vweights( _nodes.size() ); | |||||
| for( int i=0;i<n_verts;i+=3 ){ | |||||
| for( int j=0;j<3;++j ){ | |||||
| Vertex &v=_vertices[face->mIndices[j]]; | |||||
| *mv++=v.vertex; | |||||
| if( mn ) *mn++=v.normal; | |||||
| if( mc ) *mc++=v.texcoords; | |||||
| face->mIndices[j]=i+j; | |||||
| for( int k=0;k<4;++k ){ | |||||
| if( !v.weights[k] ) break; | |||||
| int bone=v.bones[k]; | |||||
| float weight=v.weights[k]; | |||||
| vweights[bone].push_back( aiVertexWeight(i+j,weight) ); | |||||
| } | |||||
| } | |||||
| ++face; | |||||
| } | |||||
| vector<aiBone*> bones; | |||||
| for(size_t i=0;i<vweights.size();++i ){ | |||||
| vector<aiVertexWeight> &weights=vweights[i]; | |||||
| if( !weights.size() ) continue; | |||||
| aiBone *bone=new aiBone; | |||||
| bones.push_back( bone ); | |||||
| aiNode *bnode=_nodes[i]; | |||||
| bone->mName=bnode->mName; | |||||
| bone->mNumWeights=weights.size(); | |||||
| bone->mWeights=to_array( weights ); | |||||
| aiMatrix4x4 mat=bnode->mTransformation; | |||||
| while( bnode->mParent ){ | |||||
| bnode=bnode->mParent; | |||||
| mat=bnode->mTransformation * mat; | |||||
| } | |||||
| bone->mOffsetMatrix=mat.Inverse(); | |||||
| } | |||||
| mesh->mNumBones=bones.size(); | |||||
| mesh->mBones=to_array( bones ); | |||||
| } | |||||
| } | |||||
| //nodes | |||||
| scene->mRootNode=_nodes[0]; | |||||
| //material | |||||
| if( !_materials.size() ){ | |||||
| _materials.push_back( new aiMaterial ); | |||||
| } | |||||
| scene->mNumMaterials=_materials.size(); | |||||
| scene->mMaterials=to_array( _materials ); | |||||
| //meshes | |||||
| scene->mNumMeshes=_meshes.size(); | |||||
| scene->mMeshes=to_array( _meshes ); | |||||
| //animations | |||||
| if( _animations.size()==1 && _nodeAnims.size() ){ | |||||
| aiAnimation *anim=_animations.back(); | |||||
| anim->mNumChannels=_nodeAnims.size(); | |||||
| anim->mChannels=to_array( _nodeAnims ); | |||||
| scene->mNumAnimations=_animations.size(); | |||||
| scene->mAnimations=to_array( _animations ); | |||||
| } | |||||
| // convert to RH | |||||
| MakeLeftHandedProcess makeleft; | |||||
| makeleft.Execute( scene ); | |||||
| FlipWindingOrderProcess flip; | |||||
| flip.Execute( scene ); | |||||
| } | |||||
| #endif // !! ASSIMP_BUILD_NO_B3D_IMPORTER | |||||
| @@ -0,0 +1,126 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file Definition of the .b3d importer class. */ | |||||
| #ifndef AI_B3DIMPORTER_H_INC | |||||
| #define AI_B3DIMPORTER_H_INC | |||||
| #include "../include/assimp/types.h" | |||||
| #include "../include/assimp/mesh.h" | |||||
| #include "../include/assimp/material.h" | |||||
| #include <string> | |||||
| #include <vector> | |||||
| namespace Assimp{ | |||||
| class B3DImporter : public BaseImporter{ | |||||
| public: | |||||
| 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: | |||||
| int ReadByte(); | |||||
| int ReadInt(); | |||||
| float ReadFloat(); | |||||
| aiVector2D ReadVec2(); | |||||
| aiVector3D ReadVec3(); | |||||
| aiQuaternion ReadQuat(); | |||||
| std::string ReadString(); | |||||
| std::string ReadChunk(); | |||||
| void ExitChunk(); | |||||
| unsigned ChunkSize(); | |||||
| template<class T> | |||||
| T *to_array( const std::vector<T> &v ); | |||||
| struct Vertex{ | |||||
| aiVector3D vertex; | |||||
| aiVector3D normal; | |||||
| aiVector3D texcoords; | |||||
| unsigned char bones[4]; | |||||
| float weights[4]; | |||||
| }; | |||||
| void Oops(); | |||||
| void Fail( std::string str ); | |||||
| void ReadTEXS(); | |||||
| void ReadBRUS(); | |||||
| void ReadVRTS(); | |||||
| void ReadTRIS( int v0 ); | |||||
| void ReadMESH(); | |||||
| void ReadBONE( int id ); | |||||
| void ReadKEYS( aiNodeAnim *nodeAnim ); | |||||
| void ReadANIM(); | |||||
| aiNode *ReadNODE( aiNode *parent ); | |||||
| void ReadBB3D( aiScene *scene ); | |||||
| unsigned _pos; | |||||
| // unsigned _size; | |||||
| std::vector<unsigned char> _buf; | |||||
| std::vector<unsigned> _stack; | |||||
| std::vector<std::string> _textures; | |||||
| std::vector<aiMaterial*> _materials; | |||||
| int _vflags,_tcsets,_tcsize; | |||||
| std::vector<Vertex> _vertices; | |||||
| std::vector<aiNode*> _nodes; | |||||
| std::vector<aiMesh*> _meshes; | |||||
| std::vector<aiNodeAnim*> _nodeAnims; | |||||
| std::vector<aiAnimation*> _animations; | |||||
| }; | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,534 @@ | |||||
| /** Implementation of the BVH loader */ | |||||
| /* | |||||
| --------------------------------------------------------------------------- | |||||
| Open Asset Import Library (assimp) | |||||
| --------------------------------------------------------------------------- | |||||
| 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. | |||||
| --------------------------------------------------------------------------- | |||||
| */ | |||||
| #include "AssimpPCH.h" | |||||
| #ifndef ASSIMP_BUILD_NO_BVH_IMPORTER | |||||
| #include "BVHLoader.h" | |||||
| #include "fast_atof.h" | |||||
| #include "SkeletonMeshBuilder.h" | |||||
| using namespace Assimp; | |||||
| static const aiImporterDesc desc = { | |||||
| "BVH Importer (MoCap)", | |||||
| "", | |||||
| "", | |||||
| "", | |||||
| aiImporterFlags_SupportTextFlavour, | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| "bvh" | |||||
| }; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Constructor to be privately used by Importer | |||||
| BVHLoader::BVHLoader() | |||||
| : noSkeletonMesh() | |||||
| {} | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Destructor, private as well | |||||
| BVHLoader::~BVHLoader() | |||||
| {} | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Returns whether the class can handle the format of the given file. | |||||
| bool BVHLoader::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const | |||||
| { | |||||
| // check file extension | |||||
| const std::string extension = GetExtension(pFile); | |||||
| if( extension == "bvh") | |||||
| return true; | |||||
| if ((!extension.length() || cs) && pIOHandler) { | |||||
| const char* tokens[] = {"HIERARCHY"}; | |||||
| return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); | |||||
| } | |||||
| return false; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BVHLoader::SetupProperties(const Importer* pImp) | |||||
| { | |||||
| noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Loader meta information | |||||
| const aiImporterDesc* BVHLoader::GetInfo () const | |||||
| { | |||||
| return &desc; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Imports the given file into the given scene structure. | |||||
| void BVHLoader::InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler) | |||||
| { | |||||
| mFileName = pFile; | |||||
| // read file into memory | |||||
| boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile)); | |||||
| if( file.get() == NULL) | |||||
| throw DeadlyImportError( "Failed to open file " + pFile + "."); | |||||
| size_t fileSize = file->FileSize(); | |||||
| if( fileSize == 0) | |||||
| throw DeadlyImportError( "File is too small."); | |||||
| mBuffer.resize( fileSize); | |||||
| file->Read( &mBuffer.front(), 1, fileSize); | |||||
| // start reading | |||||
| mReader = mBuffer.begin(); | |||||
| mLine = 1; | |||||
| ReadStructure( pScene); | |||||
| if (!noSkeletonMesh) { | |||||
| // build a dummy mesh for the skeleton so that we see something at least | |||||
| SkeletonMeshBuilder meshBuilder( pScene); | |||||
| } | |||||
| // construct an animation from all the motion data we read | |||||
| CreateAnimation( pScene); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Reads the file | |||||
| void BVHLoader::ReadStructure( aiScene* pScene) | |||||
| { | |||||
| // first comes hierarchy | |||||
| std::string header = GetNextToken(); | |||||
| if( header != "HIERARCHY") | |||||
| ThrowException( "Expected header string \"HIERARCHY\"."); | |||||
| ReadHierarchy( pScene); | |||||
| // then comes the motion data | |||||
| std::string motion = GetNextToken(); | |||||
| if( motion != "MOTION") | |||||
| ThrowException( "Expected beginning of motion data \"MOTION\"."); | |||||
| ReadMotion( pScene); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Reads the hierarchy | |||||
| void BVHLoader::ReadHierarchy( aiScene* pScene) | |||||
| { | |||||
| std::string root = GetNextToken(); | |||||
| if( root != "ROOT") | |||||
| ThrowException( "Expected root node \"ROOT\"."); | |||||
| // Go read the hierarchy from here | |||||
| pScene->mRootNode = ReadNode(); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Reads a node and recursively its childs and returns the created node; | |||||
| aiNode* BVHLoader::ReadNode() | |||||
| { | |||||
| // first token is name | |||||
| std::string nodeName = GetNextToken(); | |||||
| if( nodeName.empty() || nodeName == "{") | |||||
| ThrowException( boost::str( boost::format( "Expected node name, but found \"%s\".") % nodeName)); | |||||
| // then an opening brace should follow | |||||
| std::string openBrace = GetNextToken(); | |||||
| if( openBrace != "{") | |||||
| ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace)); | |||||
| // Create a node | |||||
| aiNode* node = new aiNode( nodeName); | |||||
| std::vector<aiNode*> childNodes; | |||||
| // and create an bone entry for it | |||||
| mNodes.push_back( Node( node)); | |||||
| Node& internNode = mNodes.back(); | |||||
| // now read the node's contents | |||||
| while( 1) | |||||
| { | |||||
| std::string token = GetNextToken(); | |||||
| // node offset to parent node | |||||
| if( token == "OFFSET") | |||||
| ReadNodeOffset( node); | |||||
| else if( token == "CHANNELS") | |||||
| ReadNodeChannels( internNode); | |||||
| else if( token == "JOINT") | |||||
| { | |||||
| // child node follows | |||||
| aiNode* child = ReadNode(); | |||||
| child->mParent = node; | |||||
| childNodes.push_back( child); | |||||
| } | |||||
| else if( token == "End") | |||||
| { | |||||
| // The real symbol is "End Site". Second part comes in a separate token | |||||
| std::string siteToken = GetNextToken(); | |||||
| if( siteToken != "Site") | |||||
| ThrowException( boost::str( boost::format( "Expected \"End Site\" keyword, but found \"%s %s\".") % token % siteToken)); | |||||
| aiNode* child = ReadEndSite( nodeName); | |||||
| child->mParent = node; | |||||
| childNodes.push_back( child); | |||||
| } | |||||
| else if( token == "}") | |||||
| { | |||||
| // we're done with that part of the hierarchy | |||||
| break; | |||||
| } else | |||||
| { | |||||
| // everything else is a parse error | |||||
| ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token)); | |||||
| } | |||||
| } | |||||
| // add the child nodes if there are any | |||||
| if( childNodes.size() > 0) | |||||
| { | |||||
| node->mNumChildren = childNodes.size(); | |||||
| node->mChildren = new aiNode*[node->mNumChildren]; | |||||
| std::copy( childNodes.begin(), childNodes.end(), node->mChildren); | |||||
| } | |||||
| // and return the sub-hierarchy we built here | |||||
| return node; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Reads an end node and returns the created node. | |||||
| aiNode* BVHLoader::ReadEndSite( const std::string& pParentName) | |||||
| { | |||||
| // check opening brace | |||||
| std::string openBrace = GetNextToken(); | |||||
| if( openBrace != "{") | |||||
| ThrowException( boost::str( boost::format( "Expected opening brace \"{\", but found \"%s\".") % openBrace)); | |||||
| // Create a node | |||||
| aiNode* node = new aiNode( "EndSite_" + pParentName); | |||||
| // now read the node's contents. Only possible entry is "OFFSET" | |||||
| while( 1) | |||||
| { | |||||
| std::string token = GetNextToken(); | |||||
| // end node's offset | |||||
| if( token == "OFFSET") | |||||
| { | |||||
| ReadNodeOffset( node); | |||||
| } | |||||
| else if( token == "}") | |||||
| { | |||||
| // we're done with the end node | |||||
| break; | |||||
| } else | |||||
| { | |||||
| // everything else is a parse error | |||||
| ThrowException( boost::str( boost::format( "Unknown keyword \"%s\".") % token)); | |||||
| } | |||||
| } | |||||
| // and return the sub-hierarchy we built here | |||||
| return node; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Reads a node offset for the given node | |||||
| void BVHLoader::ReadNodeOffset( aiNode* pNode) | |||||
| { | |||||
| // Offset consists of three floats to read | |||||
| aiVector3D offset; | |||||
| offset.x = GetNextTokenAsFloat(); | |||||
| offset.y = GetNextTokenAsFloat(); | |||||
| offset.z = GetNextTokenAsFloat(); | |||||
| // build a transformation matrix from it | |||||
| pNode->mTransformation = aiMatrix4x4( 1.0f, 0.0f, 0.0f, offset.x, 0.0f, 1.0f, 0.0f, offset.y, | |||||
| 0.0f, 0.0f, 1.0f, offset.z, 0.0f, 0.0f, 0.0f, 1.0f); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Reads the animation channels for the given node | |||||
| void BVHLoader::ReadNodeChannels( BVHLoader::Node& pNode) | |||||
| { | |||||
| // number of channels. Use the float reader because we're lazy | |||||
| float numChannelsFloat = GetNextTokenAsFloat(); | |||||
| unsigned int numChannels = (unsigned int) numChannelsFloat; | |||||
| for( unsigned int a = 0; a < numChannels; a++) | |||||
| { | |||||
| std::string channelToken = GetNextToken(); | |||||
| if( channelToken == "Xposition") | |||||
| pNode.mChannels.push_back( Channel_PositionX); | |||||
| else if( channelToken == "Yposition") | |||||
| pNode.mChannels.push_back( Channel_PositionY); | |||||
| else if( channelToken == "Zposition") | |||||
| pNode.mChannels.push_back( Channel_PositionZ); | |||||
| else if( channelToken == "Xrotation") | |||||
| pNode.mChannels.push_back( Channel_RotationX); | |||||
| else if( channelToken == "Yrotation") | |||||
| pNode.mChannels.push_back( Channel_RotationY); | |||||
| else if( channelToken == "Zrotation") | |||||
| pNode.mChannels.push_back( Channel_RotationZ); | |||||
| else | |||||
| ThrowException( boost::str( boost::format( "Invalid channel specifier \"%s\".") % channelToken)); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Reads the motion data | |||||
| void BVHLoader::ReadMotion( aiScene* /*pScene*/) | |||||
| { | |||||
| // Read number of frames | |||||
| std::string tokenFrames = GetNextToken(); | |||||
| if( tokenFrames != "Frames:") | |||||
| ThrowException( boost::str( boost::format( "Expected frame count \"Frames:\", but found \"%s\".") % tokenFrames)); | |||||
| float numFramesFloat = GetNextTokenAsFloat(); | |||||
| mAnimNumFrames = (unsigned int) numFramesFloat; | |||||
| // Read frame duration | |||||
| std::string tokenDuration1 = GetNextToken(); | |||||
| std::string tokenDuration2 = GetNextToken(); | |||||
| if( tokenDuration1 != "Frame" || tokenDuration2 != "Time:") | |||||
| ThrowException( boost::str( boost::format( "Expected frame duration \"Frame Time:\", but found \"%s %s\".") % tokenDuration1 % tokenDuration2)); | |||||
| mAnimTickDuration = GetNextTokenAsFloat(); | |||||
| // resize value vectors for each node | |||||
| for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it) | |||||
| it->mChannelValues.reserve( it->mChannels.size() * mAnimNumFrames); | |||||
| // now read all the data and store it in the corresponding node's value vector | |||||
| for( unsigned int frame = 0; frame < mAnimNumFrames; ++frame) | |||||
| { | |||||
| // on each line read the values for all nodes | |||||
| for( std::vector<Node>::iterator it = mNodes.begin(); it != mNodes.end(); ++it) | |||||
| { | |||||
| // get as many values as the node has channels | |||||
| for( unsigned int c = 0; c < it->mChannels.size(); ++c) | |||||
| it->mChannelValues.push_back( GetNextTokenAsFloat()); | |||||
| } | |||||
| // after one frame worth of values for all nodes there should be a newline, but we better don't rely on it | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Retrieves the next token | |||||
| std::string BVHLoader::GetNextToken() | |||||
| { | |||||
| // skip any preceeding whitespace | |||||
| while( mReader != mBuffer.end()) | |||||
| { | |||||
| if( !isspace( *mReader)) | |||||
| break; | |||||
| // count lines | |||||
| if( *mReader == '\n') | |||||
| mLine++; | |||||
| ++mReader; | |||||
| } | |||||
| // collect all chars till the next whitespace. BVH is easy in respect to that. | |||||
| std::string token; | |||||
| while( mReader != mBuffer.end()) | |||||
| { | |||||
| if( isspace( *mReader)) | |||||
| break; | |||||
| token.push_back( *mReader); | |||||
| ++mReader; | |||||
| // little extra logic to make sure braces are counted correctly | |||||
| if( token == "{" || token == "}") | |||||
| break; | |||||
| } | |||||
| // empty token means end of file, which is just fine | |||||
| return token; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Reads the next token as a float | |||||
| float BVHLoader::GetNextTokenAsFloat() | |||||
| { | |||||
| std::string token = GetNextToken(); | |||||
| if( token.empty()) | |||||
| ThrowException( "Unexpected end of file while trying to read a float"); | |||||
| // check if the float is valid by testing if the atof() function consumed every char of the token | |||||
| const char* ctoken = token.c_str(); | |||||
| float result = 0.0f; | |||||
| ctoken = fast_atoreal_move<float>( ctoken, result); | |||||
| if( ctoken != token.c_str() + token.length()) | |||||
| ThrowException( boost::str( boost::format( "Expected a floating point number, but found \"%s\".") % token)); | |||||
| return result; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Aborts the file reading with an exception | |||||
| void BVHLoader::ThrowException( const std::string& pError) | |||||
| { | |||||
| throw DeadlyImportError( boost::str( boost::format( "%s:%d - %s") % mFileName % mLine % pError)); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Constructs an animation for the motion data and stores it in the given scene | |||||
| void BVHLoader::CreateAnimation( aiScene* pScene) | |||||
| { | |||||
| // create the animation | |||||
| pScene->mNumAnimations = 1; | |||||
| pScene->mAnimations = new aiAnimation*[1]; | |||||
| aiAnimation* anim = new aiAnimation; | |||||
| pScene->mAnimations[0] = anim; | |||||
| // put down the basic parameters | |||||
| anim->mName.Set( "Motion"); | |||||
| anim->mTicksPerSecond = 1.0 / double( mAnimTickDuration); | |||||
| anim->mDuration = double( mAnimNumFrames - 1); | |||||
| // now generate the tracks for all nodes | |||||
| anim->mNumChannels = mNodes.size(); | |||||
| anim->mChannels = new aiNodeAnim*[anim->mNumChannels]; | |||||
| // FIX: set the array elements to NULL to ensure proper deletion if an exception is thrown | |||||
| for (unsigned int i = 0; i < anim->mNumChannels;++i) | |||||
| anim->mChannels[i] = NULL; | |||||
| for( unsigned int a = 0; a < anim->mNumChannels; a++) | |||||
| { | |||||
| const Node& node = mNodes[a]; | |||||
| const std::string nodeName = std::string( node.mNode->mName.data ); | |||||
| aiNodeAnim* nodeAnim = new aiNodeAnim; | |||||
| anim->mChannels[a] = nodeAnim; | |||||
| nodeAnim->mNodeName.Set( nodeName); | |||||
| // translational part, if given | |||||
| if( node.mChannels.size() == 6) | |||||
| { | |||||
| nodeAnim->mNumPositionKeys = mAnimNumFrames; | |||||
| nodeAnim->mPositionKeys = new aiVectorKey[mAnimNumFrames]; | |||||
| aiVectorKey* poskey = nodeAnim->mPositionKeys; | |||||
| for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr) | |||||
| { | |||||
| poskey->mTime = double( fr); | |||||
| // Now compute all translations in the right order | |||||
| for( unsigned int channel = 0; channel < 3; ++channel) | |||||
| { | |||||
| switch( node.mChannels[channel]) | |||||
| { | |||||
| case Channel_PositionX: poskey->mValue.x = node.mChannelValues[fr * node.mChannels.size() + channel]; break; | |||||
| case Channel_PositionY: poskey->mValue.y = node.mChannelValues[fr * node.mChannels.size() + channel]; break; | |||||
| case Channel_PositionZ: poskey->mValue.z = node.mChannelValues[fr * node.mChannels.size() + channel]; break; | |||||
| default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName ); | |||||
| } | |||||
| } | |||||
| ++poskey; | |||||
| } | |||||
| } else | |||||
| { | |||||
| // if no translation part is given, put a default sequence | |||||
| aiVector3D nodePos( node.mNode->mTransformation.a4, node.mNode->mTransformation.b4, node.mNode->mTransformation.c4); | |||||
| nodeAnim->mNumPositionKeys = 1; | |||||
| nodeAnim->mPositionKeys = new aiVectorKey[1]; | |||||
| nodeAnim->mPositionKeys[0].mTime = 0.0; | |||||
| nodeAnim->mPositionKeys[0].mValue = nodePos; | |||||
| } | |||||
| // rotation part. Always present. First find value offsets | |||||
| { | |||||
| unsigned int rotOffset = 0; | |||||
| if( node.mChannels.size() == 6) | |||||
| { | |||||
| // Offset all further calculations | |||||
| rotOffset = 3; | |||||
| } | |||||
| // Then create the number of rotation keys | |||||
| nodeAnim->mNumRotationKeys = mAnimNumFrames; | |||||
| nodeAnim->mRotationKeys = new aiQuatKey[mAnimNumFrames]; | |||||
| aiQuatKey* rotkey = nodeAnim->mRotationKeys; | |||||
| for( unsigned int fr = 0; fr < mAnimNumFrames; ++fr) | |||||
| { | |||||
| aiMatrix4x4 temp; | |||||
| aiMatrix3x3 rotMatrix; | |||||
| for( unsigned int channel = 0; channel < 3; ++channel) | |||||
| { | |||||
| // translate ZXY euler angels into a quaternion | |||||
| const float angle = node.mChannelValues[fr * node.mChannels.size() + rotOffset + channel] * float( AI_MATH_PI) / 180.0f; | |||||
| // Compute rotation transformations in the right order | |||||
| switch (node.mChannels[rotOffset+channel]) | |||||
| { | |||||
| case Channel_RotationX: aiMatrix4x4::RotationX( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; | |||||
| case Channel_RotationY: aiMatrix4x4::RotationY( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; | |||||
| case Channel_RotationZ: aiMatrix4x4::RotationZ( angle, temp); rotMatrix *= aiMatrix3x3( temp); break; | |||||
| default: throw DeadlyImportError( "Unexpected animation channel setup at node " + nodeName ); | |||||
| } | |||||
| } | |||||
| rotkey->mTime = double( fr); | |||||
| rotkey->mValue = aiQuaternion( rotMatrix); | |||||
| ++rotkey; | |||||
| } | |||||
| } | |||||
| // scaling part. Always just a default track | |||||
| { | |||||
| nodeAnim->mNumScalingKeys = 1; | |||||
| nodeAnim->mScalingKeys = new aiVectorKey[1]; | |||||
| nodeAnim->mScalingKeys[0].mTime = 0.0; | |||||
| nodeAnim->mScalingKeys[0].mValue.Set( 1.0f, 1.0f, 1.0f); | |||||
| } | |||||
| } | |||||
| } | |||||
| #endif // !! ASSIMP_BUILD_NO_BVH_IMPORTER | |||||
| @@ -0,0 +1,169 @@ | |||||
| /** Defines the BHV motion capturing loader class */ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file BVHLoader.h | |||||
| * @brief Biovision BVH import | |||||
| */ | |||||
| #ifndef AI_BVHLOADER_H_INC | |||||
| #define AI_BVHLOADER_H_INC | |||||
| #include "BaseImporter.h" | |||||
| namespace Assimp | |||||
| { | |||||
| // -------------------------------------------------------------------------------- | |||||
| /** Loader class to read Motion Capturing data from a .bvh file. | |||||
| * | |||||
| * This format only contains a hierarchy of joints and a series of keyframes for | |||||
| * the hierarchy. It contains no actual mesh data, but we generate a dummy mesh | |||||
| * inside the loader just to be able to see something. | |||||
| */ | |||||
| class BVHLoader : public BaseImporter | |||||
| { | |||||
| /** Possible animation channels for which the motion data holds the values */ | |||||
| enum ChannelType | |||||
| { | |||||
| Channel_PositionX, | |||||
| Channel_PositionY, | |||||
| Channel_PositionZ, | |||||
| Channel_RotationX, | |||||
| Channel_RotationY, | |||||
| Channel_RotationZ | |||||
| }; | |||||
| /** Collected list of node. Will be bones of the dummy mesh some day, addressed by their array index */ | |||||
| struct Node | |||||
| { | |||||
| const aiNode* mNode; | |||||
| std::vector<ChannelType> mChannels; | |||||
| std::vector<float> mChannelValues; // motion data values for that node. Of size NumChannels * NumFrames | |||||
| Node() { } | |||||
| Node( const aiNode* pNode) : mNode( pNode) { } | |||||
| }; | |||||
| public: | |||||
| BVHLoader(); | |||||
| ~BVHLoader(); | |||||
| public: | |||||
| /** Returns whether the class can handle the format of the given file. | |||||
| * See BaseImporter::CanRead() for details. */ | |||||
| bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool cs) const; | |||||
| void SetupProperties(const Importer* pImp); | |||||
| const aiImporterDesc* GetInfo () const; | |||||
| protected: | |||||
| /** Imports the given file into the given scene structure. | |||||
| * See BaseImporter::InternReadFile() for details | |||||
| */ | |||||
| void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); | |||||
| protected: | |||||
| /** Reads the file */ | |||||
| void ReadStructure( aiScene* pScene); | |||||
| /** Reads the hierarchy */ | |||||
| void ReadHierarchy( aiScene* pScene); | |||||
| /** Reads a node and recursively its childs and returns the created node. */ | |||||
| aiNode* ReadNode(); | |||||
| /** Reads an end node and returns the created node. */ | |||||
| aiNode* ReadEndSite( const std::string& pParentName); | |||||
| /** Reads a node offset for the given node */ | |||||
| void ReadNodeOffset( aiNode* pNode); | |||||
| /** Reads the animation channels into the given node */ | |||||
| void ReadNodeChannels( BVHLoader::Node& pNode); | |||||
| /** Reads the motion data */ | |||||
| void ReadMotion( aiScene* pScene); | |||||
| /** Retrieves the next token */ | |||||
| std::string GetNextToken(); | |||||
| /** Reads the next token as a float */ | |||||
| float GetNextTokenAsFloat(); | |||||
| /** Aborts the file reading with an exception */ | |||||
| void ThrowException( const std::string& pError); | |||||
| /** Constructs an animation for the motion data and stores it in the given scene */ | |||||
| void CreateAnimation( aiScene* pScene); | |||||
| protected: | |||||
| /** Filename, for a verbose error message */ | |||||
| std::string mFileName; | |||||
| /** Buffer to hold the loaded file */ | |||||
| std::vector<char> mBuffer; | |||||
| /** Next char to read from the buffer */ | |||||
| std::vector<char>::const_iterator mReader; | |||||
| /** Current line, for error messages */ | |||||
| unsigned int mLine; | |||||
| /** Collected list of nodes. Will be bones of the dummy mesh some day, addressed by their array index. | |||||
| * Also contain the motion data for the node's channels | |||||
| */ | |||||
| std::vector<Node> mNodes; | |||||
| /** basic Animation parameters */ | |||||
| float mAnimTickDuration; | |||||
| unsigned int mAnimNumFrames; | |||||
| bool noSkeletonMesh; | |||||
| }; | |||||
| } // end of namespace Assimp | |||||
| #endif // AI_BVHLOADER_H_INC | |||||
| @@ -0,0 +1,598 @@ | |||||
| /* | |||||
| --------------------------------------------------------------------------- | |||||
| Open Asset Import Library (assimp) | |||||
| --------------------------------------------------------------------------- | |||||
| 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. | |||||
| --------------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file BaseImporter.cpp | |||||
| * @brief Implementation of BaseImporter | |||||
| */ | |||||
| #include "AssimpPCH.h" | |||||
| #include "BaseImporter.h" | |||||
| #include "FileSystemFilter.h" | |||||
| #include "Importer.h" | |||||
| using namespace Assimp; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Constructor to be privately used by Importer | |||||
| BaseImporter::BaseImporter() | |||||
| : progress() | |||||
| { | |||||
| // nothing to do here | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Destructor, private as well | |||||
| BaseImporter::~BaseImporter() | |||||
| { | |||||
| // nothing to do here | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Imports the given file and returns the imported data. | |||||
| aiScene* BaseImporter::ReadFile(const Importer* pImp, const std::string& pFile, IOSystem* pIOHandler) | |||||
| { | |||||
| progress = pImp->GetProgressHandler(); | |||||
| ai_assert(progress); | |||||
| // Gather configuration properties for this run | |||||
| SetupProperties( pImp ); | |||||
| // Construct a file system filter to improve our success ratio at reading external files | |||||
| FileSystemFilter filter(pFile,pIOHandler); | |||||
| // create a scene object to hold the data | |||||
| ScopeGuard<aiScene> sc(new aiScene()); | |||||
| // dispatch importing | |||||
| try | |||||
| { | |||||
| InternReadFile( pFile, sc, &filter); | |||||
| } catch( const std::exception& err ) { | |||||
| // extract error description | |||||
| mErrorText = err.what(); | |||||
| DefaultLogger::get()->error(mErrorText); | |||||
| return NULL; | |||||
| } | |||||
| // return what we gathered from the import. | |||||
| sc.dismiss(); | |||||
| return sc; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BaseImporter::SetupProperties(const Importer* /*pImp*/) | |||||
| { | |||||
| // the default implementation does nothing | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BaseImporter::GetExtensionList(std::set<std::string>& extensions) | |||||
| { | |||||
| const aiImporterDesc* desc = GetInfo(); | |||||
| ai_assert(desc != NULL); | |||||
| const char* ext = desc->mFileExtensions; | |||||
| ai_assert(ext != NULL); | |||||
| const char* last = ext; | |||||
| do { | |||||
| if (!*ext || *ext == ' ') { | |||||
| extensions.insert(std::string(last,ext-last)); | |||||
| ai_assert(ext-last > 0); | |||||
| last = ext; | |||||
| while(*last == ' ') { | |||||
| ++last; | |||||
| } | |||||
| } | |||||
| } | |||||
| while(*ext++); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| /*static*/ bool BaseImporter::SearchFileHeaderForToken(IOSystem* pIOHandler, | |||||
| const std::string& pFile, | |||||
| const char** tokens, | |||||
| unsigned int numTokens, | |||||
| unsigned int searchBytes /* = 200 */, | |||||
| bool tokensSol /* false */) | |||||
| { | |||||
| ai_assert(NULL != tokens && 0 != numTokens && 0 != searchBytes); | |||||
| if (!pIOHandler) | |||||
| return false; | |||||
| boost::scoped_ptr<IOStream> pStream (pIOHandler->Open(pFile)); | |||||
| if (pStream.get() ) { | |||||
| // read 200 characters from the file | |||||
| boost::scoped_array<char> _buffer (new char[searchBytes+1 /* for the '\0' */]); | |||||
| char* buffer = _buffer.get(); | |||||
| const unsigned int read = pStream->Read(buffer,1,searchBytes); | |||||
| if (!read) | |||||
| return false; | |||||
| for (unsigned int i = 0; i < read;++i) | |||||
| buffer[i] = ::tolower(buffer[i]); | |||||
| // It is not a proper handling of unicode files here ... | |||||
| // ehm ... but it works in most cases. | |||||
| char* cur = buffer,*cur2 = buffer,*end = &buffer[read]; | |||||
| while (cur != end) { | |||||
| if (*cur) | |||||
| *cur2++ = *cur; | |||||
| ++cur; | |||||
| } | |||||
| *cur2 = '\0'; | |||||
| for (unsigned int i = 0; i < numTokens;++i) { | |||||
| ai_assert(NULL != tokens[i]); | |||||
| const char* r = strstr(buffer,tokens[i]); | |||||
| if (!r) | |||||
| continue; | |||||
| // We got a match, either we don't care where it is, or it happens to | |||||
| // be in the beginning of the file / line | |||||
| if (!tokensSol || r == buffer || r[-1] == '\r' || r[-1] == '\n') { | |||||
| DefaultLogger::get()->debug(std::string("Found positive match for header keyword: ") + tokens[i]); | |||||
| return true; | |||||
| } | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Simple check for file extension | |||||
| /*static*/ bool BaseImporter::SimpleExtensionCheck (const std::string& pFile, | |||||
| const char* ext0, | |||||
| const char* ext1, | |||||
| const char* ext2) | |||||
| { | |||||
| std::string::size_type pos = pFile.find_last_of('.'); | |||||
| // no file extension - can't read | |||||
| if( pos == std::string::npos) | |||||
| return false; | |||||
| const char* ext_real = & pFile[ pos+1 ]; | |||||
| if( !ASSIMP_stricmp(ext_real,ext0) ) | |||||
| return true; | |||||
| // check for other, optional, file extensions | |||||
| if (ext1 && !ASSIMP_stricmp(ext_real,ext1)) | |||||
| return true; | |||||
| if (ext2 && !ASSIMP_stricmp(ext_real,ext2)) | |||||
| return true; | |||||
| return false; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Get file extension from path | |||||
| /*static*/ std::string BaseImporter::GetExtension (const std::string& pFile) | |||||
| { | |||||
| std::string::size_type pos = pFile.find_last_of('.'); | |||||
| // no file extension at all | |||||
| if( pos == std::string::npos) | |||||
| return ""; | |||||
| std::string ret = pFile.substr(pos+1); | |||||
| std::transform(ret.begin(),ret.end(),ret.begin(),::tolower); // thanks to Andy Maloney for the hint | |||||
| return ret; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Check for magic bytes at the beginning of the file. | |||||
| /* static */ bool BaseImporter::CheckMagicToken(IOSystem* pIOHandler, const std::string& pFile, | |||||
| const void* _magic, unsigned int num, unsigned int offset, unsigned int size) | |||||
| { | |||||
| ai_assert(size <= 16 && _magic); | |||||
| if (!pIOHandler) { | |||||
| return false; | |||||
| } | |||||
| union { | |||||
| const char* magic; | |||||
| const uint16_t* magic_u16; | |||||
| const uint32_t* magic_u32; | |||||
| }; | |||||
| magic = reinterpret_cast<const char*>(_magic); | |||||
| boost::scoped_ptr<IOStream> pStream (pIOHandler->Open(pFile)); | |||||
| if (pStream.get() ) { | |||||
| // skip to offset | |||||
| pStream->Seek(offset,aiOrigin_SET); | |||||
| // read 'size' characters from the file | |||||
| union { | |||||
| char data[16]; | |||||
| uint16_t data_u16[8]; | |||||
| uint32_t data_u32[4]; | |||||
| }; | |||||
| if(size != pStream->Read(data,1,size)) { | |||||
| return false; | |||||
| } | |||||
| for (unsigned int i = 0; i < num; ++i) { | |||||
| // also check against big endian versions of tokens with size 2,4 | |||||
| // that's just for convinience, the chance that we cause conflicts | |||||
| // is quite low and it can save some lines and prevent nasty bugs | |||||
| if (2 == size) { | |||||
| uint16_t rev = *magic_u16; | |||||
| ByteSwap::Swap(&rev); | |||||
| if (data_u16[0] == *magic_u16 || data_u16[0] == rev) { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| else if (4 == size) { | |||||
| uint32_t rev = *magic_u32; | |||||
| ByteSwap::Swap(&rev); | |||||
| if (data_u32[0] == *magic_u32 || data_u32[0] == rev) { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| else { | |||||
| // any length ... just compare | |||||
| if(!memcmp(magic,data,size)) { | |||||
| return true; | |||||
| } | |||||
| } | |||||
| magic += size; | |||||
| } | |||||
| } | |||||
| 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"); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Convert to UTF8 data | |||||
| void BaseImporter::ConvertToUTF8(std::vector<char>& data) | |||||
| { | |||||
| ConversionResult result; | |||||
| if(data.size() < 8) { | |||||
| throw DeadlyImportError("File is too small"); | |||||
| } | |||||
| // UTF 8 with BOM | |||||
| if((uint8_t)data[0] == 0xEF && (uint8_t)data[1] == 0xBB && (uint8_t)data[2] == 0xBF) { | |||||
| DefaultLogger::get()->debug("Found UTF-8 BOM ..."); | |||||
| std::copy(data.begin()+3,data.end(),data.begin()); | |||||
| data.resize(data.size()-3); | |||||
| return; | |||||
| } | |||||
| // UTF 32 BE with BOM | |||||
| if(*((uint32_t*)&data.front()) == 0xFFFE0000) { | |||||
| // swap the endianess .. | |||||
| for(uint32_t* p = (uint32_t*)&data.front(), *end = (uint32_t*)&data.back(); p <= end; ++p) { | |||||
| AI_SWAP4P(p); | |||||
| } | |||||
| } | |||||
| // UTF 32 LE with BOM | |||||
| 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<char> 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); | |||||
| return; | |||||
| } | |||||
| // UTF 16 BE with BOM | |||||
| if(*((uint16_t*)&data.front()) == 0xFFFE) { | |||||
| // swap the endianess .. | |||||
| for(uint16_t* p = (uint16_t*)&data.front(), *end = (uint16_t*)&data.back(); p <= end; ++p) { | |||||
| ByteSwap::Swap2(p); | |||||
| } | |||||
| } | |||||
| // UTF 16 LE with BOM | |||||
| 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<char> 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); | |||||
| return; | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Convert to UTF8 data to ISO-8859-1 | |||||
| void BaseImporter::ConvertUTF8toISO8859_1(std::string& data) | |||||
| { | |||||
| unsigned int size = data.size(); | |||||
| unsigned int i = 0, j = 0; | |||||
| while(i < size) { | |||||
| if((unsigned char) data[i] < 0x80) { | |||||
| data[j] = data[i]; | |||||
| } else if(i < size - 1) { | |||||
| if((unsigned char) data[i] == 0xC2) { | |||||
| data[j] = data[++i]; | |||||
| } else if((unsigned char) data[i] == 0xC3) { | |||||
| data[j] = ((unsigned char) data[++i] + 0x40); | |||||
| } else { | |||||
| std::stringstream stream; | |||||
| stream << "UTF8 code " << std::hex << data[i] << data[i + 1] << " can not be converted into ISA-8859-1."; | |||||
| DefaultLogger::get()->error(stream.str()); | |||||
| data[j++] = data[i++]; | |||||
| data[j] = data[i]; | |||||
| } | |||||
| } else { | |||||
| DefaultLogger::get()->error("UTF8 code but only one character remaining"); | |||||
| data[j] = data[i]; | |||||
| } | |||||
| i++; j++; | |||||
| } | |||||
| data.resize(j); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BaseImporter::TextFileToBuffer(IOStream* stream, | |||||
| std::vector<char>& data) | |||||
| { | |||||
| ai_assert(NULL != stream); | |||||
| const size_t fileSize = stream->FileSize(); | |||||
| if(!fileSize) { | |||||
| throw DeadlyImportError("File is empty"); | |||||
| } | |||||
| data.reserve(fileSize+1); | |||||
| data.resize(fileSize); | |||||
| if(fileSize != stream->Read( &data[0], 1, fileSize)) { | |||||
| throw DeadlyImportError("File read error"); | |||||
| } | |||||
| ConvertToUTF8(data); | |||||
| // append a binary zero to simplify string parsing | |||||
| data.push_back(0); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| namespace Assimp | |||||
| { | |||||
| // Represents an import request | |||||
| struct LoadRequest | |||||
| { | |||||
| LoadRequest(const std::string& _file, unsigned int _flags,const BatchLoader::PropertyMap* _map, unsigned int _id) | |||||
| : file(_file), flags(_flags), refCnt(1),scene(NULL), loaded(false), id(_id) | |||||
| { | |||||
| if (_map) | |||||
| map = *_map; | |||||
| } | |||||
| const std::string file; | |||||
| unsigned int flags; | |||||
| unsigned int refCnt; | |||||
| aiScene* scene; | |||||
| bool loaded; | |||||
| BatchLoader::PropertyMap map; | |||||
| unsigned int id; | |||||
| bool operator== (const std::string& f) { | |||||
| return file == f; | |||||
| } | |||||
| }; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // BatchLoader::pimpl data structure | |||||
| struct Assimp::BatchData | |||||
| { | |||||
| BatchData() | |||||
| : next_id(0xffff) | |||||
| {} | |||||
| // IO system to be used for all imports | |||||
| IOSystem* pIOSystem; | |||||
| // Importer used to load all meshes | |||||
| Importer* pImporter; | |||||
| // List of all imports | |||||
| std::list<LoadRequest> requests; | |||||
| // Base path | |||||
| std::string pathBase; | |||||
| // Id for next item | |||||
| unsigned int next_id; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| BatchLoader::BatchLoader(IOSystem* pIO) | |||||
| { | |||||
| ai_assert(NULL != pIO); | |||||
| data = new BatchData(); | |||||
| data->pIOSystem = pIO; | |||||
| data->pImporter = new Importer(); | |||||
| data->pImporter->SetIOHandler(data->pIOSystem); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| BatchLoader::~BatchLoader() | |||||
| { | |||||
| // delete all scenes wthat have not been polled by the user | |||||
| for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) { | |||||
| delete (*it).scene; | |||||
| } | |||||
| data->pImporter->SetIOHandler(NULL); /* get pointer back into our posession */ | |||||
| delete data->pImporter; | |||||
| delete data; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| unsigned int BatchLoader::AddLoadRequest (const std::string& file, | |||||
| unsigned int steps /*= 0*/, const PropertyMap* map /*= NULL*/) | |||||
| { | |||||
| ai_assert(!file.empty()); | |||||
| // check whether we have this loading request already | |||||
| std::list<LoadRequest>::iterator it; | |||||
| for (it = data->requests.begin();it != data->requests.end(); ++it) { | |||||
| // Call IOSystem's path comparison function here | |||||
| if (data->pIOSystem->ComparePaths((*it).file,file)) { | |||||
| if (map) { | |||||
| if (!((*it).map == *map)) | |||||
| continue; | |||||
| } | |||||
| else if (!(*it).map.empty()) | |||||
| continue; | |||||
| (*it).refCnt++; | |||||
| return (*it).id; | |||||
| } | |||||
| } | |||||
| // no, we don't have it. So add it to the queue ... | |||||
| data->requests.push_back(LoadRequest(file,steps,map,data->next_id)); | |||||
| return data->next_id++; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| aiScene* BatchLoader::GetImport (unsigned int which) | |||||
| { | |||||
| for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) { | |||||
| if ((*it).id == which && (*it).loaded) { | |||||
| aiScene* sc = (*it).scene; | |||||
| if (!(--(*it).refCnt)) { | |||||
| data->requests.erase(it); | |||||
| } | |||||
| return sc; | |||||
| } | |||||
| } | |||||
| return NULL; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BatchLoader::LoadAll() | |||||
| { | |||||
| // no threaded implementation for the moment | |||||
| for (std::list<LoadRequest>::iterator it = data->requests.begin();it != data->requests.end(); ++it) { | |||||
| // force validation in debug builds | |||||
| unsigned int pp = (*it).flags; | |||||
| #ifdef ASSIMP_BUILD_DEBUG | |||||
| pp |= aiProcess_ValidateDataStructure; | |||||
| #endif | |||||
| // setup config properties if necessary | |||||
| ImporterPimpl* pimpl = data->pImporter->Pimpl(); | |||||
| pimpl->mFloatProperties = (*it).map.floats; | |||||
| pimpl->mIntProperties = (*it).map.ints; | |||||
| pimpl->mStringProperties = (*it).map.strings; | |||||
| pimpl->mMatrixProperties = (*it).map.matrices; | |||||
| if (!DefaultLogger::isNullLogger()) | |||||
| { | |||||
| DefaultLogger::get()->info("%%% BEGIN EXTERNAL FILE %%%"); | |||||
| DefaultLogger::get()->info("File: " + (*it).file); | |||||
| } | |||||
| data->pImporter->ReadFile((*it).file,pp); | |||||
| (*it).scene = data->pImporter->GetOrphanedScene(); | |||||
| (*it).loaded = true; | |||||
| DefaultLogger::get()->info("%%% END EXTERNAL FILE %%%"); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,368 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file Definition of the base class for all importer worker classes. */ | |||||
| #ifndef INCLUDED_AI_BASEIMPORTER_H | |||||
| #define INCLUDED_AI_BASEIMPORTER_H | |||||
| #include "Exceptional.h" | |||||
| #include <string> | |||||
| #include <map> | |||||
| #include <vector> | |||||
| #include "./../include/assimp/types.h" | |||||
| struct aiScene; | |||||
| namespace Assimp { | |||||
| class IOSystem; | |||||
| class Importer; | |||||
| class BaseImporter; | |||||
| 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])) | |||||
| // --------------------------------------------------------------------------- | |||||
| template <typename T> | |||||
| struct ScopeGuard | |||||
| { | |||||
| ScopeGuard(T* obj) : obj(obj), mdismiss() {} | |||||
| ~ScopeGuard () throw() { | |||||
| if (!mdismiss) { | |||||
| delete obj; | |||||
| } | |||||
| obj = NULL; | |||||
| } | |||||
| T* dismiss() { | |||||
| mdismiss=true; | |||||
| return obj; | |||||
| } | |||||
| operator T*() { | |||||
| return obj; | |||||
| } | |||||
| T* operator -> () { | |||||
| return obj; | |||||
| } | |||||
| private: | |||||
| T* obj; | |||||
| bool mdismiss; | |||||
| }; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** FOR IMPORTER PLUGINS ONLY: The BaseImporter defines a common interface | |||||
| * for all importer worker classes. | |||||
| * | |||||
| * The interface defines two functions: CanRead() is used to check if the | |||||
| * importer can handle the format of the given file. If an implementation of | |||||
| * this function returns true, the importer then calls ReadFile() which | |||||
| * imports the given file. ReadFile is not overridable, it just calls | |||||
| * InternReadFile() and catches any ImportErrorException that might occur. | |||||
| */ | |||||
| class ASSIMP_API BaseImporter | |||||
| { | |||||
| friend class Importer; | |||||
| public: | |||||
| /** Constructor to be privately used by #Importer */ | |||||
| BaseImporter(); | |||||
| /** Destructor, private as well */ | |||||
| virtual ~BaseImporter(); | |||||
| public: | |||||
| // ------------------------------------------------------------------- | |||||
| /** Returns whether the class can handle the format of the given file. | |||||
| * | |||||
| * The implementation should be as quick as possible. A check for | |||||
| * the file extension is enough. If no suitable loader is found with | |||||
| * this strategy, CanRead() is called again, the 'checkSig' parameter | |||||
| * set to true this time. Now the implementation is expected to | |||||
| * perform a full check of the file structure, possibly searching the | |||||
| * first bytes of the file for magic identifiers or keywords. | |||||
| * | |||||
| * @param pFile Path and file name of the file to be examined. | |||||
| * @param pIOHandler The IO handler to use for accessing any file. | |||||
| * @param checkSig Set to true if this method is called a second time. | |||||
| * This time, the implementation may take more time to examine the | |||||
| * contents of the file to be loaded for magic bytes, keywords, etc | |||||
| * to be able to load files with unknown/not existent file extensions. | |||||
| * @return true if the class can read this file, false if not. | |||||
| */ | |||||
| virtual bool CanRead( | |||||
| const std::string& pFile, | |||||
| IOSystem* pIOHandler, | |||||
| bool checkSig | |||||
| ) const = 0; | |||||
| // ------------------------------------------------------------------- | |||||
| /** Imports the given file and returns the imported data. | |||||
| * If the import succeeds, ownership of the data is transferred to | |||||
| * the caller. If the import fails, NULL is returned. The function | |||||
| * takes care that any partially constructed data is destroyed | |||||
| * beforehand. | |||||
| * | |||||
| * @param pImp #Importer object hosting this loader. | |||||
| * @param pFile Path of the file to be imported. | |||||
| * @param pIOHandler IO-Handler used to open this and possible other files. | |||||
| * @return The imported data or NULL if failed. If it failed a | |||||
| * human-readable error description can be retrieved by calling | |||||
| * GetErrorText() | |||||
| * | |||||
| * @note This function is not intended to be overridden. Implement | |||||
| * InternReadFile() to do the import. If an exception is thrown somewhere | |||||
| * in InternReadFile(), this function will catch it and transform it into | |||||
| * a suitable response to the caller. | |||||
| */ | |||||
| aiScene* ReadFile( | |||||
| const Importer* pImp, | |||||
| const std::string& pFile, | |||||
| IOSystem* pIOHandler | |||||
| ); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Returns the error description of the last error that occured. | |||||
| * @return A description of the last error that occured. An empty | |||||
| * string if there was no error. | |||||
| */ | |||||
| const std::string& GetErrorText() const { | |||||
| return mErrorText; | |||||
| } | |||||
| // ------------------------------------------------------------------- | |||||
| /** Called prior to ReadFile(). | |||||
| * The function is a request to the importer to update its configuration | |||||
| * basing on the Importer's configuration property list. | |||||
| * @param pImp Importer instance | |||||
| */ | |||||
| virtual void SetupProperties( | |||||
| 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 | |||||
| * #GetInfo and insert all file extensions into the given set. | |||||
| * @param extension set to collect file extensions in*/ | |||||
| void GetExtensionList(std::set<std::string>& extensions); | |||||
| protected: | |||||
| // ------------------------------------------------------------------- | |||||
| /** Imports the given file into the given scene structure. The | |||||
| * function is expected to throw an ImportErrorException if there is | |||||
| * an error. If it terminates normally, the data in aiScene is | |||||
| * expected to be correct. Override this function to implement the | |||||
| * actual importing. | |||||
| * <br> | |||||
| * The output scene must meet the following requirements:<br> | |||||
| * <ul> | |||||
| * <li>At least a root node must be there, even if its only purpose | |||||
| * is to reference one mesh.</li> | |||||
| * <li>aiMesh::mPrimitiveTypes may be 0. The types of primitives | |||||
| * in the mesh are determined automatically in this case.</li> | |||||
| * <li>the vertex data is stored in a pseudo-indexed "verbose" format. | |||||
| * In fact this means that every vertex that is referenced by | |||||
| * a face is unique. Or the other way round: a vertex index may | |||||
| * not occur twice in a single aiMesh.</li> | |||||
| * <li>aiAnimation::mDuration may be -1. Assimp determines the length | |||||
| * of the animation automatically in this case as the length of | |||||
| * the longest animation channel.</li> | |||||
| * <li>aiMesh::mBitangents may be NULL if tangents and normals are | |||||
| * given. In this case bitangents are computed as the cross product | |||||
| * between normal and tangent.</li> | |||||
| * <li>There needn't be a material. If none is there a default material | |||||
| * is generated. However, it is recommended practice for loaders | |||||
| * to generate a default material for yourself that matches the | |||||
| * default material setting for the file format better than Assimp's | |||||
| * generic default material. Note that default materials *should* | |||||
| * be named AI_DEFAULT_MATERIAL_NAME if they're just color-shaded | |||||
| * or AI_DEFAULT_TEXTURED_MATERIAL_NAME if they define a (dummy) | |||||
| * texture. </li> | |||||
| * </ul> | |||||
| * If the AI_SCENE_FLAGS_INCOMPLETE-Flag is <b>not</b> set:<ul> | |||||
| * <li> at least one mesh must be there</li> | |||||
| * <li> there may be no meshes with 0 vertices or faces</li> | |||||
| * </ul> | |||||
| * This won't be checked (except by the validation step): Assimp will | |||||
| * crash if one of the conditions is not met! | |||||
| * | |||||
| * @param pFile Path of the file to be imported. | |||||
| * @param pScene The scene object to hold the imported data. | |||||
| * NULL is not a valid parameter. | |||||
| * @param pIOHandler The IO handler to use for any file access. | |||||
| * NULL is not a valid parameter. */ | |||||
| virtual void InternReadFile( | |||||
| const std::string& pFile, | |||||
| aiScene* pScene, | |||||
| IOSystem* pIOHandler | |||||
| ) = 0; | |||||
| public: // static utilities | |||||
| // ------------------------------------------------------------------- | |||||
| /** A utility for CanRead(). | |||||
| * | |||||
| * The function searches the header of a file for a specific token | |||||
| * and returns true if this token is found. This works for text | |||||
| * files only. There is a rudimentary handling of UNICODE files. | |||||
| * The comparison is case independent. | |||||
| * | |||||
| * @param pIOSystem IO System to work with | |||||
| * @param file File name of the file | |||||
| * @param tokens List of tokens to search for | |||||
| * @param numTokens Size of the token array | |||||
| * @param searchBytes Number of bytes to be searched for the tokens. | |||||
| */ | |||||
| static bool SearchFileHeaderForToken( | |||||
| IOSystem* pIOSystem, | |||||
| const std::string& file, | |||||
| const char** tokens, | |||||
| unsigned int numTokens, | |||||
| unsigned int searchBytes = 200, | |||||
| bool tokensSol = false); | |||||
| // ------------------------------------------------------------------- | |||||
| /** @brief Check whether a file has a specific file extension | |||||
| * @param pFile Input file | |||||
| * @param ext0 Extension to check for. Lowercase characters only, no dot! | |||||
| * @param ext1 Optional second extension | |||||
| * @param ext2 Optional third extension | |||||
| * @note Case-insensitive | |||||
| */ | |||||
| static bool SimpleExtensionCheck ( | |||||
| const std::string& pFile, | |||||
| const char* ext0, | |||||
| const char* ext1 = NULL, | |||||
| const char* ext2 = NULL); | |||||
| // ------------------------------------------------------------------- | |||||
| /** @brief Extract file extension from a string | |||||
| * @param pFile Input file | |||||
| * @return Extension without trailing dot, all lowercase | |||||
| */ | |||||
| static std::string GetExtension ( | |||||
| const std::string& pFile); | |||||
| // ------------------------------------------------------------------- | |||||
| /** @brief Check whether a file starts with one or more magic tokens | |||||
| * @param pFile Input file | |||||
| * @param pIOHandler IO system to be used | |||||
| * @param magic n magic tokens | |||||
| * @params num Size of magic | |||||
| * @param offset Offset from file start where tokens are located | |||||
| * @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 | |||||
| * byte-swapped variant of all tokens (big endian). Only for | |||||
| * tokens of size 2,4. | |||||
| */ | |||||
| static bool CheckMagicToken( | |||||
| IOSystem* pIOHandler, | |||||
| const std::string& pFile, | |||||
| const void* magic, | |||||
| unsigned int num, | |||||
| unsigned int offset = 0, | |||||
| unsigned int size = 4); | |||||
| // ------------------------------------------------------------------- | |||||
| /** An utility for all text file loaders. It converts a file to our | |||||
| * UTF8 character set. Errors are reported, but ignored. | |||||
| * | |||||
| * @param data File buffer to be converted to UTF8 data. The buffer | |||||
| * is resized as appropriate. */ | |||||
| static void ConvertToUTF8( | |||||
| std::vector<char>& data); | |||||
| // ------------------------------------------------------------------- | |||||
| /** An utility for all text file loaders. It converts a file from our | |||||
| * UTF8 character set back to ISO-8859-1. Errors are reported, but ignored. | |||||
| * | |||||
| * @param data File buffer to be converted from UTF8 to ISO-8859-1. The buffer | |||||
| * is resized as appropriate. */ | |||||
| static void ConvertUTF8toISO8859_1( | |||||
| std::string& data); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Utility for text file loaders which copies the contents of the | |||||
| * file into a memory buffer and converts it to our UTF8 | |||||
| * representation. | |||||
| * @param stream Stream to read from. | |||||
| * @param data Output buffer to be resized and filled with the | |||||
| * converted text file data. The buffer is terminated with | |||||
| * a binary 0. */ | |||||
| static void TextFileToBuffer( | |||||
| IOStream* stream, | |||||
| std::vector<char>& data); | |||||
| protected: | |||||
| /** Error description in case there was one. */ | |||||
| std::string mErrorText; | |||||
| /** Currently set progress handler */ | |||||
| ProgressHandler* progress; | |||||
| }; | |||||
| } // end of namespace Assimp | |||||
| #endif // AI_BASEIMPORTER_H_INC | |||||
| @@ -0,0 +1,105 @@ | |||||
| /* | |||||
| --------------------------------------------------------------------------- | |||||
| Open Asset Import Library (assimp) | |||||
| --------------------------------------------------------------------------- | |||||
| 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. | |||||
| --------------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file Implementation of BaseProcess */ | |||||
| #include "AssimpPCH.h" | |||||
| #include "BaseImporter.h" | |||||
| #include "BaseProcess.h" | |||||
| #include "Importer.h" | |||||
| using namespace Assimp; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Constructor to be privately used by Importer | |||||
| BaseProcess::BaseProcess() | |||||
| : shared() | |||||
| , progress() | |||||
| { | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Destructor, private as well | |||||
| BaseProcess::~BaseProcess() | |||||
| { | |||||
| // nothing to do here | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BaseProcess::ExecuteOnScene( Importer* pImp) | |||||
| { | |||||
| ai_assert(NULL != pImp && NULL != pImp->Pimpl()->mScene); | |||||
| progress = pImp->GetProgressHandler(); | |||||
| ai_assert(progress); | |||||
| SetupProperties( pImp ); | |||||
| // catch exceptions thrown inside the PostProcess-Step | |||||
| try | |||||
| { | |||||
| Execute(pImp->Pimpl()->mScene); | |||||
| } catch( const std::exception& err ) { | |||||
| // extract error description | |||||
| pImp->Pimpl()->mErrorString = err.what(); | |||||
| DefaultLogger::get()->error(pImp->Pimpl()->mErrorString); | |||||
| // and kill the partially imported data | |||||
| delete pImp->Pimpl()->mScene; | |||||
| pImp->Pimpl()->mScene = NULL; | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BaseProcess::SetupProperties(const Importer* /*pImp*/) | |||||
| { | |||||
| // the default implementation does nothing | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| bool BaseProcess::RequireVerboseFormat() const | |||||
| { | |||||
| return true; | |||||
| } | |||||
| @@ -0,0 +1,294 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file Base class of all import post processing steps */ | |||||
| #ifndef INCLUDED_AI_BASEPROCESS_H | |||||
| #define INCLUDED_AI_BASEPROCESS_H | |||||
| #include <map> | |||||
| #include "../include/assimp/types.h" | |||||
| #include "GenericProperty.h" | |||||
| struct aiScene; | |||||
| namespace Assimp { | |||||
| class Importer; | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Helper class to allow post-processing steps to interact with each other. | |||||
| * | |||||
| * The class maintains a simple property list that can be used by pp-steps | |||||
| * to provide additional information to other steps. This is primarily | |||||
| * intended for cross-step optimizations. | |||||
| */ | |||||
| class SharedPostProcessInfo | |||||
| { | |||||
| public: | |||||
| struct Base | |||||
| { | |||||
| virtual ~Base() | |||||
| {} | |||||
| }; | |||||
| //! Represents data that is allocated on the heap, thus needs to be deleted | |||||
| template <typename T> | |||||
| struct THeapData : public Base | |||||
| { | |||||
| THeapData(T* in) | |||||
| : data (in) | |||||
| {} | |||||
| ~THeapData() | |||||
| { | |||||
| delete data; | |||||
| } | |||||
| T* data; | |||||
| }; | |||||
| //! Represents static, by-value data not allocated on the heap | |||||
| template <typename T> | |||||
| struct TStaticData : public Base | |||||
| { | |||||
| TStaticData(T in) | |||||
| : data (in) | |||||
| {} | |||||
| ~TStaticData() | |||||
| {} | |||||
| T data; | |||||
| }; | |||||
| // some typedefs for cleaner code | |||||
| typedef unsigned int KeyType; | |||||
| typedef std::map<KeyType, Base*> PropertyMap; | |||||
| public: | |||||
| //! Destructor | |||||
| ~SharedPostProcessInfo() | |||||
| { | |||||
| Clean(); | |||||
| } | |||||
| //! Remove all stored properties from the table | |||||
| void Clean() | |||||
| { | |||||
| // invoke the virtual destructor for all stored properties | |||||
| for (PropertyMap::iterator it = pmap.begin(), end = pmap.end(); | |||||
| it != end; ++it) | |||||
| { | |||||
| delete (*it).second; | |||||
| } | |||||
| pmap.clear(); | |||||
| } | |||||
| //! Add a heap property to the list | |||||
| template <typename T> | |||||
| void AddProperty( const char* name, T* in ){ | |||||
| AddProperty(name,(Base*)new THeapData<T>(in)); | |||||
| } | |||||
| //! Add a static by-value property to the list | |||||
| template <typename T> | |||||
| void AddProperty( const char* name, T in ){ | |||||
| AddProperty(name,(Base*)new TStaticData<T>(in)); | |||||
| } | |||||
| //! Get a heap property | |||||
| template <typename T> | |||||
| bool GetProperty( const char* name, T*& out ) const | |||||
| { | |||||
| THeapData<T>* t = (THeapData<T>*)GetPropertyInternal(name); | |||||
| if(!t) | |||||
| { | |||||
| out = NULL; | |||||
| return false; | |||||
| } | |||||
| out = t->data; | |||||
| return true; | |||||
| } | |||||
| //! Get a static, by-value property | |||||
| template <typename T> | |||||
| bool GetProperty( const char* name, T& out ) const | |||||
| { | |||||
| TStaticData<T>* t = (TStaticData<T>*)GetPropertyInternal(name); | |||||
| if(!t)return false; | |||||
| out = t->data; | |||||
| return true; | |||||
| } | |||||
| //! Remove a property of a specific type | |||||
| void RemoveProperty( const char* name) { | |||||
| SetGenericPropertyPtr<Base>(pmap,name,NULL); | |||||
| } | |||||
| private: | |||||
| void AddProperty( const char* name, Base* data) { | |||||
| SetGenericPropertyPtr<Base>(pmap,name,data); | |||||
| } | |||||
| Base* GetPropertyInternal( const char* name) const { | |||||
| return GetGenericProperty<Base*>(pmap,name,NULL); | |||||
| } | |||||
| private: | |||||
| //! Map of all stored properties | |||||
| PropertyMap pmap; | |||||
| }; | |||||
| #if 0 | |||||
| // --------------------------------------------------------------------------- | |||||
| /** @brief Represents a dependency table for a postprocessing steps. | |||||
| * | |||||
| * For future use. | |||||
| */ | |||||
| struct PPDependencyTable | |||||
| { | |||||
| unsigned int execute_me_before_these; | |||||
| unsigned int execute_me_after_these; | |||||
| unsigned int only_if_these_are_not_specified; | |||||
| unsigned int mutually_exclusive_with; | |||||
| }; | |||||
| #endif | |||||
| #define AI_SPP_SPATIAL_SORT "$Spat" | |||||
| // --------------------------------------------------------------------------- | |||||
| /** The BaseProcess defines a common interface for all post processing steps. | |||||
| * A post processing step is run after a successful import if the caller | |||||
| * specified the corresponding flag when calling ReadFile(). | |||||
| * Enum #aiPostProcessSteps defines which flags are available. | |||||
| * After a successful import the Importer iterates over its internal array | |||||
| * of processes and calls IsActive() on each process to evaluate if the step | |||||
| * should be executed. If the function returns true, the class' Execute() | |||||
| * function is called subsequently. | |||||
| */ | |||||
| class ASSIMP_API_WINONLY BaseProcess | |||||
| { | |||||
| friend class Importer; | |||||
| public: | |||||
| /** Constructor to be privately used by Importer */ | |||||
| BaseProcess(); | |||||
| /** Destructor, private as well */ | |||||
| virtual ~BaseProcess(); | |||||
| public: | |||||
| // ------------------------------------------------------------------- | |||||
| /** Returns whether the processing step is present in the given flag. | |||||
| * @param pFlags The processing flags the importer was called with. A | |||||
| * bitwise combination of #aiPostProcessSteps. | |||||
| * @return true if the process is present in this flag fields, | |||||
| * false if not. | |||||
| */ | |||||
| virtual bool IsActive( unsigned int pFlags) const = 0; | |||||
| // ------------------------------------------------------------------- | |||||
| /** Check whether this step expects its input vertex data to be | |||||
| * in verbose format. */ | |||||
| virtual bool RequireVerboseFormat() const; | |||||
| // ------------------------------------------------------------------- | |||||
| /** Executes the post processing step on the given imported data. | |||||
| * The function deletes the scene if the postprocess step fails ( | |||||
| * the object pointer will be set to NULL). | |||||
| * @param pImp Importer instance (pImp->mScene must be valid) | |||||
| */ | |||||
| void ExecuteOnScene( Importer* pImp); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Called prior to ExecuteOnScene(). | |||||
| * The function is a request to the process to update its configuration | |||||
| * basing on the Importer's configuration property list. | |||||
| */ | |||||
| virtual void SetupProperties(const Importer* pImp); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Executes the post processing step on the given imported data. | |||||
| * A process should throw an ImportErrorException* if it fails. | |||||
| * This method must be implemented by deriving classes. | |||||
| * @param pScene The imported data to work at. | |||||
| */ | |||||
| virtual void Execute( aiScene* pScene) = 0; | |||||
| // ------------------------------------------------------------------- | |||||
| /** Assign a new SharedPostProcessInfo to the step. This object | |||||
| * allows multiple postprocess steps to share data. | |||||
| * @param sh May be NULL | |||||
| */ | |||||
| inline void SetSharedData(SharedPostProcessInfo* sh) { | |||||
| shared = sh; | |||||
| } | |||||
| // ------------------------------------------------------------------- | |||||
| /** Get the shared data that is assigned to the step. | |||||
| */ | |||||
| inline SharedPostProcessInfo* GetSharedData() { | |||||
| return shared; | |||||
| } | |||||
| protected: | |||||
| /** See the doc of #SharedPostProcessInfo for more details */ | |||||
| SharedPostProcessInfo* shared; | |||||
| /** Currently active progress handler */ | |||||
| ProgressHandler* progress; | |||||
| }; | |||||
| } // end of namespace Assimp | |||||
| #endif // AI_BASEPROCESS_H_INC | |||||
| @@ -0,0 +1,145 @@ | |||||
| /* | |||||
| --------------------------------------------------------------------------- | |||||
| Open Asset Import Library (assimp) | |||||
| --------------------------------------------------------------------------- | |||||
| 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. | |||||
| --------------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file Bitmap.cpp | |||||
| * @brief Defines bitmap format helper for textures | |||||
| * | |||||
| * Used for file formats which embed their textures into the model file. | |||||
| */ | |||||
| #include "AssimpPCH.h" | |||||
| #include "Bitmap.h" | |||||
| namespace Assimp { | |||||
| void Bitmap::Save(aiTexture* texture, IOStream* file) { | |||||
| if(file != NULL) { | |||||
| Header header; | |||||
| DIB dib; | |||||
| dib.size = DIB::dib_size; | |||||
| dib.width = texture->mWidth; | |||||
| dib.height = texture->mHeight; | |||||
| dib.planes = 1; | |||||
| dib.bits_per_pixel = 8 * mBytesPerPixel; | |||||
| dib.compression = 0; | |||||
| dib.image_size = (((dib.width * mBytesPerPixel) + 3) & 0x0000FFFC) * dib.height; | |||||
| dib.x_resolution = 0; | |||||
| dib.y_resolution = 0; | |||||
| dib.nb_colors = 0; | |||||
| dib.nb_important_colors = 0; | |||||
| header.type = 0x4D42; // 'BM' | |||||
| header.offset = Header::header_size + DIB::dib_size; | |||||
| header.size = header.offset + dib.image_size; | |||||
| header.reserved1 = 0; | |||||
| header.reserved2 = 0; | |||||
| WriteHeader(header, file); | |||||
| WriteDIB(dib, file); | |||||
| WriteData(texture, file); | |||||
| } | |||||
| } | |||||
| template<typename T> | |||||
| inline std::size_t Copy(uint8_t* data, T& field) { | |||||
| std::memcpy(data, &AI_BE(field), sizeof(field)); return sizeof(field); | |||||
| } | |||||
| void Bitmap::WriteHeader(Header& header, IOStream* file) { | |||||
| uint8_t data[Header::header_size]; | |||||
| std::size_t offset = 0; | |||||
| offset += Copy(&data[offset], header.type); | |||||
| offset += Copy(&data[offset], header.size); | |||||
| offset += Copy(&data[offset], header.reserved1); | |||||
| offset += Copy(&data[offset], header.reserved2); | |||||
| offset += Copy(&data[offset], header.offset); | |||||
| file->Write(data, Header::header_size, 1); | |||||
| } | |||||
| void Bitmap::WriteDIB(DIB& dib, IOStream* file) { | |||||
| uint8_t data[DIB::dib_size]; | |||||
| std::size_t offset = 0; | |||||
| offset += Copy(&data[offset], dib.size); | |||||
| offset += Copy(&data[offset], dib.width); | |||||
| offset += Copy(&data[offset], dib.height); | |||||
| offset += Copy(&data[offset], dib.planes); | |||||
| offset += Copy(&data[offset], dib.bits_per_pixel); | |||||
| offset += Copy(&data[offset], dib.compression); | |||||
| offset += Copy(&data[offset], dib.image_size); | |||||
| offset += Copy(&data[offset], dib.x_resolution); | |||||
| offset += Copy(&data[offset], dib.y_resolution); | |||||
| offset += Copy(&data[offset], dib.nb_colors); | |||||
| offset += Copy(&data[offset], dib.nb_important_colors); | |||||
| file->Write(data, DIB::dib_size, 1); | |||||
| } | |||||
| void Bitmap::WriteData(aiTexture* texture, IOStream* file) { | |||||
| static const std::size_t padding_offset = 4; | |||||
| static const uint8_t padding_data[padding_offset] = {0x0, 0x0, 0x0, 0x0}; | |||||
| unsigned int padding = (padding_offset - ((mBytesPerPixel * texture->mWidth) % padding_offset)) % padding_offset; | |||||
| uint8_t pixel[mBytesPerPixel]; | |||||
| for(std::size_t i = 0; i < texture->mHeight; ++i) { | |||||
| for(std::size_t j = 0; j < texture->mWidth; ++j) { | |||||
| const aiTexel& texel = texture->pcData[(texture->mHeight - i - 1) * texture->mWidth + j]; // Bitmap files are stored in bottom-up format | |||||
| pixel[0] = texel.r; | |||||
| pixel[1] = texel.g; | |||||
| pixel[2] = texel.b; | |||||
| pixel[3] = texel.a; | |||||
| file->Write(pixel, mBytesPerPixel, 1); | |||||
| } | |||||
| file->Write(padding_data, padding, 1); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,139 @@ | |||||
| /* | |||||
| --------------------------------------------------------------------------- | |||||
| Open Asset Import Library (assimp) | |||||
| --------------------------------------------------------------------------- | |||||
| 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. | |||||
| --------------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file Bitmap.h | |||||
| * @brief Defines bitmap format helper for textures | |||||
| * | |||||
| * Used for file formats which embed their textures into the model file. | |||||
| */ | |||||
| #ifndef AI_BITMAP_H_INC | |||||
| #define AI_BITMAP_H_INC | |||||
| namespace Assimp { | |||||
| class Bitmap { | |||||
| protected: | |||||
| struct Header { | |||||
| uint16_t type; | |||||
| uint32_t size; | |||||
| uint16_t reserved1; | |||||
| uint16_t reserved2; | |||||
| uint32_t offset; | |||||
| // We define the struct size because sizeof(Header) might return a wrong result because of structure padding. | |||||
| // Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field). | |||||
| static const std::size_t header_size = | |||||
| sizeof(uint16_t) + // type | |||||
| sizeof(uint32_t) + // size | |||||
| sizeof(uint16_t) + // reserved1 | |||||
| sizeof(uint16_t) + // reserved2 | |||||
| sizeof(uint32_t); // offset | |||||
| }; | |||||
| struct DIB { | |||||
| uint32_t size; | |||||
| int32_t width; | |||||
| int32_t height; | |||||
| uint16_t planes; | |||||
| uint16_t bits_per_pixel; | |||||
| uint32_t compression; | |||||
| uint32_t image_size; | |||||
| int32_t x_resolution; | |||||
| int32_t y_resolution; | |||||
| uint32_t nb_colors; | |||||
| uint32_t nb_important_colors; | |||||
| // We define the struct size because sizeof(DIB) might return a wrong result because of structure padding. | |||||
| // Moreover, we must use this ugly and error prone syntax because Visual Studio neither support constexpr or sizeof(name_of_field). | |||||
| static const std::size_t dib_size = | |||||
| sizeof(uint32_t) + // size | |||||
| sizeof(int32_t) + // width | |||||
| sizeof(int32_t) + // height | |||||
| sizeof(uint16_t) + // planes | |||||
| sizeof(uint16_t) + // bits_per_pixel | |||||
| sizeof(uint32_t) + // compression | |||||
| sizeof(uint32_t) + // image_size | |||||
| sizeof(int32_t) + // x_resolution | |||||
| sizeof(int32_t) + // y_resolution | |||||
| sizeof(uint32_t) + // nb_colors | |||||
| sizeof(uint32_t); // nb_important_colors | |||||
| }; | |||||
| static const std::size_t mBytesPerPixel = 4; | |||||
| public: | |||||
| static void Save(aiTexture* texture, IOStream* file); | |||||
| protected: | |||||
| static void WriteHeader(Header& header, IOStream* file); | |||||
| static void WriteDIB(DIB& dib, IOStream* file); | |||||
| static void WriteData(aiTexture* texture, IOStream* file); | |||||
| }; | |||||
| } | |||||
| #endif // AI_BITMAP_H_INC | |||||
| @@ -0,0 +1,176 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| Copyright (c) 2006-2013, 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 BlenderBMesh.cpp | |||||
| * @brief Conversion of Blender's new BMesh stuff | |||||
| */ | |||||
| #include "AssimpPCH.h" | |||||
| #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER | |||||
| #include "BlenderDNA.h" | |||||
| #include "BlenderScene.h" | |||||
| #include "BlenderBMesh.h" | |||||
| #include "BlenderTessellator.h" | |||||
| namespace Assimp | |||||
| { | |||||
| template< > const std::string LogFunctions< BlenderBMeshConverter >::log_prefix = "BLEND_BMESH: "; | |||||
| } | |||||
| using namespace Assimp; | |||||
| using namespace Assimp::Blender; | |||||
| using namespace Assimp::Formatter; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| BlenderBMeshConverter::BlenderBMeshConverter( const Mesh* mesh ): | |||||
| BMesh( mesh ), | |||||
| triMesh( NULL ) | |||||
| { | |||||
| AssertValidMesh( ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| BlenderBMeshConverter::~BlenderBMeshConverter( ) | |||||
| { | |||||
| DestroyTriMesh( ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| bool BlenderBMeshConverter::ContainsBMesh( ) const | |||||
| { | |||||
| // TODO - Should probably do some additional verification here | |||||
| return BMesh->totpoly && BMesh->totloop && BMesh->totvert; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| const Mesh* BlenderBMeshConverter::TriangulateBMesh( ) | |||||
| { | |||||
| AssertValidMesh( ); | |||||
| AssertValidSizes( ); | |||||
| PrepareTriMesh( ); | |||||
| for ( int i = 0; i < BMesh->totpoly; ++i ) | |||||
| { | |||||
| const MPoly& poly = BMesh->mpoly[ i ]; | |||||
| ConvertPolyToFaces( poly ); | |||||
| } | |||||
| return triMesh; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderBMeshConverter::AssertValidMesh( ) | |||||
| { | |||||
| if ( !ContainsBMesh( ) ) | |||||
| { | |||||
| ThrowException( "BlenderBMeshConverter requires a BMesh with \"polygons\" - please call BlenderBMeshConverter::ContainsBMesh to check this first" ); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderBMeshConverter::AssertValidSizes( ) | |||||
| { | |||||
| if ( BMesh->totpoly != static_cast<int>( BMesh->mpoly.size( ) ) ) | |||||
| { | |||||
| ThrowException( "BMesh poly array has incorrect size" ); | |||||
| } | |||||
| if ( BMesh->totloop != static_cast<int>( BMesh->mloop.size( ) ) ) | |||||
| { | |||||
| ThrowException( "BMesh loop array has incorrect size" ); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderBMeshConverter::PrepareTriMesh( ) | |||||
| { | |||||
| if ( triMesh ) | |||||
| { | |||||
| DestroyTriMesh( ); | |||||
| } | |||||
| triMesh = new Mesh( *BMesh ); | |||||
| triMesh->totface = 0; | |||||
| triMesh->mface.clear( ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderBMeshConverter::DestroyTriMesh( ) | |||||
| { | |||||
| delete triMesh; | |||||
| triMesh = NULL; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderBMeshConverter::ConvertPolyToFaces( const MPoly& poly ) | |||||
| { | |||||
| const MLoop* polyLoop = &BMesh->mloop[ poly.loopstart ]; | |||||
| if ( poly.totloop == 3 || poly.totloop == 4 ) | |||||
| { | |||||
| AddFace( polyLoop[ 0 ].v, polyLoop[ 1 ].v, polyLoop[ 2 ].v, poly.totloop == 4 ? polyLoop[ 3 ].v : 0 ); | |||||
| } | |||||
| else if ( poly.totloop > 4 ) | |||||
| { | |||||
| #if ASSIMP_BLEND_WITH_GLU_TESSELLATE | |||||
| BlenderTessellatorGL tessGL( *this ); | |||||
| tessGL.Tessellate( polyLoop, poly.totloop, triMesh->mvert ); | |||||
| #elif ASSIMP_BLEND_WITH_POLY_2_TRI | |||||
| BlenderTessellatorP2T tessP2T( *this ); | |||||
| tessP2T.Tessellate( polyLoop, poly.totloop, triMesh->mvert ); | |||||
| #endif | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderBMeshConverter::AddFace( int v1, int v2, int v3, int v4 ) | |||||
| { | |||||
| MFace face; | |||||
| face.v1 = v1; | |||||
| face.v2 = v2; | |||||
| face.v3 = v3; | |||||
| face.v4 = v4; | |||||
| // TODO - Work out how materials work | |||||
| face.mat_nr = 0; | |||||
| triMesh->mface.push_back( face ); | |||||
| triMesh->totface = triMesh->mface.size( ); | |||||
| } | |||||
| #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER | |||||
| @@ -0,0 +1,93 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| Copyright (c) 2006-2013, 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 BlenderBMesh.h | |||||
| * @brief Conversion of Blender's new BMesh stuff | |||||
| */ | |||||
| #ifndef INCLUDED_AI_BLEND_BMESH_H | |||||
| #define INCLUDED_AI_BLEND_BMESH_H | |||||
| #include "LogAux.h" | |||||
| namespace Assimp | |||||
| { | |||||
| // TinyFormatter.h | |||||
| namespace Formatter | |||||
| { | |||||
| template < typename T,typename TR, typename A > class basic_formatter; | |||||
| typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format; | |||||
| } | |||||
| // BlenderScene.h | |||||
| namespace Blender | |||||
| { | |||||
| struct Mesh; | |||||
| struct MPoly; | |||||
| struct MLoop; | |||||
| } | |||||
| class BlenderBMeshConverter: public LogFunctions< BlenderBMeshConverter > | |||||
| { | |||||
| public: | |||||
| BlenderBMeshConverter( const Blender::Mesh* mesh ); | |||||
| ~BlenderBMeshConverter( ); | |||||
| bool ContainsBMesh( ) const; | |||||
| const Blender::Mesh* TriangulateBMesh( ); | |||||
| private: | |||||
| void AssertValidMesh( ); | |||||
| void AssertValidSizes( ); | |||||
| void PrepareTriMesh( ); | |||||
| void DestroyTriMesh( ); | |||||
| void ConvertPolyToFaces( const Blender::MPoly& poly ); | |||||
| void AddFace( int v1, int v2, int v3, int v4 = 0 ); | |||||
| const Blender::Mesh* BMesh; | |||||
| Blender::Mesh* triMesh; | |||||
| friend class BlenderTessellatorGL; | |||||
| friend class BlenderTessellatorP2T; | |||||
| }; | |||||
| } // end of namespace Assimp | |||||
| #endif // INCLUDED_AI_BLEND_BMESH_H | |||||
| @@ -0,0 +1,372 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file BlenderDNA.cpp | |||||
| * @brief Implementation of the Blender `DNA`, that is its own | |||||
| * serialized set of data structures. | |||||
| */ | |||||
| #include "AssimpPCH.h" | |||||
| #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER | |||||
| #include "BlenderDNA.h" | |||||
| #include "StreamReader.h" | |||||
| #include "fast_atof.h" | |||||
| using namespace Assimp; | |||||
| using namespace Assimp::Blender; | |||||
| using namespace Assimp::Formatter; | |||||
| #define for_each BOOST_FOREACH | |||||
| bool match4(StreamReaderAny& stream, const char* string) { | |||||
| char tmp[] = { | |||||
| (stream).GetI1(), | |||||
| (stream).GetI1(), | |||||
| (stream).GetI1(), | |||||
| (stream).GetI1() | |||||
| }; | |||||
| return (tmp[0]==string[0] && tmp[1]==string[1] && tmp[2]==string[2] && tmp[3]==string[3]); | |||||
| } | |||||
| struct Type { | |||||
| size_t size; | |||||
| std::string name; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void DNAParser :: Parse () | |||||
| { | |||||
| StreamReaderAny& stream = *db.reader.get(); | |||||
| DNA& dna = db.dna; | |||||
| if(!match4(stream,"SDNA")) { | |||||
| throw DeadlyImportError("BlenderDNA: Expected SDNA chunk"); | |||||
| } | |||||
| // name dictionary | |||||
| if(!match4(stream,"NAME")) { | |||||
| throw DeadlyImportError("BlenderDNA: Expected NAME field"); | |||||
| } | |||||
| std::vector<std::string> names (stream.GetI4()); | |||||
| for_each(std::string& s, names) { | |||||
| while (char c = stream.GetI1()) { | |||||
| s += c; | |||||
| } | |||||
| } | |||||
| // type dictionary | |||||
| for (;stream.GetCurrentPos() & 0x3; stream.GetI1()); | |||||
| if(!match4(stream,"TYPE")) { | |||||
| throw DeadlyImportError("BlenderDNA: Expected TYPE field"); | |||||
| } | |||||
| std::vector<Type> types (stream.GetI4()); | |||||
| for_each(Type& s, types) { | |||||
| while (char c = stream.GetI1()) { | |||||
| s.name += c; | |||||
| } | |||||
| } | |||||
| // type length dictionary | |||||
| for (;stream.GetCurrentPos() & 0x3; stream.GetI1()); | |||||
| if(!match4(stream,"TLEN")) { | |||||
| throw DeadlyImportError("BlenderDNA: Expected TLEN field"); | |||||
| } | |||||
| for_each(Type& s, types) { | |||||
| s.size = stream.GetI2(); | |||||
| } | |||||
| // structures dictionary | |||||
| for (;stream.GetCurrentPos() & 0x3; stream.GetI1()); | |||||
| if(!match4(stream,"STRC")) { | |||||
| throw DeadlyImportError("BlenderDNA: Expected STRC field"); | |||||
| } | |||||
| size_t end = stream.GetI4(), fields = 0; | |||||
| dna.structures.reserve(end); | |||||
| for(size_t i = 0; i != end; ++i) { | |||||
| uint16_t n = stream.GetI2(); | |||||
| if (n >= types.size()) { | |||||
| throw DeadlyImportError((format(), | |||||
| "BlenderDNA: Invalid type index in structure name" ,n, | |||||
| " (there are only ", types.size(), " entries)" | |||||
| )); | |||||
| } | |||||
| // maintain separate indexes | |||||
| dna.indices[types[n].name] = dna.structures.size(); | |||||
| dna.structures.push_back(Structure()); | |||||
| Structure& s = dna.structures.back(); | |||||
| s.name = types[n].name; | |||||
| //s.index = dna.structures.size()-1; | |||||
| n = stream.GetI2(); | |||||
| s.fields.reserve(n); | |||||
| size_t offset = 0; | |||||
| for (size_t m = 0; m < n; ++m, ++fields) { | |||||
| uint16_t j = stream.GetI2(); | |||||
| if (j >= types.size()) { | |||||
| throw DeadlyImportError((format(), | |||||
| "BlenderDNA: Invalid type index in structure field ", j, | |||||
| " (there are only ", types.size(), " entries)" | |||||
| )); | |||||
| } | |||||
| s.fields.push_back(Field()); | |||||
| Field& f = s.fields.back(); | |||||
| f.offset = offset; | |||||
| f.type = types[j].name; | |||||
| f.size = types[j].size; | |||||
| j = stream.GetI2(); | |||||
| if (j >= names.size()) { | |||||
| throw DeadlyImportError((format(), | |||||
| "BlenderDNA: Invalid name index in structure field ", j, | |||||
| " (there are only ", names.size(), " entries)" | |||||
| )); | |||||
| } | |||||
| f.name = names[j]; | |||||
| f.flags = 0u; | |||||
| // pointers always specify the size of the pointee instead of their own. | |||||
| // The pointer asterisk remains a property of the lookup name. | |||||
| if (f.name[0] == '*') { | |||||
| f.size = db.i64bit ? 8 : 4; | |||||
| f.flags |= FieldFlag_Pointer; | |||||
| } | |||||
| // arrays, however, specify the size of a single element so we | |||||
| // need to parse the (possibly multi-dimensional) array declaration | |||||
| // in order to obtain the actual size of the array in the file. | |||||
| // Also we need to alter the lookup name to include no array | |||||
| // brackets anymore or size fixup won't work (if our size does | |||||
| // not match the size read from the DNA). | |||||
| if (*f.name.rbegin() == ']') { | |||||
| const std::string::size_type rb = f.name.find('['); | |||||
| if (rb == std::string::npos) { | |||||
| throw DeadlyImportError((format(), | |||||
| "BlenderDNA: Encountered invalid array declaration ", | |||||
| f.name | |||||
| )); | |||||
| } | |||||
| f.flags |= FieldFlag_Array; | |||||
| DNA::ExtractArraySize(f.name,f.array_sizes); | |||||
| f.name = f.name.substr(0,rb); | |||||
| f.size *= f.array_sizes[0] * f.array_sizes[1]; | |||||
| } | |||||
| // maintain separate indexes | |||||
| s.indices[f.name] = s.fields.size()-1; | |||||
| offset += f.size; | |||||
| } | |||||
| s.size = offset; | |||||
| } | |||||
| DefaultLogger::get()->debug((format(),"BlenderDNA: Got ",dna.structures.size(), | |||||
| " structures with totally ",fields," fields")); | |||||
| #ifdef ASSIMP_BUILD_BLENDER_DEBUG | |||||
| dna.DumpToFile(); | |||||
| #endif | |||||
| dna.AddPrimitiveStructures(); | |||||
| dna.RegisterConverters(); | |||||
| } | |||||
| #ifdef ASSIMP_BUILD_BLENDER_DEBUG | |||||
| #include <fstream> | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void DNA :: DumpToFile() | |||||
| { | |||||
| // we dont't bother using the VFS here for this is only for debugging. | |||||
| // (and all your bases are belong to us). | |||||
| std::ofstream f("dna.txt"); | |||||
| if (f.fail()) { | |||||
| DefaultLogger::get()->error("Could not dump dna to dna.txt"); | |||||
| return; | |||||
| } | |||||
| f << "Field format: type name offset size" << "\n"; | |||||
| f << "Structure format: name size" << "\n"; | |||||
| for_each(const Structure& s, structures) { | |||||
| f << s.name << " " << s.size << "\n\n"; | |||||
| for_each(const Field& ff, s.fields) { | |||||
| f << "\t" << ff.type << " " << ff.name << " " << ff.offset << " " << ff.size << std::endl; | |||||
| } | |||||
| f << std::endl; | |||||
| } | |||||
| DefaultLogger::get()->info("BlenderDNA: Dumped dna to dna.txt"); | |||||
| } | |||||
| #endif | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| /*static*/ void DNA :: ExtractArraySize( | |||||
| const std::string& out, | |||||
| size_t array_sizes[2] | |||||
| ) | |||||
| { | |||||
| array_sizes[0] = array_sizes[1] = 1; | |||||
| std::string::size_type pos = out.find('['); | |||||
| if (pos++ == std::string::npos) { | |||||
| return; | |||||
| } | |||||
| array_sizes[0] = strtoul10(&out[pos]); | |||||
| pos = out.find('[',pos); | |||||
| if (pos++ == std::string::npos) { | |||||
| return; | |||||
| } | |||||
| array_sizes[1] = strtoul10(&out[pos]); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| boost::shared_ptr< ElemBase > DNA :: ConvertBlobToStructure( | |||||
| const Structure& structure, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| std::map<std::string, FactoryPair >::const_iterator it = converters.find(structure.name); | |||||
| if (it == converters.end()) { | |||||
| return boost::shared_ptr< ElemBase >(); | |||||
| } | |||||
| boost::shared_ptr< ElemBase > ret = (structure.*((*it).second.first))(); | |||||
| (structure.*((*it).second.second))(ret,db); | |||||
| return ret; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| DNA::FactoryPair DNA :: GetBlobToStructureConverter( | |||||
| const Structure& structure, | |||||
| const FileDatabase& /*db*/ | |||||
| ) const | |||||
| { | |||||
| std::map<std::string, FactoryPair>::const_iterator it = converters.find(structure.name); | |||||
| return it == converters.end() ? FactoryPair() : (*it).second; | |||||
| } | |||||
| // basing on http://www.blender.org/development/architecture/notes-on-sdna/ | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void DNA :: AddPrimitiveStructures() | |||||
| { | |||||
| // NOTE: these are just dummies. Their presence enforces | |||||
| // Structure::Convert<target_type> to be called on these | |||||
| // empty structures. These converters are special | |||||
| // overloads which scan the name of the structure and | |||||
| // perform the required data type conversion if one | |||||
| // of these special names is found in the structure | |||||
| // in question. | |||||
| indices["int"] = structures.size(); | |||||
| structures.push_back( Structure() ); | |||||
| structures.back().name = "int"; | |||||
| structures.back().size = 4; | |||||
| indices["short"] = structures.size(); | |||||
| structures.push_back( Structure() ); | |||||
| structures.back().name = "short"; | |||||
| structures.back().size = 2; | |||||
| indices["char"] = structures.size(); | |||||
| structures.push_back( Structure() ); | |||||
| structures.back().name = "char"; | |||||
| structures.back().size = 1; | |||||
| indices["float"] = structures.size(); | |||||
| structures.push_back( Structure() ); | |||||
| structures.back().name = "float"; | |||||
| structures.back().size = 4; | |||||
| indices["double"] = structures.size(); | |||||
| structures.push_back( Structure() ); | |||||
| structures.back().name = "double"; | |||||
| structures.back().size = 8; | |||||
| // no long, seemingly. | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void SectionParser :: Next() | |||||
| { | |||||
| stream.SetCurrentPos(current.start + current.size); | |||||
| const char tmp[] = { | |||||
| stream.GetI1(), | |||||
| stream.GetI1(), | |||||
| stream.GetI1(), | |||||
| stream.GetI1() | |||||
| }; | |||||
| current.id = std::string(tmp,tmp[3]?4:tmp[2]?3:tmp[1]?2:1); | |||||
| current.size = stream.GetI4(); | |||||
| current.address.val = ptr64 ? stream.GetU8() : stream.GetU4(); | |||||
| current.dna_index = stream.GetI4(); | |||||
| current.num = stream.GetI4(); | |||||
| current.start = stream.GetCurrentPos(); | |||||
| if (stream.GetRemainingSizeToLimit() < current.size) { | |||||
| throw DeadlyImportError("BLEND: invalid size of file block"); | |||||
| } | |||||
| #ifdef ASSIMP_BUILD_BLENDER_DEBUG | |||||
| DefaultLogger::get()->debug(current.id); | |||||
| #endif | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,804 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file BlenderDNA.h | |||||
| * @brief Blender `DNA` (file format specification embedded in | |||||
| * blend file itself) loader. | |||||
| */ | |||||
| #ifndef INCLUDED_AI_BLEND_DNA_H | |||||
| #define INCLUDED_AI_BLEND_DNA_H | |||||
| #include "BaseImporter.h" | |||||
| #include "TinyFormatter.h" | |||||
| // enable verbose log output. really verbose, so be careful. | |||||
| #ifdef ASSIMP_BUILD_DEBUG | |||||
| # define ASSIMP_BUILD_BLENDER_DEBUG | |||||
| #endif | |||||
| // #define ASSIMP_BUILD_BLENDER_NO_STATS | |||||
| namespace Assimp { | |||||
| template <bool,bool> class StreamReader; | |||||
| typedef StreamReader<true,true> StreamReaderAny; | |||||
| namespace Blender { | |||||
| class FileDatabase; | |||||
| struct FileBlockHead; | |||||
| template <template <typename> class TOUT> | |||||
| class ObjectCache; | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** Exception class used by the blender loader to selectively catch exceptions | |||||
| * thrown in its own code (DeadlyImportErrors thrown in general utility | |||||
| * functions are untouched then). If such an exception is not caught by | |||||
| * the loader itself, it will still be caught by Assimp due to its | |||||
| * ancestry. */ | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct Error : DeadlyImportError | |||||
| { | |||||
| Error (const std::string& s) | |||||
| : DeadlyImportError(s) | |||||
| {} | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** The only purpose of this structure is to feed a virtual dtor into its | |||||
| * descendents. It serves as base class for all data structure fields. */ | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct ElemBase | |||||
| { | |||||
| virtual ~ElemBase() {} | |||||
| /** Type name of the element. The type | |||||
| * string points is the `c_str` of the `name` attribute of the | |||||
| * corresponding `Structure`, that is, it is only valid as long | |||||
| * as the DNA is not modified. The dna_type is only set if the | |||||
| * data type is not static, i.e. a boost::shared_ptr<ElemBase> | |||||
| * in the scene description would have its type resolved | |||||
| * at runtime, so this member is always set. */ | |||||
| const char* dna_type; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** Represents a generic pointer to a memory location, which can be either 32 | |||||
| * or 64 bits. These pointers are loaded from the BLEND file and finally | |||||
| * fixed to point to the real, converted representation of the objects | |||||
| * they used to point to.*/ | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct Pointer | |||||
| { | |||||
| Pointer() : val() {} | |||||
| uint64_t val; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** Represents a generic offset within a BLEND file */ | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct FileOffset | |||||
| { | |||||
| FileOffset() : val() {} | |||||
| uint64_t val; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** Dummy derivate of std::vector to be able to use it in templates simultaenously | |||||
| * with boost::shared_ptr, which takes only one template argument | |||||
| * while std::vector takes three. Also we need to provide some special member | |||||
| * functions of shared_ptr */ | |||||
| // ------------------------------------------------------------------------------- | |||||
| template <typename T> | |||||
| class vector : public std::vector<T> | |||||
| { | |||||
| public: | |||||
| using std::vector<T>::resize; | |||||
| using std::vector<T>::empty; | |||||
| void reset() { | |||||
| resize(0); | |||||
| } | |||||
| operator bool () const { | |||||
| return !empty(); | |||||
| } | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** Mixed flags for use in #Field */ | |||||
| // ------------------------------------------------------------------------------- | |||||
| enum FieldFlags | |||||
| { | |||||
| FieldFlag_Pointer = 0x1, | |||||
| FieldFlag_Array = 0x2 | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** Represents a single member of a data structure in a BLEND file */ | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct Field | |||||
| { | |||||
| std::string name; | |||||
| std::string type; | |||||
| size_t size; | |||||
| size_t offset; | |||||
| /** Size of each array dimension. For flat arrays, | |||||
| * the second dimension is set to 1. */ | |||||
| size_t array_sizes[2]; | |||||
| /** Any of the #FieldFlags enumerated values */ | |||||
| unsigned int flags; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** Range of possible behaviours for fields absend in the input file. Some are | |||||
| * mission critical so we need them, while others can silently be default | |||||
| * initialized and no animations are harmed. */ | |||||
| // ------------------------------------------------------------------------------- | |||||
| enum ErrorPolicy | |||||
| { | |||||
| /** Substitute default value and ignore */ | |||||
| ErrorPolicy_Igno, | |||||
| /** Substitute default value and write to log */ | |||||
| ErrorPolicy_Warn, | |||||
| /** Substitute a massive error message and crash the whole matrix. Its time for another zion */ | |||||
| ErrorPolicy_Fail | |||||
| }; | |||||
| #ifdef ASSIMP_BUILD_BLENDER_DEBUG | |||||
| # define ErrorPolicy_Igno ErrorPolicy_Warn | |||||
| #endif | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** Represents a data structure in a BLEND file. A Structure defines n fields | |||||
| * and their locatios and encodings the input stream. Usually, every | |||||
| * Structure instance pertains to one equally-named data structure in the | |||||
| * BlenderScene.h header. This class defines various utilities to map a | |||||
| * binary `blob` read from the file to such a structure instance with | |||||
| * meaningful contents. */ | |||||
| // ------------------------------------------------------------------------------- | |||||
| class Structure | |||||
| { | |||||
| template <template <typename> class> friend class ObjectCache; | |||||
| public: | |||||
| Structure() | |||||
| : cache_idx(-1) | |||||
| {} | |||||
| public: | |||||
| // publicly accessible members | |||||
| std::string name; | |||||
| vector< Field > fields; | |||||
| std::map<std::string, size_t> indices; | |||||
| size_t size; | |||||
| public: | |||||
| // -------------------------------------------------------- | |||||
| /** Access a field of the structure by its canonical name. The pointer version | |||||
| * returns NULL on failure while the reference version raises an import error. */ | |||||
| inline const Field& operator [] (const std::string& ss) const; | |||||
| inline const Field* Get (const std::string& ss) const; | |||||
| // -------------------------------------------------------- | |||||
| /** Access a field of the structure by its index */ | |||||
| inline const Field& operator [] (const size_t i) const; | |||||
| // -------------------------------------------------------- | |||||
| inline bool operator== (const Structure& other) const { | |||||
| return name == other.name; // name is meant to be an unique identifier | |||||
| } | |||||
| // -------------------------------------------------------- | |||||
| inline bool operator!= (const Structure& other) const { | |||||
| return name != other.name; | |||||
| } | |||||
| public: | |||||
| // -------------------------------------------------------- | |||||
| /** Try to read an instance of the structure from the stream | |||||
| * and attempt to convert to `T`. This is done by | |||||
| * an appropriate specialization. If none is available, | |||||
| * a compiler complain is the result. | |||||
| * @param dest Destination value to be written | |||||
| * @param db File database, including input stream. */ | |||||
| template <typename T> inline void Convert (T& dest, | |||||
| const FileDatabase& db) const; | |||||
| // -------------------------------------------------------- | |||||
| // generic converter | |||||
| template <typename T> | |||||
| void Convert(boost::shared_ptr<ElemBase> in,const FileDatabase& db) const; | |||||
| // -------------------------------------------------------- | |||||
| // generic allocator | |||||
| template <typename T> boost::shared_ptr<ElemBase> Allocate() const; | |||||
| // -------------------------------------------------------- | |||||
| // field parsing for 1d arrays | |||||
| template <int error_policy, typename T, size_t M> | |||||
| void ReadFieldArray(T (& out)[M], const char* name, | |||||
| const FileDatabase& db) const; | |||||
| // -------------------------------------------------------- | |||||
| // field parsing for 2d arrays | |||||
| template <int error_policy, typename T, size_t M, size_t N> | |||||
| void ReadFieldArray2(T (& out)[M][N], const char* name, | |||||
| const FileDatabase& db) const; | |||||
| // -------------------------------------------------------- | |||||
| // field parsing for pointer or dynamic array types | |||||
| // (boost::shared_ptr or boost::shared_array) | |||||
| // The return value indicates whether the data was already cached. | |||||
| template <int error_policy, template <typename> class TOUT, typename T> | |||||
| bool ReadFieldPtr(TOUT<T>& out, const char* name, | |||||
| const FileDatabase& db, | |||||
| bool non_recursive = false) const; | |||||
| // -------------------------------------------------------- | |||||
| // field parsing for static arrays of pointer or dynamic | |||||
| // array types (boost::shared_ptr[] or boost::shared_array[]) | |||||
| // The return value indicates whether the data was already cached. | |||||
| template <int error_policy, template <typename> class TOUT, typename T, size_t N> | |||||
| bool ReadFieldPtr(TOUT<T> (&out)[N], const char* name, | |||||
| const FileDatabase& db) const; | |||||
| // -------------------------------------------------------- | |||||
| // field parsing for `normal` values | |||||
| // The return value indicates whether the data was already cached. | |||||
| template <int error_policy, typename T> | |||||
| void ReadField(T& out, const char* name, | |||||
| const FileDatabase& db) const; | |||||
| private: | |||||
| // -------------------------------------------------------- | |||||
| template <template <typename> class TOUT, typename T> | |||||
| bool ResolvePointer(TOUT<T>& out, const Pointer & ptrval, | |||||
| const FileDatabase& db, const Field& f, | |||||
| bool non_recursive = false) const; | |||||
| // -------------------------------------------------------- | |||||
| template <template <typename> class TOUT, typename T> | |||||
| bool ResolvePointer(vector< TOUT<T> >& out, const Pointer & ptrval, | |||||
| const FileDatabase& db, const Field& f, bool) const; | |||||
| // -------------------------------------------------------- | |||||
| bool ResolvePointer( boost::shared_ptr< FileOffset >& out, const Pointer & ptrval, | |||||
| const FileDatabase& db, const Field& f, bool) const; | |||||
| // -------------------------------------------------------- | |||||
| inline const FileBlockHead* LocateFileBlockForAddress( | |||||
| const Pointer & ptrval, | |||||
| const FileDatabase& db) const; | |||||
| private: | |||||
| // ------------------------------------------------------------------------------ | |||||
| template <typename T> T* _allocate(boost::shared_ptr<T>& out, size_t& s) const { | |||||
| out = boost::shared_ptr<T>(new T()); | |||||
| s = 1; | |||||
| return out.get(); | |||||
| } | |||||
| template <typename T> T* _allocate(vector<T>& out, size_t& s) const { | |||||
| out.resize(s); | |||||
| return s ? &out.front() : NULL; | |||||
| } | |||||
| // -------------------------------------------------------- | |||||
| template <int error_policy> | |||||
| struct _defaultInitializer { | |||||
| template <typename T, unsigned int N> | |||||
| void operator ()(T (& out)[N], const char* = NULL) { | |||||
| for (unsigned int i = 0; i < N; ++i) { | |||||
| out[i] = T(); | |||||
| } | |||||
| } | |||||
| template <typename T, unsigned int N, unsigned int M> | |||||
| void operator ()(T (& out)[N][M], const char* = NULL) { | |||||
| for (unsigned int i = 0; i < N; ++i) { | |||||
| for (unsigned int j = 0; j < M; ++j) { | |||||
| out[i][j] = T(); | |||||
| } | |||||
| } | |||||
| } | |||||
| template <typename T> | |||||
| void operator ()(T& out, const char* = NULL) { | |||||
| out = T(); | |||||
| } | |||||
| }; | |||||
| private: | |||||
| mutable size_t cache_idx; | |||||
| }; | |||||
| // -------------------------------------------------------- | |||||
| template <> struct Structure :: _defaultInitializer<ErrorPolicy_Warn> { | |||||
| template <typename T> | |||||
| void operator ()(T& out, const char* reason = "<add reason>") { | |||||
| DefaultLogger::get()->warn(reason); | |||||
| // ... and let the show go on | |||||
| _defaultInitializer<0 /*ErrorPolicy_Igno*/>()(out); | |||||
| } | |||||
| }; | |||||
| template <> struct Structure :: _defaultInitializer<ErrorPolicy_Fail> { | |||||
| template <typename T> | |||||
| void operator ()(T& /*out*/,const char* = "") { | |||||
| // obviously, it is crucial that _DefaultInitializer is used | |||||
| // only from within a catch clause. | |||||
| throw; | |||||
| } | |||||
| }; | |||||
| // ------------------------------------------------------------------------------------------------------- | |||||
| template <> inline bool Structure :: ResolvePointer<boost::shared_ptr,ElemBase>(boost::shared_ptr<ElemBase>& out, | |||||
| const Pointer & ptrval, | |||||
| const FileDatabase& db, | |||||
| const Field& f, | |||||
| bool | |||||
| ) const; | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** Represents the full data structure information for a single BLEND file. | |||||
| * This data is extracted from the DNA1 chunk in the file. | |||||
| * #DNAParser does the reading and represents currently the only place where | |||||
| * DNA is altered.*/ | |||||
| // ------------------------------------------------------------------------------- | |||||
| class DNA | |||||
| { | |||||
| public: | |||||
| typedef void (Structure::*ConvertProcPtr) ( | |||||
| boost::shared_ptr<ElemBase> in, | |||||
| const FileDatabase& | |||||
| ) const; | |||||
| typedef boost::shared_ptr<ElemBase> ( | |||||
| Structure::*AllocProcPtr) () const; | |||||
| typedef std::pair< AllocProcPtr, ConvertProcPtr > FactoryPair; | |||||
| public: | |||||
| std::map<std::string, FactoryPair > converters; | |||||
| vector<Structure > structures; | |||||
| std::map<std::string, size_t> indices; | |||||
| public: | |||||
| // -------------------------------------------------------- | |||||
| /** Access a structure by its canonical name, the pointer version returns NULL on failure | |||||
| * while the reference version raises an error. */ | |||||
| inline const Structure& operator [] (const std::string& ss) const; | |||||
| inline const Structure* Get (const std::string& ss) const; | |||||
| // -------------------------------------------------------- | |||||
| /** Access a structure by its index */ | |||||
| inline const Structure& operator [] (const size_t i) const; | |||||
| public: | |||||
| // -------------------------------------------------------- | |||||
| /** Add structure definitions for all the primitive types, | |||||
| * i.e. integer, short, char, float */ | |||||
| void AddPrimitiveStructures(); | |||||
| // -------------------------------------------------------- | |||||
| /** Fill the @c converters member with converters for all | |||||
| * known data types. The implementation of this method is | |||||
| * in BlenderScene.cpp and is machine-generated. | |||||
| * Converters are used to quickly handle objects whose | |||||
| * exact data type is a runtime-property and not yet | |||||
| * known at compile time (consier Object::data).*/ | |||||
| void RegisterConverters(); | |||||
| // -------------------------------------------------------- | |||||
| /** Take an input blob from the stream, interpret it according to | |||||
| * a its structure name and convert it to the intermediate | |||||
| * representation. | |||||
| * @param structure Destination structure definition | |||||
| * @param db File database. | |||||
| * @return A null pointer if no appropriate converter is available.*/ | |||||
| boost::shared_ptr< ElemBase > ConvertBlobToStructure( | |||||
| const Structure& structure, | |||||
| const FileDatabase& db | |||||
| ) const; | |||||
| // -------------------------------------------------------- | |||||
| /** Find a suitable conversion function for a given Structure. | |||||
| * Such a converter function takes a blob from the input | |||||
| * stream, reads as much as it needs, and builds up a | |||||
| * complete object in intermediate representation. | |||||
| * @param structure Destination structure definition | |||||
| * @param db File database. | |||||
| * @return A null pointer in .first if no appropriate converter is available.*/ | |||||
| FactoryPair GetBlobToStructureConverter( | |||||
| const Structure& structure, | |||||
| const FileDatabase& db | |||||
| ) const; | |||||
| #ifdef ASSIMP_BUILD_BLENDER_DEBUG | |||||
| // -------------------------------------------------------- | |||||
| /** Dump the DNA to a text file. This is for debugging purposes. | |||||
| * The output file is `dna.txt` in the current working folder*/ | |||||
| void DumpToFile(); | |||||
| #endif | |||||
| // -------------------------------------------------------- | |||||
| /** Extract array dimensions from a C array declaration, such | |||||
| * as `...[4][6]`. Returned string would be `...[][]`. | |||||
| * @param out | |||||
| * @param array_sizes Receive maximally two array dimensions, | |||||
| * the second element is set to 1 if the array is flat. | |||||
| * Both are set to 1 if the input is not an array. | |||||
| * @throw DeadlyImportError if more than 2 dimensions are | |||||
| * encountered. */ | |||||
| static void ExtractArraySize( | |||||
| const std::string& out, | |||||
| size_t array_sizes[2] | |||||
| ); | |||||
| }; | |||||
| // special converters for primitive types | |||||
| template <> inline void Structure :: Convert<int> (int& dest,const FileDatabase& db) const; | |||||
| template <> inline void Structure :: Convert<short> (short& dest,const FileDatabase& db) const; | |||||
| template <> inline void Structure :: Convert<char> (char& dest,const FileDatabase& db) const; | |||||
| template <> inline void Structure :: Convert<float> (float& dest,const FileDatabase& db) const; | |||||
| template <> inline void Structure :: Convert<double> (double& dest,const FileDatabase& db) const; | |||||
| template <> inline void Structure :: Convert<Pointer> (Pointer& dest,const FileDatabase& db) const; | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** Describes a master file block header. Each master file sections holds n | |||||
| * elements of a certain SDNA structure (or otherwise unspecified data). */ | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct FileBlockHead | |||||
| { | |||||
| // points right after the header of the file block | |||||
| StreamReaderAny::pos start; | |||||
| std::string id; | |||||
| size_t size; | |||||
| // original memory address of the data | |||||
| Pointer address; | |||||
| // index into DNA | |||||
| unsigned int dna_index; | |||||
| // number of structure instances to follow | |||||
| size_t num; | |||||
| // file blocks are sorted by address to quickly locate specific memory addresses | |||||
| bool operator < (const FileBlockHead& o) const { | |||||
| return address.val < o.address.val; | |||||
| } | |||||
| // for std::upper_bound | |||||
| operator const Pointer& () const { | |||||
| return address; | |||||
| } | |||||
| }; | |||||
| // for std::upper_bound | |||||
| inline bool operator< (const Pointer& a, const Pointer& b) { | |||||
| return a.val < b.val; | |||||
| } | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** Utility to read all master file blocks in turn. */ | |||||
| // ------------------------------------------------------------------------------- | |||||
| class SectionParser | |||||
| { | |||||
| public: | |||||
| // -------------------------------------------------------- | |||||
| /** @param stream Inout stream, must point to the | |||||
| * first section in the file. Call Next() once | |||||
| * to have it read. | |||||
| * @param ptr64 Pointer size in file is 64 bits? */ | |||||
| SectionParser(StreamReaderAny& stream,bool ptr64) | |||||
| : stream(stream) | |||||
| , ptr64(ptr64) | |||||
| { | |||||
| current.size = current.start = 0; | |||||
| } | |||||
| public: | |||||
| // -------------------------------------------------------- | |||||
| const FileBlockHead& GetCurrent() const { | |||||
| return current; | |||||
| } | |||||
| public: | |||||
| // -------------------------------------------------------- | |||||
| /** Advance to the next section. | |||||
| * @throw DeadlyImportError if the last chunk was passed. */ | |||||
| void Next(); | |||||
| public: | |||||
| FileBlockHead current; | |||||
| StreamReaderAny& stream; | |||||
| bool ptr64; | |||||
| }; | |||||
| #ifndef ASSIMP_BUILD_BLENDER_NO_STATS | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** Import statistics, i.e. number of file blocks read*/ | |||||
| // ------------------------------------------------------------------------------- | |||||
| class Statistics { | |||||
| public: | |||||
| Statistics () | |||||
| : fields_read () | |||||
| , pointers_resolved () | |||||
| , cache_hits () | |||||
| // , blocks_read () | |||||
| , cached_objects () | |||||
| {} | |||||
| public: | |||||
| /** total number of fields we read */ | |||||
| unsigned int fields_read; | |||||
| /** total number of resolved pointers */ | |||||
| unsigned int pointers_resolved; | |||||
| /** number of pointers resolved from the cache */ | |||||
| unsigned int cache_hits; | |||||
| /** number of blocks (from FileDatabase::entries) | |||||
| we did actually read from. */ | |||||
| // unsigned int blocks_read; | |||||
| /** objects in FileData::cache */ | |||||
| unsigned int cached_objects; | |||||
| }; | |||||
| #endif | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** The object cache - all objects addressed by pointers are added here. This | |||||
| * avoids circular references and avoids object duplication. */ | |||||
| // ------------------------------------------------------------------------------- | |||||
| template <template <typename> class TOUT> | |||||
| class ObjectCache | |||||
| { | |||||
| public: | |||||
| typedef std::map< Pointer, TOUT<ElemBase> > StructureCache; | |||||
| public: | |||||
| ObjectCache(const FileDatabase& db) | |||||
| : db(db) | |||||
| { | |||||
| // currently there are only ~400 structure records per blend file. | |||||
| // we read only a small part of them and don't cache objects | |||||
| // which we don't need, so this should suffice. | |||||
| caches.reserve(64); | |||||
| } | |||||
| public: | |||||
| // -------------------------------------------------------- | |||||
| /** Check whether a specific item is in the cache. | |||||
| * @param s Data type of the item | |||||
| * @param out Output pointer. Unchanged if the | |||||
| * cache doens't know the item yet. | |||||
| * @param ptr Item address to look for. */ | |||||
| template <typename T> void get ( | |||||
| const Structure& s, | |||||
| TOUT<T>& out, | |||||
| const Pointer& ptr) const; | |||||
| // -------------------------------------------------------- | |||||
| /** Add an item to the cache after the item has | |||||
| * been fully read. Do not insert anything that | |||||
| * may be faulty or might cause the loading | |||||
| * to abort. | |||||
| * @param s Data type of the item | |||||
| * @param out Item to insert into the cache | |||||
| * @param ptr address (cache key) of the item. */ | |||||
| template <typename T> void set | |||||
| (const Structure& s, | |||||
| const TOUT<T>& out, | |||||
| const Pointer& ptr); | |||||
| private: | |||||
| mutable vector<StructureCache> caches; | |||||
| const FileDatabase& db; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| // ------------------------------------------------------------------------------- | |||||
| template <> class ObjectCache<Blender::vector> | |||||
| { | |||||
| public: | |||||
| ObjectCache(const FileDatabase&) {} | |||||
| template <typename T> void get(const Structure&, vector<T>&, const Pointer&) {} | |||||
| template <typename T> void set(const Structure&, const vector<T>&, const Pointer&) {} | |||||
| }; | |||||
| #ifdef _MSC_VER | |||||
| # pragma warning(disable:4355) | |||||
| #endif | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** Memory representation of a full BLEND file and all its dependencies. The | |||||
| * output aiScene is constructed from an instance of this data structure. */ | |||||
| // ------------------------------------------------------------------------------- | |||||
| class FileDatabase | |||||
| { | |||||
| template <template <typename> class TOUT> friend class ObjectCache; | |||||
| public: | |||||
| FileDatabase() | |||||
| : _cacheArrays(*this) | |||||
| , _cache(*this) | |||||
| , next_cache_idx() | |||||
| {} | |||||
| public: | |||||
| // publicly accessible fields | |||||
| bool i64bit; | |||||
| bool little; | |||||
| DNA dna; | |||||
| boost::shared_ptr< StreamReaderAny > reader; | |||||
| vector< FileBlockHead > entries; | |||||
| public: | |||||
| Statistics& stats() const { | |||||
| return _stats; | |||||
| } | |||||
| // For all our templates to work on both shared_ptr's and vector's | |||||
| // using the same code, a dummy cache for arrays is provided. Actually, | |||||
| // arrays of objects are never cached because we can't easily | |||||
| // ensure their proper destruction. | |||||
| template <typename T> | |||||
| ObjectCache<boost::shared_ptr>& cache(boost::shared_ptr<T>& /*in*/) const { | |||||
| return _cache; | |||||
| } | |||||
| template <typename T> | |||||
| ObjectCache<vector>& cache(vector<T>& /*in*/) const { | |||||
| return _cacheArrays; | |||||
| } | |||||
| private: | |||||
| #ifndef ASSIMP_BUILD_BLENDER_NO_STATS | |||||
| mutable Statistics _stats; | |||||
| #endif | |||||
| mutable ObjectCache<vector> _cacheArrays; | |||||
| mutable ObjectCache<boost::shared_ptr> _cache; | |||||
| mutable size_t next_cache_idx; | |||||
| }; | |||||
| #ifdef _MSC_VER | |||||
| # pragma warning(default:4355) | |||||
| #endif | |||||
| // ------------------------------------------------------------------------------- | |||||
| /** Factory to extract a #DNA from the DNA1 file block in a BLEND file. */ | |||||
| // ------------------------------------------------------------------------------- | |||||
| class DNAParser | |||||
| { | |||||
| public: | |||||
| /** Bind the parser to a empty DNA and an input stream */ | |||||
| DNAParser(FileDatabase& db) | |||||
| : db(db) | |||||
| {} | |||||
| public: | |||||
| // -------------------------------------------------------- | |||||
| /** Locate the DNA in the file and parse it. The input | |||||
| * stream is expected to point to the beginning of the DN1 | |||||
| * chunk at the time this method is called and is | |||||
| * undefined afterwards. | |||||
| * @throw DeadlyImportError if the DNA cannot be read. | |||||
| * @note The position of the stream pointer is undefined | |||||
| * afterwards.*/ | |||||
| void Parse (); | |||||
| public: | |||||
| /** Obtain a reference to the extracted DNA information */ | |||||
| const Blender::DNA& GetDNA() const { | |||||
| return db.dna; | |||||
| } | |||||
| private: | |||||
| FileDatabase& db; | |||||
| }; | |||||
| } // end Blend | |||||
| } // end Assimp | |||||
| #include "BlenderDNA.inl" | |||||
| #endif | |||||
| @@ -0,0 +1,732 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file BlenderDNA.inl | |||||
| * @brief Blender `DNA` (file format specification embedded in | |||||
| * blend file itself) loader. | |||||
| */ | |||||
| #ifndef INCLUDED_AI_BLEND_DNA_INL | |||||
| #define INCLUDED_AI_BLEND_DNA_INL | |||||
| namespace Assimp { | |||||
| namespace Blender { | |||||
| //-------------------------------------------------------------------------------- | |||||
| const Field& Structure :: operator [] (const std::string& ss) const | |||||
| { | |||||
| std::map<std::string, size_t>::const_iterator it = indices.find(ss); | |||||
| if (it == indices.end()) { | |||||
| throw Error((Formatter::format(), | |||||
| "BlendDNA: Did not find a field named `",ss,"` in structure `",name,"`" | |||||
| )); | |||||
| } | |||||
| return fields[(*it).second]; | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| const Field* Structure :: Get (const std::string& ss) const | |||||
| { | |||||
| std::map<std::string, size_t>::const_iterator it = indices.find(ss); | |||||
| return it == indices.end() ? NULL : &fields[(*it).second]; | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| const Field& Structure :: operator [] (const size_t i) const | |||||
| { | |||||
| if (i >= fields.size()) { | |||||
| throw Error((Formatter::format(), | |||||
| "BlendDNA: There is no field with index `",i,"` in structure `",name,"`" | |||||
| )); | |||||
| } | |||||
| return fields[i]; | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <typename T> boost::shared_ptr<ElemBase> Structure :: Allocate() const | |||||
| { | |||||
| return boost::shared_ptr<T>(new T()); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <typename T> void Structure :: Convert( | |||||
| boost::shared_ptr<ElemBase> in, | |||||
| const FileDatabase& db) const | |||||
| { | |||||
| Convert<T> (*static_cast<T*> ( in.get() ),db); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <int error_policy, typename T, size_t M> | |||||
| void Structure :: ReadFieldArray(T (& out)[M], const char* name, const FileDatabase& db) const | |||||
| { | |||||
| const StreamReaderAny::pos old = db.reader->GetCurrentPos(); | |||||
| try { | |||||
| const Field& f = (*this)[name]; | |||||
| const Structure& s = db.dna[f.type]; | |||||
| // is the input actually an array? | |||||
| if (!(f.flags & FieldFlag_Array)) { | |||||
| throw Error((Formatter::format(),"Field `",name,"` of structure `", | |||||
| this->name,"` ought to be an array of size ",M | |||||
| )); | |||||
| } | |||||
| db.reader->IncPtr(f.offset); | |||||
| // size conversions are always allowed, regardless of error_policy | |||||
| unsigned int i = 0; | |||||
| for(; i < std::min(f.array_sizes[0],M); ++i) { | |||||
| s.Convert(out[i],db); | |||||
| } | |||||
| for(; i < M; ++i) { | |||||
| _defaultInitializer<ErrorPolicy_Igno>()(out[i]); | |||||
| } | |||||
| } | |||||
| catch (const Error& e) { | |||||
| _defaultInitializer<error_policy>()(out,e.what()); | |||||
| } | |||||
| // and recover the previous stream position | |||||
| db.reader->SetCurrentPos(old); | |||||
| #ifndef ASSIMP_BUILD_BLENDER_NO_STATS | |||||
| ++db.stats().fields_read; | |||||
| #endif | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <int error_policy, typename T, size_t M, size_t N> | |||||
| void Structure :: ReadFieldArray2(T (& out)[M][N], const char* name, const FileDatabase& db) const | |||||
| { | |||||
| const StreamReaderAny::pos old = db.reader->GetCurrentPos(); | |||||
| try { | |||||
| const Field& f = (*this)[name]; | |||||
| const Structure& s = db.dna[f.type]; | |||||
| // is the input actually an array? | |||||
| if (!(f.flags & FieldFlag_Array)) { | |||||
| throw Error((Formatter::format(),"Field `",name,"` of structure `", | |||||
| this->name,"` ought to be an array of size ",M,"*",N | |||||
| )); | |||||
| } | |||||
| db.reader->IncPtr(f.offset); | |||||
| // size conversions are always allowed, regardless of error_policy | |||||
| unsigned int i = 0; | |||||
| for(; i < std::min(f.array_sizes[0],M); ++i) { | |||||
| unsigned int j = 0; | |||||
| for(; j < std::min(f.array_sizes[1],N); ++j) { | |||||
| s.Convert(out[i][j],db); | |||||
| } | |||||
| for(; j < N; ++j) { | |||||
| _defaultInitializer<ErrorPolicy_Igno>()(out[i][j]); | |||||
| } | |||||
| } | |||||
| for(; i < M; ++i) { | |||||
| _defaultInitializer<ErrorPolicy_Igno>()(out[i]); | |||||
| } | |||||
| } | |||||
| catch (const Error& e) { | |||||
| _defaultInitializer<error_policy>()(out,e.what()); | |||||
| } | |||||
| // and recover the previous stream position | |||||
| db.reader->SetCurrentPos(old); | |||||
| #ifndef ASSIMP_BUILD_BLENDER_NO_STATS | |||||
| ++db.stats().fields_read; | |||||
| #endif | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <int error_policy, template <typename> class TOUT, typename T> | |||||
| bool Structure :: ReadFieldPtr(TOUT<T>& out, const char* name, const FileDatabase& db, | |||||
| bool non_recursive /*= false*/) const | |||||
| { | |||||
| const StreamReaderAny::pos old = db.reader->GetCurrentPos(); | |||||
| Pointer ptrval; | |||||
| const Field* f; | |||||
| try { | |||||
| f = &(*this)[name]; | |||||
| // sanity check, should never happen if the genblenddna script is right | |||||
| if (!(f->flags & FieldFlag_Pointer)) { | |||||
| throw Error((Formatter::format(),"Field `",name,"` of structure `", | |||||
| this->name,"` ought to be a pointer")); | |||||
| } | |||||
| db.reader->IncPtr(f->offset); | |||||
| Convert(ptrval,db); | |||||
| // actually it is meaningless on which Structure the Convert is called | |||||
| // because the `Pointer` argument triggers a special implementation. | |||||
| } | |||||
| catch (const Error& e) { | |||||
| _defaultInitializer<error_policy>()(out,e.what()); | |||||
| out.reset(); | |||||
| return false; | |||||
| } | |||||
| // resolve the pointer and load the corresponding structure | |||||
| const bool res = ResolvePointer(out,ptrval,db,*f, non_recursive); | |||||
| if(!non_recursive) { | |||||
| // and recover the previous stream position | |||||
| db.reader->SetCurrentPos(old); | |||||
| } | |||||
| #ifndef ASSIMP_BUILD_BLENDER_NO_STATS | |||||
| ++db.stats().fields_read; | |||||
| #endif | |||||
| return res; | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <int error_policy, template <typename> class TOUT, typename T, size_t N> | |||||
| bool Structure :: ReadFieldPtr(TOUT<T> (&out)[N], const char* name, | |||||
| const FileDatabase& db) const | |||||
| { | |||||
| // XXX see if we can reduce this to call to the 'normal' ReadFieldPtr | |||||
| const StreamReaderAny::pos old = db.reader->GetCurrentPos(); | |||||
| Pointer ptrval[N]; | |||||
| const Field* f; | |||||
| try { | |||||
| f = &(*this)[name]; | |||||
| // sanity check, should never happen if the genblenddna script is right | |||||
| if ((FieldFlag_Pointer|FieldFlag_Pointer) != (f->flags & (FieldFlag_Pointer|FieldFlag_Pointer))) { | |||||
| throw Error((Formatter::format(),"Field `",name,"` of structure `", | |||||
| this->name,"` ought to be a pointer AND an array")); | |||||
| } | |||||
| db.reader->IncPtr(f->offset); | |||||
| size_t i = 0; | |||||
| for(; i < std::min(f->array_sizes[0],N); ++i) { | |||||
| Convert(ptrval[i],db); | |||||
| } | |||||
| for(; i < N; ++i) { | |||||
| _defaultInitializer<ErrorPolicy_Igno>()(ptrval[i]); | |||||
| } | |||||
| // actually it is meaningless on which Structure the Convert is called | |||||
| // because the `Pointer` argument triggers a special implementation. | |||||
| } | |||||
| catch (const Error& e) { | |||||
| _defaultInitializer<error_policy>()(out,e.what()); | |||||
| for(size_t i = 0; i < N; ++i) { | |||||
| out[i].reset(); | |||||
| } | |||||
| return false; | |||||
| } | |||||
| bool res = true; | |||||
| for(size_t i = 0; i < N; ++i) { | |||||
| // resolve the pointer and load the corresponding structure | |||||
| res = ResolvePointer(out[i],ptrval[i],db,*f) && res; | |||||
| } | |||||
| // and recover the previous stream position | |||||
| db.reader->SetCurrentPos(old); | |||||
| #ifndef ASSIMP_BUILD_BLENDER_NO_STATS | |||||
| ++db.stats().fields_read; | |||||
| #endif | |||||
| return res; | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <int error_policy, typename T> | |||||
| void Structure :: ReadField(T& out, const char* name, const FileDatabase& db) const | |||||
| { | |||||
| const StreamReaderAny::pos old = db.reader->GetCurrentPos(); | |||||
| try { | |||||
| const Field& f = (*this)[name]; | |||||
| // find the structure definition pertaining to this field | |||||
| const Structure& s = db.dna[f.type]; | |||||
| db.reader->IncPtr(f.offset); | |||||
| s.Convert(out,db); | |||||
| } | |||||
| catch (const Error& e) { | |||||
| _defaultInitializer<error_policy>()(out,e.what()); | |||||
| } | |||||
| // and recover the previous stream position | |||||
| db.reader->SetCurrentPos(old); | |||||
| #ifndef ASSIMP_BUILD_BLENDER_NO_STATS | |||||
| ++db.stats().fields_read; | |||||
| #endif | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <template <typename> class TOUT, typename T> | |||||
| bool Structure :: ResolvePointer(TOUT<T>& out, const Pointer & ptrval, const FileDatabase& db, | |||||
| const Field& f, | |||||
| bool non_recursive /*= false*/) const | |||||
| { | |||||
| out.reset(); // ensure null pointers work | |||||
| if (!ptrval.val) { | |||||
| return false; | |||||
| } | |||||
| const Structure& s = db.dna[f.type]; | |||||
| // find the file block the pointer is pointing to | |||||
| const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db); | |||||
| // also determine the target type from the block header | |||||
| // and check if it matches the type which we expect. | |||||
| const Structure& ss = db.dna[block->dna_index]; | |||||
| if (ss != s) { | |||||
| throw Error((Formatter::format(),"Expected target to be of type `",s.name, | |||||
| "` but seemingly it is a `",ss.name,"` instead" | |||||
| )); | |||||
| } | |||||
| // try to retrieve the object from the cache | |||||
| db.cache(out).get(s,out,ptrval); | |||||
| if (out) { | |||||
| return true; | |||||
| } | |||||
| // seek to this location, but save the previous stream pointer. | |||||
| const StreamReaderAny::pos pold = db.reader->GetCurrentPos(); | |||||
| db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) )); | |||||
| // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems. | |||||
| // I really ought to improve StreamReader to work with 64 bit indices exclusively. | |||||
| // continue conversion after allocating the required storage | |||||
| size_t num = block->size / ss.size; | |||||
| T* o = _allocate(out,num); | |||||
| // cache the object before we convert it to avoid cyclic recursion. | |||||
| db.cache(out).set(s,out,ptrval); | |||||
| // if the non_recursive flag is set, we don't do anything but leave | |||||
| // the cursor at the correct position to resolve the object. | |||||
| if (!non_recursive) { | |||||
| for (size_t i = 0; i < num; ++i,++o) { | |||||
| s.Convert(*o,db); | |||||
| } | |||||
| db.reader->SetCurrentPos(pold); | |||||
| } | |||||
| #ifndef ASSIMP_BUILD_BLENDER_NO_STATS | |||||
| if(out) { | |||||
| ++db.stats().pointers_resolved; | |||||
| } | |||||
| #endif | |||||
| return false; | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| inline bool Structure :: ResolvePointer( boost::shared_ptr< FileOffset >& out, const Pointer & ptrval, | |||||
| const FileDatabase& db, | |||||
| const Field&, | |||||
| bool) const | |||||
| { | |||||
| // Currently used exclusively by PackedFile::data to represent | |||||
| // a simple offset into the mapped BLEND file. | |||||
| out.reset(); | |||||
| if (!ptrval.val) { | |||||
| return false; | |||||
| } | |||||
| // find the file block the pointer is pointing to | |||||
| const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db); | |||||
| out = boost::shared_ptr< FileOffset > (new FileOffset()); | |||||
| out->val = block->start+ static_cast<size_t>((ptrval.val - block->address.val) ); | |||||
| return false; | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <template <typename> class TOUT, typename T> | |||||
| bool Structure :: ResolvePointer(vector< TOUT<T> >& out, const Pointer & ptrval, | |||||
| const FileDatabase& db, | |||||
| const Field& f, | |||||
| bool) const | |||||
| { | |||||
| // This is a function overload, not a template specialization. According to | |||||
| // the partial ordering rules, it should be selected by the compiler | |||||
| // for array-of-pointer inputs, i.e. Object::mats. | |||||
| out.reset(); | |||||
| if (!ptrval.val) { | |||||
| return false; | |||||
| } | |||||
| // find the file block the pointer is pointing to | |||||
| const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db); | |||||
| const size_t num = block->size / (db.i64bit?8:4); | |||||
| // keep the old stream position | |||||
| const StreamReaderAny::pos pold = db.reader->GetCurrentPos(); | |||||
| db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) )); | |||||
| bool res = false; | |||||
| // allocate raw storage for the array | |||||
| out.resize(num); | |||||
| for (size_t i = 0; i< num; ++i) { | |||||
| Pointer val; | |||||
| Convert(val,db); | |||||
| // and resolve the pointees | |||||
| res = ResolvePointer(out[i],val,db,f) && res; | |||||
| } | |||||
| db.reader->SetCurrentPos(pold); | |||||
| return res; | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> bool Structure :: ResolvePointer<boost::shared_ptr,ElemBase>(boost::shared_ptr<ElemBase>& out, | |||||
| const Pointer & ptrval, | |||||
| const FileDatabase& db, | |||||
| const Field&, | |||||
| bool | |||||
| ) const | |||||
| { | |||||
| // Special case when the data type needs to be determined at runtime. | |||||
| // Less secure than in the `strongly-typed` case. | |||||
| out.reset(); | |||||
| if (!ptrval.val) { | |||||
| return false; | |||||
| } | |||||
| // find the file block the pointer is pointing to | |||||
| const FileBlockHead* block = LocateFileBlockForAddress(ptrval,db); | |||||
| // determine the target type from the block header | |||||
| const Structure& s = db.dna[block->dna_index]; | |||||
| // try to retrieve the object from the cache | |||||
| db.cache(out).get(s,out,ptrval); | |||||
| if (out) { | |||||
| return true; | |||||
| } | |||||
| // seek to this location, but save the previous stream pointer. | |||||
| const StreamReaderAny::pos pold = db.reader->GetCurrentPos(); | |||||
| db.reader->SetCurrentPos(block->start+ static_cast<size_t>((ptrval.val - block->address.val) )); | |||||
| // FIXME: basically, this could cause problems with 64 bit pointers on 32 bit systems. | |||||
| // I really ought to improve StreamReader to work with 64 bit indices exclusively. | |||||
| // continue conversion after allocating the required storage | |||||
| DNA::FactoryPair builders = db.dna.GetBlobToStructureConverter(s,db); | |||||
| if (!builders.first) { | |||||
| // this might happen if DNA::RegisterConverters hasn't been called so far | |||||
| // or if the target type is not contained in `our` DNA. | |||||
| out.reset(); | |||||
| DefaultLogger::get()->warn((Formatter::format(), | |||||
| "Failed to find a converter for the `",s.name,"` structure" | |||||
| )); | |||||
| return false; | |||||
| } | |||||
| // allocate the object hull | |||||
| out = (s.*builders.first)(); | |||||
| // cache the object immediately to prevent infinite recursion in a | |||||
| // circular list with a single element (i.e. a self-referencing element). | |||||
| db.cache(out).set(s,out,ptrval); | |||||
| // and do the actual conversion | |||||
| (s.*builders.second)(out,db); | |||||
| db.reader->SetCurrentPos(pold); | |||||
| // store a pointer to the name string of the actual type | |||||
| // in the object itself. This allows the conversion code | |||||
| // to perform additional type checking. | |||||
| out->dna_type = s.name.c_str(); | |||||
| #ifndef ASSIMP_BUILD_BLENDER_NO_STATS | |||||
| ++db.stats().pointers_resolved; | |||||
| #endif | |||||
| return false; | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| const FileBlockHead* Structure :: LocateFileBlockForAddress(const Pointer & ptrval, const FileDatabase& db) const | |||||
| { | |||||
| // the file blocks appear in list sorted by | |||||
| // with ascending base addresses so we can run a | |||||
| // binary search to locate the pointee quickly. | |||||
| // NOTE: Blender seems to distinguish between side-by-side | |||||
| // data (stored in the same data block) and far pointers, | |||||
| // which are only used for structures starting with an ID. | |||||
| // We don't need to make this distinction, our algorithm | |||||
| // works regardless where the data is stored. | |||||
| vector<FileBlockHead>::const_iterator it = std::lower_bound(db.entries.begin(),db.entries.end(),ptrval); | |||||
| if (it == db.entries.end()) { | |||||
| // this is crucial, pointers may not be invalid. | |||||
| // this is either a corrupted file or an attempted attack. | |||||
| throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x", | |||||
| std::hex,ptrval.val,", no file block falls into this address range" | |||||
| )); | |||||
| } | |||||
| if (ptrval.val >= (*it).address.val + (*it).size) { | |||||
| throw DeadlyImportError((Formatter::format(),"Failure resolving pointer 0x", | |||||
| std::hex,ptrval.val,", nearest file block starting at 0x", | |||||
| (*it).address.val," ends at 0x", | |||||
| (*it).address.val + (*it).size | |||||
| )); | |||||
| } | |||||
| return &*it; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // NOTE: The MSVC debugger keeps showing up this annoying `a cast to a smaller data type has | |||||
| // caused a loss of data`-warning. Avoid this warning by a masking with an appropriate bitmask. | |||||
| template <typename T> struct signless; | |||||
| template <> struct signless<char> {typedef unsigned char type;}; | |||||
| template <> struct signless<short> {typedef unsigned short type;}; | |||||
| template <> struct signless<int> {typedef unsigned int type;}; | |||||
| template <typename T> | |||||
| struct static_cast_silent { | |||||
| template <typename V> | |||||
| T operator()(V in) { | |||||
| return static_cast<T>(in & static_cast<typename signless<T>::type>(-1)); | |||||
| } | |||||
| }; | |||||
| template <> struct static_cast_silent<float> { | |||||
| template <typename V> float operator()(V in) { | |||||
| return static_cast<float> (in); | |||||
| } | |||||
| }; | |||||
| template <> struct static_cast_silent<double> { | |||||
| template <typename V> double operator()(V in) { | |||||
| return static_cast<double>(in); | |||||
| } | |||||
| }; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| template <typename T> inline void ConvertDispatcher(T& out, const Structure& in,const FileDatabase& db) | |||||
| { | |||||
| if (in.name == "int") { | |||||
| out = static_cast_silent<T>()(db.reader->GetU4()); | |||||
| } | |||||
| else if (in.name == "short") { | |||||
| out = static_cast_silent<T>()(db.reader->GetU2()); | |||||
| } | |||||
| else if (in.name == "char") { | |||||
| out = static_cast_silent<T>()(db.reader->GetU1()); | |||||
| } | |||||
| else if (in.name == "float") { | |||||
| out = static_cast<T>(db.reader->GetF4()); | |||||
| } | |||||
| else if (in.name == "double") { | |||||
| out = static_cast<T>(db.reader->GetF8()); | |||||
| } | |||||
| else { | |||||
| throw DeadlyImportError("Unknown source for conversion to primitive data type: "+in.name); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| template <> inline void Structure :: Convert<int> (int& dest,const FileDatabase& db) const | |||||
| { | |||||
| ConvertDispatcher(dest,*this,db); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| template <> inline void Structure :: Convert<short> (short& dest,const FileDatabase& db) const | |||||
| { | |||||
| // automatic rescaling from short to float and vice versa (seems to be used by normals) | |||||
| if (name == "float") { | |||||
| dest = static_cast<short>(db.reader->GetF4() * 32767.f); | |||||
| //db.reader->IncPtr(-4); | |||||
| return; | |||||
| } | |||||
| else if (name == "double") { | |||||
| dest = static_cast<short>(db.reader->GetF8() * 32767.); | |||||
| //db.reader->IncPtr(-8); | |||||
| return; | |||||
| } | |||||
| ConvertDispatcher(dest,*this,db); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| template <> inline void Structure :: Convert<char> (char& dest,const FileDatabase& db) const | |||||
| { | |||||
| // automatic rescaling from char to float and vice versa (seems useful for RGB colors) | |||||
| if (name == "float") { | |||||
| dest = static_cast<char>(db.reader->GetF4() * 255.f); | |||||
| return; | |||||
| } | |||||
| else if (name == "double") { | |||||
| dest = static_cast<char>(db.reader->GetF8() * 255.f); | |||||
| return; | |||||
| } | |||||
| ConvertDispatcher(dest,*this,db); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| template <> inline void Structure :: Convert<float> (float& dest,const FileDatabase& db) const | |||||
| { | |||||
| // automatic rescaling from char to float and vice versa (seems useful for RGB colors) | |||||
| if (name == "char") { | |||||
| dest = db.reader->GetI1() / 255.f; | |||||
| return; | |||||
| } | |||||
| // automatic rescaling from short to float and vice versa (used by normals) | |||||
| else if (name == "short") { | |||||
| dest = db.reader->GetI2() / 32767.f; | |||||
| return; | |||||
| } | |||||
| ConvertDispatcher(dest,*this,db); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| template <> inline void Structure :: Convert<double> (double& dest,const FileDatabase& db) const | |||||
| { | |||||
| if (name == "char") { | |||||
| dest = db.reader->GetI1() / 255.; | |||||
| return; | |||||
| } | |||||
| else if (name == "short") { | |||||
| dest = db.reader->GetI2() / 32767.; | |||||
| return; | |||||
| } | |||||
| ConvertDispatcher(dest,*this,db); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| template <> inline void Structure :: Convert<Pointer> (Pointer& dest,const FileDatabase& db) const | |||||
| { | |||||
| if (db.i64bit) { | |||||
| dest.val = db.reader->GetU8(); | |||||
| //db.reader->IncPtr(-8); | |||||
| return; | |||||
| } | |||||
| dest.val = db.reader->GetU4(); | |||||
| //db.reader->IncPtr(-4); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| const Structure& DNA :: operator [] (const std::string& ss) const | |||||
| { | |||||
| std::map<std::string, size_t>::const_iterator it = indices.find(ss); | |||||
| if (it == indices.end()) { | |||||
| throw Error((Formatter::format(), | |||||
| "BlendDNA: Did not find a structure named `",ss,"`" | |||||
| )); | |||||
| } | |||||
| return structures[(*it).second]; | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| const Structure* DNA :: Get (const std::string& ss) const | |||||
| { | |||||
| std::map<std::string, size_t>::const_iterator it = indices.find(ss); | |||||
| return it == indices.end() ? NULL : &structures[(*it).second]; | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| const Structure& DNA :: operator [] (const size_t i) const | |||||
| { | |||||
| if (i >= structures.size()) { | |||||
| throw Error((Formatter::format(), | |||||
| "BlendDNA: There is no structure with index `",i,"`" | |||||
| )); | |||||
| } | |||||
| return structures[i]; | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <template <typename> class TOUT> template <typename T> void ObjectCache<TOUT> :: get ( | |||||
| const Structure& s, | |||||
| TOUT<T>& out, | |||||
| const Pointer& ptr | |||||
| ) const { | |||||
| if(s.cache_idx == static_cast<size_t>(-1)) { | |||||
| s.cache_idx = db.next_cache_idx++; | |||||
| caches.resize(db.next_cache_idx); | |||||
| return; | |||||
| } | |||||
| typename StructureCache::const_iterator it = caches[s.cache_idx].find(ptr); | |||||
| if (it != caches[s.cache_idx].end()) { | |||||
| out = boost::static_pointer_cast<T>( (*it).second ); | |||||
| #ifndef ASSIMP_BUILD_BLENDER_NO_STATS | |||||
| ++db.stats().cache_hits; | |||||
| #endif | |||||
| } | |||||
| // otherwise, out remains untouched | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <template <typename> class TOUT> template <typename T> void ObjectCache<TOUT> :: set ( | |||||
| const Structure& s, | |||||
| const TOUT<T>& out, | |||||
| const Pointer& ptr | |||||
| ) { | |||||
| if(s.cache_idx == static_cast<size_t>(-1)) { | |||||
| s.cache_idx = db.next_cache_idx++; | |||||
| caches.resize(db.next_cache_idx); | |||||
| } | |||||
| caches[s.cache_idx][ptr] = boost::static_pointer_cast<ElemBase>( out ); | |||||
| #ifndef ASSIMP_BUILD_BLENDER_NO_STATS | |||||
| ++db.stats().cached_objects; | |||||
| #endif | |||||
| } | |||||
| }} | |||||
| #endif | |||||
| @@ -0,0 +1,183 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file BlenderIntermediate.h | |||||
| * @brief Internal utility structures for the BlenderLoader. It also serves | |||||
| * as master include file for the whole (internal) Blender subsystem. | |||||
| */ | |||||
| #ifndef INCLUDED_AI_BLEND_INTERMEDIATE_H | |||||
| #define INCLUDED_AI_BLEND_INTERMEDIATE_H | |||||
| #include "BlenderLoader.h" | |||||
| #include "BlenderDNA.h" | |||||
| #include "BlenderScene.h" | |||||
| #include "BlenderSceneGen.h" | |||||
| #define for_each(x,y) BOOST_FOREACH(x,y) | |||||
| namespace Assimp { | |||||
| namespace Blender { | |||||
| // -------------------------------------------------------------------- | |||||
| /** Mini smart-array to avoid pulling in even more boost stuff. usable with vector and deque */ | |||||
| // -------------------------------------------------------------------- | |||||
| template <template <typename,typename> class TCLASS, typename T> | |||||
| struct TempArray { | |||||
| typedef TCLASS< T*,std::allocator<T*> > mywrap; | |||||
| TempArray() { | |||||
| } | |||||
| ~TempArray () { | |||||
| for_each(T* elem, arr) { | |||||
| delete elem; | |||||
| } | |||||
| } | |||||
| void dismiss() { | |||||
| arr.clear(); | |||||
| } | |||||
| mywrap* operator -> () { | |||||
| return &arr; | |||||
| } | |||||
| operator mywrap& () { | |||||
| return arr; | |||||
| } | |||||
| operator const mywrap& () const { | |||||
| return arr; | |||||
| } | |||||
| mywrap& get () { | |||||
| return arr; | |||||
| } | |||||
| const mywrap& get () const { | |||||
| return arr; | |||||
| } | |||||
| T* operator[] (size_t idx) const { | |||||
| return arr[idx]; | |||||
| } | |||||
| T*& operator[] (size_t idx) { | |||||
| return arr[idx]; | |||||
| } | |||||
| private: | |||||
| // no copy semantics | |||||
| void operator= (const TempArray&) { | |||||
| } | |||||
| TempArray(const TempArray& arr) { | |||||
| } | |||||
| private: | |||||
| mywrap arr; | |||||
| }; | |||||
| #ifdef _MSC_VER | |||||
| # pragma warning(disable:4351) | |||||
| #endif | |||||
| // -------------------------------------------------------------------- | |||||
| /** ConversionData acts as intermediate storage location for | |||||
| * the various ConvertXXX routines in BlenderImporter.*/ | |||||
| // -------------------------------------------------------------------- | |||||
| struct ConversionData | |||||
| { | |||||
| ConversionData(const FileDatabase& db) | |||||
| : sentinel_cnt() | |||||
| , next_texture() | |||||
| , db(db) | |||||
| {} | |||||
| std::set<const Object*> objects; | |||||
| TempArray <std::vector, aiMesh> meshes; | |||||
| TempArray <std::vector, aiCamera> cameras; | |||||
| TempArray <std::vector, aiLight> lights; | |||||
| TempArray <std::vector, aiMaterial> materials; | |||||
| TempArray <std::vector, aiTexture> textures; | |||||
| // set of all materials referenced by at least one mesh in the scene | |||||
| std::deque< boost::shared_ptr< Material > > materials_raw; | |||||
| // counter to name sentinel textures inserted as substitutes for procedural textures. | |||||
| unsigned int sentinel_cnt; | |||||
| // next texture ID for each texture type, respectively | |||||
| unsigned int next_texture[aiTextureType_UNKNOWN+1]; | |||||
| // original file data | |||||
| const FileDatabase& db; | |||||
| }; | |||||
| #ifdef _MSC_VER | |||||
| # pragma warning(default:4351) | |||||
| #endif | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| inline const char* GetTextureTypeDisplayString(Tex::Type t) | |||||
| { | |||||
| switch (t) { | |||||
| case Tex::Type_CLOUDS : return "Clouds"; | |||||
| case Tex::Type_WOOD : return "Wood"; | |||||
| case Tex::Type_MARBLE : return "Marble"; | |||||
| case Tex::Type_MAGIC : return "Magic"; | |||||
| case Tex::Type_BLEND : return "Blend"; | |||||
| case Tex::Type_STUCCI : return "Stucci"; | |||||
| case Tex::Type_NOISE : return "Noise"; | |||||
| case Tex::Type_PLUGIN : return "Plugin"; | |||||
| case Tex::Type_MUSGRAVE : return "Musgrave"; | |||||
| case Tex::Type_VORONOI : return "Voronoi"; | |||||
| case Tex::Type_DISTNOISE : return "DistortedNoise"; | |||||
| case Tex::Type_ENVMAP : return "EnvMap"; | |||||
| case Tex::Type_IMAGE : return "Image"; | |||||
| default: | |||||
| break; | |||||
| } | |||||
| return "<Unknown>"; | |||||
| } | |||||
| } // ! Blender | |||||
| } // ! Assimp | |||||
| #endif // ! INCLUDED_AI_BLEND_INTERMEDIATE_H | |||||
| @@ -0,0 +1,223 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file BlenderLoader.h | |||||
| * @brief Declaration of the Blender 3D (*.blend) importer class. | |||||
| */ | |||||
| #ifndef INCLUDED_AI_BLEND_LOADER_H | |||||
| #define INCLUDED_AI_BLEND_LOADER_H | |||||
| #include "BaseImporter.h" | |||||
| #include "LogAux.h" | |||||
| namespace Assimp { | |||||
| // TinyFormatter.h | |||||
| namespace Formatter { | |||||
| template <typename T,typename TR, typename A> class basic_formatter; | |||||
| typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format; | |||||
| } | |||||
| // BlenderDNA.h | |||||
| namespace Blender { | |||||
| class FileDatabase; | |||||
| struct ElemBase; | |||||
| } | |||||
| // BlenderScene.h | |||||
| namespace Blender { | |||||
| struct Scene; | |||||
| struct Object; | |||||
| struct Mesh; | |||||
| struct Camera; | |||||
| struct Lamp; | |||||
| struct MTex; | |||||
| struct Image; | |||||
| struct Material; | |||||
| } | |||||
| // BlenderIntermediate.h | |||||
| namespace Blender { | |||||
| struct ConversionData; | |||||
| template <template <typename,typename> class TCLASS, typename T> struct TempArray; | |||||
| } | |||||
| // BlenderModifier.h | |||||
| namespace Blender { | |||||
| class BlenderModifierShowcase; | |||||
| class BlenderModifier; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------- | |||||
| /** Load blenders official binary format. The actual file structure (the `DNA` how they | |||||
| * call it is outsourced to BlenderDNA.cpp/BlenderDNA.h. This class only performs the | |||||
| * conversion from intermediate format to aiScene. */ | |||||
| // ------------------------------------------------------------------------------------------- | |||||
| class BlenderImporter : public BaseImporter, public LogFunctions<BlenderImporter> | |||||
| { | |||||
| public: | |||||
| BlenderImporter(); | |||||
| ~BlenderImporter(); | |||||
| public: | |||||
| // -------------------- | |||||
| bool CanRead( const std::string& pFile, | |||||
| IOSystem* pIOHandler, | |||||
| bool checkSig | |||||
| ) const; | |||||
| protected: | |||||
| // -------------------- | |||||
| const aiImporterDesc* GetInfo () const; | |||||
| // -------------------- | |||||
| void GetExtensionList(std::set<std::string>& app); | |||||
| // -------------------- | |||||
| void SetupProperties(const Importer* pImp); | |||||
| // -------------------- | |||||
| void InternReadFile( const std::string& pFile, | |||||
| aiScene* pScene, | |||||
| IOSystem* pIOHandler | |||||
| ); | |||||
| // -------------------- | |||||
| void ParseBlendFile(Blender::FileDatabase& out, | |||||
| boost::shared_ptr<IOStream> stream | |||||
| ); | |||||
| // -------------------- | |||||
| void ExtractScene(Blender::Scene& out, | |||||
| const Blender::FileDatabase& file | |||||
| ); | |||||
| // -------------------- | |||||
| void ConvertBlendFile(aiScene* out, | |||||
| const Blender::Scene& in, | |||||
| const Blender::FileDatabase& file | |||||
| ); | |||||
| private: | |||||
| // -------------------- | |||||
| aiNode* ConvertNode(const Blender::Scene& in, | |||||
| const Blender::Object* obj, | |||||
| Blender::ConversionData& conv_info, | |||||
| const aiMatrix4x4& parentTransform | |||||
| ); | |||||
| // -------------------- | |||||
| void ConvertMesh(const Blender::Scene& in, | |||||
| const Blender::Object* obj, | |||||
| const Blender::Mesh* mesh, | |||||
| Blender::ConversionData& conv_data, | |||||
| Blender::TempArray<std::vector,aiMesh>& temp | |||||
| ); | |||||
| // -------------------- | |||||
| aiLight* ConvertLight(const Blender::Scene& in, | |||||
| const Blender::Object* obj, | |||||
| const Blender::Lamp* mesh, | |||||
| Blender::ConversionData& conv_data | |||||
| ); | |||||
| // -------------------- | |||||
| aiCamera* ConvertCamera(const Blender::Scene& in, | |||||
| const Blender::Object* obj, | |||||
| const Blender::Camera* mesh, | |||||
| Blender::ConversionData& conv_data | |||||
| ); | |||||
| // -------------------- | |||||
| void BuildMaterials( | |||||
| Blender::ConversionData& conv_data | |||||
| ) ; | |||||
| // -------------------- | |||||
| void ResolveTexture( | |||||
| aiMaterial* out, | |||||
| const Blender::Material* mat, | |||||
| const Blender::MTex* tex, | |||||
| Blender::ConversionData& conv_data | |||||
| ); | |||||
| // -------------------- | |||||
| void ResolveImage( | |||||
| aiMaterial* out, | |||||
| const Blender::Material* mat, | |||||
| const Blender::MTex* tex, | |||||
| const Blender::Image* img, | |||||
| Blender::ConversionData& conv_data | |||||
| ); | |||||
| void AddSentinelTexture( | |||||
| aiMaterial* out, | |||||
| const Blender::Material* mat, | |||||
| const Blender::MTex* tex, | |||||
| Blender::ConversionData& conv_data | |||||
| ); | |||||
| private: // static stuff, mostly logging and error reporting. | |||||
| // -------------------- | |||||
| static void CheckActualType(const Blender::ElemBase* dt, | |||||
| const char* check | |||||
| ); | |||||
| // -------------------- | |||||
| static void NotSupportedObjectType(const Blender::Object* obj, | |||||
| const char* type | |||||
| ); | |||||
| private: | |||||
| Blender::BlenderModifierShowcase* modifier_cache; | |||||
| }; // !class BlenderImporter | |||||
| } // end of namespace Assimp | |||||
| #endif // AI_UNREALIMPORTER_H_INC | |||||
| @@ -0,0 +1,324 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file BlenderModifier.cpp | |||||
| * @brief Implementation of some blender modifiers (i.e subdivision, mirror). | |||||
| */ | |||||
| #include "AssimpPCH.h" | |||||
| #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER | |||||
| #include "BlenderModifier.h" | |||||
| #include "SceneCombiner.h" | |||||
| #include "Subdivision.h" | |||||
| #include <functional> | |||||
| using namespace Assimp; | |||||
| using namespace Assimp::Blender; | |||||
| template <typename T> BlenderModifier* god() { | |||||
| return new T(); | |||||
| } | |||||
| // add all available modifiers here | |||||
| typedef BlenderModifier* (*fpCreateModifier)(); | |||||
| static const fpCreateModifier creators[] = { | |||||
| &god<BlenderModifier_Mirror>, | |||||
| &god<BlenderModifier_Subdivision>, | |||||
| NULL // sentinel | |||||
| }; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // just testing out some new macros to simplify logging | |||||
| #define ASSIMP_LOG_WARN_F(string,...)\ | |||||
| DefaultLogger::get()->warn((Formatter::format(string),__VA_ARGS__)) | |||||
| #define ASSIMP_LOG_ERROR_F(string,...)\ | |||||
| DefaultLogger::get()->error((Formatter::format(string),__VA_ARGS__)) | |||||
| #define ASSIMP_LOG_DEBUG_F(string,...)\ | |||||
| DefaultLogger::get()->debug((Formatter::format(string),__VA_ARGS__)) | |||||
| #define ASSIMP_LOG_INFO_F(string,...)\ | |||||
| DefaultLogger::get()->info((Formatter::format(string),__VA_ARGS__)) | |||||
| #define ASSIMP_LOG_WARN(string)\ | |||||
| DefaultLogger::get()->warn(string) | |||||
| #define ASSIMP_LOG_ERROR(string)\ | |||||
| DefaultLogger::get()->error(string) | |||||
| #define ASSIMP_LOG_DEBUG(string)\ | |||||
| DefaultLogger::get()->debug(string) | |||||
| #define ASSIMP_LOG_INFO(string)\ | |||||
| DefaultLogger::get()->info(string) | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| struct SharedModifierData : ElemBase | |||||
| { | |||||
| ModifierData modifier; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderModifierShowcase::ApplyModifiers(aiNode& out, ConversionData& conv_data, const Scene& in, const Object& orig_object ) | |||||
| { | |||||
| size_t cnt = 0u, ful = 0u; | |||||
| // NOTE: this cast is potentially unsafe by design, so we need to perform type checks before | |||||
| // we're allowed to dereference the pointers without risking to crash. We might still be | |||||
| // invoking UB btw - we're assuming that the ModifierData member of the respective modifier | |||||
| // structures is at offset sizeof(vftable) with no padding. | |||||
| const SharedModifierData* cur = boost::static_pointer_cast<const SharedModifierData> ( orig_object.modifiers.first.get() ); | |||||
| for (; cur; cur = boost::static_pointer_cast<const SharedModifierData> ( cur->modifier.next.get() ), ++ful) { | |||||
| ai_assert(cur->dna_type); | |||||
| const Structure* s = conv_data.db.dna.Get( cur->dna_type ); | |||||
| if (!s) { | |||||
| ASSIMP_LOG_WARN_F("BlendModifier: could not resolve DNA name: ",cur->dna_type); | |||||
| continue; | |||||
| } | |||||
| // this is a common trait of all XXXMirrorData structures in BlenderDNA | |||||
| const Field* f = s->Get("modifier"); | |||||
| if (!f || f->offset != 0) { | |||||
| ASSIMP_LOG_WARN("BlendModifier: expected a `modifier` member at offset 0"); | |||||
| continue; | |||||
| } | |||||
| s = conv_data.db.dna.Get( f->type ); | |||||
| if (!s || s->name != "ModifierData") { | |||||
| ASSIMP_LOG_WARN("BlendModifier: expected a ModifierData structure as first member"); | |||||
| continue; | |||||
| } | |||||
| // now, we can be sure that we should be fine to dereference *cur* as | |||||
| // ModifierData (with the above note). | |||||
| const ModifierData& dat = cur->modifier; | |||||
| const fpCreateModifier* curgod = creators; | |||||
| std::vector< BlenderModifier* >::iterator curmod = cached_modifiers->begin(), endmod = cached_modifiers->end(); | |||||
| for (;*curgod;++curgod,++curmod) { // allocate modifiers on the fly | |||||
| if (curmod == endmod) { | |||||
| cached_modifiers->push_back((*curgod)()); | |||||
| endmod = cached_modifiers->end(); | |||||
| curmod = endmod-1; | |||||
| } | |||||
| BlenderModifier* const modifier = *curmod; | |||||
| if(modifier->IsActive(dat)) { | |||||
| modifier->DoIt(out,conv_data,*boost::static_pointer_cast<const ElemBase>(cur),in,orig_object); | |||||
| cnt++; | |||||
| curgod = NULL; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (curgod) { | |||||
| ASSIMP_LOG_WARN_F("Couldn't find a handler for modifier: ",dat.name); | |||||
| } | |||||
| } | |||||
| // Even though we managed to resolve some or all of the modifiers on this | |||||
| // object, we still can't say whether our modifier implementations were | |||||
| // able to fully do their job. | |||||
| if (ful) { | |||||
| ASSIMP_LOG_DEBUG_F("BlendModifier: found handlers for ",cnt," of ",ful," modifiers on `",orig_object.id.name, | |||||
| "`, check log messages above for errors"); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| bool BlenderModifier_Mirror :: IsActive (const ModifierData& modin) | |||||
| { | |||||
| return modin.type == ModifierData::eModifierType_Mirror; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderModifier_Mirror :: DoIt(aiNode& out, ConversionData& conv_data, const ElemBase& orig_modifier, | |||||
| const Scene& /*in*/, | |||||
| const Object& orig_object ) | |||||
| { | |||||
| // hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers() | |||||
| const MirrorModifierData& mir = static_cast<const MirrorModifierData&>(orig_modifier); | |||||
| ai_assert(mir.modifier.type == ModifierData::eModifierType_Mirror); | |||||
| conv_data.meshes->reserve(conv_data.meshes->size() + out.mNumMeshes); | |||||
| // XXX not entirely correct, mirroring on two axes results in 4 distinct objects in blender ... | |||||
| // take all input meshes and clone them | |||||
| for (unsigned int i = 0; i < out.mNumMeshes; ++i) { | |||||
| aiMesh* mesh; | |||||
| SceneCombiner::Copy(&mesh,conv_data.meshes[out.mMeshes[i]]); | |||||
| const float xs = mir.flag & MirrorModifierData::Flags_AXIS_X ? -1.f : 1.f; | |||||
| const float ys = mir.flag & MirrorModifierData::Flags_AXIS_Y ? -1.f : 1.f; | |||||
| const float zs = mir.flag & MirrorModifierData::Flags_AXIS_Z ? -1.f : 1.f; | |||||
| if (mir.mirror_ob) { | |||||
| const aiVector3D center( mir.mirror_ob->obmat[3][0],mir.mirror_ob->obmat[3][1],mir.mirror_ob->obmat[3][2] ); | |||||
| for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { | |||||
| aiVector3D& v = mesh->mVertices[i]; | |||||
| v.x = center.x + xs*(center.x - v.x); | |||||
| v.y = center.y + ys*(center.y - v.y); | |||||
| v.z = center.z + zs*(center.z - v.z); | |||||
| } | |||||
| } | |||||
| else { | |||||
| for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { | |||||
| aiVector3D& v = mesh->mVertices[i]; | |||||
| v.x *= xs;v.y *= ys;v.z *= zs; | |||||
| } | |||||
| } | |||||
| if (mesh->mNormals) { | |||||
| for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { | |||||
| aiVector3D& v = mesh->mNormals[i]; | |||||
| v.x *= xs;v.y *= ys;v.z *= zs; | |||||
| } | |||||
| } | |||||
| if (mesh->mTangents) { | |||||
| for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { | |||||
| aiVector3D& v = mesh->mTangents[i]; | |||||
| v.x *= xs;v.y *= ys;v.z *= zs; | |||||
| } | |||||
| } | |||||
| if (mesh->mBitangents) { | |||||
| for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { | |||||
| aiVector3D& v = mesh->mBitangents[i]; | |||||
| v.x *= xs;v.y *= ys;v.z *= zs; | |||||
| } | |||||
| } | |||||
| const float us = mir.flag & MirrorModifierData::Flags_MIRROR_U ? -1.f : 1.f; | |||||
| const float vs = mir.flag & MirrorModifierData::Flags_MIRROR_V ? -1.f : 1.f; | |||||
| for (unsigned int n = 0; mesh->HasTextureCoords(n); ++n) { | |||||
| for (unsigned int i = 0; i < mesh->mNumVertices; ++i) { | |||||
| aiVector3D& v = mesh->mTextureCoords[n][i]; | |||||
| v.x *= us;v.y *= vs; | |||||
| } | |||||
| } | |||||
| // Only reverse the winding order if an odd number of axes were mirrored. | |||||
| if (xs * ys * zs < 0) { | |||||
| for( unsigned int i = 0; i < mesh->mNumFaces; i++) { | |||||
| aiFace& face = mesh->mFaces[i]; | |||||
| for( unsigned int fi = 0; fi < face.mNumIndices / 2; ++fi) | |||||
| std::swap( face.mIndices[fi], face.mIndices[face.mNumIndices - 1 - fi]); | |||||
| } | |||||
| } | |||||
| conv_data.meshes->push_back(mesh); | |||||
| } | |||||
| unsigned int* nind = new unsigned int[out.mNumMeshes*2]; | |||||
| 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)); | |||||
| delete[] out.mMeshes; | |||||
| out.mMeshes = nind; | |||||
| out.mNumMeshes *= 2; | |||||
| ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Mirror` modifier to `", | |||||
| orig_object.id.name,"`"); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| bool BlenderModifier_Subdivision :: IsActive (const ModifierData& modin) | |||||
| { | |||||
| return modin.type == ModifierData::eModifierType_Subsurf; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderModifier_Subdivision :: DoIt(aiNode& out, ConversionData& conv_data, const ElemBase& orig_modifier, | |||||
| const Scene& /*in*/, | |||||
| const Object& orig_object ) | |||||
| { | |||||
| // hijacking the ABI, see the big note in BlenderModifierShowcase::ApplyModifiers() | |||||
| const SubsurfModifierData& mir = static_cast<const SubsurfModifierData&>(orig_modifier); | |||||
| ai_assert(mir.modifier.type == ModifierData::eModifierType_Subsurf); | |||||
| Subdivider::Algorithm algo; | |||||
| switch (mir.subdivType) | |||||
| { | |||||
| case SubsurfModifierData::TYPE_CatmullClarke: | |||||
| algo = Subdivider::CATMULL_CLARKE; | |||||
| break; | |||||
| case SubsurfModifierData::TYPE_Simple: | |||||
| ASSIMP_LOG_WARN("BlendModifier: The `SIMPLE` subdivision algorithm is not currently implemented, using Catmull-Clarke"); | |||||
| algo = Subdivider::CATMULL_CLARKE; | |||||
| break; | |||||
| default: | |||||
| ASSIMP_LOG_WARN_F("BlendModifier: Unrecognized subdivision algorithm: ",mir.subdivType); | |||||
| return; | |||||
| }; | |||||
| boost::scoped_ptr<Subdivider> subd(Subdivider::Create(algo)); | |||||
| ai_assert(subd); | |||||
| aiMesh** const meshes = &conv_data.meshes[conv_data.meshes->size() - out.mNumMeshes]; | |||||
| boost::scoped_array<aiMesh*> tempmeshes(new aiMesh*[out.mNumMeshes]()); | |||||
| subd->Subdivide(meshes,out.mNumMeshes,tempmeshes.get(),std::max( mir.renderLevels, mir.levels ),true); | |||||
| std::copy(tempmeshes.get(),tempmeshes.get()+out.mNumMeshes,meshes); | |||||
| ASSIMP_LOG_INFO_F("BlendModifier: Applied the `Subdivision` modifier to `", | |||||
| orig_object.id.name,"`"); | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,155 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file BlenderModifier.h | |||||
| * @brief Declare dedicated helper classes to simulate some blender modifiers (i.e. mirror) | |||||
| */ | |||||
| #ifndef INCLUDED_AI_BLEND_MODIFIER_H | |||||
| #define INCLUDED_AI_BLEND_MODIFIER_H | |||||
| #include "BlenderIntermediate.h" | |||||
| #include "TinyFormatter.h" | |||||
| namespace Assimp { | |||||
| namespace Blender { | |||||
| // ------------------------------------------------------------------------------------------- | |||||
| /** Dummy base class for all blender modifiers. Modifiers are reused between imports, so | |||||
| * they should be stateless and not try to cache model data. */ | |||||
| // ------------------------------------------------------------------------------------------- | |||||
| class BlenderModifier | |||||
| { | |||||
| public: | |||||
| virtual ~BlenderModifier() { | |||||
| } | |||||
| public: | |||||
| // -------------------- | |||||
| /** Check if *this* modifier is active, given a ModifierData& block.*/ | |||||
| virtual bool IsActive( const ModifierData& /*modin*/) { | |||||
| return false; | |||||
| } | |||||
| // -------------------- | |||||
| /** Apply the modifier to a given output node. The original data used | |||||
| * to construct the node is given as well. Not called unless IsActive() | |||||
| * was called and gave positive response. */ | |||||
| virtual void DoIt(aiNode& /*out*/, | |||||
| ConversionData& /*conv_data*/, | |||||
| const ElemBase& orig_modifier, | |||||
| const Scene& /*in*/, | |||||
| const Object& /*orig_object*/ | |||||
| ) { | |||||
| DefaultLogger::get()->warn((Formatter::format("This modifier is not supported, skipping: "),orig_modifier.dna_type)); | |||||
| return; | |||||
| } | |||||
| }; | |||||
| // ------------------------------------------------------------------------------------------- | |||||
| /** Manage all known modifiers and instance and apply them if necessary */ | |||||
| // ------------------------------------------------------------------------------------------- | |||||
| class BlenderModifierShowcase | |||||
| { | |||||
| public: | |||||
| // -------------------- | |||||
| /** Apply all requested modifiers provided we support them. */ | |||||
| void ApplyModifiers(aiNode& out, | |||||
| ConversionData& conv_data, | |||||
| const Scene& in, | |||||
| const Object& orig_object | |||||
| ); | |||||
| private: | |||||
| TempArray< std::vector,BlenderModifier > cached_modifiers; | |||||
| }; | |||||
| // MODIFIERS | |||||
| // ------------------------------------------------------------------------------------------- | |||||
| /** Mirror modifier. Status: implemented. */ | |||||
| // ------------------------------------------------------------------------------------------- | |||||
| class BlenderModifier_Mirror : public BlenderModifier | |||||
| { | |||||
| public: | |||||
| // -------------------- | |||||
| virtual bool IsActive( const ModifierData& modin); | |||||
| // -------------------- | |||||
| virtual void DoIt(aiNode& out, | |||||
| ConversionData& conv_data, | |||||
| const ElemBase& orig_modifier, | |||||
| const Scene& in, | |||||
| const Object& orig_object | |||||
| ) ; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------------------- | |||||
| /** Subdivision modifier. Status: dummy. */ | |||||
| // ------------------------------------------------------------------------------------------- | |||||
| class BlenderModifier_Subdivision : public BlenderModifier | |||||
| { | |||||
| public: | |||||
| // -------------------- | |||||
| virtual bool IsActive( const ModifierData& modin); | |||||
| // -------------------- | |||||
| virtual void DoIt(aiNode& out, | |||||
| ConversionData& conv_data, | |||||
| const ElemBase& orig_modifier, | |||||
| const Scene& in, | |||||
| const Object& orig_object | |||||
| ) ; | |||||
| }; | |||||
| }} | |||||
| #endif // !INCLUDED_AI_BLEND_MODIFIER_H | |||||
| @@ -0,0 +1,716 @@ | |||||
| /* | |||||
| Open Asset Import Library (ASSIMP) | |||||
| ---------------------------------------------------------------------- | |||||
| Copyright (c) 2006-2010, ASSIMP Development 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 Development 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 BlenderScene.cpp | |||||
| * @brief MACHINE GENERATED BY ./scripts/BlenderImporter/genblenddna.py | |||||
| */ | |||||
| #include "AssimpPCH.h" | |||||
| #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER | |||||
| #include "BlenderDNA.h" | |||||
| #include "BlenderScene.h" | |||||
| #include "BlenderSceneGen.h" | |||||
| using namespace Assimp; | |||||
| using namespace Assimp::Blender; | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<Object> ( | |||||
| Object& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Fail>(dest.id,"id",db); | |||||
| ReadField<ErrorPolicy_Fail>((int&)dest.type,"type",db); | |||||
| ReadFieldArray2<ErrorPolicy_Warn>(dest.obmat,"obmat",db); | |||||
| ReadFieldArray2<ErrorPolicy_Warn>(dest.parentinv,"parentinv",db); | |||||
| ReadFieldArray<ErrorPolicy_Warn>(dest.parsubstr,"parsubstr",db); | |||||
| { | |||||
| boost::shared_ptr<Object> parent; | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(parent,"*parent",db); | |||||
| dest.parent = parent.get(); | |||||
| } | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(dest.track,"*track",db); | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy,"*proxy",db); | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy_from,"*proxy_from",db); | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(dest.proxy_group,"*proxy_group",db); | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(dest.dup_group,"*dup_group",db); | |||||
| ReadFieldPtr<ErrorPolicy_Fail>(dest.data,"*data",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.modifiers,"modifiers",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<Group> ( | |||||
| Group& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Fail>(dest.id,"id",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.layer,"layer",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.gobject,"*gobject",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<MTex> ( | |||||
| MTex& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Igno>((short&)dest.mapto,"mapto",db); | |||||
| ReadField<ErrorPolicy_Igno>((int&)dest.blendtype,"blendtype",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.object,"*object",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.tex,"*tex",db); | |||||
| ReadFieldArray<ErrorPolicy_Igno>(dest.uvname,"uvname",db); | |||||
| ReadField<ErrorPolicy_Igno>((int&)dest.projx,"projx",db); | |||||
| ReadField<ErrorPolicy_Igno>((int&)dest.projy,"projy",db); | |||||
| ReadField<ErrorPolicy_Igno>((int&)dest.projz,"projz",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.mapping,"mapping",db); | |||||
| ReadFieldArray<ErrorPolicy_Igno>(dest.ofs,"ofs",db); | |||||
| ReadFieldArray<ErrorPolicy_Igno>(dest.size,"size",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.rot,"rot",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.texflag,"texflag",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.colormodel,"colormodel",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.pmapto,"pmapto",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.pmaptoneg,"pmaptoneg",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.r,"r",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.g,"g",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.b,"b",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.k,"k",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.colspecfac,"colspecfac",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.mirrfac,"mirrfac",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.alphafac,"alphafac",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.difffac,"difffac",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.specfac,"specfac",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.emitfac,"emitfac",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.hardfac,"hardfac",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.norfac,"norfac",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<TFace> ( | |||||
| TFace& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadFieldArray2<ErrorPolicy_Fail>(dest.uv,"uv",db); | |||||
| ReadFieldArray<ErrorPolicy_Fail>(dest.col,"col",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.mode,"mode",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.tile,"tile",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.unwrap,"unwrap",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<SubsurfModifierData> ( | |||||
| SubsurfModifierData& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Fail>(dest.modifier,"modifier",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.subdivType,"subdivType",db); | |||||
| ReadField<ErrorPolicy_Fail>(dest.levels,"levels",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.renderLevels,"renderLevels",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.flags,"flags",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<MFace> ( | |||||
| MFace& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Fail>(dest.v1,"v1",db); | |||||
| ReadField<ErrorPolicy_Fail>(dest.v2,"v2",db); | |||||
| ReadField<ErrorPolicy_Fail>(dest.v3,"v3",db); | |||||
| ReadField<ErrorPolicy_Fail>(dest.v4,"v4",db); | |||||
| ReadField<ErrorPolicy_Fail>(dest.mat_nr,"mat_nr",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<Lamp> ( | |||||
| Lamp& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Fail>(dest.id,"id",db); | |||||
| ReadField<ErrorPolicy_Fail>((int&)dest.type,"type",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.flags,"flags",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.colormodel,"colormodel",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.totex,"totex",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.r,"r",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.g,"g",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.b,"b",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.k,"k",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.energy,"energy",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.dist,"dist",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.spotsize,"spotsize",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.spotblend,"spotblend",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.att1,"att1",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.att2,"att2",db); | |||||
| ReadField<ErrorPolicy_Igno>((int&)dest.falloff_type,"falloff_type",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.sun_brightness,"sun_brightness",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<MDeformWeight> ( | |||||
| MDeformWeight& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Fail>(dest.def_nr,"def_nr",db); | |||||
| ReadField<ErrorPolicy_Fail>(dest.weight,"weight",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<PackedFile> ( | |||||
| PackedFile& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Warn>(dest.size,"size",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.seek,"seek",db); | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(dest.data,"*data",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<Base> ( | |||||
| Base& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| // note: as per https://github.com/assimp/assimp/issues/128, | |||||
| // reading the Object linked list recursively is prone to stack overflow. | |||||
| // This structure converter is therefore an hand-written exception that | |||||
| // does it iteratively. | |||||
| const int initial_pos = db.reader->GetCurrentPos(); | |||||
| std::pair<Base*, int> todo = std::make_pair(&dest, initial_pos); | |||||
| for ( ;; ) { | |||||
| Base& cur_dest = *todo.first; | |||||
| db.reader->SetCurrentPos(todo.second); | |||||
| // we know that this is a double-linked, circular list which we never | |||||
| // traverse backwards, so don't bother resolving the back links. | |||||
| cur_dest.prev = NULL; | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.object,"*object",db); | |||||
| // the return value of ReadFieldPtr indicates whether the object | |||||
| // was already cached. In this case, we don't need to resolve | |||||
| // it again. | |||||
| if(!ReadFieldPtr<ErrorPolicy_Warn>(cur_dest.next,"*next",db, true) && cur_dest.next) { | |||||
| todo = std::make_pair(&*cur_dest.next, db.reader->GetCurrentPos()); | |||||
| continue; | |||||
| } | |||||
| break; | |||||
| } | |||||
| db.reader->SetCurrentPos(initial_pos + size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<MTFace> ( | |||||
| MTFace& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadFieldArray2<ErrorPolicy_Fail>(dest.uv,"uv",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.mode,"mode",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.tile,"tile",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.unwrap,"unwrap",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<Material> ( | |||||
| Material& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Fail>(dest.id,"id",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.r,"r",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.g,"g",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.b,"b",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.specr,"specr",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.specg,"specg",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.specb,"specb",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.har,"har",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.ambr,"ambr",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.ambg,"ambg",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.ambb,"ambb",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.mirr,"mirr",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.mirg,"mirg",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.mirb,"mirb",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.emit,"emit",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.alpha,"alpha",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.ref,"ref",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.translucency,"translucency",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.roughness,"roughness",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.darkness,"darkness",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.refrac,"refrac",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.group,"*group",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.diff_shader,"diff_shader",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.spec_shader,"spec_shader",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.mtex,"*mtex",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<MTexPoly> ( | |||||
| MTexPoly& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| { | |||||
| boost::shared_ptr<Image> tpage; | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(tpage,"*tpage",db); | |||||
| dest.tpage = tpage.get(); | |||||
| } | |||||
| ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.transp,"transp",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.mode,"mode",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.tile,"tile",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.pad,"pad",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<Mesh> ( | |||||
| Mesh& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Fail>(dest.id,"id",db); | |||||
| ReadField<ErrorPolicy_Fail>(dest.totface,"totface",db); | |||||
| ReadField<ErrorPolicy_Fail>(dest.totedge,"totedge",db); | |||||
| ReadField<ErrorPolicy_Fail>(dest.totvert,"totvert",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.totloop,"totloop",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.totpoly,"totpoly",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.subdiv,"subdiv",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.subdivr,"subdivr",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.subsurftype,"subsurftype",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.smoothresh,"smoothresh",db); | |||||
| ReadFieldPtr<ErrorPolicy_Fail>(dest.mface,"*mface",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.mtface,"*mtface",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.tface,"*tface",db); | |||||
| ReadFieldPtr<ErrorPolicy_Fail>(dest.mvert,"*mvert",db); | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(dest.medge,"*medge",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.mloop,"*mloop",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.mloopuv,"*mloopuv",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.mloopcol,"*mloopcol",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.mpoly,"*mpoly",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.mtpoly,"*mtpoly",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.dvert,"*dvert",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.mcol,"*mcol",db); | |||||
| ReadFieldPtr<ErrorPolicy_Fail>(dest.mat,"**mat",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<MDeformVert> ( | |||||
| MDeformVert& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(dest.dw,"*dw",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.totweight,"totweight",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<World> ( | |||||
| World& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Fail>(dest.id,"id",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<MLoopCol> ( | |||||
| MLoopCol& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Igno>(dest.r,"r",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.g,"g",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.b,"b",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.a,"a",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<MVert> ( | |||||
| MVert& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadFieldArray<ErrorPolicy_Fail>(dest.co,"co",db); | |||||
| ReadFieldArray<ErrorPolicy_Fail>(dest.no,"no",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.mat_nr,"mat_nr",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.bweight,"bweight",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<MEdge> ( | |||||
| MEdge& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Fail>(dest.v1,"v1",db); | |||||
| ReadField<ErrorPolicy_Fail>(dest.v2,"v2",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.crease,"crease",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.bweight,"bweight",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<MLoopUV> ( | |||||
| MLoopUV& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadFieldArray<ErrorPolicy_Igno>(dest.uv,"uv",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<GroupObject> ( | |||||
| GroupObject& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadFieldPtr<ErrorPolicy_Fail>(dest.prev,"*prev",db); | |||||
| ReadFieldPtr<ErrorPolicy_Fail>(dest.next,"*next",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.ob,"*ob",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<ListBase> ( | |||||
| ListBase& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.first,"*first",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.last,"*last",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<MLoop> ( | |||||
| MLoop& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Igno>(dest.v,"v",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.e,"e",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<ModifierData> ( | |||||
| ModifierData& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(dest.next,"*next",db); | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(dest.prev,"*prev",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.type,"type",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.mode,"mode",db); | |||||
| ReadFieldArray<ErrorPolicy_Igno>(dest.name,"name",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<ID> ( | |||||
| ID& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadFieldArray<ErrorPolicy_Warn>(dest.name,"name",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<MCol> ( | |||||
| MCol& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Fail>(dest.r,"r",db); | |||||
| ReadField<ErrorPolicy_Fail>(dest.g,"g",db); | |||||
| ReadField<ErrorPolicy_Fail>(dest.b,"b",db); | |||||
| ReadField<ErrorPolicy_Fail>(dest.a,"a",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<MPoly> ( | |||||
| MPoly& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Igno>(dest.loopstart,"loopstart",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.totloop,"totloop",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.mat_nr,"mat_nr",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<Scene> ( | |||||
| Scene& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Fail>(dest.id,"id",db); | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(dest.camera,"*camera",db); | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(dest.world,"*world",db); | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(dest.basact,"*basact",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.base,"base",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<Library> ( | |||||
| Library& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Fail>(dest.id,"id",db); | |||||
| ReadFieldArray<ErrorPolicy_Warn>(dest.name,"name",db); | |||||
| ReadFieldArray<ErrorPolicy_Fail>(dest.filename,"filename",db); | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(dest.parent,"*parent",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<Tex> ( | |||||
| Tex& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Igno>((short&)dest.imaflag,"imaflag",db); | |||||
| ReadField<ErrorPolicy_Fail>((int&)dest.type,"type",db); | |||||
| ReadFieldPtr<ErrorPolicy_Warn>(dest.ima,"*ima",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<Camera> ( | |||||
| Camera& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Fail>(dest.id,"id",db); | |||||
| ReadField<ErrorPolicy_Warn>((int&)dest.type,"type",db); | |||||
| ReadField<ErrorPolicy_Warn>((int&)dest.flag,"flag",db); | |||||
| ReadField<ErrorPolicy_Warn>(dest.angle,"angle",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<MirrorModifierData> ( | |||||
| MirrorModifierData& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Fail>(dest.modifier,"modifier",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.axis,"axis",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.tolerance,"tolerance",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.mirror_ob,"*mirror_ob",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| template <> void Structure :: Convert<Image> ( | |||||
| Image& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| { | |||||
| ReadField<ErrorPolicy_Fail>(dest.id,"id",db); | |||||
| ReadFieldArray<ErrorPolicy_Warn>(dest.name,"name",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.ok,"ok",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.flag,"flag",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.source,"source",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.type,"type",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.pad,"pad",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.pad1,"pad1",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.lastframe,"lastframe",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.tpageflag,"tpageflag",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.totbind,"totbind",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.xrep,"xrep",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.yrep,"yrep",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.twsta,"twsta",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.twend,"twend",db); | |||||
| ReadFieldPtr<ErrorPolicy_Igno>(dest.packedfile,"*packedfile",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.lastupdate,"lastupdate",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.lastused,"lastused",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.animspeed,"animspeed",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.gen_x,"gen_x",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.gen_y,"gen_y",db); | |||||
| ReadField<ErrorPolicy_Igno>(dest.gen_type,"gen_type",db); | |||||
| db.reader->IncPtr(size); | |||||
| } | |||||
| //-------------------------------------------------------------------------------- | |||||
| void DNA::RegisterConverters() { | |||||
| converters["Object"] = DNA::FactoryPair( &Structure::Allocate<Object>, &Structure::Convert<Object> ); | |||||
| converters["Group"] = DNA::FactoryPair( &Structure::Allocate<Group>, &Structure::Convert<Group> ); | |||||
| converters["MTex"] = DNA::FactoryPair( &Structure::Allocate<MTex>, &Structure::Convert<MTex> ); | |||||
| converters["TFace"] = DNA::FactoryPair( &Structure::Allocate<TFace>, &Structure::Convert<TFace> ); | |||||
| converters["SubsurfModifierData"] = DNA::FactoryPair( &Structure::Allocate<SubsurfModifierData>, &Structure::Convert<SubsurfModifierData> ); | |||||
| converters["MFace"] = DNA::FactoryPair( &Structure::Allocate<MFace>, &Structure::Convert<MFace> ); | |||||
| converters["Lamp"] = DNA::FactoryPair( &Structure::Allocate<Lamp>, &Structure::Convert<Lamp> ); | |||||
| converters["MDeformWeight"] = DNA::FactoryPair( &Structure::Allocate<MDeformWeight>, &Structure::Convert<MDeformWeight> ); | |||||
| converters["PackedFile"] = DNA::FactoryPair( &Structure::Allocate<PackedFile>, &Structure::Convert<PackedFile> ); | |||||
| converters["Base"] = DNA::FactoryPair( &Structure::Allocate<Base>, &Structure::Convert<Base> ); | |||||
| converters["MTFace"] = DNA::FactoryPair( &Structure::Allocate<MTFace>, &Structure::Convert<MTFace> ); | |||||
| converters["Material"] = DNA::FactoryPair( &Structure::Allocate<Material>, &Structure::Convert<Material> ); | |||||
| converters["MTexPoly"] = DNA::FactoryPair( &Structure::Allocate<MTexPoly>, &Structure::Convert<MTexPoly> ); | |||||
| converters["Mesh"] = DNA::FactoryPair( &Structure::Allocate<Mesh>, &Structure::Convert<Mesh> ); | |||||
| converters["MDeformVert"] = DNA::FactoryPair( &Structure::Allocate<MDeformVert>, &Structure::Convert<MDeformVert> ); | |||||
| converters["World"] = DNA::FactoryPair( &Structure::Allocate<World>, &Structure::Convert<World> ); | |||||
| converters["MLoopCol"] = DNA::FactoryPair( &Structure::Allocate<MLoopCol>, &Structure::Convert<MLoopCol> ); | |||||
| converters["MVert"] = DNA::FactoryPair( &Structure::Allocate<MVert>, &Structure::Convert<MVert> ); | |||||
| converters["MEdge"] = DNA::FactoryPair( &Structure::Allocate<MEdge>, &Structure::Convert<MEdge> ); | |||||
| converters["MLoopUV"] = DNA::FactoryPair( &Structure::Allocate<MLoopUV>, &Structure::Convert<MLoopUV> ); | |||||
| converters["GroupObject"] = DNA::FactoryPair( &Structure::Allocate<GroupObject>, &Structure::Convert<GroupObject> ); | |||||
| converters["ListBase"] = DNA::FactoryPair( &Structure::Allocate<ListBase>, &Structure::Convert<ListBase> ); | |||||
| converters["MLoop"] = DNA::FactoryPair( &Structure::Allocate<MLoop>, &Structure::Convert<MLoop> ); | |||||
| converters["ModifierData"] = DNA::FactoryPair( &Structure::Allocate<ModifierData>, &Structure::Convert<ModifierData> ); | |||||
| converters["ID"] = DNA::FactoryPair( &Structure::Allocate<ID>, &Structure::Convert<ID> ); | |||||
| converters["MCol"] = DNA::FactoryPair( &Structure::Allocate<MCol>, &Structure::Convert<MCol> ); | |||||
| converters["MPoly"] = DNA::FactoryPair( &Structure::Allocate<MPoly>, &Structure::Convert<MPoly> ); | |||||
| converters["Scene"] = DNA::FactoryPair( &Structure::Allocate<Scene>, &Structure::Convert<Scene> ); | |||||
| converters["Library"] = DNA::FactoryPair( &Structure::Allocate<Library>, &Structure::Convert<Library> ); | |||||
| converters["Tex"] = DNA::FactoryPair( &Structure::Allocate<Tex>, &Structure::Convert<Tex> ); | |||||
| converters["Camera"] = DNA::FactoryPair( &Structure::Allocate<Camera>, &Structure::Convert<Camera> ); | |||||
| converters["MirrorModifierData"] = DNA::FactoryPair( &Structure::Allocate<MirrorModifierData>, &Structure::Convert<MirrorModifierData> ); | |||||
| converters["Image"] = DNA::FactoryPair( &Structure::Allocate<Image>, &Structure::Convert<Image> ); | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,757 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file BlenderScene.h | |||||
| * @brief Intermediate representation of a BLEND scene. | |||||
| */ | |||||
| #ifndef INCLUDED_AI_BLEND_SCENE_H | |||||
| #define INCLUDED_AI_BLEND_SCENE_H | |||||
| namespace Assimp { | |||||
| namespace Blender { | |||||
| // Minor parts of this file are extracts from blender data structures, | |||||
| // declared in the ./source/blender/makesdna directory. | |||||
| // Stuff that is not used by Assimp is commented. | |||||
| // NOTE | |||||
| // this file serves as input data to the `./scripts/genblenddna.py` | |||||
| // script. This script generates the actual binding code to read a | |||||
| // blender file with a possibly different DNA into our structures. | |||||
| // Only `struct` declarations are considered and the following | |||||
| // rules must be obeyed in order for the script to work properly: | |||||
| // | |||||
| // * C++ style comments only | |||||
| // | |||||
| // * Structures may include the primitive types char, int, short, | |||||
| // float, double. Signedness specifiers are not allowed on | |||||
| // integers. Enum types are allowed, but they must have been | |||||
| // defined in this header. | |||||
| // | |||||
| // * Structures may aggregate other structures, unless not defined | |||||
| // in this header. | |||||
| // | |||||
| // * Pointers to other structures or primitive types are allowed. | |||||
| // No references or double pointers or arrays of pointers. | |||||
| // A pointer to a T is normally written as boost::shared_ptr, while a | |||||
| // pointer to an array of elements is written as boost:: | |||||
| // shared_array. To avoid cyclic pointers, use raw pointers in | |||||
| // one direction. | |||||
| // | |||||
| // * Arrays can have maximally two-dimensions. Any non-pointer | |||||
| // type can form them. | |||||
| // | |||||
| // * Multiple fields can be declare in a single line (i.e `int a,b;`) | |||||
| // provided they are neither pointers nor arrays. | |||||
| // | |||||
| // * One of WARN, FAIL can be appended to the declaration ( | |||||
| // prior to the semiolon to specifiy the error handling policy if | |||||
| // this field is missing in the input DNA). If none of those | |||||
| // is specified the default policy is to subtitute a default | |||||
| // value for the field. | |||||
| // | |||||
| #define WARN // warn if field is missing, substitute default value | |||||
| #define FAIL // fail the import if the field does not exist | |||||
| struct Object; | |||||
| struct MTex; | |||||
| struct Image; | |||||
| #define AI_BLEND_MESH_MAX_VERTS 2000000000L | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct ID : ElemBase { | |||||
| char name[24] WARN; | |||||
| short flag; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct ListBase : ElemBase { | |||||
| boost::shared_ptr<ElemBase> first; | |||||
| boost::shared_ptr<ElemBase> last; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct PackedFile : ElemBase { | |||||
| int size WARN; | |||||
| int seek WARN; | |||||
| boost::shared_ptr< FileOffset > data WARN; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct GroupObject : ElemBase { | |||||
| boost::shared_ptr<GroupObject> prev,next FAIL; | |||||
| boost::shared_ptr<Object> ob; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct Group : ElemBase { | |||||
| ID id FAIL; | |||||
| int layer; | |||||
| boost::shared_ptr<GroupObject> gobject; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct World : ElemBase { | |||||
| ID id FAIL; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct MVert : ElemBase { | |||||
| float co[3] FAIL; | |||||
| float no[3] FAIL; | |||||
| char flag; | |||||
| int mat_nr WARN; | |||||
| int bweight; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct MEdge : ElemBase { | |||||
| int v1, v2 FAIL; | |||||
| char crease, bweight; | |||||
| short flag; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct MLoop : ElemBase { | |||||
| int v, e; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct MLoopUV : ElemBase { | |||||
| float uv[2]; | |||||
| int flag; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| // Note that red and blue are not swapped, as with MCol | |||||
| struct MLoopCol : ElemBase { | |||||
| char r, g, b, a; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct MPoly : ElemBase { | |||||
| int loopstart; | |||||
| int totloop; | |||||
| short mat_nr; | |||||
| char flag; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct MTexPoly : ElemBase { | |||||
| Image* tpage; | |||||
| char flag, transp; | |||||
| short mode, tile, pad; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct MCol : ElemBase { | |||||
| char r,g,b,a FAIL; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct MFace : ElemBase { | |||||
| int v1,v2,v3,v4 FAIL; | |||||
| int mat_nr FAIL; | |||||
| char flag; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct TFace : ElemBase { | |||||
| float uv[4][2] FAIL; | |||||
| int col[4] FAIL; | |||||
| char flag; | |||||
| short mode; | |||||
| short tile; | |||||
| short unwrap; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct MTFace : ElemBase { | |||||
| float uv[4][2] FAIL; | |||||
| char flag; | |||||
| short mode; | |||||
| short tile; | |||||
| short unwrap; | |||||
| // boost::shared_ptr<Image> tpage; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct MDeformWeight : ElemBase { | |||||
| int def_nr FAIL; | |||||
| float weight FAIL; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct MDeformVert : ElemBase { | |||||
| vector<MDeformWeight> dw WARN; | |||||
| int totweight; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct Material : ElemBase { | |||||
| ID id FAIL; | |||||
| float r,g,b WARN; | |||||
| float specr,specg,specb WARN; | |||||
| short har; | |||||
| float ambr,ambg,ambb WARN; | |||||
| float mirr,mirg,mirb; | |||||
| float emit WARN; | |||||
| float alpha WARN; | |||||
| float ref; | |||||
| float translucency; | |||||
| float roughness; | |||||
| float darkness; | |||||
| float refrac; | |||||
| boost::shared_ptr<Group> group; | |||||
| short diff_shader WARN; | |||||
| short spec_shader WARN; | |||||
| boost::shared_ptr<MTex> mtex[18]; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct Mesh : ElemBase { | |||||
| ID id FAIL; | |||||
| int totface FAIL; | |||||
| int totedge FAIL; | |||||
| int totvert FAIL; | |||||
| int totloop; | |||||
| int totpoly; | |||||
| short subdiv; | |||||
| short subdivr; | |||||
| short subsurftype; | |||||
| short smoothresh; | |||||
| vector<MFace> mface FAIL; | |||||
| vector<MTFace> mtface; | |||||
| vector<TFace> tface; | |||||
| vector<MVert> mvert FAIL; | |||||
| vector<MEdge> medge WARN; | |||||
| vector<MLoop> mloop; | |||||
| vector<MLoopUV> mloopuv; | |||||
| vector<MLoopCol> mloopcol; | |||||
| vector<MPoly> mpoly; | |||||
| vector<MTexPoly> mtpoly; | |||||
| vector<MDeformVert> dvert; | |||||
| vector<MCol> mcol; | |||||
| vector< boost::shared_ptr<Material> > mat FAIL; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct Library : ElemBase { | |||||
| ID id FAIL; | |||||
| char name[240] WARN; | |||||
| char filename[240] FAIL; | |||||
| boost::shared_ptr<Library> parent WARN; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct Camera : ElemBase { | |||||
| enum Type { | |||||
| Type_PERSP = 0 | |||||
| ,Type_ORTHO = 1 | |||||
| }; | |||||
| ID id FAIL; | |||||
| // struct AnimData *adt; | |||||
| Type type,flag WARN; | |||||
| float angle WARN; | |||||
| //float passepartalpha, angle; | |||||
| //float clipsta, clipend; | |||||
| //float lens, ortho_scale, drawsize; | |||||
| //float shiftx, shifty; | |||||
| //float YF_dofdist, YF_aperture; | |||||
| //short YF_bkhtype, YF_bkhbias; | |||||
| //float YF_bkhrot; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct Lamp : ElemBase { | |||||
| enum FalloffType { | |||||
| FalloffType_Constant = 0x0 | |||||
| ,FalloffType_InvLinear = 0x1 | |||||
| ,FalloffType_InvSquare = 0x2 | |||||
| //,FalloffType_Curve = 0x3 | |||||
| //,FalloffType_Sliders = 0x4 | |||||
| }; | |||||
| enum Type { | |||||
| Type_Local = 0x0 | |||||
| ,Type_Sun = 0x1 | |||||
| ,Type_Spot = 0x2 | |||||
| ,Type_Hemi = 0x3 | |||||
| ,Type_Area = 0x4 | |||||
| //,Type_YFPhoton = 0x5 | |||||
| }; | |||||
| ID id FAIL; | |||||
| //AnimData *adt; | |||||
| Type type FAIL; | |||||
| short flags; | |||||
| //int mode; | |||||
| short colormodel, totex; | |||||
| float r,g,b,k WARN; | |||||
| //float shdwr, shdwg, shdwb; | |||||
| float energy, dist, spotsize, spotblend; | |||||
| //float haint; | |||||
| float att1, att2; | |||||
| //struct CurveMapping *curfalloff; | |||||
| FalloffType falloff_type; | |||||
| //float clipsta, clipend, shadspotsize; | |||||
| //float bias, soft, compressthresh; | |||||
| //short bufsize, samp, buffers, filtertype; | |||||
| //char bufflag, buftype; | |||||
| //short ray_samp, ray_sampy, ray_sampz; | |||||
| //short ray_samp_type; | |||||
| //short area_shape; | |||||
| //float area_size, area_sizey, area_sizez; | |||||
| //float adapt_thresh; | |||||
| //short ray_samp_method; | |||||
| //short texact, shadhalostep; | |||||
| //short sun_effect_type; | |||||
| //short skyblendtype; | |||||
| //float horizon_brightness; | |||||
| //float spread; | |||||
| float sun_brightness; | |||||
| //float sun_size; | |||||
| //float backscattered_light; | |||||
| //float sun_intensity; | |||||
| //float atm_turbidity; | |||||
| //float atm_inscattering_factor; | |||||
| //float atm_extinction_factor; | |||||
| //float atm_distance_factor; | |||||
| //float skyblendfac; | |||||
| //float sky_exposure; | |||||
| //short sky_colorspace; | |||||
| // int YF_numphotons, YF_numsearch; | |||||
| // short YF_phdepth, YF_useqmc, YF_bufsize, YF_pad; | |||||
| // float YF_causticblur, YF_ltradius; | |||||
| // float YF_glowint, YF_glowofs; | |||||
| // short YF_glowtype, YF_pad2; | |||||
| //struct Ipo *ipo; | |||||
| //struct MTex *mtex[18]; | |||||
| // short pr_texture; | |||||
| //struct PreviewImage *preview; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct ModifierData : ElemBase { | |||||
| enum ModifierType { | |||||
| eModifierType_None = 0, | |||||
| eModifierType_Subsurf, | |||||
| eModifierType_Lattice, | |||||
| eModifierType_Curve, | |||||
| eModifierType_Build, | |||||
| eModifierType_Mirror, | |||||
| eModifierType_Decimate, | |||||
| eModifierType_Wave, | |||||
| eModifierType_Armature, | |||||
| eModifierType_Hook, | |||||
| eModifierType_Softbody, | |||||
| eModifierType_Boolean, | |||||
| eModifierType_Array, | |||||
| eModifierType_EdgeSplit, | |||||
| eModifierType_Displace, | |||||
| eModifierType_UVProject, | |||||
| eModifierType_Smooth, | |||||
| eModifierType_Cast, | |||||
| eModifierType_MeshDeform, | |||||
| eModifierType_ParticleSystem, | |||||
| eModifierType_ParticleInstance, | |||||
| eModifierType_Explode, | |||||
| eModifierType_Cloth, | |||||
| eModifierType_Collision, | |||||
| eModifierType_Bevel, | |||||
| eModifierType_Shrinkwrap, | |||||
| eModifierType_Fluidsim, | |||||
| eModifierType_Mask, | |||||
| eModifierType_SimpleDeform, | |||||
| eModifierType_Multires, | |||||
| eModifierType_Surface, | |||||
| eModifierType_Smoke, | |||||
| eModifierType_ShapeKey | |||||
| }; | |||||
| boost::shared_ptr<ElemBase> next WARN; | |||||
| boost::shared_ptr<ElemBase> prev WARN; | |||||
| int type, mode; | |||||
| char name[32]; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct SubsurfModifierData : ElemBase { | |||||
| enum Type { | |||||
| TYPE_CatmullClarke = 0x0, | |||||
| TYPE_Simple = 0x1 | |||||
| }; | |||||
| enum Flags { | |||||
| // some omitted | |||||
| FLAGS_SubsurfUV =1<<3 | |||||
| }; | |||||
| ModifierData modifier FAIL; | |||||
| short subdivType WARN; | |||||
| short levels FAIL; | |||||
| short renderLevels ; | |||||
| short flags; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct MirrorModifierData : ElemBase { | |||||
| enum Flags { | |||||
| Flags_CLIPPING =1<<0, | |||||
| Flags_MIRROR_U =1<<1, | |||||
| Flags_MIRROR_V =1<<2, | |||||
| Flags_AXIS_X =1<<3, | |||||
| Flags_AXIS_Y =1<<4, | |||||
| Flags_AXIS_Z =1<<5, | |||||
| Flags_VGROUP =1<<6 | |||||
| }; | |||||
| ModifierData modifier FAIL; | |||||
| short axis, flag; | |||||
| float tolerance; | |||||
| boost::shared_ptr<Object> mirror_ob; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct Object : ElemBase { | |||||
| ID id FAIL; | |||||
| enum Type { | |||||
| Type_EMPTY = 0 | |||||
| ,Type_MESH = 1 | |||||
| ,Type_CURVE = 2 | |||||
| ,Type_SURF = 3 | |||||
| ,Type_FONT = 4 | |||||
| ,Type_MBALL = 5 | |||||
| ,Type_LAMP = 10 | |||||
| ,Type_CAMERA = 11 | |||||
| ,Type_WAVE = 21 | |||||
| ,Type_LATTICE = 22 | |||||
| }; | |||||
| Type type FAIL; | |||||
| float obmat[4][4] WARN; | |||||
| float parentinv[4][4] WARN; | |||||
| char parsubstr[32] WARN; | |||||
| Object* parent WARN; | |||||
| boost::shared_ptr<Object> track WARN; | |||||
| boost::shared_ptr<Object> proxy,proxy_from,proxy_group WARN; | |||||
| boost::shared_ptr<Group> dup_group WARN; | |||||
| boost::shared_ptr<ElemBase> data FAIL; | |||||
| ListBase modifiers; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct Base : ElemBase { | |||||
| Base* prev WARN; | |||||
| boost::shared_ptr<Base> next WARN; | |||||
| boost::shared_ptr<Object> object WARN; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct Scene : ElemBase { | |||||
| ID id FAIL; | |||||
| boost::shared_ptr<Object> camera WARN; | |||||
| boost::shared_ptr<World> world WARN; | |||||
| boost::shared_ptr<Base> basact WARN; | |||||
| ListBase base; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct Image : ElemBase { | |||||
| ID id FAIL; | |||||
| char name[240] WARN; | |||||
| //struct anim *anim; | |||||
| short ok, flag; | |||||
| short source, type, pad, pad1; | |||||
| int lastframe; | |||||
| short tpageflag, totbind; | |||||
| short xrep, yrep; | |||||
| short twsta, twend; | |||||
| //unsigned int bindcode; | |||||
| //unsigned int *repbind; | |||||
| boost::shared_ptr<PackedFile> packedfile; | |||||
| //struct PreviewImage * preview; | |||||
| float lastupdate; | |||||
| int lastused; | |||||
| short animspeed; | |||||
| short gen_x, gen_y, gen_type; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct Tex : ElemBase { | |||||
| // actually, the only texture type we support is Type_IMAGE | |||||
| enum Type { | |||||
| Type_CLOUDS = 1 | |||||
| ,Type_WOOD = 2 | |||||
| ,Type_MARBLE = 3 | |||||
| ,Type_MAGIC = 4 | |||||
| ,Type_BLEND = 5 | |||||
| ,Type_STUCCI = 6 | |||||
| ,Type_NOISE = 7 | |||||
| ,Type_IMAGE = 8 | |||||
| ,Type_PLUGIN = 9 | |||||
| ,Type_ENVMAP = 10 | |||||
| ,Type_MUSGRAVE = 11 | |||||
| ,Type_VORONOI = 12 | |||||
| ,Type_DISTNOISE = 13 | |||||
| ,Type_POINTDENSITY = 14 | |||||
| ,Type_VOXELDATA = 15 | |||||
| }; | |||||
| enum ImageFlags { | |||||
| ImageFlags_INTERPOL = 1 | |||||
| ,ImageFlags_USEALPHA = 2 | |||||
| ,ImageFlags_MIPMAP = 4 | |||||
| ,ImageFlags_IMAROT = 16 | |||||
| ,ImageFlags_CALCALPHA = 32 | |||||
| ,ImageFlags_NORMALMAP = 2048 | |||||
| ,ImageFlags_GAUSS_MIP = 4096 | |||||
| ,ImageFlags_FILTER_MIN = 8192 | |||||
| ,ImageFlags_DERIVATIVEMAP = 16384 | |||||
| }; | |||||
| ID id FAIL; | |||||
| // AnimData *adt; | |||||
| //float noisesize, turbul; | |||||
| //float bright, contrast, rfac, gfac, bfac; | |||||
| //float filtersize; | |||||
| //float mg_H, mg_lacunarity, mg_octaves, mg_offset, mg_gain; | |||||
| //float dist_amount, ns_outscale; | |||||
| //float vn_w1; | |||||
| //float vn_w2; | |||||
| //float vn_w3; | |||||
| //float vn_w4; | |||||
| //float vn_mexp; | |||||
| //short vn_distm, vn_coltype; | |||||
| //short noisedepth, noisetype; | |||||
| //short noisebasis, noisebasis2; | |||||
| //short flag; | |||||
| ImageFlags imaflag; | |||||
| Type type FAIL; | |||||
| //short stype; | |||||
| //float cropxmin, cropymin, cropxmax, cropymax; | |||||
| //int texfilter; | |||||
| //int afmax; | |||||
| //short xrepeat, yrepeat; | |||||
| //short extend; | |||||
| //short fie_ima; | |||||
| //int len; | |||||
| //int frames, offset, sfra; | |||||
| //float checkerdist, nabla; | |||||
| //float norfac; | |||||
| //ImageUser iuser; | |||||
| //bNodeTree *nodetree; | |||||
| //Ipo *ipo; | |||||
| boost::shared_ptr<Image> ima WARN; | |||||
| //PluginTex *plugin; | |||||
| //ColorBand *coba; | |||||
| //EnvMap *env; | |||||
| //PreviewImage * preview; | |||||
| //PointDensity *pd; | |||||
| //VoxelData *vd; | |||||
| //char use_nodes; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------- | |||||
| struct MTex : ElemBase { | |||||
| enum Projection { | |||||
| Proj_N = 0 | |||||
| ,Proj_X = 1 | |||||
| ,Proj_Y = 2 | |||||
| ,Proj_Z = 3 | |||||
| }; | |||||
| enum Flag { | |||||
| Flag_RGBTOINT = 0x1 | |||||
| ,Flag_STENCIL = 0x2 | |||||
| ,Flag_NEGATIVE = 0x4 | |||||
| ,Flag_ALPHAMIX = 0x8 | |||||
| ,Flag_VIEWSPACE = 0x10 | |||||
| }; | |||||
| enum BlendType { | |||||
| BlendType_BLEND = 0 | |||||
| ,BlendType_MUL = 1 | |||||
| ,BlendType_ADD = 2 | |||||
| ,BlendType_SUB = 3 | |||||
| ,BlendType_DIV = 4 | |||||
| ,BlendType_DARK = 5 | |||||
| ,BlendType_DIFF = 6 | |||||
| ,BlendType_LIGHT = 7 | |||||
| ,BlendType_SCREEN = 8 | |||||
| ,BlendType_OVERLAY = 9 | |||||
| ,BlendType_BLEND_HUE = 10 | |||||
| ,BlendType_BLEND_SAT = 11 | |||||
| ,BlendType_BLEND_VAL = 12 | |||||
| ,BlendType_BLEND_COLOR = 13 | |||||
| }; | |||||
| enum MapType { | |||||
| MapType_COL = 1 | |||||
| ,MapType_NORM = 2 | |||||
| ,MapType_COLSPEC = 4 | |||||
| ,MapType_COLMIR = 8 | |||||
| ,MapType_REF = 16 | |||||
| ,MapType_SPEC = 32 | |||||
| ,MapType_EMIT = 64 | |||||
| ,MapType_ALPHA = 128 | |||||
| ,MapType_HAR = 256 | |||||
| ,MapType_RAYMIRR = 512 | |||||
| ,MapType_TRANSLU = 1024 | |||||
| ,MapType_AMB = 2048 | |||||
| ,MapType_DISPLACE = 4096 | |||||
| ,MapType_WARP = 8192 | |||||
| }; | |||||
| // short texco, maptoneg; | |||||
| MapType mapto; | |||||
| BlendType blendtype; | |||||
| boost::shared_ptr<Object> object; | |||||
| boost::shared_ptr<Tex> tex; | |||||
| char uvname[32]; | |||||
| Projection projx,projy,projz; | |||||
| char mapping; | |||||
| float ofs[3], size[3], rot; | |||||
| int texflag; | |||||
| short colormodel, pmapto, pmaptoneg; | |||||
| //short normapspace, which_output; | |||||
| //char brush_map_mode; | |||||
| float r,g,b,k WARN; | |||||
| //float def_var, rt; | |||||
| //float colfac, varfac; | |||||
| float norfac; | |||||
| //float dispfac, warpfac; | |||||
| float colspecfac, mirrfac, alphafac; | |||||
| float difffac, specfac, emitfac, hardfac; | |||||
| //float raymirrfac, translfac, ambfac; | |||||
| //float colemitfac, colreflfac, coltransfac; | |||||
| //float densfac, scatterfac, reflfac; | |||||
| //float timefac, lengthfac, clumpfac; | |||||
| //float kinkfac, roughfac, padensfac; | |||||
| //float lifefac, sizefac, ivelfac, pvelfac; | |||||
| //float shadowfac; | |||||
| //float zenupfac, zendownfac, blendfac; | |||||
| }; | |||||
| } | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,253 @@ | |||||
| /* | |||||
| Open Asset Import Library (ASSIMP) | |||||
| ---------------------------------------------------------------------- | |||||
| Copyright (c) 2006-2010, ASSIMP Development 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 Development 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 BlenderSceneGen.h | |||||
| * @brief MACHINE GENERATED BY ./scripts/BlenderImporter/genblenddna.py | |||||
| */ | |||||
| #ifndef INCLUDED_AI_BLEND_SCENEGEN_H | |||||
| #define INCLUDED_AI_BLEND_SCENEGEN_H | |||||
| namespace Assimp { | |||||
| namespace Blender { | |||||
| template <> void Structure :: Convert<Object> ( | |||||
| Object& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<Group> ( | |||||
| Group& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<MTex> ( | |||||
| MTex& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<TFace> ( | |||||
| TFace& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<SubsurfModifierData> ( | |||||
| SubsurfModifierData& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<MFace> ( | |||||
| MFace& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<Lamp> ( | |||||
| Lamp& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<MDeformWeight> ( | |||||
| MDeformWeight& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<PackedFile> ( | |||||
| PackedFile& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<Base> ( | |||||
| Base& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<MTFace> ( | |||||
| MTFace& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<Material> ( | |||||
| Material& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<MTexPoly> ( | |||||
| MTexPoly& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<Mesh> ( | |||||
| Mesh& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<MDeformVert> ( | |||||
| MDeformVert& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<World> ( | |||||
| World& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<MLoopCol> ( | |||||
| MLoopCol& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<MVert> ( | |||||
| MVert& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<MEdge> ( | |||||
| MEdge& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<MLoopUV> ( | |||||
| MLoopUV& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<GroupObject> ( | |||||
| GroupObject& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<ListBase> ( | |||||
| ListBase& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<MLoop> ( | |||||
| MLoop& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<ModifierData> ( | |||||
| ModifierData& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<ID> ( | |||||
| ID& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<MCol> ( | |||||
| MCol& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<MPoly> ( | |||||
| MPoly& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<Scene> ( | |||||
| Scene& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<Library> ( | |||||
| Library& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<Tex> ( | |||||
| Tex& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<Camera> ( | |||||
| Camera& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<MirrorModifierData> ( | |||||
| MirrorModifierData& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| template <> void Structure :: Convert<Image> ( | |||||
| Image& dest, | |||||
| const FileDatabase& db | |||||
| ) const | |||||
| ; | |||||
| } | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,520 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| Copyright (c) 2006-2013, 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 BlenderTessellator.cpp | |||||
| * @brief A simple tessellation wrapper | |||||
| */ | |||||
| #include "AssimpPCH.h" | |||||
| #ifndef ASSIMP_BUILD_NO_BLEND_IMPORTER | |||||
| #include "BlenderDNA.h" | |||||
| #include "BlenderScene.h" | |||||
| #include "BlenderBMesh.h" | |||||
| #include "BlenderTessellator.h" | |||||
| static const unsigned int BLEND_TESS_MAGIC = 0x83ed9ac3; | |||||
| #if ASSIMP_BLEND_WITH_GLU_TESSELLATE | |||||
| namspace Assimp | |||||
| { | |||||
| template< > const std::string LogFunctions< BlenderTessellatorGL >::log_prefix = "BLEND_TESS_GL: "; | |||||
| } | |||||
| using namespace Assimp; | |||||
| using namespace Assimp::Blender; | |||||
| #ifndef CALLBACK | |||||
| #define CALLBACK | |||||
| #endif | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| BlenderTessellatorGL::BlenderTessellatorGL( BlenderBMeshConverter& converter ): | |||||
| converter( &converter ) | |||||
| { | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| BlenderTessellatorGL::~BlenderTessellatorGL( ) | |||||
| { | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorGL::Tessellate( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices ) | |||||
| { | |||||
| AssertVertexCount( vertexCount ); | |||||
| std::vector< VertexGL > polyLoopGL; | |||||
| GenerateLoopVerts( polyLoopGL, polyLoop, vertexCount, vertices ); | |||||
| TessDataGL tessData; | |||||
| Tesssellate( polyLoopGL, tessData ); | |||||
| TriangulateDrawCalls( tessData ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorGL::AssertVertexCount( int vertexCount ) | |||||
| { | |||||
| if ( vertexCount <= 4 ) | |||||
| { | |||||
| ThrowException( "Expected more than 4 vertices for tessellation" ); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorGL::GenerateLoopVerts( std::vector< VertexGL >& polyLoopGL, const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices ) | |||||
| { | |||||
| for ( int i = 0; i < vertexCount; ++i ) | |||||
| { | |||||
| const MLoop& loopItem = polyLoop[ i ]; | |||||
| const MVert& vertex = vertices[ loopItem.v ]; | |||||
| polyLoopGL.push_back( VertexGL( vertex.co[ 0 ], vertex.co[ 1 ], vertex.co[ 2 ], loopItem.v, BLEND_TESS_MAGIC ) ); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorGL::Tesssellate( std::vector< VertexGL >& polyLoopGL, TessDataGL& tessData ) | |||||
| { | |||||
| GLUtesselator* tessellator = gluNewTess( ); | |||||
| gluTessCallback( tessellator, GLU_TESS_BEGIN_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateBegin ) ); | |||||
| gluTessCallback( tessellator, GLU_TESS_END_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateEnd ) ); | |||||
| gluTessCallback( tessellator, GLU_TESS_VERTEX_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateVertex ) ); | |||||
| gluTessCallback( tessellator, GLU_TESS_COMBINE_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateCombine ) ); | |||||
| gluTessCallback( tessellator, GLU_TESS_EDGE_FLAG_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateEdgeFlag ) ); | |||||
| gluTessCallback( tessellator, GLU_TESS_ERROR_DATA, reinterpret_cast< void ( CALLBACK * )( ) >( TessellateError ) ); | |||||
| gluTessProperty( tessellator, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO ); | |||||
| gluTessBeginPolygon( tessellator, &tessData ); | |||||
| gluTessBeginContour( tessellator ); | |||||
| for ( unsigned int i = 0; i < polyLoopGL.size( ); ++i ) | |||||
| { | |||||
| gluTessVertex( tessellator, reinterpret_cast< GLdouble* >( &polyLoopGL[ i ] ), &polyLoopGL[ i ] ); | |||||
| } | |||||
| gluTessEndContour( tessellator ); | |||||
| gluTessEndPolygon( tessellator ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorGL::TriangulateDrawCalls( const TessDataGL& tessData ) | |||||
| { | |||||
| // NOTE - Because we are supplying a callback to GLU_TESS_EDGE_FLAG_DATA we don't technically | |||||
| // need support for GL_TRIANGLE_STRIP and GL_TRIANGLE_FAN but we'll keep it here in case | |||||
| // GLU tessellate changes or tristrips and fans are wanted. | |||||
| // See: http://www.opengl.org/sdk/docs/man2/xhtml/gluTessCallback.xml | |||||
| for ( unsigned int i = 0; i < tessData.drawCalls.size( ); ++i ) | |||||
| { | |||||
| const DrawCallGL& drawCallGL = tessData.drawCalls[ i ]; | |||||
| const VertexGL* vertices = &tessData.vertices[ drawCallGL.baseVertex ]; | |||||
| if ( drawCallGL.drawMode == GL_TRIANGLES ) | |||||
| { | |||||
| MakeFacesFromTris( vertices, drawCallGL.vertexCount ); | |||||
| } | |||||
| else if ( drawCallGL.drawMode == GL_TRIANGLE_STRIP ) | |||||
| { | |||||
| MakeFacesFromTriStrip( vertices, drawCallGL.vertexCount ); | |||||
| } | |||||
| else if ( drawCallGL.drawMode == GL_TRIANGLE_FAN ) | |||||
| { | |||||
| MakeFacesFromTriFan( vertices, drawCallGL.vertexCount ); | |||||
| } | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorGL::MakeFacesFromTris( const VertexGL* vertices, int vertexCount ) | |||||
| { | |||||
| int triangleCount = vertexCount / 3; | |||||
| for ( int i = 0; i < triangleCount; ++i ) | |||||
| { | |||||
| int vertexBase = i * 3; | |||||
| converter->AddFace( vertices[ vertexBase + 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index ); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorGL::MakeFacesFromTriStrip( const VertexGL* vertices, int vertexCount ) | |||||
| { | |||||
| int triangleCount = vertexCount - 2; | |||||
| for ( int i = 0; i < triangleCount; ++i ) | |||||
| { | |||||
| int vertexBase = i; | |||||
| converter->AddFace( vertices[ vertexBase + 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index ); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorGL::MakeFacesFromTriFan( const VertexGL* vertices, int vertexCount ) | |||||
| { | |||||
| int triangleCount = vertexCount - 2; | |||||
| for ( int i = 0; i < triangleCount; ++i ) | |||||
| { | |||||
| int vertexBase = i; | |||||
| converter->AddFace( vertices[ 0 ].index, vertices[ vertexBase + 1 ].index, vertices[ vertexBase + 2 ].index ); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorGL::TessellateBegin( GLenum drawModeGL, void* userData ) | |||||
| { | |||||
| TessDataGL& tessData = *reinterpret_cast< TessDataGL* >( userData ); | |||||
| tessData.drawCalls.push_back( DrawCallGL( drawModeGL, tessData.vertices.size( ) ) ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorGL::TessellateEnd( void* ) | |||||
| { | |||||
| // Do nothing | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorGL::TessellateVertex( const void* vtxData, void* userData ) | |||||
| { | |||||
| TessDataGL& tessData = *reinterpret_cast< TessDataGL* >( userData ); | |||||
| const VertexGL& vertex = *reinterpret_cast< const VertexGL* >( vtxData ); | |||||
| if ( vertex.magic != BLEND_TESS_MAGIC ) | |||||
| { | |||||
| ThrowException( "Point returned by GLU Tessellate was probably not one of ours. This indicates we need a new way to store vertex information" ); | |||||
| } | |||||
| tessData.vertices.push_back( vertex ); | |||||
| if ( tessData.drawCalls.size( ) == 0 ) | |||||
| { | |||||
| ThrowException( "\"Vertex\" callback received before \"Begin\"" ); | |||||
| } | |||||
| ++( tessData.drawCalls.back( ).vertexCount ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorGL::TessellateCombine( const GLdouble intersection[ 3 ], const GLdouble* [ 4 ], const GLfloat [ 4 ], GLdouble** out, void* userData ) | |||||
| { | |||||
| ThrowException( "Intersected polygon loops are not yet supported" ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorGL::TessellateEdgeFlag( GLboolean, void* ) | |||||
| { | |||||
| // Do nothing | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorGL::TessellateError( GLenum errorCode, void* ) | |||||
| { | |||||
| ThrowException( reinterpret_cast< const char* >( gluErrorString( errorCode ) ) ); | |||||
| } | |||||
| #endif // ASSIMP_BLEND_WITH_GLU_TESSELLATE | |||||
| #if ASSIMP_BLEND_WITH_POLY_2_TRI | |||||
| namespace Assimp | |||||
| { | |||||
| template< > const std::string LogFunctions< BlenderTessellatorP2T >::log_prefix = "BLEND_TESS_P2T: "; | |||||
| } | |||||
| using namespace Assimp; | |||||
| using namespace Assimp::Blender; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| BlenderTessellatorP2T::BlenderTessellatorP2T( BlenderBMeshConverter& converter ): | |||||
| converter( &converter ) | |||||
| { | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| BlenderTessellatorP2T::~BlenderTessellatorP2T( ) | |||||
| { | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorP2T::Tessellate( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices ) | |||||
| { | |||||
| AssertVertexCount( vertexCount ); | |||||
| // NOTE - We have to hope that points in a Blender polygon are roughly on the same plane. | |||||
| // There may be some triangulation artifacts if they are wildly different. | |||||
| std::vector< PointP2T > points; | |||||
| Copy3DVertices( polyLoop, vertexCount, vertices, points ); | |||||
| PlaneP2T plane = FindLLSQPlane( points ); | |||||
| aiMatrix4x4 transform = GeneratePointTransformMatrix( plane ); | |||||
| TransformAndFlattenVectices( transform, points ); | |||||
| std::vector< p2t::Point* > pointRefs; | |||||
| ReferencePoints( points, pointRefs ); | |||||
| p2t::CDT cdt( pointRefs ); | |||||
| cdt.Triangulate( ); | |||||
| std::vector< p2t::Triangle* > triangles = cdt.GetTriangles( ); | |||||
| MakeFacesFromTriangles( triangles ); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorP2T::AssertVertexCount( int vertexCount ) | |||||
| { | |||||
| if ( vertexCount <= 4 ) | |||||
| { | |||||
| ThrowException( "Expected more than 4 vertices for tessellation" ); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorP2T::Copy3DVertices( const MLoop* polyLoop, int vertexCount, const std::vector< MVert >& vertices, std::vector< PointP2T >& points ) const | |||||
| { | |||||
| points.resize( vertexCount ); | |||||
| for ( int i = 0; i < vertexCount; ++i ) | |||||
| { | |||||
| const MLoop& loop = polyLoop[ i ]; | |||||
| const MVert& vert = vertices[ loop.v ]; | |||||
| PointP2T& point = points[ i ]; | |||||
| point.point3D.Set( vert.co[ 0 ], vert.co[ 1 ], vert.co[ 2 ] ); | |||||
| point.index = loop.v; | |||||
| point.magic = BLEND_TESS_MAGIC; | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| aiMatrix4x4 BlenderTessellatorP2T::GeneratePointTransformMatrix( const Blender::PlaneP2T& plane ) const | |||||
| { | |||||
| aiVector3D sideA( 1.0f, 0.0f, 0.0f ); | |||||
| if ( fabs( plane.normal * sideA ) > 0.999f ) | |||||
| { | |||||
| sideA = aiVector3D( 0.0f, 1.0f, 0.0f ); | |||||
| } | |||||
| aiVector3D sideB( plane.normal ^ sideA ); | |||||
| sideB.Normalize( ); | |||||
| sideA = sideB ^ plane.normal; | |||||
| aiMatrix4x4 result; | |||||
| result.a1 = sideA.x; | |||||
| result.a2 = sideA.y; | |||||
| result.a3 = sideA.z; | |||||
| result.b1 = sideB.x; | |||||
| result.b2 = sideB.y; | |||||
| result.b3 = sideB.z; | |||||
| result.c1 = plane.normal.x; | |||||
| result.c2 = plane.normal.y; | |||||
| result.c3 = plane.normal.z; | |||||
| result.a4 = plane.centre.x; | |||||
| result.b4 = plane.centre.y; | |||||
| result.c4 = plane.centre.z; | |||||
| result.Inverse( ); | |||||
| return result; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorP2T::TransformAndFlattenVectices( const aiMatrix4x4& transform, std::vector< Blender::PointP2T >& vertices ) const | |||||
| { | |||||
| for ( unsigned int i = 0; i < vertices.size( ); ++i ) | |||||
| { | |||||
| PointP2T& point = vertices[ i ]; | |||||
| point.point3D = transform * point.point3D; | |||||
| point.point2D.set( point.point3D.y, point.point3D.z ); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorP2T::ReferencePoints( std::vector< Blender::PointP2T >& points, std::vector< p2t::Point* >& pointRefs ) const | |||||
| { | |||||
| pointRefs.resize( points.size( ) ); | |||||
| for ( unsigned int i = 0; i < points.size( ); ++i ) | |||||
| { | |||||
| pointRefs[ i ] = &points[ i ].point2D; | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Yes this is filthy... but we have no choice | |||||
| #define OffsetOf( Class, Member ) ( static_cast< unsigned int >( \ | |||||
| reinterpret_cast<uint8_t*>(&( reinterpret_cast< Class* >( NULL )->*( &Class::Member ) )) - \ | |||||
| static_cast<uint8_t*>(NULL) ) ) | |||||
| inline PointP2T& BlenderTessellatorP2T::GetActualPointStructure( p2t::Point& point ) const | |||||
| { | |||||
| unsigned int pointOffset = OffsetOf( PointP2T, point2D ); | |||||
| PointP2T& pointStruct = *reinterpret_cast< PointP2T* >( reinterpret_cast< char* >( &point ) - pointOffset ); | |||||
| if ( pointStruct.magic != static_cast<int>( BLEND_TESS_MAGIC ) ) | |||||
| { | |||||
| ThrowException( "Point returned by poly2tri was probably not one of ours. This indicates we need a new way to store vertex information" ); | |||||
| } | |||||
| return pointStruct; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void BlenderTessellatorP2T::MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const | |||||
| { | |||||
| for ( unsigned int i = 0; i < triangles.size( ); ++i ) | |||||
| { | |||||
| p2t::Triangle& Triangle = *triangles[ i ]; | |||||
| PointP2T& pointA = GetActualPointStructure( *Triangle.GetPoint( 0 ) ); | |||||
| PointP2T& pointB = GetActualPointStructure( *Triangle.GetPoint( 1 ) ); | |||||
| PointP2T& pointC = GetActualPointStructure( *Triangle.GetPoint( 2 ) ); | |||||
| converter->AddFace( pointA.index, pointB.index, pointC.index ); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| inline float p2tMax( float a, float b ) | |||||
| { | |||||
| return a > b ? a : b; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html | |||||
| float BlenderTessellatorP2T::FindLargestMatrixElem( const aiMatrix3x3& mtx ) const | |||||
| { | |||||
| float result = 0.0f; | |||||
| for ( int x = 0; x < 3; ++x ) | |||||
| { | |||||
| for ( int y = 0; y < 3; ++y ) | |||||
| { | |||||
| result = p2tMax( fabs( mtx[ x ][ y ] ), result ); | |||||
| } | |||||
| } | |||||
| return result; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Aparently Assimp doesn't have matrix scaling | |||||
| aiMatrix3x3 BlenderTessellatorP2T::ScaleMatrix( const aiMatrix3x3& mtx, float scale ) const | |||||
| { | |||||
| aiMatrix3x3 result; | |||||
| for ( int x = 0; x < 3; ++x ) | |||||
| { | |||||
| for ( int y = 0; y < 3; ++y ) | |||||
| { | |||||
| result[ x ][ y ] = mtx[ x ][ y ] * scale; | |||||
| } | |||||
| } | |||||
| return result; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html | |||||
| aiVector3D BlenderTessellatorP2T::GetEigenVectorFromLargestEigenValue( const aiMatrix3x3& mtx ) const | |||||
| { | |||||
| float scale = FindLargestMatrixElem( mtx ); | |||||
| aiMatrix3x3 mc = ScaleMatrix( mtx, 1.0f / scale ); | |||||
| mc = mc * mc * mc; | |||||
| aiVector3D v( 1.0f ); | |||||
| aiVector3D lastV = v; | |||||
| for ( int i = 0; i < 100; ++i ) | |||||
| { | |||||
| v = mc * v; | |||||
| v.Normalize( ); | |||||
| if ( ( v - lastV ).SquareLength( ) < 1e-16f ) | |||||
| { | |||||
| break; | |||||
| } | |||||
| lastV = v; | |||||
| } | |||||
| return v; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html | |||||
| PlaneP2T BlenderTessellatorP2T::FindLLSQPlane( const std::vector< PointP2T >& points ) const | |||||
| { | |||||
| PlaneP2T result; | |||||
| aiVector3D sum( 0.0f ); | |||||
| for ( unsigned int i = 0; i < points.size( ); ++i ) | |||||
| { | |||||
| sum += points[ i ].point3D; | |||||
| } | |||||
| result.centre = sum * ( 1.0f / points.size( ) ); | |||||
| float sumXX = 0.0f; | |||||
| float sumXY = 0.0f; | |||||
| float sumXZ = 0.0f; | |||||
| float sumYY = 0.0f; | |||||
| float sumYZ = 0.0f; | |||||
| float sumZZ = 0.0f; | |||||
| for ( unsigned int i = 0; i < points.size( ); ++i ) | |||||
| { | |||||
| aiVector3D offset = points[ i ].point3D - result.centre; | |||||
| sumXX += offset.x * offset.x; | |||||
| sumXY += offset.x * offset.y; | |||||
| sumXZ += offset.x * offset.z; | |||||
| sumYY += offset.y * offset.y; | |||||
| sumYZ += offset.y * offset.z; | |||||
| sumZZ += offset.z * offset.z; | |||||
| } | |||||
| aiMatrix3x3 mtx( sumXX, sumXY, sumXZ, sumXY, sumYY, sumYZ, sumXZ, sumYZ, sumZZ ); | |||||
| float det = mtx.Determinant( ); | |||||
| if ( det == 0.0f ) | |||||
| { | |||||
| result.normal = aiVector3D( 0.0f ); | |||||
| } | |||||
| else | |||||
| { | |||||
| aiMatrix3x3 invMtx = mtx; | |||||
| invMtx.Inverse( ); | |||||
| result.normal = GetEigenVectorFromLargestEigenValue( invMtx ); | |||||
| } | |||||
| return result; | |||||
| } | |||||
| #endif // ASSIMP_BLEND_WITH_POLY_2_TRI | |||||
| #endif // ASSIMP_BUILD_NO_BLEND_IMPORTER | |||||
| @@ -0,0 +1,208 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| Copyright (c) 2006-2013, 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 BlenderTessellator.h | |||||
| * @brief A simple tessellation wrapper | |||||
| */ | |||||
| #ifndef INCLUDED_AI_BLEND_TESSELLATOR_H | |||||
| #define INCLUDED_AI_BLEND_TESSELLATOR_H | |||||
| // Use these to toggle between GLU Tessellate or poly2tri | |||||
| // Note (acg) keep GLU Tesselate disabled by default - if it is turned on, | |||||
| // assimp needs to be linked against GLU, which is currently not yet | |||||
| // made configurable in CMake and potentially not wanted by most users | |||||
| // as it requires a Gl environment. | |||||
| #ifndef ASSIMP_BLEND_WITH_GLU_TESSELLATE | |||||
| # define ASSIMP_BLEND_WITH_GLU_TESSELLATE 0 | |||||
| #endif | |||||
| #ifndef ASSIMP_BLEND_WITH_POLY_2_TRI | |||||
| # define ASSIMP_BLEND_WITH_POLY_2_TRI 1 | |||||
| #endif | |||||
| #include "LogAux.h" | |||||
| #if ASSIMP_BLEND_WITH_GLU_TESSELLATE | |||||
| #if defined( WIN32 ) || defined( _WIN32 ) || defined( _MSC_VER ) | |||||
| #include <windows.h> | |||||
| #endif | |||||
| #include <GL/glu.h> | |||||
| namespace Assimp | |||||
| { | |||||
| class BlenderBMeshConverter; | |||||
| // TinyFormatter.h | |||||
| namespace Formatter | |||||
| { | |||||
| template < typename T,typename TR, typename A > class basic_formatter; | |||||
| typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format; | |||||
| } | |||||
| // BlenderScene.h | |||||
| namespace Blender | |||||
| { | |||||
| struct MLoop; | |||||
| struct MVert; | |||||
| struct VertexGL | |||||
| { | |||||
| GLdouble X; | |||||
| GLdouble Y; | |||||
| GLdouble Z; | |||||
| int index; | |||||
| int magic; | |||||
| VertexGL( GLdouble X, GLdouble Y, GLdouble Z, int index, int magic ): X( X ), Y( Y ), Z( Z ), index( index ), magic( magic ) { } | |||||
| }; | |||||
| struct DrawCallGL | |||||
| { | |||||
| GLenum drawMode; | |||||
| int baseVertex; | |||||
| int vertexCount; | |||||
| DrawCallGL( GLenum drawMode, int baseVertex ): drawMode( drawMode ), baseVertex( baseVertex ), vertexCount( 0 ) { } | |||||
| }; | |||||
| struct TessDataGL | |||||
| { | |||||
| std::vector< DrawCallGL > drawCalls; | |||||
| std::vector< VertexGL > vertices; | |||||
| }; | |||||
| } | |||||
| class BlenderTessellatorGL: public LogFunctions< BlenderTessellatorGL > | |||||
| { | |||||
| public: | |||||
| BlenderTessellatorGL( BlenderBMeshConverter& converter ); | |||||
| ~BlenderTessellatorGL( ); | |||||
| void Tessellate( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices ); | |||||
| private: | |||||
| void AssertVertexCount( int vertexCount ); | |||||
| void GenerateLoopVerts( std::vector< Blender::VertexGL >& polyLoopGL, const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices ); | |||||
| void Tesssellate( std::vector< Blender::VertexGL >& polyLoopGL, Blender::TessDataGL& tessData ); | |||||
| void TriangulateDrawCalls( const Blender::TessDataGL& tessData ); | |||||
| void MakeFacesFromTris( const Blender::VertexGL* vertices, int vertexCount ); | |||||
| void MakeFacesFromTriStrip( const Blender::VertexGL* vertices, int vertexCount ); | |||||
| void MakeFacesFromTriFan( const Blender::VertexGL* vertices, int vertexCount ); | |||||
| static void TessellateBegin( GLenum drawModeGL, void* userData ); | |||||
| static void TessellateEnd( void* userData ); | |||||
| static void TessellateVertex( const void* vtxData, void* userData ); | |||||
| static void TessellateCombine( const GLdouble intersection[ 3 ], const GLdouble* [ 4 ], const GLfloat [ 4 ], GLdouble** out, void* userData ); | |||||
| static void TessellateEdgeFlag( GLboolean edgeFlag, void* userData ); | |||||
| static void TessellateError( GLenum errorCode, void* userData ); | |||||
| BlenderBMeshConverter* converter; | |||||
| }; | |||||
| } // end of namespace Assimp | |||||
| #endif // ASSIMP_BLEND_WITH_GLU_TESSELLATE | |||||
| #if ASSIMP_BLEND_WITH_POLY_2_TRI | |||||
| #include "../contrib/poly2tri/poly2tri/poly2tri.h" | |||||
| namespace Assimp | |||||
| { | |||||
| class BlenderBMeshConverter; | |||||
| // TinyFormatter.h | |||||
| namespace Formatter | |||||
| { | |||||
| template < typename T,typename TR, typename A > class basic_formatter; | |||||
| typedef class basic_formatter< char, std::char_traits< char >, std::allocator< char > > format; | |||||
| } | |||||
| // BlenderScene.h | |||||
| namespace Blender | |||||
| { | |||||
| struct MLoop; | |||||
| struct MVert; | |||||
| struct PointP2T | |||||
| { | |||||
| aiVector3D point3D; | |||||
| p2t::Point point2D; | |||||
| int magic; | |||||
| int index; | |||||
| }; | |||||
| struct PlaneP2T | |||||
| { | |||||
| aiVector3D centre; | |||||
| aiVector3D normal; | |||||
| }; | |||||
| } | |||||
| class BlenderTessellatorP2T: public LogFunctions< BlenderTessellatorP2T > | |||||
| { | |||||
| public: | |||||
| BlenderTessellatorP2T( BlenderBMeshConverter& converter ); | |||||
| ~BlenderTessellatorP2T( ); | |||||
| void Tessellate( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices ); | |||||
| private: | |||||
| void AssertVertexCount( int vertexCount ); | |||||
| void Copy3DVertices( const Blender::MLoop* polyLoop, int vertexCount, const std::vector< Blender::MVert >& vertices, std::vector< Blender::PointP2T >& targetVertices ) const; | |||||
| aiMatrix4x4 GeneratePointTransformMatrix( const Blender::PlaneP2T& plane ) const; | |||||
| void TransformAndFlattenVectices( const aiMatrix4x4& transform, std::vector< Blender::PointP2T >& vertices ) const; | |||||
| void ReferencePoints( std::vector< Blender::PointP2T >& points, std::vector< p2t::Point* >& pointRefs ) const; | |||||
| inline Blender::PointP2T& GetActualPointStructure( p2t::Point& point ) const; | |||||
| void MakeFacesFromTriangles( std::vector< p2t::Triangle* >& triangles ) const; | |||||
| // Adapted from: http://missingbytes.blogspot.co.uk/2012/06/fitting-plane-to-point-cloud.html | |||||
| float FindLargestMatrixElem( const aiMatrix3x3& mtx ) const; | |||||
| aiMatrix3x3 ScaleMatrix( const aiMatrix3x3& mtx, float scale ) const; | |||||
| aiVector3D GetEigenVectorFromLargestEigenValue( const aiMatrix3x3& mtx ) const; | |||||
| Blender::PlaneP2T FindLLSQPlane( const std::vector< Blender::PointP2T >& points ) const; | |||||
| BlenderBMeshConverter* converter; | |||||
| }; | |||||
| } // end of namespace Assimp | |||||
| #endif // ASSIMP_BLEND_WITH_POLY_2_TRI | |||||
| #endif // INCLUDED_AI_BLEND_TESSELLATOR_H | |||||
| @@ -0,0 +1,326 @@ | |||||
| /* | |||||
| --------------------------------------------------------------------------- | |||||
| Open Asset Import Library (assimp) | |||||
| --------------------------------------------------------------------------- | |||||
| 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. | |||||
| --------------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file Provides cheat implementations for IOSystem and IOStream to | |||||
| * redirect exporter output to a blob chain.*/ | |||||
| #ifndef AI_BLOBIOSYSTEM_H_INCLUDED | |||||
| #define AI_BLOBIOSYSTEM_H_INCLUDED | |||||
| namespace Assimp { | |||||
| class BlobIOSystem; | |||||
| // -------------------------------------------------------------------------------------------- | |||||
| /** Redirect IOStream to a blob */ | |||||
| // -------------------------------------------------------------------------------------------- | |||||
| class BlobIOStream : public IOStream | |||||
| { | |||||
| public: | |||||
| BlobIOStream(BlobIOSystem* creator, const std::string& file, size_t initial = 4096) | |||||
| : buffer() | |||||
| , cur_size() | |||||
| , file_size() | |||||
| , cursor() | |||||
| , initial(initial) | |||||
| , file(file) | |||||
| , creator(creator) | |||||
| { | |||||
| } | |||||
| virtual ~BlobIOStream(); | |||||
| public: | |||||
| // ------------------------------------------------------------------- | |||||
| aiExportDataBlob* GetBlob() | |||||
| { | |||||
| aiExportDataBlob* blob = new aiExportDataBlob(); | |||||
| blob->size = file_size; | |||||
| blob->data = buffer; | |||||
| buffer = NULL; | |||||
| return blob; | |||||
| } | |||||
| public: | |||||
| // ------------------------------------------------------------------- | |||||
| virtual size_t Read( void *, | |||||
| size_t, | |||||
| size_t ) | |||||
| { | |||||
| return 0; | |||||
| } | |||||
| // ------------------------------------------------------------------- | |||||
| virtual size_t Write(const void* pvBuffer, | |||||
| size_t pSize, | |||||
| size_t pCount) | |||||
| { | |||||
| pSize *= pCount; | |||||
| if (cursor + pSize > cur_size) { | |||||
| Grow(cursor + pSize); | |||||
| } | |||||
| memcpy(buffer+cursor, pvBuffer, pSize); | |||||
| cursor += pSize; | |||||
| file_size = std::max(file_size,cursor); | |||||
| return pCount; | |||||
| } | |||||
| // ------------------------------------------------------------------- | |||||
| virtual aiReturn Seek(size_t pOffset, | |||||
| aiOrigin pOrigin) | |||||
| { | |||||
| switch(pOrigin) | |||||
| { | |||||
| case aiOrigin_CUR: | |||||
| cursor += pOffset; | |||||
| case aiOrigin_END: | |||||
| cursor = file_size - pOffset; | |||||
| case aiOrigin_SET: | |||||
| cursor = pOffset; | |||||
| break; | |||||
| default: | |||||
| return AI_FAILURE; | |||||
| } | |||||
| if (cursor > file_size) { | |||||
| Grow(cursor); | |||||
| } | |||||
| file_size = std::max(cursor,file_size); | |||||
| return AI_SUCCESS; | |||||
| } | |||||
| // ------------------------------------------------------------------- | |||||
| virtual size_t Tell() const | |||||
| { | |||||
| return cursor; | |||||
| } | |||||
| // ------------------------------------------------------------------- | |||||
| virtual size_t FileSize() const | |||||
| { | |||||
| return file_size; | |||||
| } | |||||
| // ------------------------------------------------------------------- | |||||
| virtual void Flush() | |||||
| { | |||||
| // ignore | |||||
| } | |||||
| private: | |||||
| // ------------------------------------------------------------------- | |||||
| void Grow(size_t need = 0) | |||||
| { | |||||
| // 1.5 and phi are very heap-friendly growth factors (the first | |||||
| // allows for frequent re-use of heap blocks, the second | |||||
| // forms a fibonacci sequence with similar characteristics - | |||||
| // since this heavily depends on the heap implementation | |||||
| // and other factors as well, i'll just go with 1.5 since | |||||
| // it is quicker to compute). | |||||
| size_t new_size = std::max(initial, std::max( need, cur_size+(cur_size>>1) )); | |||||
| const uint8_t* const old = buffer; | |||||
| buffer = new uint8_t[new_size]; | |||||
| if (old) { | |||||
| memcpy(buffer,old,cur_size); | |||||
| delete[] old; | |||||
| } | |||||
| cur_size = new_size; | |||||
| } | |||||
| private: | |||||
| uint8_t* buffer; | |||||
| size_t cur_size,file_size, cursor, initial; | |||||
| const std::string file; | |||||
| BlobIOSystem* const creator; | |||||
| }; | |||||
| #define AI_BLOBIO_MAGIC "$blobfile" | |||||
| // -------------------------------------------------------------------------------------------- | |||||
| /** Redirect IOSystem to a blob */ | |||||
| // -------------------------------------------------------------------------------------------- | |||||
| class BlobIOSystem : public IOSystem | |||||
| { | |||||
| friend class BlobIOStream; | |||||
| typedef std::pair<std::string, aiExportDataBlob*> BlobEntry; | |||||
| public: | |||||
| BlobIOSystem() | |||||
| { | |||||
| } | |||||
| virtual ~BlobIOSystem() | |||||
| { | |||||
| BOOST_FOREACH(BlobEntry& blobby, blobs) { | |||||
| delete blobby.second; | |||||
| } | |||||
| } | |||||
| public: | |||||
| // ------------------------------------------------------------------- | |||||
| const char* GetMagicFileName() const | |||||
| { | |||||
| return AI_BLOBIO_MAGIC; | |||||
| } | |||||
| // ------------------------------------------------------------------- | |||||
| aiExportDataBlob* GetBlobChain() | |||||
| { | |||||
| // one must be the master | |||||
| aiExportDataBlob* master = NULL, *cur; | |||||
| BOOST_FOREACH(const BlobEntry& blobby, blobs) { | |||||
| if (blobby.first == AI_BLOBIO_MAGIC) { | |||||
| master = blobby.second; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (!master) { | |||||
| DefaultLogger::get()->error("BlobIOSystem: no data written or master file was not closed properly."); | |||||
| return NULL; | |||||
| } | |||||
| master->name.Set(""); | |||||
| cur = master; | |||||
| BOOST_FOREACH(const BlobEntry& blobby, blobs) { | |||||
| if (blobby.second == master) { | |||||
| continue; | |||||
| } | |||||
| cur->next = blobby.second; | |||||
| cur = cur->next; | |||||
| // extract the file extension from the file written | |||||
| const std::string::size_type s = blobby.first.find_first_of('.'); | |||||
| cur->name.Set(s == std::string::npos ? blobby.first : blobby.first.substr(s+1)); | |||||
| } | |||||
| // give up blob ownership | |||||
| blobs.clear(); | |||||
| return master; | |||||
| } | |||||
| public: | |||||
| // ------------------------------------------------------------------- | |||||
| virtual bool Exists( const char* pFile) const { | |||||
| return created.find(std::string(pFile)) != created.end(); | |||||
| } | |||||
| // ------------------------------------------------------------------- | |||||
| virtual char getOsSeparator() const { | |||||
| return '/'; | |||||
| } | |||||
| // ------------------------------------------------------------------- | |||||
| virtual IOStream* Open(const char* pFile, | |||||
| const char* pMode) | |||||
| { | |||||
| if (pMode[0] != 'w') { | |||||
| return NULL; | |||||
| } | |||||
| created.insert(std::string(pFile)); | |||||
| return new BlobIOStream(this,std::string(pFile)); | |||||
| } | |||||
| // ------------------------------------------------------------------- | |||||
| virtual void Close( IOStream* pFile) | |||||
| { | |||||
| delete pFile; | |||||
| } | |||||
| private: | |||||
| // ------------------------------------------------------------------- | |||||
| void OnDestruct(const std::string& filename, BlobIOStream* child) | |||||
| { | |||||
| // we don't know in which the files are closed, so we | |||||
| // can't reliably say that the first must be the master | |||||
| // file ... | |||||
| blobs.push_back( BlobEntry(filename,child->GetBlob()) ); | |||||
| } | |||||
| private: | |||||
| std::set<std::string> created; | |||||
| std::vector< BlobEntry > blobs; | |||||
| }; | |||||
| // -------------------------------------------------------------------------------------------- | |||||
| BlobIOStream :: ~BlobIOStream() | |||||
| { | |||||
| creator->OnDestruct(file,this); | |||||
| delete[] buffer; | |||||
| } | |||||
| } // end Assimp | |||||
| #endif | |||||
| @@ -0,0 +1,23 @@ | |||||
| Boost Software License - Version 1.0 - August 17th, 2003 | |||||
| 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. | |||||
| @@ -0,0 +1,99 @@ | |||||
| #ifndef BOOST_FOREACH | |||||
| /////////////////////////////////////////////////////////////////////////////// | |||||
| // A stripped down version of FOREACH for | |||||
| // illustration purposes. NOT FOR GENERAL USE. | |||||
| // For a complete implementation, see BOOST_FOREACH at | |||||
| // http://boost-sandbox.sourceforge.net/vault/index.php?directory=eric_niebler | |||||
| // | |||||
| // Copyright 2004 Eric Niebler. | |||||
| // Distributed under the Boost Software License, Version 1.0. (See | |||||
| // accompanying file LICENSE_1_0.txt or copy at | |||||
| // http://www.boost.org/LICENSE_1_0.txt) | |||||
| // | |||||
| // Adapted to Assimp November 29th, 2008 (Alexander Gessler). | |||||
| // Added code to handle both const and non-const iterators, simplified some | |||||
| // parts. | |||||
| /////////////////////////////////////////////////////////////////////////////// | |||||
| namespace boost { | |||||
| namespace foreach_detail { | |||||
| /////////////////////////////////////////////////////////////////////////////// | |||||
| // auto_any | |||||
| struct auto_any_base | |||||
| { | |||||
| operator bool() const { return false; } | |||||
| }; | |||||
| template<typename T> | |||||
| struct auto_any : auto_any_base | |||||
| { | |||||
| auto_any(T const& t) : item(t) {} | |||||
| mutable T item; | |||||
| }; | |||||
| template<typename T> | |||||
| T& auto_any_cast(auto_any_base const& any) | |||||
| { | |||||
| return static_cast<auto_any<T> const&>(any).item; | |||||
| } | |||||
| /////////////////////////////////////////////////////////////////////////////// | |||||
| // FOREACH helper function | |||||
| template<typename T> | |||||
| auto_any<typename T::const_iterator> begin(T const& t) | |||||
| { | |||||
| return t.begin(); | |||||
| } | |||||
| template<typename T> | |||||
| auto_any<typename T::const_iterator> end(T const& t) | |||||
| { | |||||
| return t.end(); | |||||
| } | |||||
| // iterator | |||||
| template<typename T> | |||||
| bool done(auto_any_base const& cur, auto_any_base const& end, T&) | |||||
| { | |||||
| typedef typename T::iterator iter_type; | |||||
| return auto_any_cast<iter_type>(cur) == auto_any_cast<iter_type>(end); | |||||
| } | |||||
| template<typename T> | |||||
| void next(auto_any_base const& cur, T&) | |||||
| { | |||||
| ++auto_any_cast<typename T::iterator>(cur); | |||||
| } | |||||
| template<typename T> | |||||
| typename T::reference deref(auto_any_base const& cur, T&) | |||||
| { | |||||
| return *auto_any_cast<typename T::iterator>(cur); | |||||
| } | |||||
| template<typename T> | |||||
| typename T::const_reference deref(auto_any_base const& cur, const T&) | |||||
| { | |||||
| return *auto_any_cast<typename T::iterator>(cur); | |||||
| } | |||||
| } // end foreach_detail | |||||
| /////////////////////////////////////////////////////////////////////////////// | |||||
| // FOREACH | |||||
| #define BOOST_FOREACH(item, container) \ | |||||
| if(boost::foreach_detail::auto_any_base const& foreach_magic_b = boost::foreach_detail::begin(container)) {} else \ | |||||
| if(boost::foreach_detail::auto_any_base const& foreach_magic_e = boost::foreach_detail::end(container)) {} else \ | |||||
| for(;!boost::foreach_detail::done(foreach_magic_b,foreach_magic_e,container); boost::foreach_detail::next(foreach_magic_b,container)) \ | |||||
| if (bool ugly_and_unique_break = false) {} else \ | |||||
| for(item = boost::foreach_detail::deref(foreach_magic_b,container); !ugly_and_unique_break; ugly_and_unique_break = true) | |||||
| } // end boost | |||||
| #endif | |||||
| @@ -0,0 +1,81 @@ | |||||
| /* DEPRECATED! - use code/TinyFormatter.h instead. | |||||
| * | |||||
| * | |||||
| * */ | |||||
| #ifndef AI_BOOST_FORMAT_DUMMY_INCLUDED | |||||
| #define AI_BOOST_FORMAT_DUMMY_INCLUDED | |||||
| #if (!defined BOOST_FORMAT_HPP) || (defined ASSIMP_FORCE_NOBOOST) | |||||
| #include <string> | |||||
| #include <vector> | |||||
| namespace boost | |||||
| { | |||||
| class format | |||||
| { | |||||
| public: | |||||
| format (const std::string& _d) | |||||
| : d(_d) | |||||
| { | |||||
| } | |||||
| template <typename T> | |||||
| format& operator % (T in) | |||||
| { | |||||
| // XXX add replacement for boost::lexical_cast? | |||||
| std::ostringstream ss; | |||||
| ss << in; // note: ss cannot be an rvalue, or the global operator << (const char*) is not called for T == const char*. | |||||
| chunks.push_back( ss.str()); | |||||
| return *this; | |||||
| } | |||||
| operator std::string () const { | |||||
| std::string res; // pray for NRVO to kick in | |||||
| size_t start = 0, last = 0; | |||||
| std::vector<std::string>::const_iterator chunkin = chunks.begin(); | |||||
| for ( start = d.find('%');start != std::string::npos; start = d.find('%',last)) { | |||||
| res += d.substr(last,start-last); | |||||
| last = start+2; | |||||
| if (d[start+1] == '%') { | |||||
| res += "%"; | |||||
| continue; | |||||
| } | |||||
| if (chunkin == chunks.end()) { | |||||
| break; | |||||
| } | |||||
| res += *chunkin++; | |||||
| } | |||||
| res += d.substr(last); | |||||
| return res; | |||||
| } | |||||
| private: | |||||
| std::string d; | |||||
| std::vector<std::string> chunks; | |||||
| }; | |||||
| inline std::string str(const std::string& s) { | |||||
| return s; | |||||
| } | |||||
| } | |||||
| #else | |||||
| # error "format.h was already included" | |||||
| #endif // | |||||
| #endif // !! AI_BOOST_FORMAT_DUMMY_INCLUDED | |||||
| @@ -0,0 +1,26 @@ | |||||
| /// A quick replacement for boost::lexical_cast for all the Boost haters out there | |||||
| #ifndef __AI_BOOST_WORKAROUND_LEXICAL_CAST | |||||
| #define __AI_BOOST_WORKAROUND_LEXICAL_CAST | |||||
| #include <sstream> | |||||
| namespace boost | |||||
| { | |||||
| /// A quick replacement for boost::lexical_cast - should work for all types a stringstream can handle | |||||
| template <typename TargetType, typename SourceType> | |||||
| TargetType lexical_cast( const SourceType& source) | |||||
| { | |||||
| std::stringstream stream; | |||||
| TargetType result; | |||||
| stream << source; | |||||
| stream >> result; | |||||
| return result; | |||||
| } | |||||
| } // namespace boost | |||||
| #endif // __AI_BOOST_WORKAROUND_LEXICAL_CAST | |||||
| @@ -0,0 +1,57 @@ | |||||
| // please note that this replacement implementation does not | |||||
| // provide the performance benefit of the original, which | |||||
| // makes only one allocation as opposed to two allocations | |||||
| // (smart pointer counter and payload) which are usually | |||||
| // required if object and smart pointer are constructed | |||||
| // independently. | |||||
| #ifndef INCLUDED_AI_BOOST_MAKE_SHARED | |||||
| #define INCLUDED_AI_BOOST_MAKE_SHARED | |||||
| namespace boost { | |||||
| template <typename T> | |||||
| shared_ptr<T> make_shared() { | |||||
| return shared_ptr<T>(new T()); | |||||
| } | |||||
| template <typename T, typename T0> | |||||
| shared_ptr<T> make_shared(const T0& t0) { | |||||
| return shared_ptr<T>(new T(t0)); | |||||
| } | |||||
| template <typename T, typename T0,typename T1> | |||||
| shared_ptr<T> make_shared(const T0& t0, const T1& t1) { | |||||
| return shared_ptr<T>(new T(t0,t1)); | |||||
| } | |||||
| template <typename T, typename T0,typename T1,typename T2> | |||||
| shared_ptr<T> make_shared(const T0& t0, const T1& t1, const T2& t2) { | |||||
| return shared_ptr<T>(new T(t0,t1,t2)); | |||||
| } | |||||
| template <typename T, typename T0,typename T1,typename T2,typename T3> | |||||
| shared_ptr<T> make_shared(const T0& t0, const T1& t1, const T2& t2, const T3& t3) { | |||||
| return shared_ptr<T>(new T(t0,t1,t2,t3)); | |||||
| } | |||||
| template <typename T, typename T0,typename T1,typename T2,typename T3, typename T4> | |||||
| shared_ptr<T> make_shared(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4) { | |||||
| return shared_ptr<T>(new T(t0,t1,t2,t3,t4)); | |||||
| } | |||||
| template <typename T, typename T0,typename T1,typename T2,typename T3, typename T4, typename T5> | |||||
| shared_ptr<T> make_shared(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5) { | |||||
| return shared_ptr<T>(new T(t0,t1,t2,t3,t4,t5)); | |||||
| } | |||||
| template <typename T, typename T0,typename T1,typename T2,typename T3, typename T4, typename T5, typename T6> | |||||
| shared_ptr<T> make_shared(const T0& t0, const T1& t1, const T2& t2, const T3& t3, const T4& t4, const T5& t5, const T6& t6) { | |||||
| return shared_ptr<T>(new T(t0,t1,t2,t3,t4,t5,t6)); | |||||
| } | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,37 @@ | |||||
| #ifndef BOOST_MATH_COMMON_FACTOR_RT_HPP | |||||
| #define BOOST_MATH_COMMON_FACTOR_RT_HPP | |||||
| namespace boost { | |||||
| namespace math { | |||||
| // TODO: use binary GCD for unsigned integers .... | |||||
| template < typename IntegerType > | |||||
| IntegerType gcd( IntegerType a, IntegerType b ) | |||||
| { | |||||
| const IntegerType zero = (IntegerType)0; | |||||
| while ( true ) | |||||
| { | |||||
| if ( a == zero ) | |||||
| return b; | |||||
| b %= a; | |||||
| if ( b == zero ) | |||||
| return a; | |||||
| a %= b; | |||||
| } | |||||
| } | |||||
| template < typename IntegerType > | |||||
| IntegerType lcm( IntegerType a, IntegerType b ) | |||||
| { | |||||
| const IntegerType t = gcd (a,b); | |||||
| if (!t)return t; | |||||
| return a / t * b; | |||||
| } | |||||
| }} | |||||
| #endif | |||||
| @@ -0,0 +1,36 @@ | |||||
| // Boost noncopyable.hpp header file --------------------------------------// | |||||
| // (C) Copyright Beman Dawes 1999-2003. Distributed under the Boost | |||||
| // Software License, Version 1.0. (See accompanying file | |||||
| // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |||||
| // See http://www.boost.org/libs/utility for documentation. | |||||
| #ifndef BOOST_NONCOPYABLE_HPP_INCLUDED | |||||
| #define BOOST_NONCOPYABLE_HPP_INCLUDED | |||||
| namespace boost { | |||||
| // Private copy constructor and copy assignment ensure classes derived from | |||||
| // class noncopyable cannot be copied. | |||||
| // Contributed by Dave Abrahams | |||||
| namespace noncopyable_ // protection from unintended ADL | |||||
| { | |||||
| class noncopyable | |||||
| { | |||||
| protected: | |||||
| noncopyable() {} | |||||
| ~noncopyable() {} | |||||
| private: // emphasize the following members are private | |||||
| noncopyable( const noncopyable& ); | |||||
| const noncopyable& operator=( const noncopyable& ); | |||||
| }; | |||||
| } | |||||
| typedef noncopyable_::noncopyable noncopyable; | |||||
| } // namespace boost | |||||
| #endif // BOOST_NONCOPYABLE_HPP_INCLUDED | |||||
| @@ -0,0 +1,45 @@ | |||||
| ////////////////////////////////////////////////////////////////////////////// | |||||
| // | |||||
| // (C) Copyright Ion Gaztanaga 2005. | |||||
| // Distributed under the Boost Software License, Version 1.0. | |||||
| // (See accompanying file LICENSE_1_0.txt or copy at | |||||
| // http://www.boost.org/LICENSE_1_0.txt) | |||||
| // | |||||
| ////////////////////////////////////////////////////////////////////////////// | |||||
| #ifndef BOOST_POINTER_CAST_HPP | |||||
| #define BOOST_POINTER_CAST_HPP | |||||
| namespace boost { | |||||
| //static_pointer_cast overload for raw pointers | |||||
| template<class T, class U> | |||||
| inline T* static_pointer_cast(U *ptr) | |||||
| { | |||||
| return static_cast<T*>(ptr); | |||||
| } | |||||
| //dynamic_pointer_cast overload for raw pointers | |||||
| template<class T, class U> | |||||
| inline T* dynamic_pointer_cast(U *ptr) | |||||
| { | |||||
| return dynamic_cast<T*>(ptr); | |||||
| } | |||||
| //const_pointer_cast overload for raw pointers | |||||
| template<class T, class U> | |||||
| inline T* const_pointer_cast(U *ptr) | |||||
| { | |||||
| return const_cast<T*>(ptr); | |||||
| } | |||||
| //reinterpret_pointer_cast overload for raw pointers | |||||
| template<class T, class U> | |||||
| inline T* reinterpret_pointer_cast(U *ptr) | |||||
| { | |||||
| return reinterpret_cast<T*>(ptr); | |||||
| } | |||||
| } // namespace boost | |||||
| #endif //BOOST_POINTER_CAST_HPP | |||||
| @@ -0,0 +1,79 @@ | |||||
| #ifndef __AI_BOOST_SCOPED_ARRAY_INCLUDED | |||||
| #define __AI_BOOST_SCOPED_ARRAY_INCLUDED | |||||
| #ifndef BOOST_SCOPED_ARRAY_HPP_INCLUDED | |||||
| namespace boost { | |||||
| // small replacement for boost::scoped_array | |||||
| template <class T> | |||||
| class scoped_array | |||||
| { | |||||
| public: | |||||
| // provide a default construtctor | |||||
| scoped_array() | |||||
| : ptr(0) | |||||
| { | |||||
| } | |||||
| // construction from an existing heap object of type T | |||||
| scoped_array(T* _ptr) | |||||
| : ptr(_ptr) | |||||
| { | |||||
| } | |||||
| // automatic destruction of the wrapped object at the | |||||
| // end of our lifetime | |||||
| ~scoped_array() | |||||
| { | |||||
| delete[] ptr; | |||||
| } | |||||
| inline T* get() | |||||
| { | |||||
| return ptr; | |||||
| } | |||||
| inline T* operator-> () | |||||
| { | |||||
| return ptr; | |||||
| } | |||||
| inline void reset (T* t = 0) | |||||
| { | |||||
| delete[] ptr; | |||||
| ptr = t; | |||||
| } | |||||
| T & operator[](std::ptrdiff_t i) const | |||||
| { | |||||
| return ptr[i]; | |||||
| } | |||||
| void swap(scoped_array & b) | |||||
| { | |||||
| std::swap(ptr, b.ptr); | |||||
| } | |||||
| private: | |||||
| // encapsulated object pointer | |||||
| T* ptr; | |||||
| }; | |||||
| template<class T> | |||||
| inline void swap(scoped_array<T> & a, scoped_array<T> & b) | |||||
| { | |||||
| a.swap(b); | |||||
| } | |||||
| } // end of namespace boost | |||||
| #else | |||||
| # error "scoped_array.h was already included" | |||||
| #endif | |||||
| #endif // __AI_BOOST_SCOPED_ARRAY_INCLUDED | |||||
| @@ -0,0 +1,79 @@ | |||||
| #ifndef __AI_BOOST_SCOPED_PTR_INCLUDED | |||||
| #define __AI_BOOST_SCOPED_PTR_INCLUDED | |||||
| #ifndef BOOST_SCOPED_PTR_HPP_INCLUDED | |||||
| namespace boost { | |||||
| // small replacement for boost::scoped_ptr | |||||
| template <class T> | |||||
| class scoped_ptr | |||||
| { | |||||
| public: | |||||
| // provide a default construtctor | |||||
| scoped_ptr() | |||||
| : ptr(0) | |||||
| { | |||||
| } | |||||
| // construction from an existing heap object of type T | |||||
| scoped_ptr(T* _ptr) | |||||
| : ptr(_ptr) | |||||
| { | |||||
| } | |||||
| // automatic destruction of the wrapped object at the | |||||
| // end of our lifetime | |||||
| ~scoped_ptr() | |||||
| { | |||||
| delete ptr; | |||||
| } | |||||
| inline T* get() const | |||||
| { | |||||
| return ptr; | |||||
| } | |||||
| inline operator T*() | |||||
| { | |||||
| return ptr; | |||||
| } | |||||
| inline T* operator-> () | |||||
| { | |||||
| return ptr; | |||||
| } | |||||
| inline void reset (T* t = 0) | |||||
| { | |||||
| delete ptr; | |||||
| ptr = t; | |||||
| } | |||||
| void swap(scoped_ptr & b) | |||||
| { | |||||
| std::swap(ptr, b.ptr); | |||||
| } | |||||
| private: | |||||
| // encapsulated object pointer | |||||
| T* ptr; | |||||
| }; | |||||
| template<class T> | |||||
| inline void swap(scoped_ptr<T> & a, scoped_ptr<T> & b) | |||||
| { | |||||
| a.swap(b); | |||||
| } | |||||
| } // end of namespace boost | |||||
| #else | |||||
| # error "scoped_ptr.h was already included" | |||||
| #endif | |||||
| #endif // __AI_BOOST_SCOPED_PTR_INCLUDED | |||||
| @@ -0,0 +1,228 @@ | |||||
| #ifndef INCLUDED_AI_BOOST_SHARED_ARRAY | |||||
| #define INCLUDED_AI_BOOST_SHARED_ARRAY | |||||
| #ifndef BOOST_SHARED_ARRAY_HPP_INCLUDED | |||||
| // ------------------------------ | |||||
| // Internal stub | |||||
| namespace boost { | |||||
| namespace array_detail { | |||||
| class controller { | |||||
| public: | |||||
| controller() | |||||
| : cnt(1) | |||||
| {} | |||||
| public: | |||||
| template <typename T> | |||||
| controller* decref(T* pt) { | |||||
| if (--cnt <= 0) { | |||||
| delete this; | |||||
| delete[] pt; | |||||
| } | |||||
| return NULL; | |||||
| } | |||||
| controller* incref() { | |||||
| ++cnt; | |||||
| return this; | |||||
| } | |||||
| long get() const { | |||||
| return cnt; | |||||
| } | |||||
| private: | |||||
| long cnt; | |||||
| }; | |||||
| struct empty {}; | |||||
| template <typename DEST, typename SRC> | |||||
| struct is_convertible_stub { | |||||
| struct yes {char s[1];}; | |||||
| struct no {char s[2];}; | |||||
| static yes foo(DEST*); | |||||
| static no foo(...); | |||||
| enum {result = (sizeof(foo((SRC*)0)) == sizeof(yes) ? 1 : 0)}; | |||||
| }; | |||||
| template <bool> struct enable_if {}; | |||||
| template <> struct enable_if<true> { | |||||
| typedef empty result; | |||||
| }; | |||||
| template <typename DEST, typename SRC> | |||||
| struct is_convertible : public enable_if<is_convertible_stub<DEST,SRC>::result > { | |||||
| }; | |||||
| } | |||||
| // ------------------------------ | |||||
| // Small replacement for boost::shared_array, not threadsafe because no | |||||
| // atomic reference counter is in use. | |||||
| // ------------------------------ | |||||
| template <class T> | |||||
| class shared_array | |||||
| { | |||||
| template <typename TT> friend class shared_array; | |||||
| template<class TT> friend bool operator== (const shared_array<TT>& a, const shared_array<TT>& b); | |||||
| template<class TT> friend bool operator!= (const shared_array<TT>& a, const shared_array<TT>& b); | |||||
| template<class TT> friend bool operator< (const shared_array<TT>& a, const shared_array<TT>& b); | |||||
| public: | |||||
| typedef T element_type; | |||||
| public: | |||||
| // provide a default constructor | |||||
| shared_array() | |||||
| : ptr() | |||||
| , ctr(NULL) | |||||
| { | |||||
| } | |||||
| // construction from an existing object of type T | |||||
| explicit shared_array(T* ptr) | |||||
| : ptr(ptr) | |||||
| , ctr(ptr ? new array_detail::controller() : NULL) | |||||
| { | |||||
| } | |||||
| shared_array(const shared_array& r) | |||||
| : ptr(r.ptr) | |||||
| , ctr(r.ctr ? r.ctr->incref() : NULL) | |||||
| { | |||||
| } | |||||
| template <typename Y> | |||||
| shared_array(const shared_array<Y>& r,typename detail::is_convertible<T,Y>::result = detail::empty()) | |||||
| : ptr(r.ptr) | |||||
| , ctr(r.ctr ? r.ctr->incref() : NULL) | |||||
| { | |||||
| } | |||||
| // automatic destruction of the wrapped object when all | |||||
| // references are freed. | |||||
| ~shared_array() { | |||||
| if (ctr) { | |||||
| ctr = ctr->decref(ptr); | |||||
| } | |||||
| } | |||||
| shared_array& operator=(const shared_array& r) { | |||||
| if (this == &r) { | |||||
| return *this; | |||||
| } | |||||
| if (ctr) { | |||||
| ctr->decref(ptr); | |||||
| } | |||||
| ptr = r.ptr; | |||||
| ctr = ptr?r.ctr->incref():NULL; | |||||
| return *this; | |||||
| } | |||||
| template <typename Y> | |||||
| shared_array& operator=(const shared_array<Y>& r) { | |||||
| if (this == &r) { | |||||
| return *this; | |||||
| } | |||||
| if (ctr) { | |||||
| ctr->decref(ptr); | |||||
| } | |||||
| ptr = r.ptr; | |||||
| ctr = ptr?r.ctr->incref():NULL; | |||||
| return *this; | |||||
| } | |||||
| // pointer access | |||||
| inline operator T*() { | |||||
| return ptr; | |||||
| } | |||||
| inline T* operator-> () const { | |||||
| return ptr; | |||||
| } | |||||
| // standard semantics | |||||
| inline T* get() { | |||||
| return ptr; | |||||
| } | |||||
| T& operator[] (std::ptrdiff_t index) const { | |||||
| return ptr[index]; | |||||
| } | |||||
| inline const T* get() const { | |||||
| return ptr; | |||||
| } | |||||
| inline operator bool () const { | |||||
| return ptr != NULL; | |||||
| } | |||||
| inline bool unique() const { | |||||
| return use_count() == 1; | |||||
| } | |||||
| inline long use_count() const { | |||||
| return ctr->get(); | |||||
| } | |||||
| inline void reset (T* t = 0) { | |||||
| if (ctr) { | |||||
| ctr->decref(ptr); | |||||
| } | |||||
| ptr = t; | |||||
| ctr = ptr?new array_detail::controller():NULL; | |||||
| } | |||||
| void swap(shared_array & b) { | |||||
| std::swap(ptr, b.ptr); | |||||
| std::swap(ctr, b.ctr); | |||||
| } | |||||
| private: | |||||
| // encapsulated object pointer | |||||
| T* ptr; | |||||
| // control block | |||||
| array_detail::controller* ctr; | |||||
| }; | |||||
| template<class T> | |||||
| inline void swap(shared_array<T> & a, shared_array<T> & b) | |||||
| { | |||||
| a.swap(b); | |||||
| } | |||||
| template<class T> | |||||
| bool operator== (const shared_array<T>& a, const shared_array<T>& b) { | |||||
| return a.ptr == b.ptr; | |||||
| } | |||||
| template<class T> | |||||
| bool operator!= (const shared_array<T>& a, const shared_array<T>& b) { | |||||
| return a.ptr != b.ptr; | |||||
| } | |||||
| template<class T> | |||||
| bool operator< (const shared_array<T>& a, const shared_array<T>& b) { | |||||
| return a.ptr < b.ptr; | |||||
| } | |||||
| } // end of namespace boost | |||||
| #else | |||||
| # error "shared_array.h was already included" | |||||
| #endif | |||||
| #endif // INCLUDED_AI_BOOST_SHARED_ARRAY | |||||
| @@ -0,0 +1,257 @@ | |||||
| #ifndef INCLUDED_AI_BOOST_SHARED_PTR | |||||
| #define INCLUDED_AI_BOOST_SHARED_PTR | |||||
| #ifndef BOOST_SHARED_PTR_HPP_INCLUDED | |||||
| // ------------------------------ | |||||
| // Internal stub | |||||
| namespace boost { | |||||
| namespace detail { | |||||
| class controller { | |||||
| public: | |||||
| controller() | |||||
| : cnt(1) | |||||
| {} | |||||
| public: | |||||
| template <typename T> | |||||
| controller* decref(T* pt) { | |||||
| if (--cnt <= 0) { | |||||
| delete this; | |||||
| delete pt; | |||||
| } | |||||
| return NULL; | |||||
| } | |||||
| controller* incref() { | |||||
| ++cnt; | |||||
| return this; | |||||
| } | |||||
| long get() const { | |||||
| return cnt; | |||||
| } | |||||
| private: | |||||
| long cnt; | |||||
| }; | |||||
| struct empty {}; | |||||
| template <typename DEST, typename SRC> | |||||
| struct is_convertible_stub { | |||||
| struct yes {char s[1];}; | |||||
| struct no {char s[2];}; | |||||
| static yes foo(DEST*); | |||||
| static no foo(...); | |||||
| enum {result = (sizeof(foo((SRC*)0)) == sizeof(yes) ? 1 : 0)}; | |||||
| }; | |||||
| template <bool> struct enable_if {}; | |||||
| template <> struct enable_if<true> { | |||||
| typedef empty result; | |||||
| }; | |||||
| template <typename DEST, typename SRC> | |||||
| struct is_convertible : public enable_if<is_convertible_stub<DEST,SRC>::result > { | |||||
| }; | |||||
| } | |||||
| // ------------------------------ | |||||
| // Small replacement for boost::shared_ptr, not threadsafe because no | |||||
| // atomic reference counter is in use. | |||||
| // ------------------------------ | |||||
| template <class T> | |||||
| class shared_ptr | |||||
| { | |||||
| template <typename TT> friend class shared_ptr; | |||||
| template<class TT, class U> friend shared_ptr<TT> static_pointer_cast (shared_ptr<U> ptr); | |||||
| template<class TT, class U> friend shared_ptr<TT> dynamic_pointer_cast (shared_ptr<U> ptr); | |||||
| template<class TT, class U> friend shared_ptr<TT> const_pointer_cast (shared_ptr<U> ptr); | |||||
| template<class TT> friend bool operator== (const shared_ptr<TT>& a, const shared_ptr<TT>& b); | |||||
| template<class TT> friend bool operator!= (const shared_ptr<TT>& a, const shared_ptr<TT>& b); | |||||
| template<class TT> friend bool operator< (const shared_ptr<TT>& a, const shared_ptr<TT>& b); | |||||
| public: | |||||
| typedef T element_type; | |||||
| public: | |||||
| // provide a default constructor | |||||
| shared_ptr() | |||||
| : ptr() | |||||
| , ctr(NULL) | |||||
| { | |||||
| } | |||||
| // construction from an existing object of type T | |||||
| explicit shared_ptr(T* ptr) | |||||
| : ptr(ptr) | |||||
| , ctr(ptr ? new detail::controller() : NULL) | |||||
| { | |||||
| } | |||||
| shared_ptr(const shared_ptr& r) | |||||
| : ptr(r.ptr) | |||||
| , ctr(r.ctr ? r.ctr->incref() : NULL) | |||||
| { | |||||
| } | |||||
| template <typename Y> | |||||
| shared_ptr(const shared_ptr<Y>& r,typename detail::is_convertible<T,Y>::result = detail::empty()) | |||||
| : ptr(r.ptr) | |||||
| , ctr(r.ctr ? r.ctr->incref() : NULL) | |||||
| { | |||||
| } | |||||
| // automatic destruction of the wrapped object when all | |||||
| // references are freed. | |||||
| ~shared_ptr() { | |||||
| if (ctr) { | |||||
| ctr = ctr->decref(ptr); | |||||
| } | |||||
| } | |||||
| shared_ptr& operator=(const shared_ptr& r) { | |||||
| if (this == &r) { | |||||
| return *this; | |||||
| } | |||||
| if (ctr) { | |||||
| ctr->decref(ptr); | |||||
| } | |||||
| ptr = r.ptr; | |||||
| ctr = ptr?r.ctr->incref():NULL; | |||||
| return *this; | |||||
| } | |||||
| template <typename Y> | |||||
| shared_ptr& operator=(const shared_ptr<Y>& r) { | |||||
| if (this == &r) { | |||||
| return *this; | |||||
| } | |||||
| if (ctr) { | |||||
| ctr->decref(ptr); | |||||
| } | |||||
| ptr = r.ptr; | |||||
| ctr = ptr?r.ctr->incref():NULL; | |||||
| return *this; | |||||
| } | |||||
| // pointer access | |||||
| inline operator T*() const { | |||||
| return ptr; | |||||
| } | |||||
| inline T* operator-> () const { | |||||
| return ptr; | |||||
| } | |||||
| // standard semantics | |||||
| inline T* get() { | |||||
| return ptr; | |||||
| } | |||||
| inline const T* get() const { | |||||
| return ptr; | |||||
| } | |||||
| inline operator bool () const { | |||||
| return ptr != NULL; | |||||
| } | |||||
| inline bool unique() const { | |||||
| return use_count() == 1; | |||||
| } | |||||
| inline long use_count() const { | |||||
| return ctr->get(); | |||||
| } | |||||
| inline void reset (T* t = 0) { | |||||
| if (ctr) { | |||||
| ctr->decref(ptr); | |||||
| } | |||||
| ptr = t; | |||||
| ctr = ptr?new detail::controller():NULL; | |||||
| } | |||||
| void swap(shared_ptr & b) { | |||||
| std::swap(ptr, b.ptr); | |||||
| std::swap(ctr, b.ctr); | |||||
| } | |||||
| private: | |||||
| // for use by the various xxx_pointer_cast helper templates | |||||
| explicit shared_ptr(T* ptr, detail::controller* ctr) | |||||
| : ptr(ptr) | |||||
| , ctr(ctr->incref()) | |||||
| { | |||||
| } | |||||
| private: | |||||
| // encapsulated object pointer | |||||
| T* ptr; | |||||
| // control block | |||||
| detail::controller* ctr; | |||||
| }; | |||||
| template<class T> | |||||
| inline void swap(shared_ptr<T> & a, shared_ptr<T> & b) | |||||
| { | |||||
| a.swap(b); | |||||
| } | |||||
| template<class T> | |||||
| bool operator== (const shared_ptr<T>& a, const shared_ptr<T>& b) { | |||||
| return a.ptr == b.ptr; | |||||
| } | |||||
| template<class T> | |||||
| bool operator!= (const shared_ptr<T>& a, const shared_ptr<T>& b) { | |||||
| return a.ptr != b.ptr; | |||||
| } | |||||
| template<class T> | |||||
| bool operator< (const shared_ptr<T>& a, const shared_ptr<T>& b) { | |||||
| return a.ptr < b.ptr; | |||||
| } | |||||
| template<class T, class U> | |||||
| inline shared_ptr<T> static_pointer_cast( shared_ptr<U> ptr) | |||||
| { | |||||
| return shared_ptr<T>(static_cast<T*>(ptr.ptr),ptr.ctr); | |||||
| } | |||||
| template<class T, class U> | |||||
| inline shared_ptr<T> dynamic_pointer_cast( shared_ptr<U> ptr) | |||||
| { | |||||
| return shared_ptr<T>(dynamic_cast<T*>(ptr.ptr),ptr.ctr); | |||||
| } | |||||
| template<class T, class U> | |||||
| inline shared_ptr<T> const_pointer_cast( shared_ptr<U> ptr) | |||||
| { | |||||
| return shared_ptr<T>(const_cast<T*>(ptr.ptr),ptr.ctr); | |||||
| } | |||||
| } // end of namespace boost | |||||
| #else | |||||
| # error "shared_ptr.h was already included" | |||||
| #endif | |||||
| #endif // INCLUDED_AI_BOOST_SHARED_PTR | |||||
| @@ -0,0 +1,20 @@ | |||||
| #ifndef AI_BOOST_STATIC_ASSERT_INCLUDED | |||||
| #define AI_BOOST_STATIC_ASSERT_INCLUDED | |||||
| #ifndef BOOST_STATIC_ASSERT | |||||
| namespace boost { | |||||
| namespace detail { | |||||
| template <bool b> class static_assertion_failure; | |||||
| template <> class static_assertion_failure<true> {}; | |||||
| } | |||||
| } | |||||
| #define BOOST_STATIC_ASSERT(eval) \ | |||||
| {boost::detail::static_assertion_failure<(eval)> assert_dummy;(void)assert_dummy;} | |||||
| #endif | |||||
| #endif // !! AI_BOOST_STATIC_ASSERT_INCLUDED | |||||
| @@ -0,0 +1,72 @@ | |||||
| // boost timer.hpp header file ---------------------------------------------// | |||||
| // Copyright Beman Dawes 1994-99. Distributed under the Boost | |||||
| // Software License, Version 1.0. (See accompanying file | |||||
| // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |||||
| // See http://www.boost.org/libs/timer for documentation. | |||||
| // Revision History | |||||
| // 01 Apr 01 Modified to use new <boost/limits.hpp> header. (JMaddock) | |||||
| // 12 Jan 01 Change to inline implementation to allow use without library | |||||
| // builds. See docs for more rationale. (Beman Dawes) | |||||
| // 25 Sep 99 elapsed_max() and elapsed_min() added (John Maddock) | |||||
| // 16 Jul 99 Second beta | |||||
| // 6 Jul 99 Initial boost version | |||||
| #ifndef BOOST_TIMER_HPP | |||||
| #define BOOST_TIMER_HPP | |||||
| //#include <boost/config.hpp> | |||||
| #include <ctime> | |||||
| //#include <boost/limits.hpp> | |||||
| # ifdef BOOST_NO_STDC_NAMESPACE | |||||
| namespace std { using ::clock_t; using ::clock; } | |||||
| # endif | |||||
| namespace boost { | |||||
| // timer -------------------------------------------------------------------// | |||||
| // A timer object measures elapsed time. | |||||
| // It is recommended that implementations measure wall clock rather than CPU | |||||
| // time since the intended use is performance measurement on systems where | |||||
| // total elapsed time is more important than just process or CPU time. | |||||
| // Warnings: The maximum measurable elapsed time may well be only 596.5+ hours | |||||
| // due to implementation limitations. The accuracy of timings depends on the | |||||
| // accuracy of timing information provided by the underlying platform, and | |||||
| // this varies a great deal from platform to platform. | |||||
| class timer | |||||
| { | |||||
| public: | |||||
| timer() { _start_time = std::clock(); } // postcondition: elapsed()==0 | |||||
| // timer( const timer& src ); // post: elapsed()==src.elapsed() | |||||
| // ~timer(){} | |||||
| // timer& operator=( const timer& src ); // post: elapsed()==src.elapsed() | |||||
| void restart() { _start_time = std::clock(); } // post: elapsed()==0 | |||||
| double elapsed() const // return elapsed time in seconds | |||||
| { return double(std::clock() - _start_time) / CLOCKS_PER_SEC; } | |||||
| double elapsed_max() const // return estimated maximum value for elapsed() | |||||
| // Portability warning: elapsed_max() may return too high a value on systems | |||||
| // where std::clock_t overflows or resets at surprising values. | |||||
| { | |||||
| return (double((std::numeric_limits<std::clock_t>::max)()) | |||||
| - double(_start_time)) / double(CLOCKS_PER_SEC); | |||||
| } | |||||
| double elapsed_min() const // return minimum value for elapsed() | |||||
| { return double(1)/double(CLOCKS_PER_SEC); } | |||||
| private: | |||||
| std::clock_t _start_time; | |||||
| }; // timer | |||||
| } // namespace boost | |||||
| #endif // BOOST_TIMER_HPP | |||||
| @@ -0,0 +1,283 @@ | |||||
| // A very small replacement for boost::tuple | |||||
| // (c) Alexander Gessler, 2008 [alexander.gessler@gmx.net] | |||||
| #ifndef BOOST_TUPLE_INCLUDED | |||||
| #define BOOST_TUPLE_INCLUDED | |||||
| namespace boost { | |||||
| namespace detail { | |||||
| // Represents an empty tuple slot (up to 5 supported) | |||||
| struct nulltype {}; | |||||
| // For readable error messages | |||||
| struct tuple_component_idx_out_of_bounds; | |||||
| // To share some code for the const/nonconst versions of the getters | |||||
| template <bool b, typename T> | |||||
| struct ConstIf { | |||||
| typedef T t; | |||||
| }; | |||||
| template <typename T> | |||||
| struct ConstIf<true,T> { | |||||
| typedef const T t; | |||||
| }; | |||||
| // Predeclare some stuff | |||||
| template <typename, unsigned, typename, bool, unsigned> struct value_getter; | |||||
| // Helper to obtain the type of a tuple element | |||||
| template <typename T, unsigned NIDX, typename TNEXT, unsigned N /*= 0*/> | |||||
| struct type_getter { | |||||
| typedef type_getter<typename TNEXT::type,NIDX+1,typename TNEXT::next_type,N> next_elem_getter; | |||||
| typedef typename next_elem_getter::type type; | |||||
| }; | |||||
| template <typename T, unsigned NIDX, typename TNEXT > | |||||
| struct type_getter <T,NIDX,TNEXT,NIDX> { | |||||
| typedef T type; | |||||
| }; | |||||
| // Base class for all explicit specializations of list_elem | |||||
| template <typename T, unsigned NIDX, typename TNEXT > | |||||
| struct list_elem_base { | |||||
| // Store template parameters | |||||
| typedef TNEXT next_type; | |||||
| typedef T type; | |||||
| static const unsigned nidx = NIDX; | |||||
| }; | |||||
| // Represents an element in the tuple component list | |||||
| template <typename T, unsigned NIDX, typename TNEXT > | |||||
| struct list_elem : list_elem_base<T,NIDX,TNEXT>{ | |||||
| // Real members | |||||
| T me; | |||||
| TNEXT next; | |||||
| // Get the value of a specific tuple element | |||||
| template <unsigned N> | |||||
| typename type_getter<T,NIDX,TNEXT,N>::type& get () { | |||||
| value_getter <T,NIDX,TNEXT,false,N> s; | |||||
| return s(*this); | |||||
| } | |||||
| // Get the value of a specific tuple element | |||||
| template <unsigned N> | |||||
| const typename type_getter<T,NIDX,TNEXT,N>::type& get () const { | |||||
| value_getter <T,NIDX,TNEXT,true,N> s; | |||||
| return s(*this); | |||||
| } | |||||
| // Explicit cast | |||||
| template <typename T2, typename TNEXT2 > | |||||
| operator list_elem<T2,NIDX,TNEXT2> () const { | |||||
| list_elem<T2,NIDX,TNEXT2> ret; | |||||
| ret.me = (T2)me; | |||||
| ret.next = next; | |||||
| return ret; | |||||
| } | |||||
| // Recursively compare two elements (last element returns always true) | |||||
| bool operator == (const list_elem& s) const { | |||||
| return (me == s.me && next == s.next); | |||||
| } | |||||
| }; | |||||
| // Represents a non-used tuple element - the very last element processed | |||||
| template <typename TNEXT, unsigned NIDX > | |||||
| struct list_elem<nulltype,NIDX,TNEXT> : list_elem_base<nulltype,NIDX,TNEXT> { | |||||
| template <unsigned N, bool IS_CONST = true> struct value_getter { | |||||
| /* just dummy members to produce readable error messages */ | |||||
| tuple_component_idx_out_of_bounds operator () (typename ConstIf<IS_CONST,list_elem>::t& me); | |||||
| }; | |||||
| template <unsigned N> struct type_getter { | |||||
| /* just dummy members to produce readable error messages */ | |||||
| typedef tuple_component_idx_out_of_bounds type; | |||||
| }; | |||||
| // dummy | |||||
| list_elem& operator = (const list_elem& other) { | |||||
| return *this; | |||||
| } | |||||
| // dummy | |||||
| bool operator == (const list_elem& other) { | |||||
| return true; | |||||
| } | |||||
| }; | |||||
| // Represents the absolute end of the list | |||||
| typedef list_elem<nulltype,0,int> list_end; | |||||
| // Helper obtain to query the value of a tuple element | |||||
| // NOTE: This can't be a nested class as the compiler won't accept a full or | |||||
| // partial specialization of a nested class of a non-specialized template | |||||
| template <typename T, unsigned NIDX, typename TNEXT, bool IS_CONST, unsigned N> | |||||
| struct value_getter { | |||||
| // calling list_elem | |||||
| typedef list_elem<T,NIDX,TNEXT> outer_elem; | |||||
| // typedef for the getter for next element | |||||
| typedef value_getter<typename TNEXT::type,NIDX+1,typename TNEXT::next_type, | |||||
| IS_CONST, N> next_value_getter; | |||||
| typename ConstIf<IS_CONST,typename type_getter<T,NIDX,TNEXT,N>::type>::t& | |||||
| operator () (typename ConstIf<IS_CONST,outer_elem >::t& me) { | |||||
| next_value_getter s; | |||||
| return s(me.next); | |||||
| } | |||||
| }; | |||||
| template <typename T, unsigned NIDX, typename TNEXT, bool IS_CONST> | |||||
| struct value_getter <T,NIDX,TNEXT,IS_CONST,NIDX> { | |||||
| typedef list_elem<T,NIDX,TNEXT> outer_elem; | |||||
| typename ConstIf<IS_CONST,T>::t& operator () (typename ConstIf<IS_CONST,outer_elem >::t& me) { | |||||
| return me.me; | |||||
| } | |||||
| }; | |||||
| }; | |||||
| // A very minimal implementation for up to 5 elements | |||||
| template <typename T0 = detail::nulltype, | |||||
| typename T1 = detail::nulltype, | |||||
| typename T2 = detail::nulltype, | |||||
| typename T3 = detail::nulltype, | |||||
| typename T4 = detail::nulltype> | |||||
| class tuple { | |||||
| template <typename T0b, | |||||
| typename T1b, | |||||
| typename T2b, | |||||
| typename T3b, | |||||
| typename T4b > | |||||
| friend class tuple; | |||||
| private: | |||||
| typedef detail::list_elem<T0,0, | |||||
| detail::list_elem<T1,1, | |||||
| detail::list_elem<T2,2, | |||||
| detail::list_elem<T3,3, | |||||
| detail::list_elem<T4,4, | |||||
| detail::list_end > > > > > very_long; | |||||
| very_long m; | |||||
| public: | |||||
| // Get a specific tuple element | |||||
| template <unsigned N> | |||||
| typename detail::type_getter<T0,0,typename very_long::next_type, N>::type& get () { | |||||
| return m.template get<N>(); | |||||
| } | |||||
| // ... and the const version | |||||
| template <unsigned N> | |||||
| const typename detail::type_getter<T0,0,typename very_long::next_type, N>::type& get () const { | |||||
| return m.template get<N>(); | |||||
| } | |||||
| // comparison operators | |||||
| bool operator== (const tuple& other) const { | |||||
| return m == other.m; | |||||
| } | |||||
| // ... and the other way round | |||||
| bool operator!= (const tuple& other) const { | |||||
| return !(m == other.m); | |||||
| } | |||||
| // cast to another tuple - all single elements must be convertible | |||||
| template <typename T0b, typename T1b,typename T2b,typename T3b, typename T4b> | |||||
| operator tuple <T0b,T1b,T2b,T3b,T4b> () const { | |||||
| tuple <T0b,T1b,T2b,T3b,T4b> s; | |||||
| s.m = (typename tuple <T0b,T1b,T2b,T3b,T4b>::very_long)m; | |||||
| return s; | |||||
| } | |||||
| }; | |||||
| // Another way to access an element ... | |||||
| template <unsigned N,typename T0,typename T1,typename T2,typename T3,typename T4> | |||||
| inline typename tuple<T0,T1,T2,T3,T4>::very_long::template type_getter<N>::type& get ( | |||||
| tuple<T0,T1,T2,T3,T4>& m) { | |||||
| return m.template get<N>(); | |||||
| } | |||||
| // ... and the const version | |||||
| template <unsigned N,typename T0,typename T1,typename T2,typename T3,typename T4> | |||||
| inline const typename tuple<T0,T1,T2,T3,T4>::very_long::template type_getter<N>::type& get ( | |||||
| const tuple<T0,T1,T2,T3,T4>& m) { | |||||
| return m.template get<N>(); | |||||
| } | |||||
| // Constructs a tuple with 5 elements | |||||
| template <typename T0,typename T1,typename T2,typename T3,typename T4> | |||||
| inline tuple <T0,T1,T2,T3,T4> make_tuple (const T0& t0, | |||||
| const T1& t1,const T2& t2,const T3& t3,const T4& t4) { | |||||
| tuple <T0,T1,T2,T3,T4> t; | |||||
| t.template get<0>() = t0; | |||||
| t.template get<1>() = t1; | |||||
| t.template get<2>() = t2; | |||||
| t.template get<3>() = t3; | |||||
| t.template get<4>() = t4; | |||||
| return t; | |||||
| } | |||||
| // Constructs a tuple with 4 elements | |||||
| template <typename T0,typename T1,typename T2,typename T3> | |||||
| inline tuple <T0,T1,T2,T3> make_tuple (const T0& t0, | |||||
| const T1& t1,const T2& t2,const T3& t3) { | |||||
| tuple <T0,T1,T2,T3> t; | |||||
| t.template get<0>() = t0; | |||||
| t.template get<1>() = t1; | |||||
| t.template get<2>() = t2; | |||||
| t.template get<3>() = t3; | |||||
| return t; | |||||
| } | |||||
| // Constructs a tuple with 3 elements | |||||
| template <typename T0,typename T1,typename T2> | |||||
| inline tuple <T0,T1,T2> make_tuple (const T0& t0, | |||||
| const T1& t1,const T2& t2) { | |||||
| tuple <T0,T1,T2> t; | |||||
| t.template get<0>() = t0; | |||||
| t.template get<1>() = t1; | |||||
| t.template get<2>() = t2; | |||||
| return t; | |||||
| } | |||||
| // Constructs a tuple with 2 elements | |||||
| template <typename T0,typename T1> | |||||
| inline tuple <T0,T1> make_tuple (const T0& t0, | |||||
| const T1& t1) { | |||||
| tuple <T0,T1> t; | |||||
| t.template get<0>() = t0; | |||||
| t.template get<1>() = t1; | |||||
| return t; | |||||
| } | |||||
| // Constructs a tuple with 1 elements (well ...) | |||||
| template <typename T0> | |||||
| inline tuple <T0> make_tuple (const T0& t0) { | |||||
| tuple <T0> t; | |||||
| t.template get<0>() = t0; | |||||
| return t; | |||||
| } | |||||
| // Constructs a tuple with 0 elements (well ...) | |||||
| inline tuple <> make_tuple () { | |||||
| tuple <> t; | |||||
| return t; | |||||
| } | |||||
| }; | |||||
| #endif // !! BOOST_TUPLE_INCLUDED | |||||
| @@ -0,0 +1,285 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file Helper class tp perform various byte oder swappings | |||||
| (e.g. little to big endian) */ | |||||
| #ifndef AI_BYTESWAP_H_INC | |||||
| #define AI_BYTESWAP_H_INC | |||||
| #include "../include/assimp/ai_assert.h" | |||||
| #include "../include/assimp/types.h" | |||||
| #if _MSC_VER >= 1400 | |||||
| #include <stdlib.h> | |||||
| #endif | |||||
| namespace Assimp { | |||||
| // -------------------------------------------------------------------------------------- | |||||
| /** Defines some useful byte order swap routines. | |||||
| * | |||||
| * This is required to read big-endian model formats on little-endian machines, | |||||
| * and vice versa. Direct use of this class is DEPRECATED. Use #StreamReader instead. */ | |||||
| // -------------------------------------------------------------------------------------- | |||||
| class ByteSwap | |||||
| { | |||||
| ByteSwap() {} | |||||
| public: | |||||
| // ---------------------------------------------------------------------- | |||||
| /** Swap two bytes of data | |||||
| * @param[inout] _szOut A void* to save the reintcasts for the caller. */ | |||||
| static inline void Swap2(void* _szOut) | |||||
| { | |||||
| ai_assert(_szOut); | |||||
| #if _MSC_VER >= 1400 | |||||
| uint16_t* const szOut = reinterpret_cast<uint16_t*>(_szOut); | |||||
| *szOut = _byteswap_ushort(*szOut); | |||||
| #else | |||||
| uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut); | |||||
| std::swap(szOut[0],szOut[1]); | |||||
| #endif | |||||
| } | |||||
| // ---------------------------------------------------------------------- | |||||
| /** Swap four bytes of data | |||||
| * @param[inout] _szOut A void* to save the reintcasts for the caller. */ | |||||
| static inline void Swap4(void* _szOut) | |||||
| { | |||||
| ai_assert(_szOut); | |||||
| #if _MSC_VER >= 1400 | |||||
| uint32_t* const szOut = reinterpret_cast<uint32_t*>(_szOut); | |||||
| *szOut = _byteswap_ulong(*szOut); | |||||
| #else | |||||
| uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut); | |||||
| std::swap(szOut[0],szOut[3]); | |||||
| std::swap(szOut[1],szOut[2]); | |||||
| #endif | |||||
| } | |||||
| // ---------------------------------------------------------------------- | |||||
| /** Swap eight bytes of data | |||||
| * @param[inout] _szOut A void* to save the reintcasts for the caller. */ | |||||
| static inline void Swap8(void* _szOut) | |||||
| { | |||||
| ai_assert(_szOut); | |||||
| #if _MSC_VER >= 1400 | |||||
| uint64_t* const szOut = reinterpret_cast<uint64_t*>(_szOut); | |||||
| *szOut = _byteswap_uint64(*szOut); | |||||
| #else | |||||
| uint8_t* const szOut = reinterpret_cast<uint8_t*>(_szOut); | |||||
| std::swap(szOut[0],szOut[7]); | |||||
| std::swap(szOut[1],szOut[6]); | |||||
| std::swap(szOut[2],szOut[5]); | |||||
| std::swap(szOut[3],szOut[4]); | |||||
| #endif | |||||
| } | |||||
| // ---------------------------------------------------------------------- | |||||
| /** ByteSwap a float. Not a joke. | |||||
| * @param[inout] fOut ehm. .. */ | |||||
| static inline void Swap(float* fOut) { | |||||
| Swap4(fOut); | |||||
| } | |||||
| // ---------------------------------------------------------------------- | |||||
| /** ByteSwap a double. Not a joke. | |||||
| * @param[inout] fOut ehm. .. */ | |||||
| static inline void Swap(double* fOut) { | |||||
| Swap8(fOut); | |||||
| } | |||||
| // ---------------------------------------------------------------------- | |||||
| /** ByteSwap an int16t. Not a joke. | |||||
| * @param[inout] fOut ehm. .. */ | |||||
| static inline void Swap(int16_t* fOut) { | |||||
| Swap2(fOut); | |||||
| } | |||||
| static inline void Swap(uint16_t* fOut) { | |||||
| Swap2(fOut); | |||||
| } | |||||
| // ---------------------------------------------------------------------- | |||||
| /** ByteSwap an int32t. Not a joke. | |||||
| * @param[inout] fOut ehm. .. */ | |||||
| static inline void Swap(int32_t* fOut){ | |||||
| Swap4(fOut); | |||||
| } | |||||
| static inline void Swap(uint32_t* fOut){ | |||||
| Swap4(fOut); | |||||
| } | |||||
| // ---------------------------------------------------------------------- | |||||
| /** ByteSwap an int64t. Not a joke. | |||||
| * @param[inout] fOut ehm. .. */ | |||||
| static inline void Swap(int64_t* fOut) { | |||||
| Swap8(fOut); | |||||
| } | |||||
| static inline void Swap(uint64_t* fOut) { | |||||
| Swap8(fOut); | |||||
| } | |||||
| // ---------------------------------------------------------------------- | |||||
| //! Templatized ByteSwap | |||||
| //! \returns param tOut as swapped | |||||
| template<typename Type> | |||||
| static inline Type Swapped(Type tOut) | |||||
| { | |||||
| return _swapper<Type,sizeof(Type)>()(tOut); | |||||
| } | |||||
| private: | |||||
| template <typename T, size_t size> struct _swapper; | |||||
| }; | |||||
| template <typename T> struct ByteSwap::_swapper<T,2> { | |||||
| T operator() (T tOut) { | |||||
| Swap2(&tOut); | |||||
| return tOut; | |||||
| } | |||||
| }; | |||||
| template <typename T> struct ByteSwap::_swapper<T,4> { | |||||
| T operator() (T tOut) { | |||||
| Swap4(&tOut); | |||||
| return tOut; | |||||
| } | |||||
| }; | |||||
| template <typename T> struct ByteSwap::_swapper<T,8> { | |||||
| T operator() (T tOut) { | |||||
| Swap8(&tOut); | |||||
| return tOut; | |||||
| } | |||||
| }; | |||||
| // -------------------------------------------------------------------------------------- | |||||
| // ByteSwap macros for BigEndian/LittleEndian support | |||||
| // -------------------------------------------------------------------------------------- | |||||
| #if (defined AI_BUILD_BIG_ENDIAN) | |||||
| # define AI_LE(t) (t) | |||||
| # define AI_BE(t) ByteSwap::Swapped(t) | |||||
| # define AI_LSWAP2(p) | |||||
| # define AI_LSWAP4(p) | |||||
| # define AI_LSWAP8(p) | |||||
| # define AI_LSWAP2P(p) | |||||
| # define AI_LSWAP4P(p) | |||||
| # define AI_LSWAP8P(p) | |||||
| # define LE_NCONST const | |||||
| # define AI_SWAP2(p) ByteSwap::Swap2(&(p)) | |||||
| # define AI_SWAP4(p) ByteSwap::Swap4(&(p)) | |||||
| # define AI_SWAP8(p) ByteSwap::Swap8(&(p)) | |||||
| # define AI_SWAP2P(p) ByteSwap::Swap2((p)) | |||||
| # define AI_SWAP4P(p) ByteSwap::Swap4((p)) | |||||
| # define AI_SWAP8P(p) ByteSwap::Swap8((p)) | |||||
| # define BE_NCONST | |||||
| #else | |||||
| # define AI_BE(t) (t) | |||||
| # define AI_LE(t) ByteSwap::Swapped(t) | |||||
| # define AI_SWAP2(p) | |||||
| # define AI_SWAP4(p) | |||||
| # define AI_SWAP8(p) | |||||
| # define AI_SWAP2P(p) | |||||
| # define AI_SWAP4P(p) | |||||
| # define AI_SWAP8P(p) | |||||
| # define BE_NCONST const | |||||
| # define AI_LSWAP2(p) ByteSwap::Swap2(&(p)) | |||||
| # define AI_LSWAP4(p) ByteSwap::Swap4(&(p)) | |||||
| # define AI_LSWAP8(p) ByteSwap::Swap8(&(p)) | |||||
| # define AI_LSWAP2P(p) ByteSwap::Swap2((p)) | |||||
| # define AI_LSWAP4P(p) ByteSwap::Swap4((p)) | |||||
| # define AI_LSWAP8P(p) ByteSwap::Swap8((p)) | |||||
| # define LE_NCONST | |||||
| #endif | |||||
| namespace Intern { | |||||
| // -------------------------------------------------------------------------------------------- | |||||
| template <typename T, bool doit> | |||||
| struct ByteSwapper { | |||||
| void operator() (T* inout) { | |||||
| ByteSwap::Swap(inout); | |||||
| } | |||||
| }; | |||||
| template <typename T> | |||||
| struct ByteSwapper<T,false> { | |||||
| void operator() (T*) { | |||||
| } | |||||
| }; | |||||
| // -------------------------------------------------------------------------------------------- | |||||
| template <bool SwapEndianess, typename T, bool RuntimeSwitch> | |||||
| struct Getter { | |||||
| void operator() (T* inout, bool le) { | |||||
| #ifdef AI_BUILD_BIG_ENDIAN | |||||
| le = le; | |||||
| #else | |||||
| le = !le; | |||||
| #endif | |||||
| if (le) { | |||||
| ByteSwapper<T,(sizeof(T)>1?true:false)> () (inout); | |||||
| } | |||||
| else ByteSwapper<T,false> () (inout); | |||||
| } | |||||
| }; | |||||
| template <bool SwapEndianess, typename T> | |||||
| struct Getter<SwapEndianess,T,false> { | |||||
| void operator() (T* inout, bool /*le*/) { | |||||
| // static branch | |||||
| ByteSwapper<T,(SwapEndianess && sizeof(T)>1)> () (inout); | |||||
| } | |||||
| }; | |||||
| } // end Intern | |||||
| } // end Assimp | |||||
| #endif //!! AI_BYTESWAP_H_INC | |||||
| @@ -0,0 +1,158 @@ | |||||
| /* | |||||
| --------------------------------------------------------------------------- | |||||
| Open Asset Import Library (assimp) | |||||
| --------------------------------------------------------------------------- | |||||
| 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. | |||||
| --------------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file aiFileIO -> IOSystem wrapper*/ | |||||
| #ifndef AI_CIOSYSTEM_H_INCLUDED | |||||
| #define AI_CIOSYSTEM_H_INCLUDED | |||||
| #include "../include/assimp/cfileio.h" | |||||
| namespace Assimp { | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Custom IOStream implementation for the C-API | |||||
| class CIOStreamWrapper : public IOStream | |||||
| { | |||||
| friend class CIOSystemWrapper; | |||||
| public: | |||||
| CIOStreamWrapper(aiFile* pFile) | |||||
| : mFile(pFile) | |||||
| {} | |||||
| // ................................................................... | |||||
| size_t Read(void* pvBuffer, | |||||
| size_t pSize, | |||||
| size_t pCount | |||||
| ){ | |||||
| // need to typecast here as C has no void* | |||||
| return mFile->ReadProc(mFile,(char*)pvBuffer,pSize,pCount); | |||||
| } | |||||
| // ................................................................... | |||||
| size_t Write(const void* pvBuffer, | |||||
| size_t pSize, | |||||
| size_t pCount | |||||
| ){ | |||||
| // need to typecast here as C has no void* | |||||
| return mFile->WriteProc(mFile,(const char*)pvBuffer,pSize,pCount); | |||||
| } | |||||
| // ................................................................... | |||||
| aiReturn Seek(size_t pOffset, | |||||
| aiOrigin pOrigin | |||||
| ){ | |||||
| return mFile->SeekProc(mFile,pOffset,pOrigin); | |||||
| } | |||||
| // ................................................................... | |||||
| size_t Tell(void) const { | |||||
| return mFile->TellProc(mFile); | |||||
| } | |||||
| // ................................................................... | |||||
| size_t FileSize() const { | |||||
| return mFile->FileSizeProc(mFile); | |||||
| } | |||||
| // ................................................................... | |||||
| void Flush () { | |||||
| return mFile->FlushProc(mFile); | |||||
| } | |||||
| private: | |||||
| aiFile* mFile; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Custom IOStream implementation for the C-API | |||||
| class CIOSystemWrapper : public IOSystem | |||||
| { | |||||
| public: | |||||
| CIOSystemWrapper(aiFileIO* pFile) | |||||
| : mFileSystem(pFile) | |||||
| {} | |||||
| // ................................................................... | |||||
| bool Exists( const char* pFile) const { | |||||
| aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,"rb"); | |||||
| if (p){ | |||||
| mFileSystem->CloseProc(mFileSystem,p); | |||||
| return true; | |||||
| } | |||||
| return false; | |||||
| } | |||||
| // ................................................................... | |||||
| char getOsSeparator() const { | |||||
| #ifndef _WIN32 | |||||
| return '/'; | |||||
| #else | |||||
| return '\\'; | |||||
| #endif | |||||
| } | |||||
| // ................................................................... | |||||
| IOStream* Open(const char* pFile,const char* pMode = "rb") { | |||||
| aiFile* p = mFileSystem->OpenProc(mFileSystem,pFile,pMode); | |||||
| if (!p) { | |||||
| return NULL; | |||||
| } | |||||
| return new CIOStreamWrapper(p); | |||||
| } | |||||
| // ................................................................... | |||||
| void Close( IOStream* pFile) { | |||||
| if (!pFile) { | |||||
| return; | |||||
| } | |||||
| mFileSystem->CloseProc(mFileSystem,((CIOStreamWrapper*) pFile)->mFile); | |||||
| delete pFile; | |||||
| } | |||||
| private: | |||||
| aiFileIO* mFileSystem; | |||||
| }; | |||||
| } | |||||
| #endif | |||||
| @@ -0,0 +1,742 @@ | |||||
| # Listing and grouping of all the source files. | |||||
| # 1) Set the file lists for each component | |||||
| # 2) Create a Source Group for each component, for IDE project orginization | |||||
| # 3) Add libassimp using the file lists (eliminates duplication of file names between | |||||
| # source groups and library command) | |||||
| # | |||||
| cmake_minimum_required( VERSION 2.6 ) | |||||
| SET( HEADER_PATH ../include/assimp ) | |||||
| SET( COMPILER_HEADERS | |||||
| ${HEADER_PATH}/Compiler/pushpack1.h | |||||
| ${HEADER_PATH}/Compiler/poppack1.h | |||||
| ${HEADER_PATH}/Compiler/pstdint.h | |||||
| ) | |||||
| SOURCE_GROUP( Compiler FILES ${COMPILER_HEADERS}) | |||||
| SET( PUBLIC_HEADERS | |||||
| ${HEADER_PATH}/anim.h | |||||
| ${HEADER_PATH}/ai_assert.h | |||||
| ${HEADER_PATH}/camera.h | |||||
| ${HEADER_PATH}/color4.h | |||||
| ${HEADER_PATH}/color4.inl | |||||
| ${HEADER_PATH}/config.h | |||||
| ${HEADER_PATH}/defs.h | |||||
| ${HEADER_PATH}/cfileio.h | |||||
| ${HEADER_PATH}/light.h | |||||
| ${HEADER_PATH}/material.h | |||||
| ${HEADER_PATH}/material.inl | |||||
| ${HEADER_PATH}/matrix3x3.h | |||||
| ${HEADER_PATH}/matrix3x3.inl | |||||
| ${HEADER_PATH}/matrix4x4.h | |||||
| ${HEADER_PATH}/matrix4x4.inl | |||||
| ${HEADER_PATH}/mesh.h | |||||
| ${HEADER_PATH}/postprocess.h | |||||
| ${HEADER_PATH}/quaternion.h | |||||
| ${HEADER_PATH}/quaternion.inl | |||||
| ${HEADER_PATH}/scene.h | |||||
| ${HEADER_PATH}/metadata.h | |||||
| ${HEADER_PATH}/texture.h | |||||
| ${HEADER_PATH}/types.h | |||||
| ${HEADER_PATH}/vector2.h | |||||
| ${HEADER_PATH}/vector2.inl | |||||
| ${HEADER_PATH}/vector3.h | |||||
| ${HEADER_PATH}/vector3.inl | |||||
| ${HEADER_PATH}/version.h | |||||
| ${HEADER_PATH}/cimport.h | |||||
| ${HEADER_PATH}/importerdesc.h | |||||
| ${HEADER_PATH}/Importer.hpp | |||||
| ${HEADER_PATH}/DefaultLogger.hpp | |||||
| ${HEADER_PATH}/ProgressHandler.hpp | |||||
| ${HEADER_PATH}/IOStream.hpp | |||||
| ${HEADER_PATH}/IOSystem.hpp | |||||
| ${HEADER_PATH}/Logger.hpp | |||||
| ${HEADER_PATH}/LogStream.hpp | |||||
| ${HEADER_PATH}/NullLogger.hpp | |||||
| ${HEADER_PATH}/cexport.h | |||||
| ${HEADER_PATH}/Exporter.hpp | |||||
| ) | |||||
| SET( Core_SRCS | |||||
| Assimp.cpp | |||||
| ) | |||||
| SET( Boost_SRCS | |||||
| BoostWorkaround/boost/math/common_factor_rt.hpp | |||||
| BoostWorkaround/boost/foreach.hpp | |||||
| BoostWorkaround/boost/format.hpp | |||||
| BoostWorkaround/boost/scoped_array.hpp | |||||
| BoostWorkaround/boost/scoped_ptr.hpp | |||||
| BoostWorkaround/boost/shared_array.hpp | |||||
| BoostWorkaround/boost/shared_ptr.hpp | |||||
| BoostWorkaround/boost/make_shared.hpp | |||||
| BoostWorkaround/boost/static_assert.hpp | |||||
| BoostWorkaround/boost/tuple/tuple.hpp | |||||
| ) | |||||
| SOURCE_GROUP(Boost FILES ${Boost_SRCS}) | |||||
| SET( Logging_SRCS | |||||
| ${HEADER_PATH}/DefaultLogger.hpp | |||||
| ${HEADER_PATH}/LogStream.hpp | |||||
| ${HEADER_PATH}/Logger.hpp | |||||
| ${HEADER_PATH}/NullLogger.hpp | |||||
| Win32DebugLogStream.h | |||||
| DefaultLogger.cpp | |||||
| FileLogStream.h | |||||
| StdOStreamLogStream.h | |||||
| ) | |||||
| SOURCE_GROUP(Logging FILES ${Logging_SRCS}) | |||||
| SET( Common_SRCS | |||||
| fast_atof.h | |||||
| qnan.h | |||||
| BaseImporter.cpp | |||||
| BaseImporter.h | |||||
| BaseProcess.cpp | |||||
| BaseProcess.h | |||||
| Importer.h | |||||
| ScenePrivate.h | |||||
| PostStepRegistry.cpp | |||||
| ImporterRegistry.cpp | |||||
| ByteSwap.h | |||||
| DefaultProgressHandler.h | |||||
| DefaultIOStream.cpp | |||||
| DefaultIOStream.h | |||||
| DefaultIOSystem.cpp | |||||
| DefaultIOSystem.h | |||||
| CInterfaceIOWrapper.h | |||||
| Hash.h | |||||
| Importer.cpp | |||||
| IFF.h | |||||
| MemoryIOWrapper.h | |||||
| ParsingUtils.h | |||||
| StreamReader.h | |||||
| StringComparison.h | |||||
| SGSpatialSort.cpp | |||||
| SGSpatialSort.h | |||||
| VertexTriangleAdjacency.cpp | |||||
| VertexTriangleAdjacency.h | |||||
| GenericProperty.h | |||||
| SpatialSort.cpp | |||||
| SpatialSort.h | |||||
| SceneCombiner.cpp | |||||
| SceneCombiner.h | |||||
| ScenePreprocessor.cpp | |||||
| ScenePreprocessor.h | |||||
| SkeletonMeshBuilder.cpp | |||||
| SkeletonMeshBuilder.h | |||||
| SplitByBoneCountProcess.cpp | |||||
| SplitByBoneCountProcess.h | |||||
| SmoothingGroups.h | |||||
| StandardShapes.cpp | |||||
| StandardShapes.h | |||||
| TargetAnimation.cpp | |||||
| TargetAnimation.h | |||||
| RemoveComments.cpp | |||||
| RemoveComments.h | |||||
| Subdivision.cpp | |||||
| Subdivision.h | |||||
| Vertex.h | |||||
| LineSplitter.h | |||||
| TinyFormatter.h | |||||
| Profiler.h | |||||
| LogAux.h | |||||
| Bitmap.cpp | |||||
| Bitmap.h | |||||
| ) | |||||
| SOURCE_GROUP(Common FILES ${Common_SRCS}) | |||||
| SET( 3DS_SRCS | |||||
| 3DSConverter.cpp | |||||
| 3DSHelper.h | |||||
| 3DSLoader.cpp | |||||
| 3DSLoader.h | |||||
| ) | |||||
| SOURCE_GROUP(3DS FILES ${3DS_SRCS}) | |||||
| SET( AC_SRCS | |||||
| ACLoader.cpp | |||||
| ACLoader.h | |||||
| ) | |||||
| SOURCE_GROUP( AC FILES ${AC_SRCS}) | |||||
| SET( ASE_SRCS | |||||
| ASELoader.cpp | |||||
| ASELoader.h | |||||
| ASEParser.cpp | |||||
| ASEParser.h | |||||
| ) | |||||
| SOURCE_GROUP( ASE FILES ${ASE_SRCS}) | |||||
| SET( B3D_SRCS | |||||
| B3DImporter.cpp | |||||
| B3DImporter.h | |||||
| ) | |||||
| SOURCE_GROUP( B3D FILES ${B3D_SRCS}) | |||||
| SET( BVH_SRCS | |||||
| BVHLoader.cpp | |||||
| BVHLoader.h | |||||
| ) | |||||
| SOURCE_GROUP( BVH FILES ${BVH_SRCS}) | |||||
| SET( Collada_SRCS | |||||
| ColladaHelper.h | |||||
| ColladaLoader.cpp | |||||
| ColladaLoader.h | |||||
| ColladaParser.cpp | |||||
| ColladaParser.h | |||||
| ColladaExporter.h | |||||
| ColladaExporter.cpp | |||||
| ) | |||||
| SOURCE_GROUP( Collada FILES ${Collada_SRCS}) | |||||
| SET( DXF_SRCS | |||||
| DXFLoader.cpp | |||||
| DXFLoader.h | |||||
| DXFHelper.h | |||||
| ) | |||||
| SOURCE_GROUP( DXF FILES ${DXF_SRCS}) | |||||
| SET( CSM_SRCS | |||||
| CSMLoader.cpp | |||||
| CSMLoader.h | |||||
| ) | |||||
| SOURCE_GROUP( CSM FILES ${CSM_SRCS}) | |||||
| SET( HMP_SRCS | |||||
| HMPFileData.h | |||||
| HMPLoader.cpp | |||||
| HMPLoader.h | |||||
| HalfLifeFileData.h | |||||
| ) | |||||
| SOURCE_GROUP( HMP FILES ${HMP_SRCS}) | |||||
| SET( Irr_SRCS | |||||
| IRRLoader.cpp | |||||
| IRRLoader.h | |||||
| IRRMeshLoader.cpp | |||||
| IRRMeshLoader.h | |||||
| IRRShared.cpp | |||||
| IRRShared.h | |||||
| ) | |||||
| SOURCE_GROUP( Irr FILES ${Irr_SRCS}) | |||||
| SET( LWO_SRCS | |||||
| LWOAnimation.cpp | |||||
| LWOAnimation.h | |||||
| LWOBLoader.cpp | |||||
| LWOFileData.h | |||||
| LWOLoader.cpp | |||||
| LWOLoader.h | |||||
| LWOMaterial.cpp | |||||
| ) | |||||
| SOURCE_GROUP( LWO FILES ${LWO_SRCS}) | |||||
| SET( LWS_SRCS | |||||
| LWSLoader.cpp | |||||
| LWSLoader.h | |||||
| ) | |||||
| SOURCE_GROUP( LWS FILES ${LWS_SRCS}) | |||||
| SET( MD2_SRCS | |||||
| MD2FileData.h | |||||
| MD2Loader.cpp | |||||
| MD2Loader.h | |||||
| MD2NormalTable.h | |||||
| ) | |||||
| SOURCE_GROUP( MD2 FILES ${MD2_SRCS}) | |||||
| SET( MD3_SRCS | |||||
| MD3FileData.h | |||||
| MD3Loader.cpp | |||||
| MD3Loader.h | |||||
| ) | |||||
| SOURCE_GROUP( MD3 FILES ${MD3_SRCS}) | |||||
| SET( MD5_SRCS | |||||
| MD5Loader.cpp | |||||
| MD5Loader.h | |||||
| MD5Parser.cpp | |||||
| MD5Parser.h | |||||
| ) | |||||
| SOURCE_GROUP( MD5 FILES ${MD5_SRCS}) | |||||
| SET( MDC_SRCS | |||||
| MDCFileData.h | |||||
| MDCLoader.cpp | |||||
| MDCLoader.h | |||||
| MDCNormalTable.h | |||||
| ) | |||||
| SOURCE_GROUP( MDC FILES ${MDC_SRCS}) | |||||
| SET( MDL_SRCS | |||||
| MDLDefaultColorMap.h | |||||
| MDLFileData.h | |||||
| MDLLoader.cpp | |||||
| MDLLoader.h | |||||
| MDLMaterialLoader.cpp | |||||
| ) | |||||
| SOURCE_GROUP( MDL FILES ${MDL_SRCS}) | |||||
| SET( MaterialSystem_SRCS | |||||
| MaterialSystem.cpp | |||||
| MaterialSystem.h | |||||
| ) | |||||
| SOURCE_GROUP( MaterialSystem FILES ${MaterialSystem_SRCS}) | |||||
| SET( NFF_SRCS | |||||
| NFFLoader.cpp | |||||
| NFFLoader.h | |||||
| ) | |||||
| SOURCE_GROUP( NFF FILES ${NFF_SRCS}) | |||||
| SET( NDO_SRCS | |||||
| NDOLoader.cpp | |||||
| NDOLoader.h | |||||
| ) | |||||
| SOURCE_GROUP( NDO FILES ${NDO_SRCS}) | |||||
| SET( OFFFormat_SRCS | |||||
| OFFLoader.cpp | |||||
| OFFLoader.h | |||||
| ) | |||||
| SOURCE_GROUP( OFFFormat FILES ${OFFFormat_SRCS}) | |||||
| SET( Obj_SRCS | |||||
| ObjFileData.h | |||||
| ObjFileImporter.cpp | |||||
| ObjFileImporter.h | |||||
| ObjFileMtlImporter.cpp | |||||
| ObjFileMtlImporter.h | |||||
| ObjFileParser.cpp | |||||
| ObjFileParser.h | |||||
| ObjTools.h | |||||
| ObjExporter.h | |||||
| ObjExporter.cpp | |||||
| ) | |||||
| SOURCE_GROUP( Obj FILES ${Obj_SRCS}) | |||||
| SET( Ogre_SRCS | |||||
| OgreImporter.h | |||||
| OgreStructs.h | |||||
| OgreParsingUtils.h | |||||
| OgreBinarySerializer.h | |||||
| OgreXmlSerializer.h | |||||
| OgreImporter.cpp | |||||
| OgreStructs.cpp | |||||
| OgreBinarySerializer.cpp | |||||
| OgreXmlSerializer.cpp | |||||
| OgreMaterial.cpp | |||||
| ) | |||||
| SOURCE_GROUP( Ogre FILES ${Ogre_SRCS}) | |||||
| SET( Ply_SRCS | |||||
| PlyLoader.cpp | |||||
| PlyLoader.h | |||||
| PlyParser.cpp | |||||
| PlyParser.h | |||||
| PlyExporter.cpp | |||||
| PlyExporter.h | |||||
| ) | |||||
| SOURCE_GROUP( Ply FILES ${Ply_SRCS}) | |||||
| SET(MS3D_SRCS | |||||
| MS3DLoader.cpp | |||||
| MS3DLoader.h | |||||
| ) | |||||
| SOURCE_GROUP( MS3D FILES ${MS3D_SRCS}) | |||||
| SET(COB_SRCS | |||||
| COBLoader.cpp | |||||
| COBLoader.h | |||||
| COBScene.h | |||||
| ) | |||||
| SOURCE_GROUP( COB FILES ${COB_SRCS}) | |||||
| SET(BLENDER_SRCS | |||||
| BlenderLoader.cpp | |||||
| BlenderLoader.h | |||||
| BlenderDNA.cpp | |||||
| BlenderDNA.h | |||||
| BlenderDNA.inl | |||||
| BlenderScene.cpp | |||||
| BlenderScene.h | |||||
| BlenderSceneGen.h | |||||
| BlenderIntermediate.h | |||||
| BlenderModifier.h | |||||
| BlenderModifier.cpp | |||||
| BlenderBMesh.h | |||||
| BlenderBMesh.cpp | |||||
| BlenderTessellator.h | |||||
| BlenderTessellator.cpp | |||||
| ) | |||||
| SOURCE_GROUP( BLENDER FILES ${BLENDER_SRCS}) | |||||
| SET(IFC_SRCS | |||||
| IFCLoader.cpp | |||||
| IFCLoader.h | |||||
| IFCReaderGen.cpp | |||||
| IFCReaderGen.h | |||||
| IFCUtil.h | |||||
| IFCUtil.cpp | |||||
| IFCGeometry.cpp | |||||
| IFCMaterial.cpp | |||||
| IFCProfile.cpp | |||||
| IFCCurve.cpp | |||||
| IFCBoolean.cpp | |||||
| IFCOpenings.cpp | |||||
| STEPFile.h | |||||
| STEPFileReader.h | |||||
| STEPFileReader.cpp | |||||
| STEPFileEncoding.cpp | |||||
| STEPFileEncoding.h | |||||
| ) | |||||
| SOURCE_GROUP( IFC FILES ${IFC_SRCS}) | |||||
| SET( XGL_SRCS | |||||
| XGLLoader.cpp | |||||
| XGLLoader.h | |||||
| ) | |||||
| SOURCE_GROUP( XGL FILES ${XGL_SRCS}) | |||||
| SET(FBX_SRCS | |||||
| FBXImporter.cpp | |||||
| FBXCompileConfig.h | |||||
| FBXImporter.h | |||||
| FBXParser.cpp | |||||
| FBXParser.h | |||||
| FBXTokenizer.cpp | |||||
| FBXTokenizer.h | |||||
| FBXImportSettings.h | |||||
| FBXConverter.h | |||||
| FBXConverter.cpp | |||||
| FBXUtil.h | |||||
| FBXUtil.cpp | |||||
| FBXDocument.h | |||||
| FBXDocument.cpp | |||||
| FBXProperties.h | |||||
| FBXProperties.cpp | |||||
| FBXMeshGeometry.cpp | |||||
| FBXMaterial.cpp | |||||
| FBXModel.cpp | |||||
| FBXAnimation.cpp | |||||
| FBXNodeAttribute.cpp | |||||
| FBXDeformer.cpp | |||||
| FBXBinaryTokenizer.cpp | |||||
| FBXDocumentUtil.cpp | |||||
| ) | |||||
| SOURCE_GROUP( FBX FILES ${FBX_SRCS}) | |||||
| SET( PostProcessing_SRCS | |||||
| CalcTangentsProcess.cpp | |||||
| CalcTangentsProcess.h | |||||
| ComputeUVMappingProcess.cpp | |||||
| ComputeUVMappingProcess.h | |||||
| ConvertToLHProcess.cpp | |||||
| ConvertToLHProcess.h | |||||
| FindDegenerates.cpp | |||||
| FindDegenerates.h | |||||
| FindInstancesProcess.cpp | |||||
| FindInstancesProcess.h | |||||
| FindInvalidDataProcess.cpp | |||||
| FindInvalidDataProcess.h | |||||
| FixNormalsStep.cpp | |||||
| FixNormalsStep.h | |||||
| GenFaceNormalsProcess.cpp | |||||
| GenFaceNormalsProcess.h | |||||
| GenVertexNormalsProcess.cpp | |||||
| GenVertexNormalsProcess.h | |||||
| PretransformVertices.cpp | |||||
| PretransformVertices.h | |||||
| ImproveCacheLocality.cpp | |||||
| ImproveCacheLocality.h | |||||
| JoinVerticesProcess.cpp | |||||
| JoinVerticesProcess.h | |||||
| LimitBoneWeightsProcess.cpp | |||||
| LimitBoneWeightsProcess.h | |||||
| RemoveRedundantMaterials.cpp | |||||
| RemoveRedundantMaterials.h | |||||
| RemoveVCProcess.cpp | |||||
| RemoveVCProcess.h | |||||
| SortByPTypeProcess.cpp | |||||
| SortByPTypeProcess.h | |||||
| SplitLargeMeshes.cpp | |||||
| SplitLargeMeshes.h | |||||
| TextureTransform.cpp | |||||
| TextureTransform.h | |||||
| TriangulateProcess.cpp | |||||
| TriangulateProcess.h | |||||
| ValidateDataStructure.cpp | |||||
| ValidateDataStructure.h | |||||
| OptimizeGraph.cpp | |||||
| OptimizeGraph.h | |||||
| OptimizeMeshes.cpp | |||||
| OptimizeMeshes.h | |||||
| DeboneProcess.cpp | |||||
| DeboneProcess.h | |||||
| ProcessHelper.h | |||||
| ProcessHelper.cpp | |||||
| PolyTools.h | |||||
| MakeVerboseFormat.cpp | |||||
| MakeVerboseFormat.h | |||||
| ) | |||||
| SOURCE_GROUP( PostProcessing FILES ${PostProcessing_SRCS}) | |||||
| SET( Q3D_SRCS | |||||
| Q3DLoader.cpp | |||||
| Q3DLoader.h | |||||
| ) | |||||
| SOURCE_GROUP( Q3D FILES ${Q3D_SRCS}) | |||||
| SET( Q3BSP_SRCS | |||||
| Q3BSPFileData.h | |||||
| Q3BSPFileParser.h | |||||
| Q3BSPFileParser.cpp | |||||
| Q3BSPFileImporter.h | |||||
| Q3BSPFileImporter.cpp | |||||
| Q3BSPZipArchive.h | |||||
| Q3BSPZipArchive.cpp | |||||
| ) | |||||
| SOURCE_GROUP( Q3BSP FILES ${Q3BSP_SRCS}) | |||||
| SET( Raw_SRCS | |||||
| RawLoader.cpp | |||||
| RawLoader.h | |||||
| ) | |||||
| SOURCE_GROUP( Raw FILES ${Raw_SRCS}) | |||||
| SET( SMD_SRCS | |||||
| SMDLoader.cpp | |||||
| SMDLoader.h | |||||
| ) | |||||
| SOURCE_GROUP( SMD FILES ${SMD_SRCS}) | |||||
| SET( STL_SRCS | |||||
| STLLoader.cpp | |||||
| STLLoader.h | |||||
| STLExporter.h | |||||
| STLExporter.cpp | |||||
| ) | |||||
| SOURCE_GROUP( STL FILES ${STL_SRCS}) | |||||
| SET( Terragen_SRCS | |||||
| TerragenLoader.cpp | |||||
| TerragenLoader.h | |||||
| ) | |||||
| SOURCE_GROUP( Terragen FILES ${Terragen_SRCS}) | |||||
| SET( Unreal_SRCS | |||||
| UnrealLoader.cpp | |||||
| UnrealLoader.h | |||||
| ) | |||||
| SOURCE_GROUP( Unreal FILES ${Unreal_SRCS}) | |||||
| SET( XFile_SRCS | |||||
| XFileHelper.h | |||||
| XFileImporter.cpp | |||||
| XFileImporter.h | |||||
| XFileParser.cpp | |||||
| XFileParser.h | |||||
| ) | |||||
| SOURCE_GROUP( XFile FILES ${XFile_SRCS}) | |||||
| SET( Exporter_SRCS | |||||
| Exporter.cpp | |||||
| AssimpCExport.cpp | |||||
| BlobIOSystem.h | |||||
| ) | |||||
| SOURCE_GROUP( Exporter FILES ${Exporter_SRCS}) | |||||
| SET( Extra_SRCS | |||||
| MD4FileData.h | |||||
| ) | |||||
| 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 | |||||
| ../contrib/clipper/clipper.cpp | |||||
| ) | |||||
| SOURCE_GROUP( Clipper FILES ${Clipper_SRCS}) | |||||
| SET( Poly2Tri_SRCS | |||||
| ../contrib/poly2tri/poly2tri/common/shapes.cc | |||||
| ../contrib/poly2tri/poly2tri/common/shapes.h | |||||
| ../contrib/poly2tri/poly2tri/common/utils.h | |||||
| ../contrib/poly2tri/poly2tri/sweep/advancing_front.h | |||||
| ../contrib/poly2tri/poly2tri/sweep/advancing_front.cc | |||||
| ../contrib/poly2tri/poly2tri/sweep/cdt.cc | |||||
| ../contrib/poly2tri/poly2tri/sweep/cdt.h | |||||
| ../contrib/poly2tri/poly2tri/sweep/sweep.cc | |||||
| ../contrib/poly2tri/poly2tri/sweep/sweep.h | |||||
| ../contrib/poly2tri/poly2tri/sweep/sweep_context.cc | |||||
| ../contrib/poly2tri/poly2tri/sweep/sweep_context.h | |||||
| ) | |||||
| SOURCE_GROUP( Poly2Tri FILES ${Poly2Tri_SRCS}) | |||||
| SET( unzip_SRCS | |||||
| ../contrib/unzip/crypt.h | |||||
| ../contrib/unzip/ioapi.c | |||||
| ../contrib/unzip/ioapi.h | |||||
| ../contrib/unzip/unzip.c | |||||
| ../contrib/unzip/unzip.h | |||||
| ) | |||||
| SOURCE_GROUP( unzip FILES ${unzip_SRCS}) | |||||
| # VC2010 fixes | |||||
| if(MSVC10) | |||||
| OPTION( VC10_STDINT_FIX "Fix for VC10 Compiler regarding pstdint.h redefinition errors" OFF ) | |||||
| if( VC10_STDINT_FIX ) | |||||
| ADD_DEFINITIONS( -D_STDINT ) | |||||
| endif( VC10_STDINT_FIX ) | |||||
| endif(MSVC10) | |||||
| ADD_DEFINITIONS( -DASSIMP_BUILD_DLL_EXPORT ) | |||||
| if ( MSVC ) | |||||
| ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS ) | |||||
| ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) | |||||
| endif ( MSVC ) | |||||
| if (UNZIP_FOUND) | |||||
| SET (unzip_compile_SRCS "") | |||||
| else (UNZIP_FOUND) | |||||
| SET (unzip_compile_SRCS ${unzip_SRCS}) | |||||
| endif (UNZIP_FOUND) | |||||
| SET( assimp_src | |||||
| # Assimp Files | |||||
| ${Core_SRCS} | |||||
| ${Common_SRCS} | |||||
| ${Logging_SRCS} | |||||
| ${Exporter_SRCS} | |||||
| ${PostProcessing_SRCS} | |||||
| # Model Support | |||||
| ${3DS_SRCS} | |||||
| ${AC_SRCS} | |||||
| ${ASE_SRCS} | |||||
| ${B3D_SRCS} | |||||
| ${BVH_SRCS} | |||||
| ${Collada_SRCS} | |||||
| ${DXF_SRCS} | |||||
| ${CSM_SRCS} | |||||
| ${HMP_SRCS} | |||||
| ${Irr_SRCS} | |||||
| ${LWO_SRCS} | |||||
| ${LWS_SRCS} | |||||
| ${MD2_SRCS} | |||||
| ${MD3_SRCS} | |||||
| ${MD5_SRCS} | |||||
| ${MDC_SRCS} | |||||
| ${MDL_SRCS} | |||||
| ${MaterialSystem_SRCS} | |||||
| ${NFF_SRCS} | |||||
| ${OFFFormat_SRCS} | |||||
| ${Obj_SRCS} | |||||
| ${Ogre_SRCS} | |||||
| ${Ply_SRCS} | |||||
| ${Q3D_SRCS} | |||||
| ${Q3BSP_SRCS} | |||||
| ${Raw_SRCS} | |||||
| ${SMD_SRCS} | |||||
| ${STL_SRCS} | |||||
| ${Terragen_SRCS} | |||||
| ${Unreal_SRCS} | |||||
| ${XFile_SRCS} | |||||
| ${Extra_SRCS} | |||||
| ${MS3D_SRCS} | |||||
| ${COB_SRCS} | |||||
| ${BLENDER_SRCS} | |||||
| ${NDO_SRCS} | |||||
| ${IFC_SRCS} | |||||
| ${XGL_SRCS} | |||||
| ${FBX_SRCS} | |||||
| # Third-party libraries | |||||
| ${IrrXML_SRCS} | |||||
| ${ConvertUTF_SRCS} | |||||
| ${unzip_compile_SRCS} | |||||
| ${Poly2Tri_SRCS} | |||||
| ${Clipper_SRCS} | |||||
| # Necessary to show the headers in the project when using the VC++ generator: | |||||
| ${Boost_SRCS} | |||||
| ${PUBLIC_HEADERS} | |||||
| ${COMPILER_HEADERS} | |||||
| # Old precompiled header | |||||
| # (removed because the precompiled header is not updated when visual studio switch configuration which leads to failed compilation. | |||||
| # Moreover it's a drag to recompile assimp entirely each time a modification is made to one of the included header, which is definitely counter-productive.) | |||||
| AssimpPCH.cpp | |||||
| ) | |||||
| #ADD_MSVC_PRECOMPILED_HEADER("AssimpPCH.h" "AssimpPCH.cpp" assimp_src) | |||||
| ADD_LIBRARY( assimp ${assimp_src} ) | |||||
| SET_PROPERTY(TARGET assimp PROPERTY DEBUG_POSTFIX ${ASSIMP_DEBUG_POSTFIX}) | |||||
| TARGET_LINK_LIBRARIES(assimp ${ZLIB_LIBRARIES}) | |||||
| SET_TARGET_PROPERTIES( assimp PROPERTIES | |||||
| VERSION ${ASSIMP_VERSION} | |||||
| SOVERSION ${ASSIMP_SOVERSION} # use full version | |||||
| OUTPUT_NAME assimp${ASSIMP_LIBRARY_SUFFIX} | |||||
| ) | |||||
| if (APPLE) | |||||
| SET_TARGET_PROPERTIES( assimp PROPERTIES INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}") | |||||
| endif() | |||||
| # Build against external unzip, or add ../contrib/unzip so | |||||
| # assimp can #include "unzip.h" | |||||
| if (UNZIP_FOUND) | |||||
| INCLUDE_DIRECTORIES(${UNZIP_INCLUDE_DIRS}) | |||||
| TARGET_LINK_LIBRARIES(assimp ${UNZIP_LIBRARIES}) | |||||
| else (UNZIP_FOUND) | |||||
| INCLUDE_DIRECTORIES("../contrib/unzip") | |||||
| endif (UNZIP_FOUND) | |||||
| INSTALL( TARGETS assimp | |||||
| LIBRARY DESTINATION ${ASSIMP_LIB_INSTALL_DIR} | |||||
| ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} | |||||
| RUNTIME DESTINATION ${ASSIMP_BIN_INSTALL_DIR} | |||||
| COMPONENT ${LIBASSIMP_COMPONENT}) | |||||
| INSTALL( FILES ${PUBLIC_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp COMPONENT assimp-dev) | |||||
| INSTALL( FILES ${COMPILER_HEADERS} DESTINATION ${ASSIMP_INCLUDE_INSTALL_DIR}/assimp/Compiler COMPONENT assimp-dev) | |||||
| if(MSVC AND ASSIMP_INSTALL_PDB) | |||||
| install(FILES ${Assimp_BINARY_DIR}/code/Debug/assimp${ASSIMP_DEBUG_POSTFIX}.pdb | |||||
| DESTINATION ${ASSIMP_LIB_INSTALL_DIR} | |||||
| CONFIGURATIONS Debug | |||||
| ) | |||||
| install(FILES ${Assimp_BINARY_DIR}/code/RelWithDebInfo/assimp.pdb | |||||
| DESTINATION ${ASSIMP_LIB_INSTALL_DIR} | |||||
| CONFIGURATIONS RelWithDebInfo | |||||
| ) | |||||
| endif () | |||||
| @@ -0,0 +1,170 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file COBLoader.h | |||||
| * @brief Declaration of the TrueSpace (*.cob,*.scn) importer class. | |||||
| */ | |||||
| #ifndef INCLUDED_AI_COB_LOADER_H | |||||
| #define INCLUDED_AI_COB_LOADER_H | |||||
| #include "BaseImporter.h" | |||||
| namespace Assimp { | |||||
| class LineSplitter; | |||||
| // TinyFormatter.h | |||||
| namespace Formatter { | |||||
| template <typename T,typename TR, typename A> class basic_formatter; | |||||
| typedef class basic_formatter< char, std::char_traits<char>, std::allocator<char> > format; | |||||
| } | |||||
| // COBScene.h | |||||
| namespace COB { | |||||
| struct ChunkInfo; | |||||
| struct Node; | |||||
| struct Scene; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------- | |||||
| /** Importer class to load TrueSpace files (cob,scn) up to v6. | |||||
| * | |||||
| * Currently relatively limited, loads only ASCII files and needs more test coverage. */ | |||||
| // ------------------------------------------------------------------------------------------- | |||||
| class COBImporter : public BaseImporter | |||||
| { | |||||
| public: | |||||
| COBImporter(); | |||||
| ~COBImporter(); | |||||
| public: | |||||
| // -------------------- | |||||
| bool CanRead( const std::string& pFile, IOSystem* pIOHandler, | |||||
| bool checkSig) const; | |||||
| protected: | |||||
| // -------------------- | |||||
| const aiImporterDesc* GetInfo () const; | |||||
| // -------------------- | |||||
| void SetupProperties(const Importer* pImp); | |||||
| // -------------------- | |||||
| void InternReadFile( const std::string& pFile, aiScene* pScene, | |||||
| IOSystem* pIOHandler); | |||||
| private: | |||||
| // ------------------------------------------------------------------- | |||||
| /** Prepend 'COB: ' and throw msg.*/ | |||||
| static void ThrowException(const std::string& msg); | |||||
| // ------------------------------------------------------------------- | |||||
| /** @brief Read from an ascii scene/object file | |||||
| * @param out Receives output data. | |||||
| * @param stream Stream to read from. */ | |||||
| void ReadAsciiFile(COB::Scene& out, StreamReaderLE* stream); | |||||
| // ------------------------------------------------------------------- | |||||
| /** @brief Read from a binary scene/object file | |||||
| * @param out Receives output data. | |||||
| * @param stream Stream to read from. */ | |||||
| void ReadBinaryFile(COB::Scene& out, StreamReaderLE* stream); | |||||
| private: | |||||
| // Conversion to Assimp output format | |||||
| aiNode* BuildNodes(const COB::Node& root,const COB::Scene& scin,aiScene* fill); | |||||
| private: | |||||
| // ASCII file support | |||||
| void UnsupportedChunk_Ascii(LineSplitter& splitter, const COB::ChunkInfo& nfo, const char* name); | |||||
| void ReadChunkInfo_Ascii(COB::ChunkInfo& out, const LineSplitter& splitter); | |||||
| void ReadBasicNodeInfo_Ascii(COB::Node& msh, LineSplitter& splitter, const COB::ChunkInfo& nfo); | |||||
| template <typename T> void ReadFloat3Tuple_Ascii(T& fill, const char** in); | |||||
| void ReadPolH_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo); | |||||
| void ReadBitM_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo); | |||||
| void ReadMat1_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo); | |||||
| void ReadGrou_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo); | |||||
| void ReadBone_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo); | |||||
| void ReadCame_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo); | |||||
| void ReadLght_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo); | |||||
| void ReadUnit_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo); | |||||
| void ReadChan_Ascii(COB::Scene& out, LineSplitter& splitter, const COB::ChunkInfo& nfo); | |||||
| // ASCII file logging stuff to add proper line numbers to messages | |||||
| static void LogWarn_Ascii (const LineSplitter& splitter, const Formatter::format& message); | |||||
| static void LogError_Ascii(const LineSplitter& splitter, const Formatter::format& message); | |||||
| static void LogInfo_Ascii (const LineSplitter& splitter, const Formatter::format& message); | |||||
| static void LogDebug_Ascii(const LineSplitter& splitter, const Formatter::format& message); | |||||
| static void LogWarn_Ascii (const Formatter::format& message); | |||||
| static void LogError_Ascii (const Formatter::format& message); | |||||
| static void LogInfo_Ascii (const Formatter::format& message); | |||||
| static void LogDebug_Ascii (const Formatter::format& message); | |||||
| // Binary file support | |||||
| void UnsupportedChunk_Binary(StreamReaderLE& reader, const COB::ChunkInfo& nfo, const char* name); | |||||
| void ReadString_Binary(std::string& out, StreamReaderLE& reader); | |||||
| void ReadBasicNodeInfo_Binary(COB::Node& msh, StreamReaderLE& reader, const COB::ChunkInfo& nfo); | |||||
| void ReadPolH_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo); | |||||
| void ReadBitM_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo); | |||||
| void ReadMat1_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo); | |||||
| void ReadCame_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo); | |||||
| void ReadLght_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo); | |||||
| void ReadGrou_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo); | |||||
| void ReadUnit_Binary(COB::Scene& out, StreamReaderLE& reader, const COB::ChunkInfo& nfo); | |||||
| }; // !class COBImporter | |||||
| } // end of namespace Assimp | |||||
| #endif // AI_UNREALIMPORTER_H_INC | |||||
| @@ -0,0 +1,271 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file COBScene.h | |||||
| * @brief Utilities for the COB importer. | |||||
| */ | |||||
| #ifndef INCLUDED_AI_COB_SCENE_H | |||||
| #define INCLUDED_AI_COB_SCENE_H | |||||
| #include <boost/shared_ptr.hpp> | |||||
| #include "BaseImporter.h" | |||||
| namespace Assimp { | |||||
| namespace COB { | |||||
| // ------------------ | |||||
| /** Represents a single vertex index in a face */ | |||||
| struct VertexIndex | |||||
| { | |||||
| // intentionally uninitialized | |||||
| unsigned int pos_idx,uv_idx; | |||||
| }; | |||||
| // ------------------ | |||||
| /** COB Face data structure */ | |||||
| struct Face | |||||
| { | |||||
| // intentionally uninitialized | |||||
| unsigned int material, flags; | |||||
| std::vector<VertexIndex> indices; | |||||
| }; | |||||
| // ------------------ | |||||
| /** COB chunk header information */ | |||||
| struct ChunkInfo | |||||
| { | |||||
| enum {NO_SIZE=UINT_MAX}; | |||||
| ChunkInfo () | |||||
| : id (0) | |||||
| , parent_id (0) | |||||
| , version (0) | |||||
| , size (NO_SIZE) | |||||
| {} | |||||
| // Id of this chunk, unique within file | |||||
| unsigned int id; | |||||
| // and the corresponding parent | |||||
| unsigned int parent_id; | |||||
| // version. v1.23 becomes 123 | |||||
| unsigned int version; | |||||
| // chunk size in bytes, only relevant for binary files | |||||
| // NO_SIZE is also valid. | |||||
| unsigned int size; | |||||
| }; | |||||
| // ------------------ | |||||
| /** A node in the scenegraph */ | |||||
| struct Node : public ChunkInfo | |||||
| { | |||||
| enum Type { | |||||
| TYPE_MESH,TYPE_GROUP,TYPE_LIGHT,TYPE_CAMERA,TYPE_BONE | |||||
| }; | |||||
| virtual ~Node() {} | |||||
| Node(Type type) : type(type), unit_scale(1.f){} | |||||
| Type type; | |||||
| // used during resolving | |||||
| typedef std::deque<const Node*> ChildList; | |||||
| mutable ChildList temp_children; | |||||
| // unique name | |||||
| std::string name; | |||||
| // local mesh transformation | |||||
| aiMatrix4x4 transform; | |||||
| // scaling for this node to get to the metric system | |||||
| float unit_scale; | |||||
| }; | |||||
| // ------------------ | |||||
| /** COB Mesh data structure */ | |||||
| struct Mesh : public Node | |||||
| { | |||||
| using ChunkInfo::operator=; | |||||
| enum DrawFlags { | |||||
| SOLID = 0x1, | |||||
| TRANS = 0x2, | |||||
| WIRED = 0x4, | |||||
| BBOX = 0x8, | |||||
| HIDE = 0x10 | |||||
| }; | |||||
| Mesh() | |||||
| : Node(TYPE_MESH) | |||||
| , draw_flags(SOLID) | |||||
| {} | |||||
| // vertex elements | |||||
| std::vector<aiVector2D> texture_coords; | |||||
| std::vector<aiVector3D> vertex_positions; | |||||
| // face data | |||||
| std::vector<Face> faces; | |||||
| // misc. drawing flags | |||||
| unsigned int draw_flags; | |||||
| // used during resolving | |||||
| typedef std::deque<Face*> FaceRefList; | |||||
| typedef std::map< unsigned int,FaceRefList > TempMap; | |||||
| TempMap temp_map; | |||||
| }; | |||||
| // ------------------ | |||||
| /** COB Group data structure */ | |||||
| struct Group : public Node | |||||
| { | |||||
| using ChunkInfo::operator=; | |||||
| Group() : Node(TYPE_GROUP) {} | |||||
| }; | |||||
| // ------------------ | |||||
| /** COB Bone data structure */ | |||||
| struct Bone : public Node | |||||
| { | |||||
| using ChunkInfo::operator=; | |||||
| Bone() : Node(TYPE_BONE) {} | |||||
| }; | |||||
| // ------------------ | |||||
| /** COB Light data structure */ | |||||
| struct Light : public Node | |||||
| { | |||||
| enum LightType { | |||||
| SPOT,LOCAL,INFINITE | |||||
| }; | |||||
| using ChunkInfo::operator=; | |||||
| Light() : Node(TYPE_LIGHT),angle(),inner_angle(),ltype(SPOT) {} | |||||
| aiColor3D color; | |||||
| float angle,inner_angle; | |||||
| LightType ltype; | |||||
| }; | |||||
| // ------------------ | |||||
| /** COB Camera data structure */ | |||||
| struct Camera : public Node | |||||
| { | |||||
| using ChunkInfo::operator=; | |||||
| Camera() : Node(TYPE_CAMERA) {} | |||||
| }; | |||||
| // ------------------ | |||||
| /** COB Texture data structure */ | |||||
| struct Texture | |||||
| { | |||||
| std::string path; | |||||
| aiUVTransform transform; | |||||
| }; | |||||
| // ------------------ | |||||
| /** COB Material data structure */ | |||||
| struct Material : ChunkInfo | |||||
| { | |||||
| using ChunkInfo::operator=; | |||||
| enum Shader { | |||||
| FLAT,PHONG,METAL | |||||
| }; | |||||
| enum AutoFacet { | |||||
| FACETED,AUTOFACETED,SMOOTH | |||||
| }; | |||||
| Material() : alpha(),exp(),ior(),ka(),ks(1.f), | |||||
| matnum(UINT_MAX), | |||||
| shader(FLAT),autofacet(FACETED), | |||||
| autofacet_angle() | |||||
| {} | |||||
| std::string type; | |||||
| aiColor3D rgb; | |||||
| float alpha, exp, ior,ka,ks; | |||||
| unsigned int matnum; | |||||
| Shader shader; | |||||
| AutoFacet autofacet; | |||||
| float autofacet_angle; | |||||
| boost::shared_ptr<Texture> tex_env,tex_bump,tex_color; | |||||
| }; | |||||
| // ------------------ | |||||
| /** Embedded bitmap, for instance for the thumbnail image */ | |||||
| struct Bitmap : ChunkInfo | |||||
| { | |||||
| Bitmap() : orig_size() {} | |||||
| struct BitmapHeader | |||||
| { | |||||
| }; | |||||
| BitmapHeader head; | |||||
| size_t orig_size; | |||||
| std::vector<char> buff_zipped; | |||||
| }; | |||||
| typedef std::deque< boost::shared_ptr<Node> > NodeList; | |||||
| typedef std::vector< Material > MaterialList; | |||||
| // ------------------ | |||||
| /** Represents a master COB scene, even if we loaded just a single COB file */ | |||||
| struct Scene | |||||
| { | |||||
| NodeList nodes; | |||||
| MaterialList materials; | |||||
| // becomes *0 later | |||||
| Bitmap thumbnail; | |||||
| }; | |||||
| } // end COB | |||||
| } // end Assimp | |||||
| #endif | |||||
| @@ -0,0 +1,299 @@ | |||||
| /* | |||||
| --------------------------------------------------------------------------- | |||||
| Open Asset Import Library (assimp) | |||||
| --------------------------------------------------------------------------- | |||||
| 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. | |||||
| --------------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file CSMLoader.cpp | |||||
| * Implementation of the CSM importer class. | |||||
| */ | |||||
| #include "AssimpPCH.h" | |||||
| #ifndef ASSIMP_BUILD_NO_CSM_IMPORTER | |||||
| #include "CSMLoader.h" | |||||
| #include "SkeletonMeshBuilder.h" | |||||
| #include "ParsingUtils.h" | |||||
| #include "fast_atof.h" | |||||
| using namespace Assimp; | |||||
| static const aiImporterDesc desc = { | |||||
| "CharacterStudio Motion Importer (MoCap)", | |||||
| "", | |||||
| "", | |||||
| "", | |||||
| aiImporterFlags_SupportTextFlavour, | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| 0, | |||||
| "csm" | |||||
| }; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Constructor to be privately used by Importer | |||||
| CSMImporter::CSMImporter() | |||||
| : noSkeletonMesh() | |||||
| {} | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Destructor, private as well | |||||
| CSMImporter::~CSMImporter() | |||||
| {} | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Returns whether the class can handle the format of the given file. | |||||
| bool CSMImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const | |||||
| { | |||||
| // check file extension | |||||
| const std::string extension = GetExtension(pFile); | |||||
| if( extension == "csm") | |||||
| return true; | |||||
| if ((checkSig || !extension.length()) && pIOHandler) { | |||||
| const char* tokens[] = {"$Filename"}; | |||||
| return SearchFileHeaderForToken(pIOHandler,pFile,tokens,1); | |||||
| } | |||||
| return false; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Build a string of all file extensions supported | |||||
| const aiImporterDesc* CSMImporter::GetInfo () const | |||||
| { | |||||
| return &desc; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Setup configuration properties for the loader | |||||
| void CSMImporter::SetupProperties(const Importer* pImp) | |||||
| { | |||||
| noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Imports the given file into the given scene structure. | |||||
| void CSMImporter::InternReadFile( const std::string& pFile, | |||||
| aiScene* pScene, IOSystem* pIOHandler) | |||||
| { | |||||
| boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb")); | |||||
| // Check whether we can read from the file | |||||
| if( file.get() == NULL) { | |||||
| throw DeadlyImportError( "Failed to open CSM file " + pFile + "."); | |||||
| } | |||||
| // allocate storage and copy the contents of the file to a memory buffer | |||||
| std::vector<char> mBuffer2; | |||||
| TextFileToBuffer(file.get(),mBuffer2); | |||||
| const char* buffer = &mBuffer2[0]; | |||||
| aiAnimation* anim = new aiAnimation(); | |||||
| int first = 0, last = 0x00ffffff; | |||||
| // now process the file and look out for '$' sections | |||||
| while (1) { | |||||
| SkipSpaces(&buffer); | |||||
| if ('\0' == *buffer) | |||||
| break; | |||||
| if ('$' == *buffer) { | |||||
| ++buffer; | |||||
| if (TokenMatchI(buffer,"firstframe",10)) { | |||||
| SkipSpaces(&buffer); | |||||
| first = strtol10(buffer,&buffer); | |||||
| } | |||||
| else if (TokenMatchI(buffer,"lastframe",9)) { | |||||
| SkipSpaces(&buffer); | |||||
| last = strtol10(buffer,&buffer); | |||||
| } | |||||
| else if (TokenMatchI(buffer,"rate",4)) { | |||||
| SkipSpaces(&buffer); | |||||
| float d; | |||||
| buffer = fast_atoreal_move<float>(buffer,d); | |||||
| anim->mTicksPerSecond = d; | |||||
| } | |||||
| else if (TokenMatchI(buffer,"order",5)) { | |||||
| std::vector< aiNodeAnim* > anims_temp; | |||||
| anims_temp.reserve(30); | |||||
| while (1) { | |||||
| SkipSpaces(&buffer); | |||||
| if (IsLineEnd(*buffer) && SkipSpacesAndLineEnd(&buffer) && *buffer == '$') | |||||
| break; // next section | |||||
| // Construct a new node animation channel and setup its name | |||||
| anims_temp.push_back(new aiNodeAnim()); | |||||
| aiNodeAnim* nda = anims_temp.back(); | |||||
| char* ot = nda->mNodeName.data; | |||||
| while (!IsSpaceOrNewLine(*buffer)) | |||||
| *ot++ = *buffer++; | |||||
| *ot = '\0'; | |||||
| nda->mNodeName.length = (size_t)(ot-nda->mNodeName.data); | |||||
| } | |||||
| anim->mNumChannels = anims_temp.size(); | |||||
| if (!anim->mNumChannels) | |||||
| throw DeadlyImportError("CSM: Empty $order section"); | |||||
| // copy over to the output animation | |||||
| anim->mChannels = new aiNodeAnim*[anim->mNumChannels]; | |||||
| ::memcpy(anim->mChannels,&anims_temp[0],sizeof(aiNodeAnim*)*anim->mNumChannels); | |||||
| } | |||||
| else if (TokenMatchI(buffer,"points",6)) { | |||||
| if (!anim->mNumChannels) | |||||
| throw DeadlyImportError("CSM: \'$order\' section is required to appear prior to \'$points\'"); | |||||
| // If we know how many frames we'll read, we can preallocate some storage | |||||
| unsigned int alloc = 100; | |||||
| if (last != 0x00ffffff) | |||||
| { | |||||
| alloc = last-first; | |||||
| alloc += alloc>>2u; // + 25% | |||||
| for (unsigned int i = 0; i < anim->mNumChannels;++i) | |||||
| anim->mChannels[i]->mPositionKeys = new aiVectorKey[alloc]; | |||||
| } | |||||
| unsigned int filled = 0; | |||||
| // Now read all point data. | |||||
| while (1) { | |||||
| SkipSpaces(&buffer); | |||||
| if (IsLineEnd(*buffer) && (!SkipSpacesAndLineEnd(&buffer) || *buffer == '$')) { | |||||
| break; // next section | |||||
| } | |||||
| // read frame | |||||
| const int frame = ::strtoul10(buffer,&buffer); | |||||
| last = std::max(frame,last); | |||||
| first = std::min(frame,last); | |||||
| for (unsigned int i = 0; i < anim->mNumChannels;++i) { | |||||
| aiNodeAnim* s = anim->mChannels[i]; | |||||
| if (s->mNumPositionKeys == alloc) { /* need to reallocate? */ | |||||
| aiVectorKey* old = s->mPositionKeys; | |||||
| s->mPositionKeys = new aiVectorKey[s->mNumPositionKeys = alloc*2]; | |||||
| ::memcpy(s->mPositionKeys,old,sizeof(aiVectorKey)*alloc); | |||||
| delete[] old; | |||||
| } | |||||
| // read x,y,z | |||||
| if(!SkipSpacesAndLineEnd(&buffer)) | |||||
| throw DeadlyImportError("CSM: Unexpected EOF occured reading sample x coord"); | |||||
| if (TokenMatchI(buffer, "DROPOUT", 7)) { | |||||
| // seems this is invalid marker data; at least the doc says it's possible | |||||
| DefaultLogger::get()->warn("CSM: Encountered invalid marker data (DROPOUT)"); | |||||
| } | |||||
| else { | |||||
| aiVectorKey* sub = s->mPositionKeys + s->mNumPositionKeys; | |||||
| sub->mTime = (double)frame; | |||||
| buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.x); | |||||
| if(!SkipSpacesAndLineEnd(&buffer)) | |||||
| throw DeadlyImportError("CSM: Unexpected EOF occured reading sample y coord"); | |||||
| buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.y); | |||||
| if(!SkipSpacesAndLineEnd(&buffer)) | |||||
| throw DeadlyImportError("CSM: Unexpected EOF occured reading sample z coord"); | |||||
| buffer = fast_atoreal_move<float>(buffer, (float&)sub->mValue.z); | |||||
| ++s->mNumPositionKeys; | |||||
| } | |||||
| } | |||||
| // update allocation granularity | |||||
| if (filled == alloc) | |||||
| alloc *= 2; | |||||
| ++filled; | |||||
| } | |||||
| // all channels must be complete in order to continue safely. | |||||
| for (unsigned int i = 0; i < anim->mNumChannels;++i) { | |||||
| if (!anim->mChannels[i]->mNumPositionKeys) | |||||
| throw DeadlyImportError("CSM: Invalid marker track"); | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| // advance to the next line | |||||
| SkipLine(&buffer); | |||||
| } | |||||
| } | |||||
| // Setup a proper animation duration | |||||
| anim->mDuration = last - std::min( first, 0 ); | |||||
| // build a dummy root node with the tiny markers as children | |||||
| pScene->mRootNode = new aiNode(); | |||||
| pScene->mRootNode->mName.Set("$CSM_DummyRoot"); | |||||
| pScene->mRootNode->mNumChildren = anim->mNumChannels; | |||||
| pScene->mRootNode->mChildren = new aiNode* [anim->mNumChannels]; | |||||
| for (unsigned int i = 0; i < anim->mNumChannels;++i) { | |||||
| aiNodeAnim* na = anim->mChannels[i]; | |||||
| aiNode* nd = pScene->mRootNode->mChildren[i] = new aiNode(); | |||||
| nd->mName = anim->mChannels[i]->mNodeName; | |||||
| nd->mParent = pScene->mRootNode; | |||||
| aiMatrix4x4::Translation(na->mPositionKeys[0].mValue, nd->mTransformation); | |||||
| } | |||||
| // Store the one and only animation in the scene | |||||
| pScene->mAnimations = new aiAnimation*[pScene->mNumAnimations=1]; | |||||
| pScene->mAnimations[0] = anim; | |||||
| anim->mName.Set("$CSM_MasterAnim"); | |||||
| // mark the scene as incomplete and run SkeletonMeshBuilder on it | |||||
| pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE; | |||||
| if (!noSkeletonMesh) { | |||||
| SkeletonMeshBuilder maker(pScene,pScene->mRootNode,true); | |||||
| } | |||||
| } | |||||
| #endif // !! ASSIMP_BUILD_NO_CSM_IMPORTER | |||||
| @@ -0,0 +1,88 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file CSMLoader.h | |||||
| * Declaration of the CharacterStudio Motion importer class. | |||||
| */ | |||||
| #ifndef INCLUDED_AI_CSM_LOADER_H | |||||
| #define INCLUDED_AI_CSM_LOADER_H | |||||
| namespace Assimp { | |||||
| // --------------------------------------------------------------------------- | |||||
| /** Importer class to load MOCAPs in CharacterStudio Motion format. | |||||
| * | |||||
| * A very rudimentary loader for the moment. No support for the hierarchy, | |||||
| * every marker is returned as child of root. | |||||
| * | |||||
| * Link to file format specification: | |||||
| * <max_8_dvd>\samples\Motion\Docs\CSM.rtf | |||||
| */ | |||||
| class CSMImporter : public BaseImporter | |||||
| { | |||||
| public: | |||||
| CSMImporter(); | |||||
| ~CSMImporter(); | |||||
| public: | |||||
| // ------------------------------------------------------------------- | |||||
| bool CanRead( const std::string& pFile, IOSystem* pIOHandler, | |||||
| bool checkSig) const; | |||||
| protected: | |||||
| // ------------------------------------------------------------------- | |||||
| const aiImporterDesc* GetInfo () const; | |||||
| // ------------------------------------------------------------------- | |||||
| void SetupProperties(const Importer* pImp); | |||||
| // ------------------------------------------------------------------- | |||||
| void InternReadFile( const std::string& pFile, aiScene* pScene, | |||||
| IOSystem* pIOHandler); | |||||
| private: | |||||
| bool noSkeletonMesh; | |||||
| }; // end of class CSMImporter | |||||
| } // end of namespace Assimp | |||||
| #endif // AI_AC3DIMPORTER_H_INC | |||||
| @@ -0,0 +1,318 @@ | |||||
| /* | |||||
| --------------------------------------------------------------------------- | |||||
| Open Asset Import Library (assimp) | |||||
| --------------------------------------------------------------------------- | |||||
| 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. | |||||
| --------------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file Implementation of the post processing step to calculate | |||||
| * tangents and bitangents for all imported meshes | |||||
| */ | |||||
| #include "AssimpPCH.h" | |||||
| // internal headers | |||||
| #include "CalcTangentsProcess.h" | |||||
| #include "ProcessHelper.h" | |||||
| #include "TinyFormatter.h" | |||||
| using namespace Assimp; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Constructor to be privately used by Importer | |||||
| CalcTangentsProcess::CalcTangentsProcess() | |||||
| : configMaxAngle( AI_DEG_TO_RAD(45.f) ) | |||||
| , configSourceUV( 0 ) { | |||||
| // nothing to do here | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Destructor, private as well | |||||
| CalcTangentsProcess::~CalcTangentsProcess() | |||||
| { | |||||
| // nothing to do here | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Returns whether the processing step is present in the given flag field. | |||||
| bool CalcTangentsProcess::IsActive( unsigned int pFlags) const | |||||
| { | |||||
| return (pFlags & aiProcess_CalcTangentSpace) != 0; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Executes the post processing step on the given imported data. | |||||
| void CalcTangentsProcess::SetupProperties(const Importer* pImp) | |||||
| { | |||||
| ai_assert( NULL != pImp ); | |||||
| // get the current value of the property | |||||
| configMaxAngle = pImp->GetPropertyFloat(AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE,45.f); | |||||
| configMaxAngle = std::max(std::min(configMaxAngle,45.0f),0.0f); | |||||
| configMaxAngle = AI_DEG_TO_RAD(configMaxAngle); | |||||
| configSourceUV = pImp->GetPropertyInteger(AI_CONFIG_PP_CT_TEXTURE_CHANNEL_INDEX,0); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Executes the post processing step on the given imported data. | |||||
| void CalcTangentsProcess::Execute( aiScene* pScene) | |||||
| { | |||||
| ai_assert( NULL != pScene ); | |||||
| DefaultLogger::get()->debug("CalcTangentsProcess begin"); | |||||
| bool bHas = false; | |||||
| for ( unsigned int a = 0; a < pScene->mNumMeshes; a++ ) { | |||||
| if(ProcessMesh( pScene->mMeshes[a],a))bHas = true; | |||||
| } | |||||
| if ( bHas ) { | |||||
| DefaultLogger::get()->info("CalcTangentsProcess finished. Tangents have been calculated"); | |||||
| } else { | |||||
| DefaultLogger::get()->debug("CalcTangentsProcess finished"); | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Calculates tangents and bitangents for the given mesh | |||||
| bool CalcTangentsProcess::ProcessMesh( aiMesh* pMesh, unsigned int meshIndex) | |||||
| { | |||||
| // we assume that the mesh is still in the verbose vertex format where each face has its own set | |||||
| // of vertices and no vertices are shared between faces. Sadly I don't know any quick test to | |||||
| // assert() it here. | |||||
| //assert( must be verbose, dammit); | |||||
| if (pMesh->mTangents) // thisimplies that mBitangents is also there | |||||
| return false; | |||||
| // If the mesh consists of lines and/or points but not of | |||||
| // triangles or higher-order polygons the normal vectors | |||||
| // are undefined. | |||||
| if (!(pMesh->mPrimitiveTypes & (aiPrimitiveType_TRIANGLE | aiPrimitiveType_POLYGON))) | |||||
| { | |||||
| DefaultLogger::get()->info("Tangents are undefined for line and point meshes"); | |||||
| return false; | |||||
| } | |||||
| // what we can check, though, is if the mesh has normals and texture coordinates. That's a requirement | |||||
| if( pMesh->mNormals == NULL) | |||||
| { | |||||
| DefaultLogger::get()->error("Failed to compute tangents; need normals"); | |||||
| return false; | |||||
| } | |||||
| if( configSourceUV >= AI_MAX_NUMBER_OF_TEXTURECOORDS || !pMesh->mTextureCoords[configSourceUV] ) | |||||
| { | |||||
| DefaultLogger::get()->error((Formatter::format("Failed to compute tangents; need UV data in channel"),configSourceUV)); | |||||
| return false; | |||||
| } | |||||
| const float angleEpsilon = 0.9999f; | |||||
| std::vector<bool> vertexDone( pMesh->mNumVertices, false); | |||||
| const float qnan = get_qnan(); | |||||
| // create space for the tangents and bitangents | |||||
| pMesh->mTangents = new aiVector3D[pMesh->mNumVertices]; | |||||
| pMesh->mBitangents = new aiVector3D[pMesh->mNumVertices]; | |||||
| const aiVector3D* meshPos = pMesh->mVertices; | |||||
| const aiVector3D* meshNorm = pMesh->mNormals; | |||||
| const aiVector3D* meshTex = pMesh->mTextureCoords[configSourceUV]; | |||||
| aiVector3D* meshTang = pMesh->mTangents; | |||||
| aiVector3D* meshBitang = pMesh->mBitangents; | |||||
| // calculate the tangent and bitangent for every face | |||||
| for( unsigned int a = 0; a < pMesh->mNumFaces; a++) | |||||
| { | |||||
| const aiFace& face = pMesh->mFaces[a]; | |||||
| if (face.mNumIndices < 3) | |||||
| { | |||||
| // There are less than three indices, thus the tangent vector | |||||
| // is not defined. We are finished with these vertices now, | |||||
| // their tangent vectors are set to qnan. | |||||
| for (unsigned int i = 0; i < face.mNumIndices;++i) | |||||
| { | |||||
| register unsigned int idx = face.mIndices[i]; | |||||
| vertexDone [idx] = true; | |||||
| meshTang [idx] = aiVector3D(qnan); | |||||
| meshBitang [idx] = aiVector3D(qnan); | |||||
| } | |||||
| continue; | |||||
| } | |||||
| // triangle or polygon... we always use only the first three indices. A polygon | |||||
| // is supposed to be planar anyways.... | |||||
| // FIXME: (thom) create correct calculation for multi-vertex polygons maybe? | |||||
| const unsigned int p0 = face.mIndices[0], p1 = face.mIndices[1], p2 = face.mIndices[2]; | |||||
| // position differences p1->p2 and p1->p3 | |||||
| aiVector3D v = meshPos[p1] - meshPos[p0], w = meshPos[p2] - meshPos[p0]; | |||||
| // texture offset p1->p2 and p1->p3 | |||||
| float sx = meshTex[p1].x - meshTex[p0].x, sy = meshTex[p1].y - meshTex[p0].y; | |||||
| float tx = meshTex[p2].x - meshTex[p0].x, ty = meshTex[p2].y - meshTex[p0].y; | |||||
| float dirCorrection = (tx * sy - ty * sx) < 0.0f ? -1.0f : 1.0f; | |||||
| // when t1, t2, t3 in same position in UV space, just use default UV direction. | |||||
| if ( 0 == sx && 0 ==sy && 0 == tx && 0 == ty ) { | |||||
| sx = 0.0; sy = 1.0; | |||||
| tx = 1.0; ty = 0.0; | |||||
| } | |||||
| // tangent points in the direction where to positive X axis of the texture coord's would point in model space | |||||
| // bitangent's points along the positive Y axis of the texture coord's, respectively | |||||
| aiVector3D tangent, bitangent; | |||||
| tangent.x = (w.x * sy - v.x * ty) * dirCorrection; | |||||
| tangent.y = (w.y * sy - v.y * ty) * dirCorrection; | |||||
| tangent.z = (w.z * sy - v.z * ty) * dirCorrection; | |||||
| bitangent.x = (w.x * sx - v.x * tx) * dirCorrection; | |||||
| bitangent.y = (w.y * sx - v.y * tx) * dirCorrection; | |||||
| bitangent.z = (w.z * sx - v.z * tx) * dirCorrection; | |||||
| // store for every vertex of that face | |||||
| for( unsigned int b = 0; b < face.mNumIndices; ++b ) { | |||||
| unsigned int p = face.mIndices[b]; | |||||
| // project tangent and bitangent into the plane formed by the vertex' normal | |||||
| aiVector3D localTangent = tangent - meshNorm[p] * (tangent * meshNorm[p]); | |||||
| aiVector3D localBitangent = bitangent - meshNorm[p] * (bitangent * meshNorm[p]); | |||||
| localTangent.Normalize(); localBitangent.Normalize(); | |||||
| // reconstruct tangent/bitangent according to normal and bitangent/tangent when it's infinite or NaN. | |||||
| bool invalid_tangent = is_special_float(localTangent.x) || is_special_float(localTangent.y) || is_special_float(localTangent.z); | |||||
| bool invalid_bitangent = is_special_float(localBitangent.x) || is_special_float(localBitangent.y) || is_special_float(localBitangent.z); | |||||
| if (invalid_tangent != invalid_bitangent) { | |||||
| if (invalid_tangent) { | |||||
| localTangent = meshNorm[p] ^ localBitangent; | |||||
| localTangent.Normalize(); | |||||
| } else { | |||||
| localBitangent = localTangent ^ meshNorm[p]; | |||||
| localBitangent.Normalize(); | |||||
| } | |||||
| } | |||||
| // and write it into the mesh. | |||||
| meshTang[ p ] = localTangent; | |||||
| meshBitang[ p ] = localBitangent; | |||||
| } | |||||
| } | |||||
| // create a helper to quickly find locally close vertices among the vertex array | |||||
| // FIX: check whether we can reuse the SpatialSort of a previous step | |||||
| SpatialSort* vertexFinder = NULL; | |||||
| SpatialSort _vertexFinder; | |||||
| float posEpsilon; | |||||
| if (shared) | |||||
| { | |||||
| std::vector<std::pair<SpatialSort,float> >* avf; | |||||
| shared->GetProperty(AI_SPP_SPATIAL_SORT,avf); | |||||
| if (avf) | |||||
| { | |||||
| std::pair<SpatialSort,float>& blubb = avf->operator [] (meshIndex); | |||||
| vertexFinder = &blubb.first; | |||||
| posEpsilon = blubb.second;; | |||||
| } | |||||
| } | |||||
| if (!vertexFinder) | |||||
| { | |||||
| _vertexFinder.Fill(pMesh->mVertices, pMesh->mNumVertices, sizeof( aiVector3D)); | |||||
| vertexFinder = &_vertexFinder; | |||||
| posEpsilon = ComputePositionEpsilon(pMesh); | |||||
| } | |||||
| std::vector<unsigned int> verticesFound; | |||||
| const float fLimit = cosf(configMaxAngle); | |||||
| std::vector<unsigned int> closeVertices; | |||||
| // in the second pass we now smooth out all tangents and bitangents at the same local position | |||||
| // if they are not too far off. | |||||
| for( unsigned int a = 0; a < pMesh->mNumVertices; a++) | |||||
| { | |||||
| if( vertexDone[a]) | |||||
| continue; | |||||
| const aiVector3D& origPos = pMesh->mVertices[a]; | |||||
| const aiVector3D& origNorm = pMesh->mNormals[a]; | |||||
| const aiVector3D& origTang = pMesh->mTangents[a]; | |||||
| const aiVector3D& origBitang = pMesh->mBitangents[a]; | |||||
| closeVertices.clear(); | |||||
| // find all vertices close to that position | |||||
| vertexFinder->FindPositions( origPos, posEpsilon, verticesFound); | |||||
| closeVertices.reserve (verticesFound.size()+5); | |||||
| closeVertices.push_back( a); | |||||
| // look among them for other vertices sharing the same normal and a close-enough tangent/bitangent | |||||
| for( unsigned int b = 0; b < verticesFound.size(); b++) | |||||
| { | |||||
| unsigned int idx = verticesFound[b]; | |||||
| if( vertexDone[idx]) | |||||
| continue; | |||||
| if( meshNorm[idx] * origNorm < angleEpsilon) | |||||
| continue; | |||||
| if( meshTang[idx] * origTang < fLimit) | |||||
| continue; | |||||
| if( meshBitang[idx] * origBitang < fLimit) | |||||
| continue; | |||||
| // it's similar enough -> add it to the smoothing group | |||||
| closeVertices.push_back( idx); | |||||
| vertexDone[idx] = true; | |||||
| } | |||||
| // smooth the tangents and bitangents of all vertices that were found to be close enough | |||||
| aiVector3D smoothTangent( 0, 0, 0), smoothBitangent( 0, 0, 0); | |||||
| for( unsigned int b = 0; b < closeVertices.size(); ++b) | |||||
| { | |||||
| smoothTangent += meshTang[ closeVertices[b] ]; | |||||
| smoothBitangent += meshBitang[ closeVertices[b] ]; | |||||
| } | |||||
| smoothTangent.Normalize(); | |||||
| smoothBitangent.Normalize(); | |||||
| // and write it back into all affected tangents | |||||
| for( unsigned int b = 0; b < closeVertices.size(); ++b) | |||||
| { | |||||
| meshTang[ closeVertices[b] ] = smoothTangent; | |||||
| meshBitang[ closeVertices[b] ] = smoothBitangent; | |||||
| } | |||||
| } | |||||
| return true; | |||||
| } | |||||
| @@ -0,0 +1,115 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file Defines a post processing step to calculate tangents and | |||||
| bitangents on all imported meshes.*/ | |||||
| #ifndef AI_CALCTANGENTSPROCESS_H_INC | |||||
| #define AI_CALCTANGENTSPROCESS_H_INC | |||||
| #include "BaseProcess.h" | |||||
| struct aiMesh; | |||||
| namespace Assimp | |||||
| { | |||||
| // --------------------------------------------------------------------------- | |||||
| /** The CalcTangentsProcess calculates the tangent and bitangent for any vertex | |||||
| * of all meshes. It is expected to be run before the JoinVerticesProcess runs | |||||
| * because the joining of vertices also considers tangents and bitangents for | |||||
| * uniqueness. | |||||
| */ | |||||
| class ASSIMP_API_WINONLY CalcTangentsProcess : public BaseProcess | |||||
| { | |||||
| public: | |||||
| CalcTangentsProcess(); | |||||
| ~CalcTangentsProcess(); | |||||
| public: | |||||
| // ------------------------------------------------------------------- | |||||
| /** Returns whether the processing step is present in the given flag. | |||||
| * @param pFlags The processing flags the importer was called with. | |||||
| * A bitwise combination of #aiPostProcessSteps. | |||||
| * @return true if the process is present in this flag fields, | |||||
| * false if not. | |||||
| */ | |||||
| bool IsActive( unsigned int pFlags) const; | |||||
| // ------------------------------------------------------------------- | |||||
| /** Called prior to ExecuteOnScene(). | |||||
| * The function is a request to the process to update its configuration | |||||
| * basing on the Importer's configuration property list. | |||||
| */ | |||||
| void SetupProperties(const Importer* pImp); | |||||
| // setter for configMaxAngle | |||||
| inline void SetMaxSmoothAngle(float f) | |||||
| { | |||||
| configMaxAngle =f; | |||||
| } | |||||
| protected: | |||||
| // ------------------------------------------------------------------- | |||||
| /** Calculates tangents and bitangents for a specific mesh. | |||||
| * @param pMesh The mesh to process. | |||||
| * @param meshIndex Index of the mesh | |||||
| */ | |||||
| bool ProcessMesh( aiMesh* pMesh, unsigned int meshIndex); | |||||
| // ------------------------------------------------------------------- | |||||
| /** Executes the post processing step on the given imported data. | |||||
| * @param pScene The imported data to work at. | |||||
| */ | |||||
| void Execute( aiScene* pScene); | |||||
| private: | |||||
| /** Configuration option: maximum smoothing angle, in radians*/ | |||||
| float configMaxAngle; | |||||
| unsigned int configSourceUV; | |||||
| }; | |||||
| } // end of namespace Assimp | |||||
| #endif // AI_CALCTANGENTSPROCESS_H_INC | |||||
| @@ -0,0 +1,821 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| #include "AssimpPCH.h" | |||||
| #ifndef ASSIMP_BUILD_NO_EXPORT | |||||
| #ifndef ASSIMP_BUILD_NO_COLLADA_EXPORTER | |||||
| #include "ColladaExporter.h" | |||||
| #include "Bitmap.h" | |||||
| #include "fast_atof.h" | |||||
| #include "SceneCombiner.h" | |||||
| #include <ctime> | |||||
| #include <set> | |||||
| using namespace Assimp; | |||||
| namespace Assimp | |||||
| { | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Worker function for exporting a scene to Collada. Prototyped and registered in Exporter.cpp | |||||
| void ExportSceneCollada(const char* pFile,IOSystem* pIOSystem, const aiScene* pScene) | |||||
| { | |||||
| std::string path = ""; | |||||
| std::string file = pFile; | |||||
| // We need to test both types of folder separators because pIOSystem->getOsSeparator() is not reliable. | |||||
| // Moreover, the path given by some applications is not even consistent with the OS specific type of separator. | |||||
| const char* end_path = std::max(strrchr(pFile, '\\'), strrchr(pFile, '/')); | |||||
| if(end_path != NULL) { | |||||
| path = std::string(pFile, end_path + 1 - pFile); | |||||
| file = file.substr(end_path + 1 - pFile, file.npos); | |||||
| std::size_t pos = file.find_last_of('.'); | |||||
| if(pos != file.npos) { | |||||
| file = file.substr(0, pos); | |||||
| } | |||||
| } | |||||
| // invoke the exporter | |||||
| ColladaExporter iDoTheExportThing( pScene, pIOSystem, path, file); | |||||
| // we're still here - export successfully completed. Write result to the given IOSYstem | |||||
| boost::scoped_ptr<IOStream> outfile (pIOSystem->Open(pFile,"wt")); | |||||
| if(outfile == NULL) { | |||||
| throw DeadlyExportError("could not open output .dae file: " + std::string(pFile)); | |||||
| } | |||||
| // XXX maybe use a small wrapper around IOStream that behaves like std::stringstream in order to avoid the extra copy. | |||||
| outfile->Write( iDoTheExportThing.mOutput.str().c_str(), static_cast<size_t>(iDoTheExportThing.mOutput.tellp()),1); | |||||
| } | |||||
| } // end of namespace Assimp | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Constructor for a specific scene to export | |||||
| ColladaExporter::ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file) : mIOSystem(pIOSystem), mPath(path), mFile(file) | |||||
| { | |||||
| // make sure that all formatting happens using the standard, C locale and not the user's current locale | |||||
| mOutput.imbue( std::locale("C") ); | |||||
| mScene = pScene; | |||||
| mSceneOwned = false; | |||||
| // set up strings | |||||
| endstr = "\n"; | |||||
| // start writing | |||||
| WriteFile(); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Destructor | |||||
| ColladaExporter::~ColladaExporter() | |||||
| { | |||||
| if(mSceneOwned) { | |||||
| delete mScene; | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Starts writing the contents | |||||
| void ColladaExporter::WriteFile() | |||||
| { | |||||
| // write the DTD | |||||
| mOutput << "<?xml version=\"1.0\"?>" << endstr; | |||||
| // COLLADA element start | |||||
| mOutput << "<COLLADA xmlns=\"http://www.collada.org/2005/11/COLLADASchema\" version=\"1.4.1\">" << endstr; | |||||
| PushTag(); | |||||
| WriteTextures(); | |||||
| WriteHeader(); | |||||
| WriteMaterials(); | |||||
| WriteGeometryLibrary(); | |||||
| WriteSceneLibrary(); | |||||
| // useless Collada fu at the end, just in case we haven't had enough indirections, yet. | |||||
| mOutput << startstr << "<scene>" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<instance_visual_scene url=\"#" + std::string(mScene->mRootNode->mName.C_Str()) + "\" />" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</scene>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << "</COLLADA>" << endstr; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Writes the asset header | |||||
| void ColladaExporter::WriteHeader() | |||||
| { | |||||
| static const float epsilon = 0.000001f; | |||||
| static const aiQuaternion x_rot(aiMatrix3x3( | |||||
| 0, -1, 0, | |||||
| 1, 0, 0, | |||||
| 0, 0, 1)); | |||||
| static const aiQuaternion y_rot(aiMatrix3x3( | |||||
| 1, 0, 0, | |||||
| 0, 1, 0, | |||||
| 0, 0, 1)); | |||||
| static const aiQuaternion z_rot(aiMatrix3x3( | |||||
| 1, 0, 0, | |||||
| 0, 0, 1, | |||||
| 0, -1, 0)); | |||||
| static const unsigned int date_nb_chars = 20; | |||||
| char date_str[date_nb_chars]; | |||||
| std::time_t date = std::time(NULL); | |||||
| std::strftime(date_str, date_nb_chars, "%Y-%m-%dT%H:%M:%S", std::localtime(&date)); | |||||
| std::string scene_name = mScene->mRootNode->mName.C_Str(); | |||||
| aiVector3D scaling; | |||||
| aiQuaternion rotation; | |||||
| aiVector3D position; | |||||
| mScene->mRootNode->mTransformation.Decompose(scaling, rotation, position); | |||||
| bool add_root_node = false; | |||||
| float scale = 1.0; | |||||
| if(std::abs(scaling.x - scaling.y) <= epsilon && std::abs(scaling.x - scaling.z) <= epsilon && std::abs(scaling.y - scaling.z) <= epsilon) { | |||||
| scale = (float) ((((double) scaling.x) + ((double) scaling.y) + ((double) scaling.z)) / 3.0); | |||||
| } else { | |||||
| add_root_node = true; | |||||
| } | |||||
| std::string up_axis = "Y_UP"; | |||||
| if(rotation.Equal(x_rot, epsilon)) { | |||||
| up_axis = "X_UP"; | |||||
| } else if(rotation.Equal(y_rot, epsilon)) { | |||||
| up_axis = "Y_UP"; | |||||
| } else if(rotation.Equal(z_rot, epsilon)) { | |||||
| up_axis = "Z_UP"; | |||||
| } else { | |||||
| add_root_node = true; | |||||
| } | |||||
| if(! position.Equal(aiVector3D(0, 0, 0))) { | |||||
| add_root_node = true; | |||||
| } | |||||
| if(mScene->mRootNode->mNumChildren == 0) { | |||||
| add_root_node = true; | |||||
| } | |||||
| if(add_root_node) { | |||||
| aiScene* scene; | |||||
| SceneCombiner::CopyScene(&scene, mScene); | |||||
| aiNode* root = new aiNode("Scene"); | |||||
| root->mNumChildren = 1; | |||||
| root->mChildren = new aiNode*[root->mNumChildren]; | |||||
| root->mChildren[0] = scene->mRootNode; | |||||
| scene->mRootNode->mParent = root; | |||||
| scene->mRootNode = root; | |||||
| mScene = scene; | |||||
| mSceneOwned = true; | |||||
| up_axis = "Y_UP"; | |||||
| scale = 1.0; | |||||
| } | |||||
| mOutput << startstr << "<asset>" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<contributor>" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<author>Assimp</author>" << endstr; | |||||
| mOutput << startstr << "<authoring_tool>Assimp Collada Exporter</authoring_tool>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</contributor>" << endstr; | |||||
| mOutput << startstr << "<created>" << date_str << "</created>" << endstr; | |||||
| mOutput << startstr << "<modified>" << date_str << "</modified>" << endstr; | |||||
| mOutput << startstr << "<unit name=\"meter\" meter=\"" << scale << "\" />" << endstr; | |||||
| mOutput << startstr << "<up_axis>" << up_axis << "</up_axis>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</asset>" << endstr; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Write the embedded textures | |||||
| void ColladaExporter::WriteTextures() { | |||||
| static const unsigned int buffer_size = 1024; | |||||
| char str[buffer_size]; | |||||
| if(mScene->HasTextures()) { | |||||
| for(unsigned int i = 0; i < mScene->mNumTextures; i++) { | |||||
| // It would be great to be able to create a directory in portable standard C++, but it's not the case, | |||||
| // so we just write the textures in the current directory. | |||||
| aiTexture* texture = mScene->mTextures[i]; | |||||
| ASSIMP_itoa10(str, buffer_size, i + 1); | |||||
| std::string name = mFile + "_texture_" + (i < 1000 ? "0" : "") + (i < 100 ? "0" : "") + (i < 10 ? "0" : "") + str + "." + ((const char*) texture->achFormatHint); | |||||
| boost::scoped_ptr<IOStream> outfile(mIOSystem->Open(mPath + name, "wb")); | |||||
| if(outfile == NULL) { | |||||
| throw DeadlyExportError("could not open output texture file: " + mPath + name); | |||||
| } | |||||
| if(texture->mHeight == 0) { | |||||
| outfile->Write((void*) texture->pcData, texture->mWidth, 1); | |||||
| } else { | |||||
| Bitmap::Save(texture, outfile.get()); | |||||
| } | |||||
| outfile->Flush(); | |||||
| textures.insert(std::make_pair(i, name)); | |||||
| } | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Reads a single surface entry from the given material keys | |||||
| void ColladaExporter::ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex) | |||||
| { | |||||
| if( pSrcMat->GetTextureCount( pTexture) > 0 ) | |||||
| { | |||||
| aiString texfile; | |||||
| unsigned int uvChannel = 0; | |||||
| pSrcMat->GetTexture( pTexture, 0, &texfile, NULL, &uvChannel); | |||||
| std::string index_str(texfile.C_Str()); | |||||
| if(index_str.size() != 0 && index_str[0] == '*') | |||||
| { | |||||
| unsigned int index; | |||||
| index_str = index_str.substr(1, std::string::npos); | |||||
| try { | |||||
| index = (unsigned int) strtoul10_64(index_str.c_str()); | |||||
| } catch(std::exception& error) { | |||||
| throw DeadlyExportError(error.what()); | |||||
| } | |||||
| std::map<unsigned int, std::string>::const_iterator name = textures.find(index); | |||||
| if(name != textures.end()) { | |||||
| poSurface.texture = name->second; | |||||
| } else { | |||||
| throw DeadlyExportError("could not find embedded texture at index " + index_str); | |||||
| } | |||||
| } else | |||||
| { | |||||
| poSurface.texture = texfile.C_Str(); | |||||
| } | |||||
| poSurface.channel = uvChannel; | |||||
| poSurface.exist = true; | |||||
| } else | |||||
| { | |||||
| if( pKey ) | |||||
| poSurface.exist = pSrcMat->Get( pKey, pType, pIndex, poSurface.color) == aiReturn_SUCCESS; | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Writes an image entry for the given surface | |||||
| void ColladaExporter::WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd) | |||||
| { | |||||
| if( !pSurface.texture.empty() ) | |||||
| { | |||||
| mOutput << startstr << "<image id=\"" << pNameAdd << "\">" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<init_from>"; | |||||
| for( std::string::const_iterator it = pSurface.texture.begin(); it != pSurface.texture.end(); ++it ) | |||||
| { | |||||
| if( isalnum( *it) || *it == '_' || *it == '.' || *it == '/' || *it == '\\' ) | |||||
| mOutput << *it; | |||||
| else | |||||
| mOutput << '%' << std::hex << size_t( (unsigned char) *it) << std::dec; | |||||
| } | |||||
| mOutput << "</init_from>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</image>" << endstr; | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Writes a color-or-texture entry into an effect definition | |||||
| void ColladaExporter::WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName) | |||||
| { | |||||
| if(pSurface.exist) { | |||||
| mOutput << startstr << "<" << pTypeName << ">" << endstr; | |||||
| PushTag(); | |||||
| if( pSurface.texture.empty() ) | |||||
| { | |||||
| mOutput << startstr << "<color sid=\"" << pTypeName << "\">" << pSurface.color.r << " " << pSurface.color.g << " " << pSurface.color.b << " " << pSurface.color.a << "</color>" << endstr; | |||||
| } else | |||||
| { | |||||
| mOutput << startstr << "<texture texture=\"" << pImageName << "\" texcoord=\"CHANNEL" << pSurface.channel << "\" />" << endstr; | |||||
| } | |||||
| PopTag(); | |||||
| mOutput << startstr << "</" << pTypeName << ">" << endstr; | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Writes the two parameters necessary for referencing a texture in an effect entry | |||||
| void ColladaExporter::WriteTextureParamEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pMatName) | |||||
| { | |||||
| // if surface is a texture, write out the sampler and the surface parameters necessary to reference the texture | |||||
| if( !pSurface.texture.empty() ) | |||||
| { | |||||
| mOutput << startstr << "<newparam sid=\"" << pMatName << "-" << pTypeName << "-surface\">" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<surface type=\"2D\">" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<init_from>" << pMatName << "-" << pTypeName << "-image</init_from>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</surface>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</newparam>" << endstr; | |||||
| mOutput << startstr << "<newparam sid=\"" << pMatName << "-" << pTypeName << "-sampler\">" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<sampler2D>" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<source>" << pMatName << "-" << pTypeName << "-surface</source>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</sampler2D>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</newparam>" << endstr; | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Writes a scalar property | |||||
| void ColladaExporter::WriteFloatEntry( const Property& pProperty, const std::string& pTypeName) | |||||
| { | |||||
| if(pProperty.exist) { | |||||
| mOutput << startstr << "<" << pTypeName << ">" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<float sid=\"" << pTypeName << "\">" << pProperty.value << "</float>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</" << pTypeName << ">" << endstr; | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Writes the material setup | |||||
| void ColladaExporter::WriteMaterials() | |||||
| { | |||||
| materials.resize( mScene->mNumMaterials); | |||||
| std::set<std::string> material_names; | |||||
| /// collect all materials from the scene | |||||
| size_t numTextures = 0; | |||||
| for( size_t a = 0; a < mScene->mNumMaterials; ++a ) | |||||
| { | |||||
| const aiMaterial* mat = mScene->mMaterials[a]; | |||||
| aiString name; | |||||
| if( mat->Get( AI_MATKEY_NAME, name) != aiReturn_SUCCESS ) | |||||
| name = "mat"; | |||||
| materials[a].name = std::string( "m") + boost::lexical_cast<std::string> (a) + name.C_Str(); | |||||
| for( std::string::iterator it = materials[a].name.begin(); it != materials[a].name.end(); ++it ) { | |||||
| // isalnum on MSVC asserts for code points in [0,255]. Thus prevent unwanted promotion | |||||
| // of char to signed int and take the unsigned char value. | |||||
| if( !isalnum( static_cast<uint8_t>(*it) ) ) { | |||||
| *it = '_'; | |||||
| } | |||||
| } | |||||
| aiShadingMode shading; | |||||
| materials[a].shading_model = "phong"; | |||||
| if(mat->Get( AI_MATKEY_SHADING_MODEL, shading) == aiReturn_SUCCESS) { | |||||
| if(shading == aiShadingMode_Phong) { | |||||
| materials[a].shading_model = "phong"; | |||||
| } else if(shading == aiShadingMode_Blinn) { | |||||
| materials[a].shading_model = "blinn"; | |||||
| } else if(shading == aiShadingMode_NoShading) { | |||||
| materials[a].shading_model = "constant"; | |||||
| } else if(shading == aiShadingMode_Gouraud) { | |||||
| materials[a].shading_model = "lambert"; | |||||
| } | |||||
| } | |||||
| ReadMaterialSurface( materials[a].ambient, mat, aiTextureType_AMBIENT, AI_MATKEY_COLOR_AMBIENT); | |||||
| if( !materials[a].ambient.texture.empty() ) numTextures++; | |||||
| ReadMaterialSurface( materials[a].diffuse, mat, aiTextureType_DIFFUSE, AI_MATKEY_COLOR_DIFFUSE); | |||||
| if( !materials[a].diffuse.texture.empty() ) numTextures++; | |||||
| ReadMaterialSurface( materials[a].specular, mat, aiTextureType_SPECULAR, AI_MATKEY_COLOR_SPECULAR); | |||||
| if( !materials[a].specular.texture.empty() ) numTextures++; | |||||
| ReadMaterialSurface( materials[a].emissive, mat, aiTextureType_EMISSIVE, AI_MATKEY_COLOR_EMISSIVE); | |||||
| if( !materials[a].emissive.texture.empty() ) numTextures++; | |||||
| ReadMaterialSurface( materials[a].reflective, mat, aiTextureType_REFLECTION, AI_MATKEY_COLOR_REFLECTIVE); | |||||
| if( !materials[a].reflective.texture.empty() ) numTextures++; | |||||
| ReadMaterialSurface( materials[a].transparent, mat, aiTextureType_OPACITY, AI_MATKEY_COLOR_TRANSPARENT); | |||||
| if( !materials[a].transparent.texture.empty() ) numTextures++; | |||||
| ReadMaterialSurface( materials[a].normal, mat, aiTextureType_NORMALS, NULL, 0, 0); | |||||
| if( !materials[a].normal.texture.empty() ) numTextures++; | |||||
| 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 = 1 - materials[a].transparency.value; | |||||
| materials[a].index_refraction.exist = mat->Get( AI_MATKEY_REFRACTI, materials[a].index_refraction.value) == aiReturn_SUCCESS; | |||||
| } | |||||
| // output textures if present | |||||
| if( numTextures > 0 ) | |||||
| { | |||||
| mOutput << startstr << "<library_images>" << endstr; | |||||
| PushTag(); | |||||
| for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it ) | |||||
| { | |||||
| const Material& mat = *it; | |||||
| WriteImageEntry( mat.ambient, mat.name + "-ambient-image"); | |||||
| WriteImageEntry( mat.diffuse, mat.name + "-diffuse-image"); | |||||
| WriteImageEntry( mat.specular, mat.name + "-specular-image"); | |||||
| WriteImageEntry( mat.emissive, mat.name + "-emission-image"); | |||||
| WriteImageEntry( mat.reflective, mat.name + "-reflective-image"); | |||||
| WriteImageEntry( mat.transparent, mat.name + "-transparent-image"); | |||||
| WriteImageEntry( mat.normal, mat.name + "-normal-image"); | |||||
| } | |||||
| PopTag(); | |||||
| mOutput << startstr << "</library_images>" << endstr; | |||||
| } | |||||
| // output effects - those are the actual carriers of information | |||||
| if( !materials.empty() ) | |||||
| { | |||||
| mOutput << startstr << "<library_effects>" << endstr; | |||||
| PushTag(); | |||||
| for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it ) | |||||
| { | |||||
| const Material& mat = *it; | |||||
| // this is so ridiculous it must be right | |||||
| mOutput << startstr << "<effect id=\"" << mat.name << "-fx\" name=\"" << mat.name << "\">" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<profile_COMMON>" << endstr; | |||||
| PushTag(); | |||||
| // write sampler- and surface params for the texture entries | |||||
| WriteTextureParamEntry( mat.emissive, "emission", mat.name); | |||||
| WriteTextureParamEntry( mat.ambient, "ambient", mat.name); | |||||
| WriteTextureParamEntry( mat.diffuse, "diffuse", mat.name); | |||||
| WriteTextureParamEntry( mat.specular, "specular", mat.name); | |||||
| WriteTextureParamEntry( mat.reflective, "reflective", mat.name); | |||||
| WriteTextureParamEntry( mat.transparent, "transparent", mat.name); | |||||
| WriteTextureParamEntry( mat.normal, "normal", mat.name); | |||||
| mOutput << startstr << "<technique sid=\"standard\">" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<" << mat.shading_model << ">" << endstr; | |||||
| PushTag(); | |||||
| WriteTextureColorEntry( mat.emissive, "emission", mat.name + "-emission-sampler"); | |||||
| WriteTextureColorEntry( mat.ambient, "ambient", mat.name + "-ambient-sampler"); | |||||
| WriteTextureColorEntry( mat.diffuse, "diffuse", mat.name + "-diffuse-sampler"); | |||||
| WriteTextureColorEntry( mat.specular, "specular", mat.name + "-specular-sampler"); | |||||
| WriteFloatEntry(mat.shininess, "shininess"); | |||||
| WriteTextureColorEntry( mat.reflective, "reflective", mat.name + "-reflective-sampler"); | |||||
| WriteTextureColorEntry( mat.transparent, "transparent", mat.name + "-transparent-sampler"); | |||||
| WriteFloatEntry(mat.transparency, "transparency"); | |||||
| WriteFloatEntry(mat.index_refraction, "index_of_refraction"); | |||||
| if(! mat.normal.texture.empty()) { | |||||
| WriteTextureColorEntry( mat.normal, "bump", mat.name + "-normal-sampler"); | |||||
| } | |||||
| PopTag(); | |||||
| mOutput << startstr << "</" << mat.shading_model << ">" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</technique>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</profile_COMMON>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</effect>" << endstr; | |||||
| } | |||||
| PopTag(); | |||||
| mOutput << startstr << "</library_effects>" << endstr; | |||||
| // write materials - they're just effect references | |||||
| mOutput << startstr << "<library_materials>" << endstr; | |||||
| PushTag(); | |||||
| for( std::vector<Material>::const_iterator it = materials.begin(); it != materials.end(); ++it ) | |||||
| { | |||||
| const Material& mat = *it; | |||||
| mOutput << startstr << "<material id=\"" << mat.name << "\" name=\"" << mat.name << "\">" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<instance_effect url=\"#" << mat.name << "-fx\"/>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</material>" << endstr; | |||||
| } | |||||
| PopTag(); | |||||
| mOutput << startstr << "</library_materials>" << endstr; | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Writes the geometry library | |||||
| void ColladaExporter::WriteGeometryLibrary() | |||||
| { | |||||
| mOutput << startstr << "<library_geometries>" << endstr; | |||||
| PushTag(); | |||||
| for( size_t a = 0; a < mScene->mNumMeshes; ++a) | |||||
| WriteGeometry( a); | |||||
| PopTag(); | |||||
| mOutput << startstr << "</library_geometries>" << endstr; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Writes the given mesh | |||||
| void ColladaExporter::WriteGeometry( size_t pIndex) | |||||
| { | |||||
| const aiMesh* mesh = mScene->mMeshes[pIndex]; | |||||
| std::string idstr = GetMeshId( pIndex); | |||||
| if( mesh->mNumFaces == 0 || mesh->mNumVertices == 0 ) | |||||
| return; | |||||
| // opening tag | |||||
| mOutput << startstr << "<geometry id=\"" << idstr << "\" name=\"" << idstr << "_name\" >" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<mesh>" << endstr; | |||||
| PushTag(); | |||||
| // Positions | |||||
| WriteFloatArray( idstr + "-positions", FloatType_Vector, (float*) mesh->mVertices, mesh->mNumVertices); | |||||
| // Normals, if any | |||||
| if( mesh->HasNormals() ) | |||||
| WriteFloatArray( idstr + "-normals", FloatType_Vector, (float*) mesh->mNormals, mesh->mNumVertices); | |||||
| // texture coords | |||||
| for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) | |||||
| { | |||||
| if( mesh->HasTextureCoords( a) ) | |||||
| { | |||||
| WriteFloatArray( idstr + "-tex" + boost::lexical_cast<std::string> (a), mesh->mNumUVComponents[a] == 3 ? FloatType_TexCoord3 : FloatType_TexCoord2, | |||||
| (float*) mesh->mTextureCoords[a], mesh->mNumVertices); | |||||
| } | |||||
| } | |||||
| // vertex colors | |||||
| for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a) | |||||
| { | |||||
| if( mesh->HasVertexColors( a) ) | |||||
| WriteFloatArray( idstr + "-color" + boost::lexical_cast<std::string> (a), FloatType_Color, (float*) mesh->mColors[a], mesh->mNumVertices); | |||||
| } | |||||
| // assemble vertex structure | |||||
| mOutput << startstr << "<vertices id=\"" << idstr << "-vertices" << "\">" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<input semantic=\"POSITION\" source=\"#" << idstr << "-positions\" />" << endstr; | |||||
| if( mesh->HasNormals() ) | |||||
| mOutput << startstr << "<input semantic=\"NORMAL\" source=\"#" << idstr << "-normals\" />" << endstr; | |||||
| for( size_t a = 0; a < AI_MAX_NUMBER_OF_TEXTURECOORDS; ++a ) | |||||
| { | |||||
| if( mesh->HasTextureCoords( a) ) | |||||
| mOutput << startstr << "<input semantic=\"TEXCOORD\" source=\"#" << idstr << "-tex" << a << "\" " /*<< "set=\"" << a << "\"" */ << " />" << endstr; | |||||
| } | |||||
| for( size_t a = 0; a < AI_MAX_NUMBER_OF_COLOR_SETS; ++a ) | |||||
| { | |||||
| if( mesh->HasVertexColors( a) ) | |||||
| mOutput << startstr << "<input semantic=\"COLOR\" source=\"#" << idstr << "-color" << a << "\" " /*<< set=\"" << a << "\"" */ << " />" << endstr; | |||||
| } | |||||
| PopTag(); | |||||
| mOutput << startstr << "</vertices>" << endstr; | |||||
| // write face setup | |||||
| mOutput << startstr << "<polylist count=\"" << mesh->mNumFaces << "\" material=\"theresonlyone\">" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<input offset=\"0\" semantic=\"VERTEX\" source=\"#" << idstr << "-vertices\" />" << endstr; | |||||
| mOutput << startstr << "<vcount>"; | |||||
| for( size_t a = 0; a < mesh->mNumFaces; ++a ) | |||||
| mOutput << mesh->mFaces[a].mNumIndices << " "; | |||||
| mOutput << "</vcount>" << endstr; | |||||
| mOutput << startstr << "<p>"; | |||||
| for( size_t a = 0; a < mesh->mNumFaces; ++a ) | |||||
| { | |||||
| const aiFace& face = mesh->mFaces[a]; | |||||
| for( size_t b = 0; b < face.mNumIndices; ++b ) | |||||
| mOutput << face.mIndices[b] << " "; | |||||
| } | |||||
| mOutput << "</p>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</polylist>" << endstr; | |||||
| // closing tags | |||||
| PopTag(); | |||||
| mOutput << startstr << "</mesh>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</geometry>" << endstr; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Writes a float array of the given type | |||||
| void ColladaExporter::WriteFloatArray( const std::string& pIdString, FloatDataType pType, const float* pData, size_t pElementCount) | |||||
| { | |||||
| size_t floatsPerElement = 0; | |||||
| switch( pType ) | |||||
| { | |||||
| case FloatType_Vector: floatsPerElement = 3; break; | |||||
| case FloatType_TexCoord2: floatsPerElement = 2; break; | |||||
| case FloatType_TexCoord3: floatsPerElement = 3; break; | |||||
| case FloatType_Color: floatsPerElement = 3; break; | |||||
| default: | |||||
| return; | |||||
| } | |||||
| std::string arrayId = pIdString + "-array"; | |||||
| mOutput << startstr << "<source id=\"" << pIdString << "\" name=\"" << pIdString << "\">" << endstr; | |||||
| PushTag(); | |||||
| // source array | |||||
| mOutput << startstr << "<float_array id=\"" << arrayId << "\" count=\"" << pElementCount * floatsPerElement << "\"> "; | |||||
| PushTag(); | |||||
| if( pType == FloatType_TexCoord2 ) | |||||
| { | |||||
| for( size_t a = 0; a < pElementCount; ++a ) | |||||
| { | |||||
| mOutput << pData[a*3+0] << " "; | |||||
| mOutput << pData[a*3+1] << " "; | |||||
| } | |||||
| } | |||||
| else if( pType == FloatType_Color ) | |||||
| { | |||||
| for( size_t a = 0; a < pElementCount; ++a ) | |||||
| { | |||||
| mOutput << pData[a*4+0] << " "; | |||||
| mOutput << pData[a*4+1] << " "; | |||||
| mOutput << pData[a*4+2] << " "; | |||||
| } | |||||
| } | |||||
| else | |||||
| { | |||||
| for( size_t a = 0; a < pElementCount * floatsPerElement; ++a ) | |||||
| mOutput << pData[a] << " "; | |||||
| } | |||||
| mOutput << "</float_array>" << endstr; | |||||
| PopTag(); | |||||
| // the usual Collada fun. Let's bloat it even more! | |||||
| mOutput << startstr << "<technique_common>" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<accessor count=\"" << pElementCount << "\" offset=\"0\" source=\"#" << arrayId << "\" stride=\"" << floatsPerElement << "\">" << endstr; | |||||
| PushTag(); | |||||
| switch( pType ) | |||||
| { | |||||
| case FloatType_Vector: | |||||
| mOutput << startstr << "<param name=\"X\" type=\"float\" />" << endstr; | |||||
| mOutput << startstr << "<param name=\"Y\" type=\"float\" />" << endstr; | |||||
| mOutput << startstr << "<param name=\"Z\" type=\"float\" />" << endstr; | |||||
| break; | |||||
| case FloatType_TexCoord2: | |||||
| mOutput << startstr << "<param name=\"S\" type=\"float\" />" << endstr; | |||||
| mOutput << startstr << "<param name=\"T\" type=\"float\" />" << endstr; | |||||
| break; | |||||
| case FloatType_TexCoord3: | |||||
| mOutput << startstr << "<param name=\"S\" type=\"float\" />" << endstr; | |||||
| mOutput << startstr << "<param name=\"T\" type=\"float\" />" << endstr; | |||||
| mOutput << startstr << "<param name=\"P\" type=\"float\" />" << endstr; | |||||
| break; | |||||
| case FloatType_Color: | |||||
| mOutput << startstr << "<param name=\"R\" type=\"float\" />" << endstr; | |||||
| mOutput << startstr << "<param name=\"G\" type=\"float\" />" << endstr; | |||||
| mOutput << startstr << "<param name=\"B\" type=\"float\" />" << endstr; | |||||
| break; | |||||
| } | |||||
| PopTag(); | |||||
| mOutput << startstr << "</accessor>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</technique_common>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</source>" << endstr; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Writes the scene library | |||||
| void ColladaExporter::WriteSceneLibrary() | |||||
| { | |||||
| std::string scene_name = mScene->mRootNode->mName.C_Str(); | |||||
| mOutput << startstr << "<library_visual_scenes>" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<visual_scene id=\"" + scene_name + "\" name=\"" + scene_name + "\">" << endstr; | |||||
| PushTag(); | |||||
| // start recursive write at the root node | |||||
| for( size_t a = 0; a < mScene->mRootNode->mNumChildren; ++a ) | |||||
| WriteNode( mScene->mRootNode->mChildren[a]); | |||||
| PopTag(); | |||||
| mOutput << startstr << "</visual_scene>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</library_visual_scenes>" << endstr; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Recursively writes the given node | |||||
| void ColladaExporter::WriteNode( const aiNode* pNode) | |||||
| { | |||||
| mOutput << startstr << "<node id=\"" << pNode->mName.data << "\" name=\"" << pNode->mName.data << "\">" << endstr; | |||||
| PushTag(); | |||||
| // write transformation - we can directly put the matrix there | |||||
| // TODO: (thom) decompose into scale - rot - quad to allow adressing it by animations afterwards | |||||
| const aiMatrix4x4& mat = pNode->mTransformation; | |||||
| mOutput << startstr << "<matrix>"; | |||||
| 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 << " "; | |||||
| mOutput << mat.d1 << " " << mat.d2 << " " << mat.d3 << " " << mat.d4; | |||||
| mOutput << "</matrix>" << endstr; | |||||
| // instance every geometry | |||||
| 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 << "<instance_geometry url=\"#" << GetMeshId( pNode->mMeshes[a]) << "\">" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<bind_material>" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<technique_common>" << endstr; | |||||
| PushTag(); | |||||
| mOutput << startstr << "<instance_material symbol=\"theresonlyone\" target=\"#" << materials[mesh->mMaterialIndex].name << "\" />" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</technique_common>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</bind_material>" << endstr; | |||||
| PopTag(); | |||||
| mOutput << startstr << "</instance_geometry>" << endstr; | |||||
| } | |||||
| // recurse into subnodes | |||||
| for( size_t a = 0; a < pNode->mNumChildren; ++a ) | |||||
| WriteNode( pNode->mChildren[a]); | |||||
| PopTag(); | |||||
| mOutput << startstr << "</node>" << endstr; | |||||
| } | |||||
| #endif | |||||
| #endif | |||||
| @@ -0,0 +1,176 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file ColladaExporter.h | |||||
| * Declares the exporter class to write a scene to a Collada file | |||||
| */ | |||||
| #ifndef AI_COLLADAEXPORTER_H_INC | |||||
| #define AI_COLLADAEXPORTER_H_INC | |||||
| #include "../include/assimp/ai_assert.h" | |||||
| #include <sstream> | |||||
| struct aiScene; | |||||
| struct aiNode; | |||||
| namespace Assimp | |||||
| { | |||||
| /// Helper class to export a given scene to a Collada file. Just for my personal | |||||
| /// comfort when implementing it. | |||||
| class ColladaExporter | |||||
| { | |||||
| public: | |||||
| /// Constructor for a specific scene to export | |||||
| ColladaExporter( const aiScene* pScene, IOSystem* pIOSystem, const std::string& path, const std::string& file); | |||||
| /// Destructor | |||||
| virtual ~ColladaExporter(); | |||||
| protected: | |||||
| /// Starts writing the contents | |||||
| void WriteFile(); | |||||
| /// Writes the asset header | |||||
| void WriteHeader(); | |||||
| /// Writes the embedded textures | |||||
| void WriteTextures(); | |||||
| /// Writes the material setup | |||||
| void WriteMaterials(); | |||||
| /// 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 }; | |||||
| /// Writes a float array of the given type | |||||
| void WriteFloatArray( const std::string& pIdString, FloatDataType pType, const float* pData, size_t pElementCount); | |||||
| /// Writes the scene library | |||||
| void WriteSceneLibrary(); | |||||
| /// Recursively writes the given node | |||||
| void WriteNode( const aiNode* pNode); | |||||
| /// 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); } | |||||
| /// Creates a mesh ID for the given mesh | |||||
| std::string GetMeshId( size_t pIndex) const { return std::string( "meshId" ) + boost::lexical_cast<std::string> (pIndex); } | |||||
| public: | |||||
| /// Stringstream to write all output into | |||||
| std::stringstream mOutput; | |||||
| protected: | |||||
| /// The IOSystem for output | |||||
| IOSystem* mIOSystem; | |||||
| /// Path of the directory where the scene will be exported | |||||
| const std::string mPath; | |||||
| /// Name of the file (without extension) where the scene will be exported | |||||
| const std::string mFile; | |||||
| /// The scene to be written | |||||
| const aiScene* mScene; | |||||
| bool mSceneOwned; | |||||
| /// current line start string, contains the current indentation for simple stream insertion | |||||
| std::string startstr; | |||||
| /// current line end string for simple stream insertion | |||||
| std::string endstr; | |||||
| // pair of color and texture - texture precedences color | |||||
| struct Surface | |||||
| { | |||||
| bool exist; | |||||
| aiColor4D color; | |||||
| std::string texture; | |||||
| size_t channel; | |||||
| Surface() { exist = false; channel = 0; } | |||||
| }; | |||||
| struct Property | |||||
| { | |||||
| bool exist; | |||||
| float value; | |||||
| Property() { exist = false; } | |||||
| }; | |||||
| // summarize a material in an convinient way. | |||||
| struct Material | |||||
| { | |||||
| std::string name; | |||||
| std::string shading_model; | |||||
| Surface ambient, diffuse, specular, emissive, reflective, transparent, normal; | |||||
| Property shininess, transparency, index_refraction; | |||||
| Material() {} | |||||
| }; | |||||
| std::vector<Material> materials; | |||||
| std::map<unsigned int, std::string> textures; | |||||
| protected: | |||||
| /// Dammit C++ - y u no compile two-pass? No I have to add all methods below the struct definitions | |||||
| /// Reads a single surface entry from the given material keys | |||||
| void ReadMaterialSurface( Surface& poSurface, const aiMaterial* pSrcMat, aiTextureType pTexture, const char* pKey, size_t pType, size_t pIndex); | |||||
| /// Writes an image entry for the given surface | |||||
| void WriteImageEntry( const Surface& pSurface, const std::string& pNameAdd); | |||||
| /// Writes the two parameters necessary for referencing a texture in an effect entry | |||||
| void WriteTextureParamEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pMatName); | |||||
| /// Writes a color-or-texture entry into an effect definition | |||||
| void WriteTextureColorEntry( const Surface& pSurface, const std::string& pTypeName, const std::string& pImageName); | |||||
| /// Writes a scalar property | |||||
| void WriteFloatEntry( const Property& pProperty, const std::string& pTypeName); | |||||
| }; | |||||
| } | |||||
| #endif // !! AI_COLLADAEXPORTER_H_INC | |||||
| @@ -0,0 +1,604 @@ | |||||
| /** Helper structures for the Collada loader */ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| #ifndef AI_COLLADAHELPER_H_INC | |||||
| #define AI_COLLADAHELPER_H_INC | |||||
| namespace Assimp { | |||||
| namespace Collada { | |||||
| /** Collada file versions which evolved during the years ... */ | |||||
| enum FormatVersion | |||||
| { | |||||
| FV_1_5_n, | |||||
| FV_1_4_n, | |||||
| FV_1_3_n | |||||
| }; | |||||
| /** Transformation types that can be applied to a node */ | |||||
| enum TransformType | |||||
| { | |||||
| TF_LOOKAT, | |||||
| TF_ROTATE, | |||||
| TF_TRANSLATE, | |||||
| TF_SCALE, | |||||
| TF_SKEW, | |||||
| TF_MATRIX | |||||
| }; | |||||
| /** Different types of input data to a vertex or face */ | |||||
| enum InputType | |||||
| { | |||||
| IT_Invalid, | |||||
| IT_Vertex, // special type for per-index data referring to the <vertices> element carrying the per-vertex data. | |||||
| IT_Position, | |||||
| IT_Normal, | |||||
| IT_Texcoord, | |||||
| IT_Color, | |||||
| IT_Tangent, | |||||
| IT_Bitangent | |||||
| }; | |||||
| /** Contains all data for one of the different transformation types */ | |||||
| struct Transform | |||||
| { | |||||
| std::string mID; ///< SID of the transform step, by which anim channels address their target node | |||||
| TransformType mType; | |||||
| float f[16]; ///< Interpretation of data depends on the type of the transformation | |||||
| }; | |||||
| /** A collada camera. */ | |||||
| struct Camera | |||||
| { | |||||
| Camera() | |||||
| : mOrtho (false) | |||||
| , mHorFov (10e10f) | |||||
| , mVerFov (10e10f) | |||||
| , mAspect (10e10f) | |||||
| , mZNear (0.1f) | |||||
| , mZFar (1000.f) | |||||
| {} | |||||
| // Name of camera | |||||
| std::string mName; | |||||
| // True if it is an orthografic camera | |||||
| bool mOrtho; | |||||
| //! Horizontal field of view in degrees | |||||
| float mHorFov; | |||||
| //! Vertical field of view in degrees | |||||
| float mVerFov; | |||||
| //! Screen aspect | |||||
| float mAspect; | |||||
| //! Near& far z | |||||
| float mZNear, mZFar; | |||||
| }; | |||||
| #define aiLightSource_AMBIENT 0xdeaddead | |||||
| #define ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET 1e9f | |||||
| /** A collada light source. */ | |||||
| struct Light | |||||
| { | |||||
| Light() | |||||
| : mAttConstant (1.f) | |||||
| , mAttLinear (0.f) | |||||
| , mAttQuadratic (0.f) | |||||
| , mFalloffAngle (180.f) | |||||
| , mFalloffExponent (0.f) | |||||
| , mPenumbraAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET) | |||||
| , mOuterAngle (ASSIMP_COLLADA_LIGHT_ANGLE_NOT_SET) | |||||
| , mIntensity (1.f) | |||||
| {} | |||||
| //! Type of the light source aiLightSourceType + ambient | |||||
| unsigned int mType; | |||||
| //! Color of the light | |||||
| aiColor3D mColor; | |||||
| //! Light attenuation | |||||
| float mAttConstant,mAttLinear,mAttQuadratic; | |||||
| //! Spot light falloff | |||||
| float mFalloffAngle; | |||||
| float mFalloffExponent; | |||||
| // ----------------------------------------------------- | |||||
| // FCOLLADA extension from here | |||||
| //! ... related stuff from maja and max extensions | |||||
| float mPenumbraAngle; | |||||
| float mOuterAngle; | |||||
| //! Common light intensity | |||||
| float mIntensity; | |||||
| }; | |||||
| /** Short vertex index description */ | |||||
| struct InputSemanticMapEntry | |||||
| { | |||||
| InputSemanticMapEntry() | |||||
| : mSet (0) | |||||
| {} | |||||
| //! Index of set, optional | |||||
| unsigned int mSet; | |||||
| //! Name of referenced vertex input | |||||
| InputType mType; | |||||
| }; | |||||
| /** Table to map from effect to vertex input semantics */ | |||||
| struct SemanticMappingTable | |||||
| { | |||||
| //! Name of material | |||||
| std::string mMatName; | |||||
| //! List of semantic map commands, grouped by effect semantic name | |||||
| std::map<std::string, InputSemanticMapEntry> mMap; | |||||
| //! For std::find | |||||
| bool operator == (const std::string& s) const { | |||||
| return s == mMatName; | |||||
| } | |||||
| }; | |||||
| /** A reference to a mesh inside a node, including materials assigned to the various subgroups. | |||||
| * The ID refers to either a mesh or a controller which specifies the mesh | |||||
| */ | |||||
| struct MeshInstance | |||||
| { | |||||
| ///< ID of the mesh or controller to be instanced | |||||
| std::string mMeshOrController; | |||||
| ///< Map of materials by the subgroup ID they're applied to | |||||
| std::map<std::string, SemanticMappingTable> mMaterials; | |||||
| }; | |||||
| /** A reference to a camera inside a node*/ | |||||
| struct CameraInstance | |||||
| { | |||||
| ///< ID of the camera | |||||
| std::string mCamera; | |||||
| }; | |||||
| /** A reference to a light inside a node*/ | |||||
| struct LightInstance | |||||
| { | |||||
| ///< ID of the camera | |||||
| std::string mLight; | |||||
| }; | |||||
| /** A reference to a node inside a node*/ | |||||
| struct NodeInstance | |||||
| { | |||||
| ///< ID of the node | |||||
| std::string mNode; | |||||
| }; | |||||
| /** A node in a scene hierarchy */ | |||||
| struct Node | |||||
| { | |||||
| std::string mName; | |||||
| std::string mID; | |||||
| std::string mSID; | |||||
| Node* mParent; | |||||
| std::vector<Node*> mChildren; | |||||
| /** Operations in order to calculate the resulting transformation to parent. */ | |||||
| std::vector<Transform> mTransforms; | |||||
| /** Meshes at this node */ | |||||
| std::vector<MeshInstance> mMeshes; | |||||
| /** Lights at this node */ | |||||
| std::vector<LightInstance> mLights; | |||||
| /** Cameras at this node */ | |||||
| std::vector<CameraInstance> mCameras; | |||||
| /** Node instances at this node */ | |||||
| std::vector<NodeInstance> mNodeInstances; | |||||
| /** Rootnodes: Name of primary camera, if any */ | |||||
| std::string mPrimaryCamera; | |||||
| //! Constructor. Begin with a zero parent | |||||
| Node() { | |||||
| mParent = NULL; | |||||
| } | |||||
| //! Destructor: delete all children subsequently | |||||
| ~Node() { | |||||
| for( std::vector<Node*>::iterator it = mChildren.begin(); it != mChildren.end(); ++it) | |||||
| delete *it; | |||||
| } | |||||
| }; | |||||
| /** Data source array: either floats or strings */ | |||||
| struct Data | |||||
| { | |||||
| bool mIsStringArray; | |||||
| std::vector<float> mValues; | |||||
| std::vector<std::string> mStrings; | |||||
| }; | |||||
| /** Accessor to a data array */ | |||||
| struct Accessor | |||||
| { | |||||
| size_t mCount; // in number of objects | |||||
| size_t mSize; // size of an object, in elements (floats or strings, mostly 1) | |||||
| size_t mOffset; // in number of values | |||||
| size_t mStride; // Stride in number of values | |||||
| std::vector<std::string> mParams; // names of the data streams in the accessors. Empty string tells to ignore. | |||||
| size_t mSubOffset[4]; // Suboffset inside the object for the common 4 elements. For a vector, thats XYZ, for a color RGBA and so on. | |||||
| // For example, SubOffset[0] denotes which of the values inside the object is the vector X component. | |||||
| std::string mSource; // URL of the source array | |||||
| mutable const Data* mData; // Pointer to the source array, if resolved. NULL else | |||||
| Accessor() | |||||
| { | |||||
| mCount = 0; mSize = 0; mOffset = 0; mStride = 0; mData = NULL; | |||||
| mSubOffset[0] = mSubOffset[1] = mSubOffset[2] = mSubOffset[3] = 0; | |||||
| } | |||||
| }; | |||||
| /** A single face in a mesh */ | |||||
| struct Face | |||||
| { | |||||
| std::vector<size_t> mIndices; | |||||
| }; | |||||
| /** An input channel for mesh data, referring to a single accessor */ | |||||
| struct InputChannel | |||||
| { | |||||
| InputType mType; // Type of the data | |||||
| size_t mIndex; // Optional index, if multiple sets of the same data type are given | |||||
| size_t mOffset; // Index offset in the indices array of per-face indices. Don't ask, can't explain that any better. | |||||
| std::string mAccessor; // ID of the accessor where to read the actual values from. | |||||
| mutable const Accessor* mResolved; // Pointer to the accessor, if resolved. NULL else | |||||
| InputChannel() { mType = IT_Invalid; mIndex = 0; mOffset = 0; mResolved = NULL; } | |||||
| }; | |||||
| /** Subset of a mesh with a certain material */ | |||||
| struct SubMesh | |||||
| { | |||||
| std::string mMaterial; ///< subgroup identifier | |||||
| size_t mNumFaces; ///< number of faces in this submesh | |||||
| }; | |||||
| /** Contains data for a single mesh */ | |||||
| struct Mesh | |||||
| { | |||||
| Mesh() | |||||
| { | |||||
| for (unsigned int i = 0; i < AI_MAX_NUMBER_OF_TEXTURECOORDS;++i) | |||||
| mNumUVComponents[i] = 2; | |||||
| } | |||||
| std::string mName; | |||||
| // just to check if there's some sophisticated addressing involved... | |||||
| // which we don't support, and therefore should warn about. | |||||
| std::string mVertexID; | |||||
| // Vertex data addressed by vertex indices | |||||
| std::vector<InputChannel> mPerVertexData; | |||||
| // actual mesh data, assembled on encounter of a <p> element. Verbose format, not indexed | |||||
| std::vector<aiVector3D> mPositions; | |||||
| std::vector<aiVector3D> mNormals; | |||||
| std::vector<aiVector3D> mTangents; | |||||
| std::vector<aiVector3D> mBitangents; | |||||
| std::vector<aiVector3D> mTexCoords[AI_MAX_NUMBER_OF_TEXTURECOORDS]; | |||||
| std::vector<aiColor4D> mColors[AI_MAX_NUMBER_OF_COLOR_SETS]; | |||||
| unsigned int mNumUVComponents[AI_MAX_NUMBER_OF_TEXTURECOORDS]; | |||||
| // Faces. Stored are only the number of vertices for each face. | |||||
| // 1 == point, 2 == line, 3 == triangle, 4+ == poly | |||||
| std::vector<size_t> mFaceSize; | |||||
| // Position indices for all faces in the sequence given in mFaceSize - | |||||
| // necessary for bone weight assignment | |||||
| std::vector<size_t> mFacePosIndices; | |||||
| // Submeshes in this mesh, each with a given material | |||||
| std::vector<SubMesh> mSubMeshes; | |||||
| }; | |||||
| /** Which type of primitives the ReadPrimitives() function is going to read */ | |||||
| enum PrimitiveType | |||||
| { | |||||
| Prim_Invalid, | |||||
| Prim_Lines, | |||||
| Prim_LineStrip, | |||||
| Prim_Triangles, | |||||
| Prim_TriStrips, | |||||
| Prim_TriFans, | |||||
| Prim_Polylist, | |||||
| Prim_Polygon | |||||
| }; | |||||
| /** A skeleton controller to deform a mesh with the use of joints */ | |||||
| struct Controller | |||||
| { | |||||
| // the URL of the mesh deformed by the controller. | |||||
| std::string mMeshId; | |||||
| // accessor URL of the joint names | |||||
| std::string mJointNameSource; | |||||
| ///< The bind shape matrix, as array of floats. I'm not sure what this matrix actually describes, but it can't be ignored in all cases | |||||
| float mBindShapeMatrix[16]; | |||||
| // accessor URL of the joint inverse bind matrices | |||||
| std::string mJointOffsetMatrixSource; | |||||
| // input channel: joint names. | |||||
| InputChannel mWeightInputJoints; | |||||
| // input channel: joint weights | |||||
| InputChannel mWeightInputWeights; | |||||
| // Number of weights per vertex. | |||||
| std::vector<size_t> mWeightCounts; | |||||
| // JointIndex-WeightIndex pairs for all vertices | |||||
| std::vector< std::pair<size_t, size_t> > mWeights; | |||||
| }; | |||||
| /** A collada material. Pretty much the only member is a reference to an effect. */ | |||||
| struct Material | |||||
| { | |||||
| std::string mEffect; | |||||
| }; | |||||
| /** Type of the effect param */ | |||||
| enum ParamType | |||||
| { | |||||
| Param_Sampler, | |||||
| Param_Surface | |||||
| }; | |||||
| /** A param for an effect. Might be of several types, but they all just refer to each other, so I summarize them */ | |||||
| struct EffectParam | |||||
| { | |||||
| ParamType mType; | |||||
| std::string mReference; // to which other thing the param is referring to. | |||||
| }; | |||||
| /** Shading type supported by the standard effect spec of Collada */ | |||||
| enum ShadeType | |||||
| { | |||||
| Shade_Invalid, | |||||
| Shade_Constant, | |||||
| Shade_Lambert, | |||||
| Shade_Phong, | |||||
| Shade_Blinn | |||||
| }; | |||||
| /** Represents a texture sampler in collada */ | |||||
| struct Sampler | |||||
| { | |||||
| Sampler() | |||||
| : mWrapU (true) | |||||
| , mWrapV (true) | |||||
| , mMirrorU () | |||||
| , mMirrorV () | |||||
| , mOp (aiTextureOp_Multiply) | |||||
| , mUVId (UINT_MAX) | |||||
| , mWeighting (1.f) | |||||
| , mMixWithPrevious (1.f) | |||||
| {} | |||||
| /** Name of image reference | |||||
| */ | |||||
| std::string mName; | |||||
| /** Wrap U? | |||||
| */ | |||||
| bool mWrapU; | |||||
| /** Wrap V? | |||||
| */ | |||||
| bool mWrapV; | |||||
| /** Mirror U? | |||||
| */ | |||||
| bool mMirrorU; | |||||
| /** Mirror V? | |||||
| */ | |||||
| bool mMirrorV; | |||||
| /** Blend mode | |||||
| */ | |||||
| aiTextureOp mOp; | |||||
| /** UV transformation | |||||
| */ | |||||
| aiUVTransform mTransform; | |||||
| /** Name of source UV channel | |||||
| */ | |||||
| std::string mUVChannel; | |||||
| /** Resolved UV channel index or UINT_MAX if not known | |||||
| */ | |||||
| unsigned int mUVId; | |||||
| // OKINO/MAX3D extensions from here | |||||
| // ------------------------------------------------------- | |||||
| /** Weighting factor | |||||
| */ | |||||
| float mWeighting; | |||||
| /** Mixing factor from OKINO | |||||
| */ | |||||
| float mMixWithPrevious; | |||||
| }; | |||||
| /** A collada effect. Can contain about anything according to the Collada spec, | |||||
| but we limit our version to a reasonable subset. */ | |||||
| struct Effect | |||||
| { | |||||
| // Shading mode | |||||
| ShadeType mShadeType; | |||||
| // Colors | |||||
| aiColor4D mEmissive, mAmbient, mDiffuse, mSpecular, | |||||
| mTransparent, mReflective; | |||||
| // Textures | |||||
| Sampler mTexEmissive, mTexAmbient, mTexDiffuse, mTexSpecular, | |||||
| mTexTransparent, mTexBump, mTexReflective; | |||||
| // Scalar factory | |||||
| float mShininess, mRefractIndex, mReflectivity; | |||||
| float mTransparency; | |||||
| // local params referring to each other by their SID | |||||
| typedef std::map<std::string, Collada::EffectParam> ParamLibrary; | |||||
| ParamLibrary mParams; | |||||
| // MAX3D extensions | |||||
| // --------------------------------------------------------- | |||||
| // Double-sided? | |||||
| bool mDoubleSided, mWireframe, mFaceted; | |||||
| Effect() | |||||
| : mShadeType (Shade_Phong) | |||||
| , mEmissive ( 0, 0, 0, 1) | |||||
| , mAmbient ( 0.1f, 0.1f, 0.1f, 1) | |||||
| , mDiffuse ( 0.6f, 0.6f, 0.6f, 1) | |||||
| , mSpecular ( 0.4f, 0.4f, 0.4f, 1) | |||||
| , mTransparent ( 0, 0, 0, 1) | |||||
| , mShininess (10.0f) | |||||
| , mRefractIndex (1.f) | |||||
| , mReflectivity (1.f) | |||||
| , mTransparency (0.f) | |||||
| , mDoubleSided (false) | |||||
| , mWireframe (false) | |||||
| , mFaceted (false) | |||||
| { | |||||
| } | |||||
| }; | |||||
| /** An image, meaning texture */ | |||||
| struct Image | |||||
| { | |||||
| std::string mFileName; | |||||
| /** If image file name is zero, embedded image data | |||||
| */ | |||||
| std::vector<uint8_t> mImageData; | |||||
| /** If image file name is zero, file format of | |||||
| * embedded image data. | |||||
| */ | |||||
| std::string mEmbeddedFormat; | |||||
| }; | |||||
| /** An animation channel. */ | |||||
| struct AnimationChannel | |||||
| { | |||||
| /** URL of the data to animate. Could be about anything, but we support only the | |||||
| * "NodeID/TransformID.SubElement" notation | |||||
| */ | |||||
| std::string mTarget; | |||||
| /** Source URL of the time values. Collada calls them "input". Meh. */ | |||||
| std::string mSourceTimes; | |||||
| /** Source URL of the value values. Collada calls them "output". */ | |||||
| std::string mSourceValues; | |||||
| }; | |||||
| /** An animation. Container for 0-x animation channels or 0-x animations */ | |||||
| struct Animation | |||||
| { | |||||
| /** Anim name */ | |||||
| std::string mName; | |||||
| /** the animation channels, if any */ | |||||
| std::vector<AnimationChannel> mChannels; | |||||
| /** the sub-animations, if any */ | |||||
| std::vector<Animation*> mSubAnims; | |||||
| /** Destructor */ | |||||
| ~Animation() | |||||
| { | |||||
| for( std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) | |||||
| delete *it; | |||||
| } | |||||
| }; | |||||
| /** Description of a collada animation channel which has been determined to affect the current node */ | |||||
| struct ChannelEntry | |||||
| { | |||||
| const Collada::AnimationChannel* mChannel; ///> the source channel | |||||
| std::string mTransformId; // the ID of the transformation step of the node which is influenced | |||||
| size_t mTransformIndex; // Index into the node's transform chain to apply the channel to | |||||
| size_t mSubElement; // starting index inside the transform data | |||||
| // resolved data references | |||||
| const Collada::Accessor* mTimeAccessor; ///> Collada accessor to the time values | |||||
| const Collada::Data* mTimeData; ///> Source data array for the time values | |||||
| const Collada::Accessor* mValueAccessor; ///> Collada accessor to the key value values | |||||
| const Collada::Data* mValueData; ///> Source datat array for the key value values | |||||
| ChannelEntry() { mChannel = NULL; mSubElement = 0; } | |||||
| }; | |||||
| } // end of namespace Collada | |||||
| } // end of namespace Assimp | |||||
| #endif // AI_COLLADAHELPER_H_INC | |||||
| @@ -0,0 +1,242 @@ | |||||
| /** Defines the collada loader class */ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| #ifndef AI_COLLADALOADER_H_INC | |||||
| #define AI_COLLADALOADER_H_INC | |||||
| #include "BaseImporter.h" | |||||
| #include "ColladaParser.h" | |||||
| namespace Assimp | |||||
| { | |||||
| struct ColladaMeshIndex | |||||
| { | |||||
| std::string mMeshID; | |||||
| size_t mSubMesh; | |||||
| std::string mMaterial; | |||||
| ColladaMeshIndex( const std::string& pMeshID, size_t pSubMesh, const std::string& pMaterial) | |||||
| : mMeshID( pMeshID), mSubMesh( pSubMesh), mMaterial( pMaterial) | |||||
| { } | |||||
| bool operator < (const ColladaMeshIndex& p) const | |||||
| { | |||||
| if( mMeshID == p.mMeshID) | |||||
| { | |||||
| if( mSubMesh == p.mSubMesh) | |||||
| return mMaterial < p.mMaterial; | |||||
| else | |||||
| return mSubMesh < p.mSubMesh; | |||||
| } else | |||||
| { | |||||
| return mMeshID < p.mMeshID; | |||||
| } | |||||
| } | |||||
| }; | |||||
| /** Loader class to read Collada scenes. Collada is over-engineered to death, with every new iteration bringing | |||||
| * more useless stuff, so I limited the data to what I think is useful for games. | |||||
| */ | |||||
| class ColladaLoader : public BaseImporter | |||||
| { | |||||
| public: | |||||
| ColladaLoader(); | |||||
| ~ColladaLoader(); | |||||
| public: | |||||
| /** Returns whether the class can handle the format of the given file. | |||||
| * See BaseImporter::CanRead() for details. */ | |||||
| bool CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const; | |||||
| protected: | |||||
| /** Return importer meta information. | |||||
| * See #BaseImporter::GetInfo for the details | |||||
| */ | |||||
| const aiImporterDesc* GetInfo () const; | |||||
| void SetupProperties(const Importer* pImp); | |||||
| /** Imports the given file into the given scene structure. | |||||
| * See BaseImporter::InternReadFile() for details | |||||
| */ | |||||
| void InternReadFile( const std::string& pFile, aiScene* pScene, IOSystem* pIOHandler); | |||||
| /** Recursively constructs a scene node for the given parser node and returns it. */ | |||||
| aiNode* BuildHierarchy( const ColladaParser& pParser, const Collada::Node* pNode); | |||||
| /** Resolve node instances */ | |||||
| void ResolveNodeInstances( const ColladaParser& pParser, const Collada::Node* pNode, | |||||
| std::vector<const Collada::Node*>& resolved); | |||||
| /** Builds meshes for the given node and references them */ | |||||
| void BuildMeshesForNode( const ColladaParser& pParser, const Collada::Node* pNode, | |||||
| aiNode* pTarget); | |||||
| /** Creates a mesh for the given ColladaMesh face subset and returns the newly created mesh */ | |||||
| aiMesh* CreateMesh( const ColladaParser& pParser, const Collada::Mesh* pSrcMesh, const Collada::SubMesh& pSubMesh, | |||||
| const Collada::Controller* pSrcController, size_t pStartVertex, size_t pStartFace); | |||||
| /** Builds cameras for the given node and references them */ | |||||
| void BuildCamerasForNode( const ColladaParser& pParser, const Collada::Node* pNode, | |||||
| aiNode* pTarget); | |||||
| /** Builds lights for the given node and references them */ | |||||
| void BuildLightsForNode( const ColladaParser& pParser, const Collada::Node* pNode, | |||||
| aiNode* pTarget); | |||||
| /** Stores all meshes in the given scene */ | |||||
| void StoreSceneMeshes( aiScene* pScene); | |||||
| /** Stores all materials in the given scene */ | |||||
| void StoreSceneMaterials( aiScene* pScene); | |||||
| /** Stores all lights in the given scene */ | |||||
| void StoreSceneLights( aiScene* pScene); | |||||
| /** Stores all cameras in the given scene */ | |||||
| void StoreSceneCameras( aiScene* pScene); | |||||
| /** Stores all textures in the given scene */ | |||||
| void StoreSceneTextures( aiScene* pScene); | |||||
| /** Stores all animations | |||||
| * @param pScene target scene to store the anims | |||||
| */ | |||||
| void StoreAnimations( aiScene* pScene, const ColladaParser& pParser); | |||||
| /** Stores all animations for the given source anim and its nested child animations | |||||
| * @param pScene target scene to store the anims | |||||
| * @param pSrcAnim the source animation to process | |||||
| * @param pPrefix Prefix to the name in case of nested animations | |||||
| */ | |||||
| void StoreAnimations( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string pPrefix); | |||||
| /** Constructs the animation for the given source anim */ | |||||
| void CreateAnimation( aiScene* pScene, const ColladaParser& pParser, const Collada::Animation* pSrcAnim, const std::string& pName); | |||||
| /** Constructs materials from the collada material definitions */ | |||||
| void BuildMaterials( ColladaParser& pParser, aiScene* pScene); | |||||
| /** Fill materials from the collada material definitions */ | |||||
| void FillMaterials( const ColladaParser& pParser, aiScene* pScene); | |||||
| /** Resolve UV channel mappings*/ | |||||
| void ApplyVertexToEffectSemanticMapping(Collada::Sampler& sampler, | |||||
| const Collada::SemanticMappingTable& table); | |||||
| /** Add a texture and all of its sampling properties to a material*/ | |||||
| void AddTexture ( aiMaterial& mat, const ColladaParser& pParser, | |||||
| const Collada::Effect& effect, | |||||
| const Collada::Sampler& sampler, | |||||
| aiTextureType type, unsigned int idx = 0); | |||||
| /** Resolves the texture name for the given effect texture entry */ | |||||
| aiString FindFilenameForEffectTexture( const ColladaParser& pParser, | |||||
| const Collada::Effect& pEffect, const std::string& pName); | |||||
| /** Converts a path read from a collada file to the usual representation */ | |||||
| void ConvertPath( aiString& ss); | |||||
| /** Reads a float value from an accessor and its data array. | |||||
| * @param pAccessor The accessor to use for reading | |||||
| * @param pData The data array to read from | |||||
| * @param pIndex The index of the element to retrieve | |||||
| * @param pOffset Offset into the element, for multipart elements such as vectors or matrices | |||||
| * @return the specified value | |||||
| */ | |||||
| float ReadFloat( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex, size_t pOffset) const; | |||||
| /** Reads a string value from an accessor and its data array. | |||||
| * @param pAccessor The accessor to use for reading | |||||
| * @param pData The data array to read from | |||||
| * @param pIndex The index of the element to retrieve | |||||
| * @return the specified value | |||||
| */ | |||||
| const std::string& ReadString( const Collada::Accessor& pAccessor, const Collada::Data& pData, size_t pIndex) const; | |||||
| /** Recursively collects all nodes into the given array */ | |||||
| void CollectNodes( const aiNode* pNode, std::vector<const aiNode*>& poNodes) const; | |||||
| /** Finds a node in the collada scene by the given name */ | |||||
| const Collada::Node* FindNode( const Collada::Node* pNode, const std::string& pName) const; | |||||
| /** Finds a node in the collada scene by the given SID */ | |||||
| const Collada::Node* FindNodeBySID( const Collada::Node* pNode, const std::string& pSID) const; | |||||
| /** Finds a proper name for a node derived from the collada-node's properties */ | |||||
| std::string FindNameForNode( const Collada::Node* pNode) const; | |||||
| protected: | |||||
| /** Filename, for a verbose error message */ | |||||
| std::string mFileName; | |||||
| /** Which mesh-material compound was stored under which mesh ID */ | |||||
| std::map<ColladaMeshIndex, size_t> mMeshIndexByID; | |||||
| /** Which material was stored under which index in the scene */ | |||||
| std::map<std::string, size_t> mMaterialIndexByName; | |||||
| /** Accumulated meshes for the target scene */ | |||||
| std::vector<aiMesh*> mMeshes; | |||||
| /** Temporary material list */ | |||||
| std::vector<std::pair<Collada::Effect*, aiMaterial*> > newMats; | |||||
| /** Temporary camera list */ | |||||
| std::vector<aiCamera*> mCameras; | |||||
| /** Temporary light list */ | |||||
| std::vector<aiLight*> mLights; | |||||
| /** Temporary texture list */ | |||||
| std::vector<aiTexture*> mTextures; | |||||
| /** Accumulated animations for the target scene */ | |||||
| std::vector<aiAnimation*> mAnims; | |||||
| bool noSkeletonMesh; | |||||
| bool ignoreUpDirection; | |||||
| }; | |||||
| } // end of namespace Assimp | |||||
| #endif // AI_COLLADALOADER_H_INC | |||||
| @@ -0,0 +1,341 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file ColladaParser.h | |||||
| * @brief Defines the parser helper class for the collada loader | |||||
| */ | |||||
| #ifndef AI_COLLADAPARSER_H_INC | |||||
| #define AI_COLLADAPARSER_H_INC | |||||
| #include "irrXMLWrapper.h" | |||||
| #include "ColladaHelper.h" | |||||
| namespace Assimp | |||||
| { | |||||
| // ------------------------------------------------------------------------------------------ | |||||
| /** Parser helper class for the Collada loader. | |||||
| * | |||||
| * Does all the XML reading and builds internal data structures from it, | |||||
| * but leaves the resolving of all the references to the loader. | |||||
| */ | |||||
| class ColladaParser | |||||
| { | |||||
| friend class ColladaLoader; | |||||
| protected: | |||||
| /** Constructor from XML file */ | |||||
| ColladaParser( IOSystem* pIOHandler, const std::string& pFile); | |||||
| /** Destructor */ | |||||
| ~ColladaParser(); | |||||
| /** Reads the contents of the file */ | |||||
| void ReadContents(); | |||||
| /** Reads the structure of the file */ | |||||
| void ReadStructure(); | |||||
| /** Reads asset informations such as coordinate system informations and legal blah */ | |||||
| void ReadAssetInfo(); | |||||
| /** Reads the animation library */ | |||||
| void ReadAnimationLibrary(); | |||||
| /** Reads an animation into the given parent structure */ | |||||
| void ReadAnimation( Collada::Animation* pParent); | |||||
| /** Reads an animation sampler into the given anim channel */ | |||||
| void ReadAnimationSampler( Collada::AnimationChannel& pChannel); | |||||
| /** Reads the skeleton controller library */ | |||||
| void ReadControllerLibrary(); | |||||
| /** Reads a controller into the given mesh structure */ | |||||
| void ReadController( Collada::Controller& pController); | |||||
| /** Reads the joint definitions for the given controller */ | |||||
| void ReadControllerJoints( Collada::Controller& pController); | |||||
| /** Reads the joint weights for the given controller */ | |||||
| void ReadControllerWeights( Collada::Controller& pController); | |||||
| /** Reads the image library contents */ | |||||
| void ReadImageLibrary(); | |||||
| /** Reads an image entry into the given image */ | |||||
| void ReadImage( Collada::Image& pImage); | |||||
| /** Reads the material library */ | |||||
| void ReadMaterialLibrary(); | |||||
| /** Reads a material entry into the given material */ | |||||
| void ReadMaterial( Collada::Material& pMaterial); | |||||
| /** Reads the camera library */ | |||||
| void ReadCameraLibrary(); | |||||
| /** Reads a camera entry into the given camera */ | |||||
| void ReadCamera( Collada::Camera& pCamera); | |||||
| /** Reads the light library */ | |||||
| void ReadLightLibrary(); | |||||
| /** Reads a light entry into the given light */ | |||||
| void ReadLight( Collada::Light& pLight); | |||||
| /** Reads the effect library */ | |||||
| void ReadEffectLibrary(); | |||||
| /** Reads an effect entry into the given effect*/ | |||||
| void ReadEffect( Collada::Effect& pEffect); | |||||
| /** Reads an COMMON effect profile */ | |||||
| void ReadEffectProfileCommon( Collada::Effect& pEffect); | |||||
| /** Read sampler properties */ | |||||
| void ReadSamplerProperties( Collada::Sampler& pSampler); | |||||
| /** Reads an effect entry containing a color or a texture defining that color */ | |||||
| void ReadEffectColor( aiColor4D& pColor, Collada::Sampler& pSampler); | |||||
| /** Reads an effect entry containing a float */ | |||||
| void ReadEffectFloat( float& pFloat); | |||||
| /** Reads an effect parameter specification of any kind */ | |||||
| void ReadEffectParam( Collada::EffectParam& pParam); | |||||
| /** Reads the geometry library contents */ | |||||
| void ReadGeometryLibrary(); | |||||
| /** Reads a geometry from the geometry library. */ | |||||
| void ReadGeometry( Collada::Mesh* pMesh); | |||||
| /** Reads a mesh from the geometry library */ | |||||
| void ReadMesh( Collada::Mesh* pMesh); | |||||
| /** Reads a source element - a combination of raw data and an accessor defining | |||||
| * things that should not be redefinable. Yes, that's another rant. | |||||
| */ | |||||
| void ReadSource(); | |||||
| /** Reads a data array holding a number of elements, and stores it in the global library. | |||||
| * Currently supported are array of floats and arrays of strings. | |||||
| */ | |||||
| void ReadDataArray(); | |||||
| /** Reads an accessor and stores it in the global library under the given ID - | |||||
| * accessors use the ID of the parent <source> element | |||||
| */ | |||||
| void ReadAccessor( const std::string& pID); | |||||
| /** Reads input declarations of per-vertex mesh data into the given mesh */ | |||||
| void ReadVertexData( Collada::Mesh* pMesh); | |||||
| /** Reads input declarations of per-index mesh data into the given mesh */ | |||||
| void ReadIndexData( Collada::Mesh* pMesh); | |||||
| /** Reads a single input channel element and stores it in the given array, if valid */ | |||||
| void ReadInputChannel( std::vector<Collada::InputChannel>& poChannels); | |||||
| /** Reads a <p> primitive index list and assembles the mesh data into the given mesh */ | |||||
| void ReadPrimitives( Collada::Mesh* pMesh, std::vector<Collada::InputChannel>& pPerIndexChannels, | |||||
| size_t pNumPrimitives, const std::vector<size_t>& pVCount, Collada::PrimitiveType pPrimType); | |||||
| /** Extracts a single object from an input channel and stores it in the appropriate mesh data array */ | |||||
| void ExtractDataObjectFromChannel( const Collada::InputChannel& pInput, size_t pLocalIndex, Collada::Mesh* pMesh); | |||||
| /** Reads the library of node hierarchies and scene parts */ | |||||
| void ReadSceneLibrary(); | |||||
| /** Reads a scene node's contents including children and stores it in the given node */ | |||||
| void ReadSceneNode( Collada::Node* pNode); | |||||
| /** Reads a node transformation entry of the given type and adds it to the given node's transformation list. */ | |||||
| void ReadNodeTransformation( Collada::Node* pNode, Collada::TransformType pType); | |||||
| /** Reads a mesh reference in a node and adds it to the node's mesh list */ | |||||
| void ReadNodeGeometry( Collada::Node* pNode); | |||||
| /** Reads the collada scene */ | |||||
| void ReadScene(); | |||||
| // Processes bind_vertex_input and bind elements | |||||
| void ReadMaterialVertexInputBinding( Collada::SemanticMappingTable& tbl); | |||||
| protected: | |||||
| /** Aborts the file reading with an exception */ | |||||
| void ThrowException( const std::string& pError) const; | |||||
| /** Skips all data until the end node of the current element */ | |||||
| void SkipElement(); | |||||
| /** Skips all data until the end node of the given element */ | |||||
| void SkipElement( const char* pElement); | |||||
| /** Compares the current xml element name to the given string and returns true if equal */ | |||||
| bool IsElement( const char* pName) const; | |||||
| /** Tests for the opening tag of the given element, throws an exception if not found */ | |||||
| void TestOpening( const char* pName); | |||||
| /** Tests for the closing tag of the given element, throws an exception if not found */ | |||||
| void TestClosing( const char* pName); | |||||
| /** Checks the present element for the presence of the attribute, returns its index | |||||
| or throws an exception if not found */ | |||||
| int GetAttribute( const char* pAttr) const; | |||||
| /** Returns the index of the named attribute or -1 if not found. Does not throw, | |||||
| therefore useful for optional attributes */ | |||||
| int TestAttribute( const char* pAttr) const; | |||||
| /** Reads the text contents of an element, throws an exception if not given. | |||||
| Skips leading whitespace. */ | |||||
| const char* GetTextContent(); | |||||
| /** Reads the text contents of an element, returns NULL if not given. | |||||
| Skips leading whitespace. */ | |||||
| const char* TestTextContent(); | |||||
| /** Reads a single bool from current text content */ | |||||
| bool ReadBoolFromTextContent(); | |||||
| /** Reads a single float from current text content */ | |||||
| float ReadFloatFromTextContent(); | |||||
| /** Calculates the resulting transformation from all the given transform steps */ | |||||
| aiMatrix4x4 CalculateResultTransform( const std::vector<Collada::Transform>& pTransforms) const; | |||||
| /** Determines the input data type for the given semantic string */ | |||||
| Collada::InputType GetTypeForSemantic( const std::string& pSemantic); | |||||
| /** Finds the item in the given library by its reference, throws if not found */ | |||||
| template <typename Type> const Type& ResolveLibraryReference( | |||||
| const std::map<std::string, Type>& pLibrary, const std::string& pURL) const; | |||||
| protected: | |||||
| /** Filename, for a verbose error message */ | |||||
| std::string mFileName; | |||||
| /** XML reader, member for everyday use */ | |||||
| irr::io::IrrXMLReader* mReader; | |||||
| /** All data arrays found in the file by ID. Might be referred to by actually | |||||
| everyone. Collada, you are a steaming pile of indirection. */ | |||||
| typedef std::map<std::string, Collada::Data> DataLibrary; | |||||
| DataLibrary mDataLibrary; | |||||
| /** Same for accessors which define how the data in a data array is accessed. */ | |||||
| typedef std::map<std::string, Collada::Accessor> AccessorLibrary; | |||||
| AccessorLibrary mAccessorLibrary; | |||||
| /** Mesh library: mesh by ID */ | |||||
| typedef std::map<std::string, Collada::Mesh*> MeshLibrary; | |||||
| MeshLibrary mMeshLibrary; | |||||
| /** node library: root node of the hierarchy part by ID */ | |||||
| typedef std::map<std::string, Collada::Node*> NodeLibrary; | |||||
| NodeLibrary mNodeLibrary; | |||||
| /** Image library: stores texture properties by ID */ | |||||
| typedef std::map<std::string, Collada::Image> ImageLibrary; | |||||
| ImageLibrary mImageLibrary; | |||||
| /** Effect library: surface attributes by ID */ | |||||
| typedef std::map<std::string, Collada::Effect> EffectLibrary; | |||||
| EffectLibrary mEffectLibrary; | |||||
| /** Material library: surface material by ID */ | |||||
| typedef std::map<std::string, Collada::Material> MaterialLibrary; | |||||
| MaterialLibrary mMaterialLibrary; | |||||
| /** Light library: surface light by ID */ | |||||
| typedef std::map<std::string, Collada::Light> LightLibrary; | |||||
| LightLibrary mLightLibrary; | |||||
| /** Camera library: surface material by ID */ | |||||
| typedef std::map<std::string, Collada::Camera> CameraLibrary; | |||||
| CameraLibrary mCameraLibrary; | |||||
| /** Controller library: joint controllers by ID */ | |||||
| typedef std::map<std::string, Collada::Controller> ControllerLibrary; | |||||
| ControllerLibrary mControllerLibrary; | |||||
| /** Pointer to the root node. Don't delete, it just points to one of | |||||
| the nodes in the node library. */ | |||||
| Collada::Node* mRootNode; | |||||
| /** Root animation container */ | |||||
| Collada::Animation mAnims; | |||||
| /** Size unit: how large compared to a meter */ | |||||
| float mUnitSize; | |||||
| /** Which is the up vector */ | |||||
| enum { UP_X, UP_Y, UP_Z } mUpDirection; | |||||
| /** Collada file format version */ | |||||
| Collada::FormatVersion mFormat; | |||||
| }; | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Check for element match | |||||
| inline bool ColladaParser::IsElement( const char* pName) const | |||||
| { | |||||
| ai_assert( mReader->getNodeType() == irr::io::EXN_ELEMENT); | |||||
| return ::strcmp( mReader->getNodeName(), pName) == 0; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Finds the item in the given library by its reference, throws if not found | |||||
| template <typename Type> | |||||
| const Type& ColladaParser::ResolveLibraryReference( const std::map<std::string, Type>& pLibrary, const std::string& pURL) const | |||||
| { | |||||
| typename std::map<std::string, Type>::const_iterator it = pLibrary.find( pURL); | |||||
| if( it == pLibrary.end()) | |||||
| ThrowException( boost::str( boost::format( "Unable to resolve library reference \"%s\".") % pURL)); | |||||
| return it->second; | |||||
| } | |||||
| } // end of namespace Assimp | |||||
| #endif // AI_COLLADAPARSER_H_INC | |||||
| @@ -0,0 +1,504 @@ | |||||
| /* | |||||
| Open Asset Import Library (assimp) | |||||
| ---------------------------------------------------------------------- | |||||
| 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. | |||||
| ---------------------------------------------------------------------- | |||||
| */ | |||||
| /** @file GenUVCoords step */ | |||||
| #include "AssimpPCH.h" | |||||
| #include "ComputeUVMappingProcess.h" | |||||
| #include "ProcessHelper.h" | |||||
| using namespace Assimp; | |||||
| namespace { | |||||
| const static aiVector3D base_axis_y(0.f,1.f,0.f); | |||||
| const static aiVector3D base_axis_x(1.f,0.f,0.f); | |||||
| const static aiVector3D base_axis_z(0.f,0.f,1.f); | |||||
| const static float angle_epsilon = 0.95f; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Constructor to be privately used by Importer | |||||
| ComputeUVMappingProcess::ComputeUVMappingProcess() | |||||
| { | |||||
| // nothing to do here | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Destructor, private as well | |||||
| ComputeUVMappingProcess::~ComputeUVMappingProcess() | |||||
| { | |||||
| // nothing to do here | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Returns whether the processing step is present in the given flag field. | |||||
| bool ComputeUVMappingProcess::IsActive( unsigned int pFlags) const | |||||
| { | |||||
| return (pFlags & aiProcess_GenUVCoords) != 0; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Check whether a ray intersects a plane and find the intersection point | |||||
| inline bool PlaneIntersect(const aiRay& ray, const aiVector3D& planePos, | |||||
| const aiVector3D& planeNormal, aiVector3D& pos) | |||||
| { | |||||
| const float b = planeNormal * (planePos - ray.pos); | |||||
| float h = ray.dir * planeNormal; | |||||
| if ((h < 10e-5f && h > -10e-5f) || (h = b/h) < 0) | |||||
| return false; | |||||
| pos = ray.pos + (ray.dir * h); | |||||
| return true; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Find the first empty UV channel in a mesh | |||||
| inline unsigned int FindEmptyUVChannel (aiMesh* mesh) | |||||
| { | |||||
| for (unsigned int m = 0; m < AI_MAX_NUMBER_OF_TEXTURECOORDS;++m) | |||||
| if (!mesh->mTextureCoords[m])return m; | |||||
| DefaultLogger::get()->error("Unable to compute UV coordinates, no free UV slot found"); | |||||
| return UINT_MAX; | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| // Try to remove UV seams | |||||
| void RemoveUVSeams (aiMesh* mesh, aiVector3D* out) | |||||
| { | |||||
| // TODO: just a very rough algorithm. I think it could be done | |||||
| // much easier, but I don't know how and am currently too tired to | |||||
| // to think about a better solution. | |||||
| const static float LOWER_LIMIT = 0.1f; | |||||
| const static float UPPER_LIMIT = 0.9f; | |||||
| const static float LOWER_EPSILON = 10e-3f; | |||||
| const static float UPPER_EPSILON = 1.f-10e-3f; | |||||
| for (unsigned int fidx = 0; fidx < mesh->mNumFaces;++fidx) | |||||
| { | |||||
| const aiFace& face = mesh->mFaces[fidx]; | |||||
| if (face.mNumIndices < 3) continue; // triangles and polygons only, please | |||||
| unsigned int small = face.mNumIndices, large = small; | |||||
| bool zero = false, one = false, round_to_zero = false; | |||||
| // Check whether this face lies on a UV seam. We can just guess, | |||||
| // but the assumption that a face with at least one very small | |||||
| // on the one side and one very large U coord on the other side | |||||
| // lies on a UV seam should work for most cases. | |||||
| for (unsigned int n = 0; n < face.mNumIndices;++n) | |||||
| { | |||||
| if (out[face.mIndices[n]].x < LOWER_LIMIT) | |||||
| { | |||||
| small = n; | |||||
| // If we have a U value very close to 0 we can't | |||||
| // round the others to 0, too. | |||||
| if (out[face.mIndices[n]].x <= LOWER_EPSILON) | |||||
| zero = true; | |||||
| else round_to_zero = true; | |||||
| } | |||||
| if (out[face.mIndices[n]].x > UPPER_LIMIT) | |||||
| { | |||||
| large = n; | |||||
| // If we have a U value very close to 1 we can't | |||||
| // round the others to 1, too. | |||||
| if (out[face.mIndices[n]].x >= UPPER_EPSILON) | |||||
| one = true; | |||||
| } | |||||
| } | |||||
| if (small != face.mNumIndices && large != face.mNumIndices) | |||||
| { | |||||
| for (unsigned int n = 0; n < face.mNumIndices;++n) | |||||
| { | |||||
| // If the u value is over the upper limit and no other u | |||||
| // value of that face is 0, round it to 0 | |||||
| if (out[face.mIndices[n]].x > UPPER_LIMIT && !zero) | |||||
| out[face.mIndices[n]].x = 0.f; | |||||
| // If the u value is below the lower limit and no other u | |||||
| // value of that face is 1, round it to 1 | |||||
| else if (out[face.mIndices[n]].x < LOWER_LIMIT && !one) | |||||
| out[face.mIndices[n]].x = 1.f; | |||||
| // The face contains both 0 and 1 as UV coords. This can occur | |||||
| // for faces which have an edge that lies directly on the seam. | |||||
| // Due to numerical inaccuracies one U coord becomes 0, the | |||||
| // other 1. But we do still have a third UV coord to determine | |||||
| // to which side we must round to. | |||||
| else if (one && zero) | |||||
| { | |||||
| if (round_to_zero && out[face.mIndices[n]].x >= UPPER_EPSILON) | |||||
| out[face.mIndices[n]].x = 0.f; | |||||
| else if (!round_to_zero && out[face.mIndices[n]].x <= LOWER_EPSILON) | |||||
| out[face.mIndices[n]].x = 1.f; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void ComputeUVMappingProcess::ComputeSphereMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) | |||||
| { | |||||
| aiVector3D center, min, max; | |||||
| FindMeshCenter(mesh, center, min, max); | |||||
| // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... | |||||
| // currently the mapping axis will always be one of x,y,z, except if the | |||||
| // PretransformVertices step is used (it transforms the meshes into worldspace, | |||||
| // thus changing the mapping axis) | |||||
| if (axis * base_axis_x >= angle_epsilon) { | |||||
| // For each point get a normalized projection vector in the sphere, | |||||
| // get its longitude and latitude and map them to their respective | |||||
| // UV axes. Problems occur around the poles ... unsolvable. | |||||
| // | |||||
| // The spherical coordinate system looks like this: | |||||
| // x = cos(lon)*cos(lat) | |||||
| // y = sin(lon)*cos(lat) | |||||
| // z = sin(lat) | |||||
| // | |||||
| // Thus we can derive: | |||||
| // lat = arcsin (z) | |||||
| // lon = arctan (y/x) | |||||
| for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { | |||||
| const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); | |||||
| out[pnt] = aiVector3D((atan2 (diff.z, diff.y) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, | |||||
| (asin (diff.x) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f); | |||||
| } | |||||
| } | |||||
| else if (axis * base_axis_y >= angle_epsilon) { | |||||
| // ... just the same again | |||||
| for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { | |||||
| const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); | |||||
| out[pnt] = aiVector3D((atan2 (diff.x, diff.z) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, | |||||
| (asin (diff.y) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f); | |||||
| } | |||||
| } | |||||
| else if (axis * base_axis_z >= angle_epsilon) { | |||||
| // ... just the same again | |||||
| for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { | |||||
| const aiVector3D diff = (mesh->mVertices[pnt]-center).Normalize(); | |||||
| out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, | |||||
| (asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f); | |||||
| } | |||||
| } | |||||
| // slower code path in case the mapping axis is not one of the coordinate system axes | |||||
| else { | |||||
| aiMatrix4x4 mTrafo; | |||||
| aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); | |||||
| // again the same, except we're applying a transformation now | |||||
| for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { | |||||
| const aiVector3D diff = ((mTrafo*mesh->mVertices[pnt])-center).Normalize(); | |||||
| out[pnt] = aiVector3D((atan2 (diff.y, diff.x) + AI_MATH_PI_F ) / AI_MATH_TWO_PI_F, | |||||
| (asin (diff.z) + AI_MATH_HALF_PI_F) / AI_MATH_PI_F, 0.f); | |||||
| } | |||||
| } | |||||
| // Now find and remove UV seams. A seam occurs if a face has a tcoord | |||||
| // close to zero on the one side, and a tcoord close to one on the | |||||
| // other side. | |||||
| RemoveUVSeams(mesh,out); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void ComputeUVMappingProcess::ComputeCylinderMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) | |||||
| { | |||||
| aiVector3D center, min, max; | |||||
| // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... | |||||
| // currently the mapping axis will always be one of x,y,z, except if the | |||||
| // PretransformVertices step is used (it transforms the meshes into worldspace, | |||||
| // thus changing the mapping axis) | |||||
| if (axis * base_axis_x >= angle_epsilon) { | |||||
| FindMeshCenter(mesh, center, min, max); | |||||
| const float diff = max.x - min.x; | |||||
| // If the main axis is 'z', the z coordinate of a point 'p' is mapped | |||||
| // directly to the texture V axis. The other axis is derived from | |||||
| // the angle between ( p.x - c.x, p.y - c.y ) and (1,0), where | |||||
| // 'c' is the center point of the mesh. | |||||
| for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { | |||||
| const aiVector3D& pos = mesh->mVertices[pnt]; | |||||
| aiVector3D& uv = out[pnt]; | |||||
| uv.y = (pos.x - min.x) / diff; | |||||
| uv.x = (atan2 ( pos.z - center.z, pos.y - center.y) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI; | |||||
| } | |||||
| } | |||||
| else if (axis * base_axis_y >= angle_epsilon) { | |||||
| FindMeshCenter(mesh, center, min, max); | |||||
| const float diff = max.y - min.y; | |||||
| // just the same ... | |||||
| for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { | |||||
| const aiVector3D& pos = mesh->mVertices[pnt]; | |||||
| aiVector3D& uv = out[pnt]; | |||||
| uv.y = (pos.y - min.y) / diff; | |||||
| uv.x = (atan2 ( pos.x - center.x, pos.z - center.z) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI; | |||||
| } | |||||
| } | |||||
| else if (axis * base_axis_z >= angle_epsilon) { | |||||
| FindMeshCenter(mesh, center, min, max); | |||||
| const float diff = max.z - min.z; | |||||
| // just the same ... | |||||
| for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { | |||||
| const aiVector3D& pos = mesh->mVertices[pnt]; | |||||
| aiVector3D& uv = out[pnt]; | |||||
| uv.y = (pos.z - min.z) / diff; | |||||
| uv.x = (atan2 ( pos.y - center.y, pos.x - center.x) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI; | |||||
| } | |||||
| } | |||||
| // slower code path in case the mapping axis is not one of the coordinate system axes | |||||
| else { | |||||
| aiMatrix4x4 mTrafo; | |||||
| aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); | |||||
| FindMeshCenterTransformed(mesh, center, min, max,mTrafo); | |||||
| const float diff = max.y - min.y; | |||||
| // again the same, except we're applying a transformation now | |||||
| for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt){ | |||||
| const aiVector3D pos = mTrafo* mesh->mVertices[pnt]; | |||||
| aiVector3D& uv = out[pnt]; | |||||
| uv.y = (pos.y - min.y) / diff; | |||||
| uv.x = (atan2 ( pos.x - center.x, pos.z - center.z) +(float)AI_MATH_PI ) / (float)AI_MATH_TWO_PI; | |||||
| } | |||||
| } | |||||
| // Now find and remove UV seams. A seam occurs if a face has a tcoord | |||||
| // close to zero on the one side, and a tcoord close to one on the | |||||
| // other side. | |||||
| RemoveUVSeams(mesh,out); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void ComputeUVMappingProcess::ComputePlaneMapping(aiMesh* mesh,const aiVector3D& axis, aiVector3D* out) | |||||
| { | |||||
| float diffu,diffv; | |||||
| aiVector3D center, min, max; | |||||
| // If the axis is one of x,y,z run a faster code path. It's worth the extra effort ... | |||||
| // currently the mapping axis will always be one of x,y,z, except if the | |||||
| // PretransformVertices step is used (it transforms the meshes into worldspace, | |||||
| // thus changing the mapping axis) | |||||
| if (axis * base_axis_x >= angle_epsilon) { | |||||
| FindMeshCenter(mesh, center, min, max); | |||||
| diffu = max.z - min.z; | |||||
| diffv = max.y - min.y; | |||||
| for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { | |||||
| const aiVector3D& pos = mesh->mVertices[pnt]; | |||||
| out[pnt].Set((pos.z - min.z) / diffu,(pos.y - min.y) / diffv,0.f); | |||||
| } | |||||
| } | |||||
| else if (axis * base_axis_y >= angle_epsilon) { | |||||
| FindMeshCenter(mesh, center, min, max); | |||||
| diffu = max.x - min.x; | |||||
| diffv = max.z - min.z; | |||||
| for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { | |||||
| const aiVector3D& pos = mesh->mVertices[pnt]; | |||||
| out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.f); | |||||
| } | |||||
| } | |||||
| else if (axis * base_axis_z >= angle_epsilon) { | |||||
| FindMeshCenter(mesh, center, min, max); | |||||
| diffu = max.y - min.y; | |||||
| diffv = max.z - min.z; | |||||
| for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { | |||||
| const aiVector3D& pos = mesh->mVertices[pnt]; | |||||
| out[pnt].Set((pos.y - min.y) / diffu,(pos.x - min.x) / diffv,0.f); | |||||
| } | |||||
| } | |||||
| // slower code path in case the mapping axis is not one of the coordinate system axes | |||||
| else | |||||
| { | |||||
| aiMatrix4x4 mTrafo; | |||||
| aiMatrix4x4::FromToMatrix(axis,base_axis_y,mTrafo); | |||||
| FindMeshCenterTransformed(mesh, center, min, max,mTrafo); | |||||
| diffu = max.x - min.x; | |||||
| diffv = max.z - min.z; | |||||
| // again the same, except we're applying a transformation now | |||||
| for (unsigned int pnt = 0; pnt < mesh->mNumVertices;++pnt) { | |||||
| const aiVector3D pos = mTrafo * mesh->mVertices[pnt]; | |||||
| out[pnt].Set((pos.x - min.x) / diffu,(pos.z - min.z) / diffv,0.f); | |||||
| } | |||||
| } | |||||
| // shouldn't be necessary to remove UV seams ... | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void ComputeUVMappingProcess::ComputeBoxMapping( aiMesh*, aiVector3D* ) | |||||
| { | |||||
| DefaultLogger::get()->error("Mapping type currently not implemented"); | |||||
| } | |||||
| // ------------------------------------------------------------------------------------------------ | |||||
| void ComputeUVMappingProcess::Execute( aiScene* pScene) | |||||
| { | |||||
| DefaultLogger::get()->debug("GenUVCoordsProcess begin"); | |||||
| char buffer[1024]; | |||||
| if (pScene->mFlags & AI_SCENE_FLAGS_NON_VERBOSE_FORMAT) | |||||
| throw DeadlyImportError("Post-processing order mismatch: expecting pseudo-indexed (\"verbose\") vertices here"); | |||||
| std::list<MappingInfo> mappingStack; | |||||
| /* Iterate through all materials and search for non-UV mapped textures | |||||
| */ | |||||
| for (unsigned int i = 0; i < pScene->mNumMaterials;++i) | |||||
| { | |||||
| mappingStack.clear(); | |||||
| aiMaterial* mat = pScene->mMaterials[i]; | |||||
| for (unsigned int a = 0; a < mat->mNumProperties;++a) | |||||
| { | |||||
| aiMaterialProperty* prop = mat->mProperties[a]; | |||||
| if (!::strcmp( prop->mKey.data, "$tex.mapping")) | |||||
| { | |||||
| aiTextureMapping& mapping = *((aiTextureMapping*)prop->mData); | |||||
| if (aiTextureMapping_UV != mapping) | |||||
| { | |||||
| if (!DefaultLogger::isNullLogger()) | |||||
| { | |||||
| sprintf(buffer, "Found non-UV mapped texture (%s,%i). Mapping type: %s", | |||||
| TextureTypeToString((aiTextureType)prop->mSemantic),prop->mIndex, | |||||
| MappingTypeToString(mapping)); | |||||
| DefaultLogger::get()->info(buffer); | |||||
| } | |||||
| if (aiTextureMapping_OTHER == mapping) | |||||
| continue; | |||||
| MappingInfo info (mapping); | |||||
| // Get further properties - currently only the major axis | |||||
| for (unsigned int a2 = 0; a2 < mat->mNumProperties;++a2) | |||||
| { | |||||
| aiMaterialProperty* prop2 = mat->mProperties[a2]; | |||||
| if (prop2->mSemantic != prop->mSemantic || prop2->mIndex != prop->mIndex) | |||||
| continue; | |||||
| if ( !::strcmp( prop2->mKey.data, "$tex.mapaxis")) { | |||||
| info.axis = *((aiVector3D*)prop2->mData); | |||||
| break; | |||||
| } | |||||
| } | |||||
| unsigned int idx; | |||||
| // Check whether we have this mapping mode already | |||||
| std::list<MappingInfo>::iterator it = std::find (mappingStack.begin(),mappingStack.end(), info); | |||||
| if (mappingStack.end() != it) | |||||
| { | |||||
| idx = (*it).uv; | |||||
| } | |||||
| else | |||||
| { | |||||
| /* We have found a non-UV mapped texture. Now | |||||
| * we need to find all meshes using this material | |||||
| * that we can compute UV channels for them. | |||||
| */ | |||||
| for (unsigned int m = 0; m < pScene->mNumMeshes;++m) | |||||
| { | |||||
| aiMesh* mesh = pScene->mMeshes[m]; | |||||
| unsigned int outIdx; | |||||
| if ( mesh->mMaterialIndex != i || ( outIdx = FindEmptyUVChannel(mesh) ) == UINT_MAX || | |||||
| !mesh->mNumVertices) | |||||
| { | |||||
| continue; | |||||
| } | |||||
| // Allocate output storage | |||||
| aiVector3D* p = mesh->mTextureCoords[outIdx] = new aiVector3D[mesh->mNumVertices]; | |||||
| switch (mapping) | |||||
| { | |||||
| case aiTextureMapping_SPHERE: | |||||
| ComputeSphereMapping(mesh,info.axis,p); | |||||
| break; | |||||
| case aiTextureMapping_CYLINDER: | |||||
| ComputeCylinderMapping(mesh,info.axis,p); | |||||
| break; | |||||
| case aiTextureMapping_PLANE: | |||||
| ComputePlaneMapping(mesh,info.axis,p); | |||||
| break; | |||||
| case aiTextureMapping_BOX: | |||||
| ComputeBoxMapping(mesh,p); | |||||
| break; | |||||
| default: | |||||
| ai_assert(false); | |||||
| } | |||||
| if (m && idx != outIdx) | |||||
| { | |||||
| DefaultLogger::get()->warn("UV index mismatch. Not all meshes assigned to " | |||||
| "this material have equal numbers of UV channels. The UV index stored in " | |||||
| "the material structure does therefore not apply for all meshes. "); | |||||
| } | |||||
| idx = outIdx; | |||||
| } | |||||
| info.uv = idx; | |||||
| mappingStack.push_back(info); | |||||
| } | |||||
| // Update the material property list | |||||
| mapping = aiTextureMapping_UV; | |||||
| ((aiMaterial*)mat)->AddProperty(&idx,1,AI_MATKEY_UVWSRC(prop->mSemantic,prop->mIndex)); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| DefaultLogger::get()->debug("GenUVCoordsProcess finished"); | |||||
| } | |||||