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