| @@ -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"); | |||
| } | |||