@@ -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 [![Build Status](https://travis-ci.org/assimp/assimp.png)](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"); | |||
} |